完成教师端题库管理:根据条件模糊搜索、新增题目、批量导入题目、编辑题目、分页展示、删除题目等接口

main
whb 3 months ago
parent 0868f2e88e
commit 8d59c46fa8

@ -1,8 +1,35 @@
package com.sztzjy.trade.controller.tch;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.sztzjy.trade.annotation.AnonymousAccess;
import com.sztzjy.trade.entity.StuLearningAssessment;
import com.sztzjy.trade.entity.dto.StuQuestionBankDTO;
import com.sztzjy.trade.entity.dto.StuQuestionBankRemoveDTO;
import com.sztzjy.trade.mapper.StuLearningAssessmentMapper;
import com.sztzjy.trade.service.StuQuestionBankService;
import com.sztzjy.trade.util.ResultEntity;
import com.sztzjy.trade.util.excel.DemoDataListener;
import com.sztzjy.trade.util.file.IFileUtil;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Date;
import java.util.List;
/**
* @author 17803
@ -13,6 +40,118 @@ import org.springframework.web.bind.annotation.RestController;
@Api(tags = "题库管理")
public class TchQuestionBankController {
@Autowired
private IFileUtil iFileUtil;
@Value("${file.path}")
private String filePath;
@Autowired
private StuQuestionBankService questionBankService;
@GetMapping("/getQuestionBankBySchoolId")
@ApiOperation("分页查询获取所有题目")
@AnonymousAccess
public ResultEntity getQuestionBankBySchoolId(@RequestParam("schoolId") String schoolId,
@ApiParam("当前页")@RequestParam(required = false, defaultValue = "1") Integer page,
@ApiParam("每页展示条数")@RequestParam(required = false,defaultValue = "10") Integer size) {
return questionBankService.getQuestionBankBySchoolId(schoolId,page,size);
}
@PostMapping("/searchFunction")
@ApiOperation("分页搜索功能")
@AnonymousAccess
public ResultEntity searchFunction(@RequestBody StuQuestionBankDTO stuQuestionBankDTO){
return questionBankService.searchFunction(stuQuestionBankDTO);
}
@PostMapping("/addQuestionBank")
@ApiOperation("新增题目功能")
@AnonymousAccess
public ResultEntity addQuestionBank(@RequestBody StuLearningAssessment stuLearningAssessment){
return questionBankService.addQuestionBank(stuLearningAssessment);
}
@PostMapping("/editQuestionBank")
@ApiOperation("编辑题目")
@AnonymousAccess
public ResultEntity editQuestionBank(@RequestBody StuLearningAssessment stuLearningAssessment){
return questionBankService.editQuestionBank(stuLearningAssessment);
}
//下架
@PostMapping("/removeQuestionBank")
@ApiOperation("下架题目")
@AnonymousAccess
public ResultEntity removeQuestionBank(@RequestBody StuQuestionBankRemoveDTO questionBankRemoveDTO){
return questionBankService.removeQuestionBank(questionBankRemoveDTO);
}
//删除
@GetMapping("/delQuestionBank")
@ApiOperation("删除题目")
@AnonymousAccess
public ResultEntity delQuestionBank(String topicId){
return questionBankService.delQuestionBank(topicId);
}
@Autowired
private StuLearningAssessmentMapper stuLearningAssessmentMapper;
//批量导入模板
//导入外部Excel格式的数据
@ApiOperation("批量导入")
@PostMapping("/uploadExcel")
@AnonymousAccess
@Transactional(rollbackFor = Exception.class)
public ResultEntity uploadExcel(@RequestPart @ApiParam("文件") MultipartFile file,
@RequestParam(required = false) String userId,
@RequestParam("schoolId") String schoolId) throws IOException {
//校验文件是否为空
DemoDataListener listener = new DemoDataListener(stuLearningAssessmentMapper, userId, schoolId);
// 这里 需要指定读用哪个class去读然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(file.getInputStream(), StuLearningAssessment.class,
listener).sheet().doRead();
// 返回错误列表
listener.getErrorList();
return new ResultEntity<>(HttpStatus.OK, "上传成功",listener.getErrorList());
}
@ApiOperation("题库导入模板下载")
@GetMapping("/templateDown")
@AnonymousAccess
public void templateDown(HttpServletResponse response){
iFileUtil.download(response,"题库导入模板.xlsx");
}
}

@ -3,44 +3,59 @@ package com.sztzjy.trade.entity;
import java.math.BigDecimal;
import java.util.Date;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
*
* @author whb
* stu_learning_assessment
*/
@EqualsAndHashCode
@Data
public class StuLearningAssessment {
@ApiModelProperty(notes = "题目ID")
private String topicId;
@ApiModelProperty(notes = "题干")
@ExcelProperty("题干")
private String topicName;
@ApiModelProperty(notes = "题目类型")
@ExcelProperty("题型")
private String topicType;
@ApiModelProperty(notes = "困难等级")
private String topicDifficultyLevel;
@ApiModelProperty(notes = "分值")
@ExcelProperty("分值")
private BigDecimal topicScore;
@ApiModelProperty(notes = "题目编号")
private Integer topicNumber;
@ApiModelProperty(notes = "选项A")
@ExcelProperty("选项A")
private String optionA;
@ApiModelProperty(notes = "选项B")
@ExcelProperty("选项B")
private String optionB;
@ApiModelProperty(notes = "选项C")
@ExcelProperty("选项C")
private String optionC;
@ApiModelProperty(notes = "选项D")
@ExcelProperty("选项D")
private String optionD;
@ApiModelProperty(notes = "备用选项E")
@ExcelProperty("选项E")
private String optionE;
@ApiModelProperty(notes = "备用选项F")
@ -50,18 +65,22 @@ public class StuLearningAssessment {
private String optionG;
@ApiModelProperty(notes = "正确答案")
@ExcelProperty("答案")
private String answer;
@ApiModelProperty(notes = "选择答案")
private String studentAnswer;
@ApiModelProperty(notes = "答案解析")
@ExcelProperty("解析")
private String questionAnswer;
@ApiModelProperty(notes = "所属课程(先设计放这,没有就为空)")
@ExcelProperty("归属课程")
private String attributionCourses;
@ApiModelProperty(notes = "归属章节")
@ExcelProperty("归属章节")
private String attributionChapter;
@ApiModelProperty(notes = "逻辑删除符(1、存在0、不存在)")

@ -0,0 +1,42 @@
package com.sztzjy.trade.entity.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NonNull;
import org.checkerframework.checker.units.qual.N;
import javax.validation.constraints.NotNull;
//试题管理搜索实体类
/**
* @author 17803
* @date 2024-12-16 14:08
*/
@Data
public class StuQuestionBankDTO {
@ApiModelProperty(notes = "题干")
private String topicName;
@ApiModelProperty(notes = "所属课程")
private String attributionCourses;
@ApiModelProperty(notes = "归属章节")
private String attributionChapter;
@ApiModelProperty(notes = "上架状态1上架0下架")
private Integer listingStatus;
@ApiModelProperty(notes = "学校ID")
@NotNull
private String schoolId;
@ApiModelProperty(notes = "当前页")
private Integer page;
@ApiModelProperty(notes = "每页展示条数")
private Integer size;
}

@ -0,0 +1,24 @@
package com.sztzjy.trade.entity.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author 17803
* @date 2024-12-16 14:39
*/
@Data
public class StuQuestionBankRemoveDTO {
@ApiModelProperty(notes = "题目ID")
private String topicId;
// @ApiModelProperty(notes = "学校ID")
// private String schoolId;
//
//
// @ApiModelProperty(notes = "老师or管理员")
// private String user;
}

@ -0,0 +1,50 @@
package com.sztzjy.trade.service;
import com.sztzjy.trade.entity.StuLearningAssessment;
import com.sztzjy.trade.entity.dto.StuQuestionBankDTO;
import com.sztzjy.trade.entity.dto.StuQuestionBankRemoveDTO;
import com.sztzjy.trade.util.ResultEntity;
/**
* @author 17803
* @date 2024-12-16 13:39
*/
public interface StuQuestionBankService {
/**
*
* @param schoolId
* @return
*/
ResultEntity getQuestionBankBySchoolId(String schoolId,Integer page,Integer size);
/**
*
* @param stuQuestionBankDTO
* @return
*/
ResultEntity searchFunction(StuQuestionBankDTO stuQuestionBankDTO);
/**
*
* @param stuLearningAssessment
* @return
*/
ResultEntity addQuestionBank(StuLearningAssessment stuLearningAssessment);
/**
*
* @param stuLearningAssessment
* @return
*/
ResultEntity editQuestionBank(StuLearningAssessment stuLearningAssessment);
//下架题目
ResultEntity removeQuestionBank(StuQuestionBankRemoveDTO questionBankRemoveDTO);
//删除题目
ResultEntity delQuestionBank(String topicId);
}

@ -0,0 +1,259 @@
package com.sztzjy.trade.service.impl;
import cn.hutool.core.util.IdUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sztzjy.trade.entity.StuLearningAssessment;
import com.sztzjy.trade.entity.StuLearningAssessmentExample;
import com.sztzjy.trade.entity.dto.StuQuestionBankDTO;
import com.sztzjy.trade.entity.dto.StuQuestionBankRemoveDTO;
import com.sztzjy.trade.mapper.StuLearningAssessmentMapper;
import com.sztzjy.trade.service.StuQuestionBankService;
import com.sztzjy.trade.util.ResultEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
/**
* @author 17803
* @date 2024-12-16 13:39
*/
@Service
public class StuQuestionBankServiceImpl implements StuQuestionBankService {
@Autowired
private StuLearningAssessmentMapper stuLearningAssessmentMapper;
/**
*
* @param schoolId
* @return
*/
@Override
public ResultEntity getQuestionBankBySchoolId(String schoolId,Integer page,Integer size) {
if (!StringUtils.hasText(schoolId)){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"schoolId不能为空");
}
//开启分页
PageHelper.startPage(page,size);
//查询当前学校所有题目按照导入时间排序
StuLearningAssessmentExample learningAssessmentExample = new StuLearningAssessmentExample();
//根据创建时间排序
learningAssessmentExample.setOrderByClause("create_time asc");
learningAssessmentExample
.createCriteria()
.andSchoolIdEqualTo(schoolId)
.andLogicEqualTo(1);
List<StuLearningAssessment> stuLearningAssessmentList = stuLearningAssessmentMapper.selectByExample(learningAssessmentExample);
if (stuLearningAssessmentList == null || stuLearningAssessmentList.size() == 0){
return new ResultEntity<>(HttpStatus.OK);
}
PageInfo<StuLearningAssessment> stuLearningAssessmentPageInfo = new PageInfo<>(stuLearningAssessmentList);
return new ResultEntity<>(stuLearningAssessmentPageInfo);
}
/**
*
* @param stuQuestionBankDTO
* @return
*/
@Override
public ResultEntity searchFunction(StuQuestionBankDTO stuQuestionBankDTO) {
if (!StringUtils.hasText(stuQuestionBankDTO.getSchoolId())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"schoolId不能为空");
}
//开启分页
PageHelper.startPage(stuQuestionBankDTO.getPage(),stuQuestionBankDTO.getSize());
//查询当前学校所有题目按照导入时间排序
StuLearningAssessmentExample learningAssessmentExample = new StuLearningAssessmentExample();
//根据创建时间排序
learningAssessmentExample.setOrderByClause("create_time asc");
StuLearningAssessmentExample.Criteria criteria = learningAssessmentExample.createCriteria();
//学校ID 和 没有被逻辑删除题目
criteria.andSchoolIdEqualTo(stuQuestionBankDTO.getSchoolId()).andLogicEqualTo(1);
//题干查询
if (stuQuestionBankDTO.getTopicName()!=null)
{
criteria.andTopicNameLike("%"+stuQuestionBankDTO.getTopicName()+"%");
}
//所属课程
if (stuQuestionBankDTO.getAttributionCourses()!=null)
{
criteria.andTopicNameLike("%"+stuQuestionBankDTO.getAttributionCourses()+"%");
}
//归属章节
if (stuQuestionBankDTO.getAttributionChapter()!=null)
{
criteria.andTopicNameLike("%"+stuQuestionBankDTO.getAttributionChapter()+"%");
}
//上架状态
if (stuQuestionBankDTO.getListingStatus()!=null)
{
criteria.andListingStatusEqualTo(stuQuestionBankDTO.getListingStatus());
}
List<StuLearningAssessment> stuLearningAssessmentList = stuLearningAssessmentMapper.selectByExample(learningAssessmentExample);
if (stuLearningAssessmentList == null || stuLearningAssessmentList.size() == 0){
return new ResultEntity<>(HttpStatus.OK);
}
PageInfo<StuLearningAssessment> stuLearningAssessmentPageInfo = new PageInfo<>(stuLearningAssessmentList);
return new ResultEntity<>(stuLearningAssessmentPageInfo);
}
/**
*
*
* @param stuLearningAssessment
* @return
*/
@Override
public ResultEntity addQuestionBank(StuLearningAssessment stuLearningAssessment) {
if (!StringUtils.hasText(stuLearningAssessment.getSchoolId())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"学校ID不能为空");
}
if (!StringUtils.hasText(stuLearningAssessment.getTopicName())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"题干不能为空");
}
if (!StringUtils.hasText(stuLearningAssessment.getTopicType())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"题目类型不能为空");
}
if (!StringUtils.hasText(stuLearningAssessment.getAnswer())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"正确答案不能为空");
}
if (!StringUtils.hasText(stuLearningAssessment.getUploadUser())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"上传用户不能为空");
}
stuLearningAssessment.setTopicId(System.currentTimeMillis()+IdUtil.simpleUUID());
int i = stuLearningAssessmentMapper.insertSelective(stuLearningAssessment);
if (i>0)
return new ResultEntity<>(HttpStatus.OK);
else
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"新增失败,请联系管理员!");
}
/**
*
* @param stuLearningAssessment
* @return
*/
@Override
public ResultEntity editQuestionBank(StuLearningAssessment stuLearningAssessment) {
if (!StringUtils.hasText(stuLearningAssessment.getTopicId())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"ID不能为空");
}
if (!StringUtils.hasText(stuLearningAssessment.getSchoolId())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"学校ID不能为空");
}
if (!StringUtils.hasText(stuLearningAssessment.getTopicName())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"题干不能为空");
}
if (!StringUtils.hasText(stuLearningAssessment.getTopicType())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"题目类型不能为空");
}
if (!StringUtils.hasText(stuLearningAssessment.getAnswer())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"正确答案不能为空");
}
if (!StringUtils.hasText(stuLearningAssessment.getUploadUser())){
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"上传用户不能为空");
}
int i = stuLearningAssessmentMapper.updateByPrimaryKeySelective(stuLearningAssessment);
if (i>0)
return new ResultEntity<>(HttpStatus.OK);
else
return new ResultEntity<>(HttpStatus.BAD_REQUEST,"编辑失败,请联系管理员!");
}
//下架题目
@Override
public ResultEntity removeQuestionBank(StuQuestionBankRemoveDTO questionBankRemoveDTO) {
//根据题目ID查询数据
StuLearningAssessment learningAssessment = stuLearningAssessmentMapper.selectByPrimaryKey(questionBankRemoveDTO.getTopicId());
learningAssessment.setListingStatus(0);
stuLearningAssessmentMapper.updateByPrimaryKeySelective(learningAssessment);
return new ResultEntity<>(HttpStatus.OK,"下架成功");
}
//删除题目
@Override
public ResultEntity delQuestionBank(String topicId) {
StuLearningAssessment learningAssessment = stuLearningAssessmentMapper.selectByPrimaryKey(topicId);
learningAssessment.setLogic(0);
stuLearningAssessmentMapper.updateByPrimaryKeySelective(learningAssessment);
return new ResultEntity<>(HttpStatus.OK,"删除成功");
}
}

