目录
- 一、新增题目
-
- 1.1、功能梳理
- [1.2 controller](#1.2 controller)
- [1.3 service](#1.3 service)
- 二、题目编辑
-
- [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、功能梳理
- 登录,登录成功之后切换至题目管理
- 点击添加题目按钮,弹出抽屉。
- 根据所要添加的题目,输入题目的相关信息,点击发布。
- 将用户输入的题目信息作为请求参数向后端发起添加题目的请求。
- 后端接收请求,对请求参数处理。
- 将数据存储到数据库中。
- 后端需要将题目添加的结果返回给前端。
- 前端接收到端的响应,如果成功:提示用户添加成功,并且在列表中将新增的题目展示在 第一个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);
实现接口方法:
- 查询标题或者内容有相同的数据没有,没有就进行转换数据插入数据库,有就抛出资源已存在的异常。
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 功能梳理
题目编辑功能:
- 对需要编辑的题目点击编辑按钮。
- 携带题目id向后端发起获取题目详情的请求。
- 后端接收到获取题目详情的请求之后,根据题目id从数据库中查询出题目详情,并将查询结果返回给前端展示。(如果查询失败编辑题目流程结束,提示给用户失败的原因)
- 根据展示出来的题目详情和对于题目的修改需要对题目的具体信息进行修改。点击发布。
- 携带题目id,以及修改之后的内容,向后端发起编辑题目的请求。
- 后端接收编辑题目的请求之后,根据题目的id从数据库中查到对应的题目,然后再根据修改之后的题目内容修改数据中存储的题目数据。并且将修改之后的结果返回给前端。
- 前端接收到后端返回的响应结果之后,如果成功,提示用户编辑成功,并且再去查看这个题目的信息的时候,应该是修改之后的。如果失败,提示给用户失败的原因。
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 功能梳理
题目删除功能:
- 找到要删除的题目,点击删除按钮。
- 前端携带着题目id向后端发起删除题目的请求。
- 后端接收到请求之后,根据题目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>