OJ在线评测系统 后端基础部分开发 完善CRUD相关接口
完善相关接口
判斷编程语言是否合法
先从用户的请求拿到Language
package com.dduo.dduoj.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dduo.dduoj.common.ErrorCode;
import com.dduo.dduoj.exception.BusinessException;
import com.dduo.dduoj.model.dto.questionsubmit.JudgeInfo;
import com.dduo.dduoj.model.dto.questionsubmit.QuestionSubmitAddRequest;
import com.dduo.dduoj.model.enums.QuestionSubmitLanguageEnum;
import com.dduo.dduoj.model.enums.QuestionSubmitStatusEnum;
import com.dduo.dduoj.service.mapper.QuestionSubmitMapper;
import com.dduo.dduoj.service.mapper.entity.Question;
import com.dduo.dduoj.service.mapper.entity.QuestionSubmit;
import com.dduo.dduoj.service.mapper.entity.User;
import com.dduo.dduoj.service.QuestionService;
import com.dduo.dduoj.service.QuestionSubmitService;
import javax.annotation.Resource;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 提交题目服务实现
*
*/
@Service
public class QuestionSubmitServiceImpl extends ServiceImpl<QuestionSubmitMapper, QuestionSubmit>
implements QuestionSubmitService {
@Resource
private QuestionService questionService;
/**
* 提交题目
*
* @param questionSubmitAddRequest
* @param loginUser
* @return
*/
@Override
public long doQuestionSubmit(QuestionSubmitAddRequest questionSubmitAddRequest, User loginUser) {
// 编程语言是否合法
String language = questionSubmitAddRequest.getLanguage();
QuestionSubmitLanguageEnum enumByValue = QuestionSubmitLanguageEnum.getEnumByValue(language);
if (enumByValue==null){
throw new BusinessException(ErrorCode.PARAMS_ERROR,"编程语言错误");
}
long questionId = questionSubmitAddRequest.getQuestionId();
// 判断实体是否存在,根据类别获取实体
Question question = questionService.getById(questionId);
if (question == null) {
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
}
// 是否提交题目
long userId = loginUser.getId();
// 每个用户串行提交题目
// 锁必须要包裹住事务方法
QuestionSubmit questionSubmit = new QuestionSubmit();
questionSubmit.setUserId(userId);
questionSubmit.setQuestionId(questionId);
questionSubmit.setCode(questionSubmitAddRequest.getCode());
questionSubmit.setLanguage(language);
//设置初始状态
questionSubmit.setStatus(QuestionSubmitStatusEnum.WATING.getValue());
questionSubmit.setJudgeInfo("{}");
boolean save = this.save(questionSubmit);
if(!save){
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"数据插入失败");
}
return questionSubmit.getId();
}
}
写好了 idea启动
代码运行成功
我们
使用接口文档提交题目试一试
数据库中数据录入成功
为了防止用户根据id爬取题目
建议把id的生成规则改成ASSIGN_ID
非连续递增
而不是从1开始递增
数值传到数据库中进行一个转换
/**
* 创建
*
* @param questionAddRequest
* @param request
* @return
*/
@PostMapping("/add")
public BaseResponse<Long> addQuestion(@RequestBody QuestionAddRequest questionAddRequest, HttpServletRequest request) {
if (questionAddRequest == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
Question question = new Question();
BeanUtils.copyProperties(questionAddRequest, question);
List<String> tags = questionAddRequest.getTags();
if (tags != null) {
question.setTags(GSON.toJson(tags));
}
List<JudgeCase> judgeCase = questionAddRequest.getJudgeCase();
if (judgeCase != null) {
question.setJudgeCase(GSON.toJson(judgeCase));
}
List<JudgeConfig> judgeConfig = questionAddRequest.getJudgeConfig();
if (judgeConfig != null) {
question.setJudgeConfig(GSON.toJson(judgeConfig));
}
questionService.validQuestion(question, true);
User loginUser = userService.getLoginUser(request);
question.setUserId(loginUser.getId());
question.setFavourNum(0);
question.setThumbNum(0);
boolean result = questionService.save(question);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
long newQuestionId = question.getId();
return ResultUtils.success(newQuestionId);
}
@PostMapping("/update")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Boolean> updateQuestion(@RequestBody QuestionUpdateRequest questionUpdateRequest) {
if (questionUpdateRequest == null || questionUpdateRequest.getId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
Question question = new Question();
BeanUtils.copyProperties(questionUpdateRequest, question);
List<String> tags = questionUpdateRequest.getTags();
if (tags != null) {
question.setTags(GSON.toJson(tags));
}
List<JudgeCase> judgeCase = questionUpdateRequest.getJudgeCase();
if (judgeCase != null) {
question.setJudgeCase(GSON.toJson(judgeCase));
}
List<JudgeConfig> judgeConfig = questionUpdateRequest.getJudgeConfig();
if (judgeConfig != null) {
question.setJudgeConfig(GSON.toJson(judgeConfig));
}
// 参数校验
questionService.validQuestion(question, false);
long id = questionUpdateRequest.getId();
// 判断是否存在
Question oldQuestion = questionService.getById(id);
ThrowUtils.throwIf(oldQuestion == null, ErrorCode.NOT_FOUND_ERROR);
boolean result = questionService.updateById(question);
return ResultUtils.success(result);
}
@PostMapping("/edit")
public BaseResponse<Boolean> editQuestion(@RequestBody QuestionEditRequest questionEditRequest, HttpServletRequest request) {
if (questionEditRequest == null || questionEditRequest.getId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
Question question = new Question();
BeanUtils.copyProperties(questionEditRequest, question);
List<String> tags = questionEditRequest.getTags();
if (tags != null) {
question.setTags(GSON.toJson(tags));
}
List<JudgeCase> judgeCase = questionEditRequest.getJudgeCase();
if (judgeCase != null) {
question.setJudgeCase(GSON.toJson(judgeCase));
}
List<JudgeConfig> judgeConfig = questionEditRequest.getJudgeConfig();
if (judgeConfig != null) {
question.setJudgeConfig(GSON.toJson(judgeConfig));
}
// 参数校验
questionService.validQuestion(question, false);
User loginUser = userService.getLoginUser(request);
long id = questionEditRequest.getId();
// 判断是否存在
Question oldQuestion = questionService.getById(id);
ThrowUtils.throwIf(oldQuestion == null, ErrorCode.NOT_FOUND_ERROR);
// 仅本人或管理员可编辑
if (!oldQuestion.getUserId().equals(loginUser.getId()) && !userService.isAdmin(loginUser)) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
boolean result = questionService.updateById(question);
return ResultUtils.success(result);
}
枯燥的测试
完善
查询提交信息
接口功能 能够根据用户id 题目id 编程语言 去查询提交记录
注意事项 仅本人和管理员能看见自己提交代码的答案 提交代码
实现方案 先查询
package com.dduo.dduoj.model.dto.questionsubmit;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
//查询请求
@Data
public class QuestionSubmitQueryRequest implements Serializable {
/**
* 编程语言
*/
private String language;
/**
* 提交状态
*/
private Integer status;
/**
* 题目id
*/
private Long questionId;
/**
* 用户id
*/
private Long userId;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
QuestionSubmitVO
/**
* 包装类转对象
*
* @param questionSubmitVO
* @return
*/
public static QuestionSubmit voToObj(QuestionSubmitVO questionSubmitVO) {
if (questionSubmitVO == null) {
return null;
}
QuestionSubmit questionSubmit = new QuestionSubmit();
BeanUtils.copyProperties(questionSubmitVO, questionSubmit);
JudgeInfo judgeInfoObj = questionSubmitVO.getJudgeInfo();
if (judgeInfoObj != null) {
questionSubmit.setJudgeInfo(JSONUtil.toJsonStr(judgeInfoObj));
}
return questionSubmit;
}
/**
* 对象转包装类
*
* @param questionSubmit
* @return
*/
public static QuestionSubmitVO objToVo(QuestionSubmit questionSubmit) {
if (questionSubmit == null) {
return null;
}
QuestionSubmitVO questionSubmitVO = new QuestionSubmitVO();
BeanUtils.copyProperties(questionSubmit, questionSubmitVO);
String judgeInfoStr = questionSubmit.getJudgeInfo();
questionSubmitVO.setJudgeInfo(JSONUtil.toBean(judgeInfoStr, JudgeInfo.class));
return questionSubmitVO;
}
先查询再根据权限去脱敏
/**
* 分页获取题目提交(除了管理员外 普通用户是能看见非答案 提交代码等非公开信息)
*
* @param questionSubmitQueryRequest
* @return
*/
@PostMapping("/list/page")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Page<QuestionSubmitVO>> listQuestionSubmitByPage(@RequestBody QuestionSubmitQueryRequest questionSubmitQueryRequest,HttpServletRequest request) {
long current = questionSubmitQueryRequest.getCurrent();
long size = questionSubmitQueryRequest.getPageSize();
//从数据库中获取信息
Page<QuestionSubmit> questionSubmitPage = questionSubmitService.page(new Page<>(current, size),
questionSubmitService.getQueryWrapper(questionSubmitQueryRequest));
//返回脱敏方法
return ResultUtils.success(questionSubmitService.getQuestionSubmitVOPage(questionSubmitPage,request));
}
脱敏处理
/*
* 单条数据
* */
@Override
public QuestionSubmitVO getQuestionSubmitVO(QuestionSubmit questionSubmit, User loginUser) {
QuestionSubmitVO questionSubmitVO = QuestionSubmitVO.objToVo(questionSubmit);
// 脱敏:仅本人和管理员能看见自己(提交 userId 和登录用户 id 不同)提交的代码
long userId = loginUser.getId();
// 处理脱敏
if (userId != questionSubmit.getUserId() && !userService.isAdmin(loginUser)) {
questionSubmitVO.setCode(null);
}
return questionSubmitVO;
}
/*
* 多条数据
* */
@Override
public Page<QuestionSubmitVO> getQuestionSubmitVOPage(Page<QuestionSubmit> questionSubmitPage, User loginUser) {
List<QuestionSubmit> questionSubmitList = questionSubmitPage.getRecords();
Page<QuestionSubmitVO> questionSubmitVOPage = new Page<>(questionSubmitPage.getCurrent(), questionSubmitPage.getSize(), questionSubmitPage.getTotal());
if (CollectionUtils.isEmpty(questionSubmitList)) {
return questionSubmitVOPage;
}
List<QuestionSubmitVO> questionSubmitVOList = questionSubmitList.stream()
.map(questionSubmit -> getQuestionSubmitVO(questionSubmit, loginUser))
.collect(Collectors.toList());
questionSubmitVOPage.setRecords(questionSubmitVOList);
return questionSubmitVOPage;
}
QuestionSubmitServiceImpl
package com.dduo.dduoj.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dduo.dduoj.common.ErrorCode;
import com.dduo.dduoj.constant.CommonConstant;
import com.dduo.dduoj.exception.BusinessException;
import com.dduo.dduoj.judge.JudgeService;
import com.dduo.dduoj.model.dto.questionsubmit.QuestionSubmitAddRequest;
import com.dduo.dduoj.model.dto.questionsubmit.QuestionSubmitQueryRequest;
import com.dduo.dduoj.model.entity.Question;
import com.dduo.dduoj.model.entity.QuestionSubmit;
import com.dduo.dduoj.model.entity.User;
import com.dduo.dduoj.model.enums.QuestionSubmitLanguageEnum;
import com.dduo.dduoj.model.enums.QuestionSubmitStatusEnum;
import com.dduo.dduoj.mapper.QuestionSubmitMapper;
import com.dduo.dduoj.model.vo.QuestionSubmitVO;
import com.dduo.dduoj.service.QuestionService;
import com.dduo.dduoj.service.QuestionSubmitService;
import javax.annotation.Resource;
import com.dduo.dduoj.service.UserService;
import com.dduo.dduoj.utils.SqlUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* 提交题目服务实现
*
*/
@Service
public class QuestionSubmitServiceImpl extends ServiceImpl<QuestionSubmitMapper, QuestionSubmit>
implements QuestionSubmitService {
@Resource
private QuestionService questionService;
@Resource
private UserService userService;
@Resource
@Lazy
private JudgeService judgeService;
/**
* 提交题目
*
* @param questionSubmitAddRequest
* @param loginUser
* @return
*/
@Override
public long doQuestionSubmit(QuestionSubmitAddRequest questionSubmitAddRequest, User loginUser) {
// 校验编程语言是否合法
String language = questionSubmitAddRequest.getLanguage();
QuestionSubmitLanguageEnum languageEnum = QuestionSubmitLanguageEnum.getEnumByValue(language);
if (languageEnum == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "编程语言错误");
}
long questionId = questionSubmitAddRequest.getQuestionId();
// 判断实体是否存在,根据类别获取实体
Question question = questionService.getById(questionId);
if (question == null) {
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
}
// 是否已提交题目
long userId = loginUser.getId();
// 每个用户串行提交题目
QuestionSubmit questionSubmit = new QuestionSubmit();
questionSubmit.setUserId(userId);
questionSubmit.setQuestionId(questionId);
questionSubmit.setCode(questionSubmitAddRequest.getCode());
questionSubmit.setLanguage(language);
// 设置初始状态
questionSubmit.setStatus(QuestionSubmitStatusEnum.WAITING.getValue());
questionSubmit.setJudgeInfo("{}");
boolean save = this.save(questionSubmit);
if (!save){
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "数据插入失败");
}
Long questionSubmitId = questionSubmit.getId();
// 执行判题服务
CompletableFuture.runAsync(() -> {
judgeService.doJudge(questionSubmitId);
});
return questionSubmitId;
}
/**
* 获取查询包装类(用户根据哪些字段查询,根据前端传来的请求对象,得到 mybatis 框架支持的查询 QueryWrapper 类)
*
* @param questionSubmitQueryRequest
* @return
*/
@Override
public QueryWrapper<QuestionSubmit> getQueryWrapper(QuestionSubmitQueryRequest questionSubmitQueryRequest) {
QueryWrapper<QuestionSubmit> queryWrapper = new QueryWrapper<>();
if (questionSubmitQueryRequest == null) {
return queryWrapper;
}
String language = questionSubmitQueryRequest.getLanguage();
Integer status = questionSubmitQueryRequest.getStatus();
Long questionId = questionSubmitQueryRequest.getQuestionId();
Long userId = questionSubmitQueryRequest.getUserId();
String sortField = questionSubmitQueryRequest.getSortField();
String sortOrder = questionSubmitQueryRequest.getSortOrder();
// 拼接查询条件
queryWrapper.eq(StringUtils.isNotBlank(language), "language", language);
queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);
queryWrapper.eq(ObjectUtils.isNotEmpty(questionId), "questionId", questionId);
queryWrapper.eq(QuestionSubmitStatusEnum.getEnumByValue(status) != null, "status", status);
queryWrapper.eq("isDelete", false);
queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
sortField);
return queryWrapper;
}
/*
* 单条数据
* */
@Override
public QuestionSubmitVO getQuestionSubmitVO(QuestionSubmit questionSubmit, User loginUser) {
QuestionSubmitVO questionSubmitVO = QuestionSubmitVO.objToVo(questionSubmit);
// 脱敏:仅本人和管理员能看见自己(提交 userId 和登录用户 id 不同)提交的代码
long userId = loginUser.getId();
// 处理脱敏
if (userId != questionSubmit.getUserId() && !userService.isAdmin(loginUser)) {
questionSubmitVO.setCode(null);
}
return questionSubmitVO;
}
/*
* 多条数据
* */
@Override
public Page<QuestionSubmitVO> getQuestionSubmitVOPage(Page<QuestionSubmit> questionSubmitPage, User loginUser) {
List<QuestionSubmit> questionSubmitList = questionSubmitPage.getRecords();
Page<QuestionSubmitVO> questionSubmitVOPage = new Page<>(questionSubmitPage.getCurrent(), questionSubmitPage.getSize(), questionSubmitPage.getTotal());
if (CollectionUtils.isEmpty(questionSubmitList)) {
return questionSubmitVOPage;
}
List<QuestionSubmitVO> questionSubmitVOList = questionSubmitList.stream()
.map(questionSubmit -> getQuestionSubmitVO(questionSubmit, loginUser))
.collect(Collectors.toList());
questionSubmitVOPage.setRecords(questionSubmitVOList);
return questionSubmitVOPage;
}
}
controller层代码
/**
* 提交题目
*
* @param questionSubmitAddRequest
* @param request
* @return 提交记录的 id
*/
@PostMapping("/")
public BaseResponse<Long> doQuestionSubmit(@RequestBody QuestionSubmitAddRequest questionSubmitAddRequest,
HttpServletRequest request) {
if (questionSubmitAddRequest == null || questionSubmitAddRequest.getQuestionId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
// 登录才能点赞
final User loginUser = userService.getLoginUser(request);
long questionSubmitId = questionSubmitService.doQuestionSubmit(questionSubmitAddRequest, loginUser);
return ResultUtils.success(questionSubmitId);
}
listQuestionSubmitByPage
/**
* 分页获取题目提交(除了管理员外 普通用户是能看见非答案 提交代码等非公开信息)
*
* @param questionSubmitQueryRequest
* @return
*/
@PostMapping("/list/page")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Page<QuestionSubmitVO>> listQuestionSubmitByPage(@RequestBody QuestionSubmitQueryRequest questionSubmitQueryRequest, HttpServletRequest request) {
long current = questionSubmitQueryRequest.getCurrent();
long size = questionSubmitQueryRequest.getPageSize();
//从数据库中获取信息
Page<QuestionSubmit> questionSubmitPage = questionSubmitService.page(new Page<>(current, size),
questionSubmitService.getQueryWrapper(questionSubmitQueryRequest));
final User loginUser = userService.getLoginUser(request);
//返回脱敏方法
return ResultUtils.success(questionSubmitService.getQuestionSubmitVOPage(questionSubmitPage, loginUser));
}