【项目】【在线判题系统】竞赛新增

目录

一、功能梳理

  1. 不包含题目的竞赛的新增。(不允许发布)
    1.1. 前端携带着用户输入的竞赛基本信息,向后端发起添加竞赛请求。
    1.2. 后端接收到请求之后,对相关参数进行处理,将竞赛信息存入数据库。并且将添加结果返回前端(成功/失败)
    1.3 前端接收到后端的响应之后,如果成功,提示用户添加成功,并且竞赛列表中能够看到新增的竞赛。如果失败,提示用户失败原因。
  2. 包含题目的竞赛的新增。
    2.1. 新增一个不含题目的竞赛。
    2.2. 点击添加题目按钮,发起获取题目列表的请请求。(请求之前实现的题目列表接口即可)
    2.3. 从题目列表中选择题目,点击提交按钮。携带着竞赛id和题目id发起为竞赛添加题目的请求。
    2.4.后端接收到请求后,处理相关的参数将竞赛题目信息存储数据库中。并且将添加结果返回给前端。
    2.5.前端接收后端的响应之后,如果成功竞赛的题目列表中要能看到新增增加进来的竞赛。如果失败的话,提示用户失败原因。

二、controller

oj-modules/oj-system/src/main/java/com/yj/system/controller/exam/ExamController.java添加新增竞赛基本信息和添加竞赛包含题目的两个方法

java 复制代码
    @PostMapping("/add")
    public R<String> add(@RequestBody @Validated ExamAddDTO examAddDTO) {
        return R.success(examService.add(examAddDTO));
    }
    @PostMapping("/question/add")
    public R<Boolean> questionAdd(@RequestBody @Validated ExamQuestionAddDTO examQuestionAddDTOAddDTO) {
        return R.success(examService.questionAdd(examQuestionAddDTOAddDTO));
    }

接收参数:

oj-modules/oj-system/src/main/java/com/yj/system/domain/exam/dto/ExamAddDTO.java,新增竞赛基本信息的参数,竞赛的标题,竞赛的开始时间与结束时间

java 复制代码
package com.yj.system.domain.exam.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;

@Getter
@Setter
public class ExamAddDTO {
    /**
     * 竞赛标题
     */
    @NotBlank(message = "竞赛标题不能为空")
    private String title;

    /**
     * 竞赛开始时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @NotBlank(message = "竞赛开始时间不能为空")
    private LocalDateTime startTime;

    /**
     * 竞赛结束时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @NotBlank(message = "竞赛结束时间不能为空")
    private LocalDateTime endTime;
}

oj-modules/oj-system/src/main/java/com/yj/system/domain/exam/dto/ExamQuestionAddDTO.java,新增竞赛包含题目,参数是竞赛id和题目id的有顺序不重复的集合

java 复制代码
package com.yj.system.domain.exam.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;

import java.util.LinkedHashSet;
import java.util.Set;
@Setter
@Getter
public class ExamQuestionAddDTO {
    /**
     * 竞赛id
     */
    @NotBlank(message = "竞赛id不能为空")
    private Long examId;
    /**
     * 题目id
     */
    private LinkedHashSet<Long> questionIdSet;

}

三、service

oj-modules/oj-system/src/main/java/com/yj/system/service/exam/IExamService.java,接口方法

java 复制代码
    String add(ExamAddDTO examAddDTO);

    boolean questionAdd(ExamQuestionAddDTO examQuestionAddDTOAddDTO);

oj-modules/oj-system/src/main/java/com/yj/system/service/exam/impl/ExamServiceImpl.java实现:在进行竞赛的题目添加的时候,由于后面竞赛修改接口也会使用,所以进行参数的校验的时候需要带上竞赛id.