@ -0,0 +1,183 @@
package com.sztzjy.trade.util.excel;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ConverterUtils;
import com.alibaba.excel.util.ListUtils;
import com.sztzjy.trade.entity.StuLearningAssessment;
import com.sztzjy.trade.mapper.StuLearningAssessmentMapper;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
// 有个很重要的点 DemoDataListener 不能被spring管理要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener<StuLearningAssessment> {
/**
* 5使100list 便
*/
private static final int BATCH_COUNT = 200;
/**
*
*/
private List<StuLearningAssessment> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
* DAOservice
*/
private StuLearningAssessmentMapper demoDAO;
private String userId;
private String schoolId;
// 存储错误信息
private List<String> errorList = new ArrayList<>();
List<String> list = new ArrayList<String>();
/**
* 使spring,使Listenerspring
*
* @param demoDAO
*/
public DemoDataListener(StuLearningAssessmentMapper demoDAO, String userId, String schoolId) {
this.schoolId = schoolId;
this.userId = userId;
this.demoDAO = demoDAO;
}
/**
*
*
* @param headMap
* @param context
*/
@Override
public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
// log.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
Map<Integer, String> integerStringMap = ConverterUtils.convertToStringMap(headMap, context);
//log.info("转换解析到的一条头数据:{}", integerStringMap);
Set<Integer> integers = integerStringMap.keySet();
for (Integer integer : integers) {
list.add(integerStringMap.get(integer));
}
// 如果想转成成 Map<Integer,String>
// 方案1 不要implements ReadListener 而是 extends AnalysisEventListener
// 方案2 调用 ConverterUtils.convertToStringMap(headMap, context) 自动会转换
}
/**
*
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(StuLearningAssessment data, AnalysisContext context) {
StringBuilder errorMsg = new StringBuilder();
boolean isValid = true;
// 校验 data 中的字段,:
if (data.getAttributionCourses() == null || data.getAttributionCourses().isEmpty()) {
isValid = false;
errorMsg.append("归属课程为空");
}
if (data.getAttributionChapter() == null || data.getAttributionChapter().isEmpty()) {
isValid = false;
errorMsg.append("归属章节为空");
}
if (data.getTopicType() == null || data.getTopicType().isEmpty()) {
isValid = false;
errorMsg.append("题型为空");
}
if (data.getTopicName() == null || data.getTopicName().isEmpty()) {
isValid = false;
errorMsg.append("题干为空");
}
if (data.getTopicScore() == null) {
isValid = false;
errorMsg.append("分值为空");
}
if (data.getAnswer() == null || data.getAnswer().isEmpty()) {
isValid = false;
errorMsg.append("答案为空");
}
if (!isValid) {
// 如果校验失败,将错误信息记录下来
errorList.add("第" + (context.readRowHolder().getRowIndex() + 1) +"行"+ ": " + errorMsg.toString());
} else {
cachedDataList.add(data);
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
// //log.info("解析到一条数据:{}", JSON.toJSONString(data));
// cachedDataList.add(data);
// // 达到BATCH_COUNT了需要去存储一次数据库防止数据几万条数据在内存容易OOM
// if (cachedDataList.size() >= BATCH_COUNT) {
// saveData();
// // 存储完成清理 list
// cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
// }
}
/**
*
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
saveData();
log.info("所有数据解析完成!" + ",当前线程:" + Thread.currentThread().getName());
}
/**
*
*/
private void saveData() {
//数据量比较小遍历导入
cachedDataList.forEach(item -> {
item.setTopicId(IdUtil.simpleUUID() + System.currentTimeMillis());
item.setSchoolId(schoolId);
item.setUploadUser(userId);
demoDAO.insertSelective(item);
});
}
// 添加一个方法来获取错误列表
public List<String> getErrorList() {
return errorList;
}
}
Loading…
Cancel
Save