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

目录

一、功能梳理

  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> {
}
相关推荐
大江东去浪淘尽千古风流人物5 天前
【HexVIO】DSP卸载双目惯性VIO:Hexagon向量化前端与单帧融合调度深度解析
前端·状态模式·slam·dsp·vio·hexagon·移动端加速
吃一碗粉只付一碗钱6 天前
12-给SPA友好的401和403响应
c#·状态模式
sunlifenger6 天前
嵌入式部署,解锁张家港智慧灯杆的“极简组网”密码
科技·状态模式
上火的金鱼妹7 天前
关于多进程sse连接通知的实战
javascript·状态模式·sse
阿俊-全栈开发7 天前
LikeShop 小程序商城首页可配置弹窗的设计与实现(Java + uni-app)
小程序·状态模式·likeshop·likeshop开源商城
lingyubb8 天前
配音工具怎么选?从 TTS 合成链路看 6 个可量化参数
状态模式
平头哥技术团队9 天前
从预订问到退房:一间山野民宿的数字人「旅程地图」——Theme07_Homestay.vue 端到端拆解
状态模式·数字人
未来之窗软件服务10 天前
web网络请求竞态问题与取消方案-东方仙盟
前端·状态模式·仙盟创梦ide·东方仙盟·网络取消
一级新生11 天前
多智能体协作:常用协作模式详解
人工智能·状态模式·agent·多智能体·智能体