java 复制代码
   @Override
    public String add(ExamAddDTO examAddDTO) {
        //参数校验,竞赛名称不能重复
        checkExamSaveParams(examAddDTO,null);
        //竞赛已发布不能操作
        extracted(examDO);
        // 3. 拷贝属性并插入
        ExamDO examDO = new ExamDO();
        BeanUtil.copyProperties(examAddDTO,examDO);
        // 4. 插入数据库
         examMapper.insert(examDO);
        return examDO.getExamId().toString();
    }

    @Override
    public boolean questionAdd(ExamQuestionAddDTO examQuestionAddDTOAddDTO) {
        //查询竞赛是否存在
        ExamDO examDO = getExamDO(examQuestionAddDTOAddDTO.getExamId());
        //竞赛是否开始
        checkExamStarted(examDO);
        //竞赛已发布不能操作
        extracted(examDO);
        //查询参数校验
        if(CollectionUtil.isEmpty(examQuestionAddDTOAddDTO.getQuestionIdSet())) return true;

        //查询要插入的题目是否都存在
        Set<Long> questionIdSet = examQuestionAddDTOAddDTO.getQuestionIdSet();
        List<QuestionDO> questionDOS = questionMapper.selectBatchIds(questionIdSet);
        if(CollectionUtil.isEmpty(questionDOS) || questionDOS.size() < questionIdSet.size()) {
            throw new ServiceException(ResultCodeEnum.EXAM_QUESTION_NOT_EXISTS);
        }
        return extracted(questionIdSet, examDO);
    }

    private boolean extracted(Set<Long> questionIdSet, ExamDO examDO) {
        //赋值
        int num = 1;
        List<ExamQuestionDO> examQuestionDOS = new ArrayList<>();
        for(Long questionId : questionIdSet) {
            ExamQuestionDO examQuestionDO = new ExamQuestionDO();
            examQuestionDO.setQuestionId(questionId);
            examQuestionDO.setExamId(examDO.getExamId());
            examQuestionDO.setQuestionOrder(num++);
            examQuestionDOS.add(examQuestionDO);
        }
        //批量插入题目
        return saveBatch(examQuestionDOS);
    }

    private ExamDO getExamDO(Long examId) {
        ExamDO examDO = examMapper.selectById(examId);
        if(null == examDO) {
            throw new ServiceException(ResultCodeEnum.EXAM_NOT_EXISTS);
        }
        return examDO;
    }
    private void checkExamSaveParams(ExamAddDTO examAddDTO, Long examId) {
        // 1.构建查询条件:标题重复
        List<ExamDO> examDOS = examMapper.selectList(new LambdaQueryWrapper<ExamDO>()
                .eq(ExamDO::getTitle, examAddDTO.getTitle())
                .ne(examId != null, ExamDO::getExamId,examId)
        );
        if(CollectionUtil.isNotEmpty(examDOS)) {
            throw new ServiceException(ResultCodeEnum.FAILED_ALREADY_EXISTS);
        }
        //2. 开始时间比现在时间晚, 比结束时间早
        if(examAddDTO.getStartTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCodeEnum.EXAM_START_TIME_BEFORE_CURRENT_TIME);

        }
        if(examAddDTO.getStartTime().isAfter(examAddDTO.getEndTime())) {
            throw new ServiceException(ResultCodeEnum.EXAM_START_TIME_AFTER_END_TIME);

        }
    }
        private  void checkExamStarted(ExamDO examDO) {
        if(examDO.getStartTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCodeEnum.EXAM_STARTED);
        }
    }
    private static void extracted(ExamDO examDO) {
        if(examDO.getStatus().equals(Constants.TRUE)) {
            throw new ServiceException(ResultCodeEnum.EXAM_PUBLISHED);
        }
    }

实现批量添加,继承:

java 复制代码
public class ExamServiceImpl extends ServiceImpl<ExamQuestionMapper,ExamQuestionDO> implements IExamService {}

四、mapper

oj-modules/oj-system/src/main/java/com/yj/system/mapper/exam/ExamQuestionMapper.java

java 复制代码
package com.yj.system.mapper.exam;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yj.system.domain.exam.ExamQuestionDO;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ExamQuestionMapper extends BaseMapper<ExamQuestionDO> {
}
相关推荐
const_qiu4 小时前
第 2.5 章 2.5.6:前端登录、Token 无感续签与路由守卫
java·前端·人工智能·状态模式
时间的情敌4 小时前
《WebGIS 前端的成长路线,三维可视化工程师需要掌握什么》
前端·状态模式
小马不起床6 小时前
Django 后端实战指南_9:前后端完整联调和问题修复
python·django·状态模式
java资料站6 小时前
十四、Spring AI Alibaba · 案例 · 基于 HumanInTheLoop 的内容审核系统
java·spring·状态模式
流星。。方1 天前
小团队官网SEO落地:前端语义化与静态生成的工程实践
前端·状态模式
马优晨1 天前
JAVA 中 VO 实体类是什么意思,为什么要做这个
java·开发语言·状态模式·java vo·java vo是什么
lexiangqicheng1 天前
亮点-组织架构与权限体系
架构·状态模式
小马不起床2 天前
零基础玩转 FastAPI_11:前端后台管理页面
前端·状态模式·fastapi
shmily麻瓜小菜鸡2 天前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式