【项目】【在线判题系统】b端题目增删改

目录

  • 一、新增题目
  • 二、题目编辑
    • [2.1 功能梳理](#2.1 功能梳理)
    • [2.2 获取题目详情](#2.2 获取题目详情)
      • [2.2.1 controller](#2.2.1 controller)
      • [2.2.2 service](#2.2.2 service)
    • [2.3 修改题目](#2.3 修改题目)
      • [2.3.1 controller](#2.3.1 controller)
      • [2.3.2 service](#2.3.2 service)
  • 三、题目删除
    • [3.1 功能梳理](#3.1 功能梳理)
    • [3.2 controller](#3.2 controller)
    • [3.3 service](#3.3 service)
  • 四、题目前端总代码

一、新增题目

1.1、功能梳理

  1. 登录,登录成功之后切换至题目管理
  2. 点击添加题目按钮,弹出抽屉。
  3. 根据所要添加的题目,输入题目的相关信息,点击发布。
  4. 将用户输入的题目信息作为请求参数向后端发起添加题目的请求。
  5. 后端接收请求,对请求参数处理。
  6. 将数据存储到数据库中。
  7. 后端需要将题目添加的结果返回给前端。
  8. 前端接收到端的响应,如果成功:提示用户添加成功,并且在列表中将新增的题目展示在 第一个8如果失败:失败原因提示给用户

1.2 controller

oj-modules/oj-system/src/main/java/com/yj/system/controller/question/QuestionController.java添加新增方法

java 复制代码
    @PostMapping("/add")
    public R<Void> add(@RequestBody @Validated QuestionAddDTO questionAddDTO) {
        return toR(questionService.add(questionAddDTO));
    }

接收请求参数:

oj-modules/oj-system/src/main/java/com/yj/system/domain/question/dto/QuestionAddDTO.java

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

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.Getter;
import lombok.Setter;

/**
 * 题目新增请求参数 DTO
 */
@Getter
@Setter
public class QuestionAddDTO {

    /**
     * 题目标题
     */
    @NotBlank(message = "题目标题不能为空")
    private String title;

    /**
     * 题目难度 1:简单 2:中等 3:困难
     */
    @NotNull(message = "题目难度不能为空")
    @Min(value = 1, message = "题目难度只能是 1、2、3")
    @Max(value = 3, message = "题目难度只能是 1、2、3")
    private Integer difficulty;

    /**
     * 时间限制(单位:ms)
     */
    @NotNull(message = "时间限制不能为空")
    @Positive(message = "时间限制必须为正整数")
    private Integer timeLimit;

    /**
     * 空间限制(单位:MB)
     */
    @NotNull(message = "空间限制不能为空")
    @Positive(message = "空间限制必须为正整数")
    private Integer spaceLimit;

    /**
     * 题目内容
     */
    @NotBlank(message = "题目内容不能为空")
    private String content;

    /**
     * 题目用例
     */
    @NotBlank(message = "题目用例不能为空")
    private String questionCase;

    /**
     * 默认代码块
     */
    @NotBlank(message = "默认代码不能为空")
    private String defaultCode;

    /**
     * 主函数代码
     */
    @NotBlank(message = "main函数不能为空")
    private String mainFuc;
}

1.3 service

oj-modules/oj-system/src/main/java/com/yj/system/service/question/IQuestionService.java新增接口方法:

java 复制代码
    int add(QuestionAddDTO questionAddDTO);

实现接口方法:

  1. 查询标题或者内容有相同的数据没有,没有就进行转换数据插入数据库,有就抛出资源已存在的异常。

oj-modules/oj-system/src/main/java/com/yj/system/service/question/impl/QuestionServiceImpl.java

java 复制代码
    @Override
    public int add(QuestionAddDTO questionAddDTO) {
        // 1.构建查询条件:标题 或 内容 重复
        List<QuestionDO> questionDOS = questionMapper.selectList(
                Wrappers.lambdaQuery(QuestionDO.class)
                        .and(wrapper -> wrapper
                                .eq(QuestionDO::getTitle, questionAddDTO.getTitle())
                                .or()
                                .eq(QuestionDO::getContent, questionAddDTO.getContent())
                        )
        );

        // 2. 如果存在重复数据,抛出异常
        if (CollectionUtil.isNotEmpty(questionDOS)) {
            throw new ServiceException(ResultCodeEnum.FAILED_ALREADY_EXISTS);
        }

        // 3. 拷贝属性并插入
        QuestionDO questionDO = new QuestionDO();
        BeanUtils.copyProperties(questionAddDTO, questionDO);

        // 4. 插入数据库
        return questionMapper.insert(questionDO);
    }

二、题目编辑

2.1 功能梳理

题目编辑功能:

  1. 对需要编辑的题目点击编辑按钮。
  2. 携带题目id向后端发起获取题目详情的请求。
  3. 后端接收到获取题目详情的请求之后,根据题目id从数据库中查询出题目详情,并将查询结果返回给前端展示。(如果查询失败编辑题目流程结束,提示给用户失败的原因)
  4. 根据展示出来的题目详情和对于题目的修改需要对题目的具体信息进行修改。点击发布。
  5. 携带题目id,以及修改之后的内容,向后端发起编辑题目的请求。
  6. 后端接收编辑题目的请求之后,根据题目的id从数据库中查到对应的题目,然后再根据修改之后的题目内容修改数据中存储的题目数据。并且将修改之后的结果返回给前端。
  7. 前端接收到后端返回的响应结果之后,如果成功,提示用户编辑成功,并且再去查看这个题目的信息的时候,应该是修改之后的。如果失败,提示给用户失败的原因。

2.2 获取题目详情

2.2.1 controller

oj-modules/oj-system/src/main/java/com/yj/system/controller/question/QuestionController.java添加方法,根据题目id获得题目信息

java 复制代码
    @GetMapping("/detail")
    public R<QuestionDetailVO> detail(Long questionId) {
        QuestionDetailVO detail = questionService.detail(questionId);
        return R.success(detail);
    }

返回值:

oj-modules/oj-system/src/main/java/com/yj/system/domain/question/vo/QuestionDetailVO.java

java 复制代码
package com.yj.system.domain.question.vo;

import lombok.Getter;
import lombok.Setter;


@Getter
@Setter
public class QuestionDetailVO {


    /**
     * 题目id(主键)
     */
    private Long questionId;

    /**
     * 题目标题
     */
    private String title;

    /**
     * 题目难度 1:简单 2:中等 3:困难
     */
    private Integer difficulty;

    /**
     * 时间限制
     */
    private Integer timeLimit;

    /**
     * 空间限制
     */
    private Integer spaceLimit;

    /**
     * 题目内容
     */
    private String content;

    /**
     * 题目用例
     */
    private String questionCase;

    /**
     * 默认代码
     */
    private String defaultCode;

    /**
     * main函数
     */
    private String mainFuc;
}

2.2.2 service

oj-modules/oj-system/src/main/java/com/yj/system/service/question/IQuestionService.java定义接口方法:

java 复制代码
    QuestionDetailVO detail(Long questionId);

oj-modules/oj-system/src/main/java/com/yj/system/service/question/impl/QuestionServiceImpl.java实现接口方法,查询数据库,如果没有数据抛异常,有进行转化返回。

java 复制代码
    @Override
    public QuestionDetailVO detail(Long questionId) {
        QuestionDO questionDO = questionMapper.selectById(questionId);
        if(null == questionDO) {
            throw new ServiceException(ResultCodeEnum.FAILED_NOT_EXISTS);
        }
        QuestionDetailVO questionDetailVO = new QuestionDetailVO();
        BeanUtils.copyProperties(questionDO, questionDetailVO);
        return questionDetailVO;
    }

2.3 修改题目

2.3.1 controller

oj-modules/oj-system/src/main/java/com/yj/system/controller/question/QuestionController.java添加方法

java 复制代码
    @PutMapping("/edit")
    public R<Void> edit(@RequestBody @Validated QuestionEditDTO questionEditDTO) {
        return toR(questionService.edit(questionEditDTO));
    }

接收参数:

oj-modules/oj-system/src/main/java/com/yj/system/domain/question/dto/QuestionEditDTO.java

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

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

/**
 * 题目新增请求参数 DTO
 */
@Getter
@Setter
public class QuestionEditDTO extends QuestionAddDTO{
    @NotBlank(message = "题目id不能为空")
    private Long questionId;
}

2.3.2 service

oj-modules/oj-system/src/main/java/com/yj/system/service/question/IQuestionService.java定义接口方法:

java 复制代码
    int edit(QuestionEditDTO questionEditDTO);

oj-modules/oj-system/src/main/java/com/yj/system/service/question/impl/QuestionServiceImpl.java实现接口方法

java 复制代码
@Override
    public int edit(QuestionEditDTO questionEditDTO) {
        // 1. 判断题目是否存在
        QuestionDO questionDO = questionMapper.selectById(questionEditDTO.getQuestionId());
        if(null == questionDO) {
            throw new ServiceException(ResultCodeEnum.FAILED_NOT_EXISTS);
        }
        // 2. 判断标题/内容是否与其他题目重复(排除自身)
        List<QuestionDO> list = questionMapper.selectList(
                Wrappers.lambdaQuery(QuestionDO.class)
                        .and(w -> w.eq(QuestionDO::getTitle, questionEditDTO.getTitle())
                                .or()
                                .eq(QuestionDO::getContent, questionEditDTO.getContent()))
                        .ne(QuestionDO::getQuestionId, questionEditDTO.getQuestionId())
        );
        if (CollectionUtil.isNotEmpty(list)) {
            throw new ServiceException(ResultCodeEnum.FAILED_ALREADY_EXISTS);
        }

        // 3. 赋值
        questionDO.setTitle(questionEditDTO.getTitle());
        questionDO.setDifficulty(questionEditDTO.getDifficulty());
        questionDO.setTimeLimit(questionEditDTO.getTimeLimit());
        questionDO.setSpaceLimit(questionEditDTO.getSpaceLimit());
        questionDO.setContent(questionEditDTO.getContent());
        questionDO.setQuestionCase(questionEditDTO.getQuestionCase());
        questionDO.setDefaultCode(questionEditDTO.getDefaultCode());
        questionDO.setMainFuc(questionEditDTO.getMainFuc());

        // 4. 修改
        return questionMapper.updateById(questionDO);
    }

三、题目删除

3.1 功能梳理

题目删除功能:

  1. 找到要删除的题目,点击删除按钮。
  2. 前端携带着题目id向后端发起删除题目的请求。
  3. 后端接收到请求之后,根据题目id删除题目。并将删除的结果返回给前端。(成功或者失败)前端接收后端响应之后,如果成功,提示用户删除成功,并将删除的题目从题目列表中移除。如果失败,提示用户失败原因。

3.2 controller

oj-modules/oj-system/src/main/java/com/yj/system/controller/question/QuestionController.java添加方法

java 复制代码
    @DeleteMapping("/delete")
    public R<Void> delete(Long questionId) {
        return toR(questionService.delete(questionId));
    }

3.3 service

oj-modules/oj-system/src/main/java/com/yj/system/service/question/IQuestionService.java定义接口方法:

java 复制代码
    int delete(Long questionId);

oj-modules/oj-system/src/main/java/com/yj/system/service/question/impl/QuestionServiceImpl.java实现接口方法

java 复制代码
    @Override
    public int delete(Long questionId) {
        // 1. 判断题目是否存在
        QuestionDO questionDO = questionMapper.selectById(questionId);
        if(null == questionDO) {
            throw new ServiceException(ResultCodeEnum.FAILED_NOT_EXISTS);
        }

        return questionMapper.deleteById(questionId);
    }

四、题目前端总代码

java 复制代码
<template>
  <el-form inline="true">
    <el-form-item>
      <selector v-model="params.difficulty" placeholder="请选择题目难度" style="width: 200px;"></selector>
    </el-form-item>
    <el-form-item>
      <el-input v-model="params.title" placeholder="请您输入要搜索的题目标题" />
    </el-form-item>
    <el-form-item>
      <el-button plain @Click="onSearch">搜索</el-button>
      <el-button plain type="info" @click="onReset">重置</el-button>
      <el-button plain type="primary" :icon="Plus" @click="onAddQuestion">添加题目</el-button>
    </el-form-item>
  </el-form>
  <el-table height="526px" :data="questionList">
    <el-table-column prop="questionId" width="180px" label="题目id" />
    <el-table-column prop="title" label="题目标题" />
    <el-table-column prop="difficulty" label="题目难度" width="90px">
      <template #default="{ row }">
        <div v-if="row.difficulty === 1" style="color:#3EC8FF;">简单</div>
        <div v-if="row.difficulty === 2" style="color:#FE7909;">中等</div>
        <div v-if="row.difficulty === 3" style="color:#FD4C40;">困难</div>
      </template>
    </el-table-column>
    <el-table-column prop="createName" label="创建人" width="140px" />
    <el-table-column prop="createTime" label="创建时间" width="180px" />
    <el-table-column label="操作" width="100px" fixed="right">
      <template #default="{ row }">
        <el-button type="text" @click="onEdit(row.questionId)">编辑
        </el-button>
        <el-button type="text" class="red" @click="onDelete(row.questionId)">删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>
  <el-pagination background size="small" layout="total, sizes, prev, pager, next, jumper" :total="total"
    v-model:current-page="params.pageNum"  v-model:page-size="params.pageSize"
    :page-sizes="[1, 5, 10, 15, 20]" @size-change="handleSizeChange" @current-change="handleCurrentChange" />

  <question-drawer ref="questionEditRef" @success="onSuccess"></question-drawer>
</template>

<script setup>
import { Plus } from "@element-plus/icons-vue"
import Selector from "@/components/QuestionSelector.vue"
import { getQuestionListService, delQuestionService } from "@/apis/question"
import { reactive, ref } from "vue";
import QuestionDrawer from "@/components/QuestionDrawer.vue"

const params = reactive({
  pageNum: 1,
  pageSize: 10,
  difficulty: '',
  title: ''
})

const questionList = ref([])
const total = ref(0)

async function getQuestionList() {
  const result = await getQuestionListService(params)
  console.log(result)
  questionList.value = result.rows
  total.value = result.total
}
getQuestionList()

function handleSizeChange(newSize) {
  // params.pageSize = newSize
  params.pageNum = 1
  getQuestionList()
}

function handleCurrentChange(newPage) {
  // params.pageNum = newPage
  getQuestionList()
}

function onSearch() {
  params.pageNum = 1
  getQuestionList()
}

function onReset() {
  params.pageNum = 1
  params.pageSize = 10
  params.title = ''
  params.difficulty = ''
  getQuestionList()
}

const questionEditRef = ref()
// 添加
const onAddQuestion = () => {
  questionEditRef.value.open()
}


function onSuccess(service) {
  if (service === 'add') {
    params.pageNum = 1
  }
  getQuestionList()
}

async function onEdit(questionId) {
  questionEditRef.value.open(questionId)
}

async function onDelete(questionId) {
  await delQuestionService(questionId)
  params.pageNum = 1
  getQuestionList()
}
</script>
相关推荐
Lhappy嘻嘻1 小时前
读懂 JVM:内存模型、类加载机制、分代回收
java·开发语言·jvm
NetX行者1 小时前
Python 工程化入门:从脚本到规范的 Python 项目结构
网络·python
MasonYyp1 小时前
asyncio并发协程
python
小小张说故事2 小时前
Python 的整数为什么永远不会溢出?拆开大整数对象,看 30 位一节的存储与运算代价
python
用户298698530142 小时前
Python 实现 Word 与 TIFF 双向转换的方案
后端·python·api
weixin_307779132 小时前
C++代码实现MATLAB中的spectralcluster函数功能
开发语言·c++·算法·matlab
鸽鸽程序猿2 小时前
【项目】【在线判题系统】c端:竞赛报名
c语言·开发语言
benchmark_cc2 小时前
实时行情和分钟 K 线应该如何配合使用?从信号计算到交易决策的完整分析
大数据·python·数据分析·pandas·量化交易·股票数据·quantdash
Wang's Blog2 小时前
Java 项目实战: 交友项目 - 个人资料管理的需求分析与接口设计
java·开发语言·交友