2002YJUN 1 year ago
parent aa4270e61b
commit 811ea95957

@ -0,0 +1,305 @@
package com.yf.exam.modules.qu.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.yf.exam.core.api.ApiRest;
import com.yf.exam.core.api.controller.BaseController;
import com.yf.exam.core.api.dto.BaseIdReqDTO;
import com.yf.exam.core.api.dto.BaseIdRespDTO;
import com.yf.exam.core.api.dto.BaseIdsReqDTO;
import com.yf.exam.core.api.dto.PagingReqDTO;
import com.yf.exam.core.exception.ServiceException;
import com.yf.exam.core.utils.BeanMapper;
import com.yf.exam.core.utils.excel.ExportExcel;
import com.yf.exam.core.utils.excel.ImportExcel;
import com.yf.exam.modules.qu.dto.QuDTO;
import com.yf.exam.modules.qu.dto.export.QuExportDTO;
import com.yf.exam.modules.qu.dto.ext.QuDetailDTO;
import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO;
import com.yf.exam.modules.qu.entity.Qu;
import com.yf.exam.modules.qu.service.QuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
///**
// * <p>
// * 问题题目控制器
// * </p>
// *
// * @author 聪明笨狗
// * @since 2020-05-25 13:25
// */
@Api(tags={"问题题目"})
@RestController
@RequestMapping("/exam/api/qu/qu")
public class QuController extends BaseController {
@Autowired
private QuService baseService;
// /**
// * 添加或修改问题题目
// *
// * @param reqDTO 包含问题题目的详细信息
// * @return ApiRest 对象,包含操作结果信息
// */
@RequiresRoles("sa")
@ApiOperation(value = "添加或修改问题题目")
@RequestMapping(value = "/save", method = {RequestMethod.POST})
public ApiRest<BaseIdRespDTO> save(@RequestBody QuDetailDTO reqDTO) {
baseService.save(reqDTO);
return super.success();
}
// /**
// * 批量删除问题题目
// *
// * @param reqDTO 包含要删除的问题题目的ID列表
// * @return ApiRest 对象,包含操作结果信息
// */
@RequiresRoles("sa")
@ApiOperation(value = "批量删除问题题目")
@RequestMapping(value = "/delete", method = {RequestMethod.POST})
public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) {
// 根据ID删除问题题目
baseService.delete(reqDTO.getIds());
return super.success();
}
// /**
// * 查找问题题目的详情
// *
// * @param reqDTO 包含要查询的问题题目的ID
// * @return ApiRest 对象,包含问题题目的详细信息
// */
@ApiOperation(value = "查找问题题目的详情")
@RequestMapping(value = "/detail", method = {RequestMethod.POST})
public ApiRest<QuDetailDTO> detail(@RequestBody BaseIdReqDTO reqDTO) {
QuDetailDTO dto = baseService.detail(reqDTO.getId());
return super.success(dto);
}
// /**
// * 分页查找问题题目
// *
// * @param reqDTO 包含分页查询的条件
// * @return ApiRest 对象,包含分页后的问题题目列表
// */
@RequiresRoles("sa")
@ApiOperation(value = "分页查找问题题目")
@RequestMapping(value = "/paging", method = {RequestMethod.POST})
public ApiRest<IPage<QuDTO>> paging(@RequestBody PagingReqDTO<QuQueryReqDTO> reqDTO) {
// 分页查询并转换为DTO对象
IPage<QuDTO> page = baseService.paging(reqDTO);
return super.success(page);
}
// /**
// * 导出Excel文件
// *
// * @param response HttpServletResponse 对象用于处理HTTP响应
// * @param reqDTO 包含查询条件的请求DTO对象
// * @return ApiRest 对象,包含导出结果信息
// */
@RequiresRoles("sa")
@ResponseBody
@RequestMapping(value = "/export")
public ApiRest exportFile(HttpServletResponse response, @RequestBody QuQueryReqDTO reqDTO) {
// 导出文件名
String fileName = "导出的试题-" + System.currentTimeMillis() + ".xlsx";
try {
int no = 0;
String quId = "";
// 获取要导出的问题列表
List<QuExportDTO> list = baseService.listForExport(reqDTO);
for (QuExportDTO item : list) {
// 如果QId不同则增加题目序号
if (!quId.equals(item.getQId())) {
quId = item.getQId();
no += 1;
} else {
// 如果QId相同则清空部分重复信息
item.setQuType("0");
item.setQContent("");
item.setQAnalysis("");
item.setRepoList(null);
item.setQImage("");
item.setQVideo("");
}
item.setNo(String.valueOf(no));
}
// 导出Excel文件
new ExportExcel("试题", QuExportDTO.class).setDataList(list).write(response, fileName).dispose();
return super.success();
} catch (Exception e) {
return failure(e.getMessage());
}
}
// /**
// * 导入Excel文件
// *
// * @param file 上传的Excel文件
// * @return ApiRest 对象,包含导入结果信息
// */
@RequiresRoles("sa")
@ResponseBody
@RequestMapping(value = "/import")
public ApiRest importFile(@RequestParam("file") MultipartFile file) {
try {
// 创建ImportExcel对象读取文件从第二行开始不使用表头
ImportExcel ei = new ImportExcel(file, 1, 0);
// 获取Excel文件中的数据列表并转换为QuExportDTO对象
List<QuExportDTO> list = ei.getDataList(QuExportDTO.class);
// 校验Excel数据的有效性
this.checkExcel(list);
// 导入数据条数
baseService.importExcel(list);
// 导入成功
return super.success();
} catch (IOException e) {
// 处理文件读取异常
} catch (InvalidFormatException e) {
// 处理Excel文件格式无效异常
} catch (IllegalAccessException e) {
// 处理数据访问异常
} catch (InstantiationException e) {
// 处理实例化异常
}
return super.failure();
}
// /**
// * 校验Excel数据的有效性
// *
// * @param list 包含从Excel导入的问题数据列表
// * @throws ServiceException 如果数据校验失败抛出ServiceException异常
// */
private void checkExcel(List<QuExportDTO> list) throws ServiceException {
// 约定第三行开始导入
int line = 3;
StringBuffer sb = new StringBuffer();
if (CollectionUtils.isEmpty(list)) {
throw new ServiceException(1, "您导入的数据似乎是一个空表格!");
}
Integer quNo = null;
for (QuExportDTO item : list) {
System.out.println(item.getNo());
if (StringUtils.isBlank(item.getNo())) {
line++;
continue;
}
System.out.println(item.getQContent());
Integer no;
try {
no = Integer.parseInt(item.getNo());
} catch (Exception e) {
line++;
continue;
}
if (no == null) {
sb.append("第" + line + "行,题目序号不能为空!<br>");
}
if (quNo == null || !quNo.equals(no)) {
if (item.getQuType() == null) {
sb.append("第" + line + "行,题目类型不能为空<br>");
}
if (StringUtils.isBlank(item.getQContent())) {
sb.append("第" + line + "行,题目内容不能为空<br>");
}
if (CollectionUtils.isEmpty(item.getRepoList())) {
sb.append("第" + line + "行,题目必须包含一个题库<br>");
}
}
if (StringUtils.isBlank(item.getAIsRight())) {
sb.append("第" + line + "行,选项是否正确不能为空<br>");
}
if (StringUtils.isBlank(item.getAContent()) && StringUtils.isBlank(item.getAImage())) {
sb.append("第" + line + "行,选项内容和选项图片必须有一个不为空<br>");
}
quNo = no;
line++;
}
// 如果存在错误信息抛出ServiceException异常
if (!"".equals(sb.toString())) {
throw new ServiceException(1, sb.toString());
}
}
// /**
// * 下载导入试题数据模板
// *
// * @param response HttpServletResponse 对象用于处理HTTP响应
// * @return ApiRest 对象,包含下载结果信息
// */
@ResponseBody
@RequestMapping(value = "import/template")
public ApiRest importFileTemplate(HttpServletResponse response) {
try {
String fileName = "试题导入模板.xlsx";
List<QuExportDTO> list = Lists.newArrayList();
// 创建模板数据
QuExportDTO l1 = new QuExportDTO();
l1.setNo("正式导入,请删除此说明行:数字,相同的数字表示同一题的序列");
l1.setQContent("问题内容");
l1.setQAnalysis("整个问题的解析");
l1.setQuType("只能填写1、2、3、41表示单选题2表示多选题3表示判断题4表示主观题");
l1.setQImage("题目图片完整URL多个用逗号隔开限制10个");
l1.setQVideo("题目视频完整URL只限一个");
l1.setAImage("答案图片完整URL只限一个");
l1.setRepoList(Arrays.asList(new String[]{"已存在题库的ID多个用逗号隔开题库ID错误无法导入"}));
l1.setAContent("候选答案1");
l1.setAIsRight("只能填写0或10表示否1表示是");
l1.setAAnalysis("这个项是正确的");
QuExportDTO l2 = new QuExportDTO();
l2.setQContent("找出以下可以被2整除的数多选");
l2.setQAnalysis("最基本的数学题,不做过多解析");
l2.setQuType("2");
l2.setNo("1");
l2.setAIsRight("1");
l2.setAContent("数字2");
l2.setAAnalysis("2除以2=1对的");
QuExportDTO l3 = new QuExportDTO();
l3.setNo("1");
l3.setAIsRight("0");
l3.setAContent("数字3");
l3.setAAnalysis("3除以2=1.5,不能被整除");
QuExportDTO l4 = new QuExportDTO();
l4.setNo("1");
l4.setAIsRight("1");
l4.setAContent("数字6");
l4.setAAnalysis("6除以2=3对的");
list.add(l1);
list.add(l2);
list.add(l3);
list.add(l4);
// 导出Excel模板文件
new ExportExcel("试题数据", QuExportDTO.class, 1).setDataList(list).write(response, fileName).dispose();
return super.success();
} catch (Exception e) {
return super.failure("导入模板下载失败!失败信息:" + e.getMessage());
}
}
}

@ -0,0 +1,56 @@
package com.yf.exam.modules.qu.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
///**
// * <p>
// * 候选答案请求类
// * </p>
// *
// * @author 聪明笨狗
// * @since 2020-05-25 13:23
// */
@Data
@ApiModel(value="候选答案", description="候选答案")
public class QuAnswerDTO implements Serializable {
private static final long serialVersionUID = 1L;
// /**
// * 答案的唯一标识ID
// */
@ApiModelProperty(value = "答案ID", required=true)
private String id;
// /**
// * 所属问题的唯一标识ID
// */
@ApiModelProperty(value = "问题ID", required=true)
private String quId;
// /**
// * 表示该答案是否正确
// */
@ApiModelProperty(value = "是否正确", required=true)
private Boolean isRight;
// /**
// * 选项的图片URL
// */
@ApiModelProperty(value = "选项图片", required=true)
private String image;
// /**
// * 答案的具体内容
// */
@ApiModelProperty(value = "答案内容", required=true)
private String content;
// /**
// * 对该答案的分析说明
// */
@ApiModelProperty(value = "答案分析", required=true)
private String analysis;
}

@ -0,0 +1,75 @@
package com.yf.exam.modules.qu.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
// * <p>
// * 问题题目请求类
// * </p>
// *
// * @author 聪明笨狗
// * @since 2020-05-25 13:23
// */
@Data
@ApiModel(value="问题题目", description="问题题目")
public class QuDTO implements Serializable {
private static final long serialVersionUID = 1L;
// /**
// * 题目的唯一标识ID
// */
@ApiModelProperty(value = "题目ID", required=true)
private String id;
// /**
// * 题目的类型
// */
@ApiModelProperty(value = "题目类型", required=true)
private Integer quType;
// /**
// * 题目的难度级别1表示普通2表示较难
// */
@ApiModelProperty(value = "1普通,2较难", required=true)
private Integer level;
// /**
// * 题目的图片URL
// */
@ApiModelProperty(value = "题目图片", required=true)
private String image;
// /**
// * 题目的具体内容
// */
@ApiModelProperty(value = "题目内容", required=true)
private String content;
// /**
// * 题目的创建时间
// */
@ApiModelProperty(value = "创建时间", required=true)
private Date createTime;
// /**
// * 题目的更新时间
// */
@ApiModelProperty(value = "更新时间", required=true)
private Date updateTime;
// /**
// * 题目的备注信息
// */
@ApiModelProperty(value = "题目备注", required=true)
private String remark;
// /**
// * 题目的整题解析
// */
@ApiModelProperty(value = "整题解析", required=true)
private String analysis;
}

@ -0,0 +1,49 @@
package com.yf.exam.modules.qu.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
///**
// * <p>
// * 试题题库请求类
// * </p>
// *
// * @author 聪明笨狗
// * @since 2020-05-25 13:23
// */
@Data
@ApiModel(value="试题题库", description="试题题库")
public class QuRepoDTO implements Serializable {
private static final long serialVersionUID = 1L;
// /**
// * 题库记录的唯一标识ID
// */
private String id;
// /**
// * 关联试题的唯一标识ID
// */
@ApiModelProperty(value = "试题", required=true)
private String quId;
// /**
// * 归属题库的唯一标识ID
// */
@ApiModelProperty(value = "归属题库", required=true)
private String repoId;
// /**
// * 试题的类型
// */
@ApiModelProperty(value = "题目类型", required=true)
private Integer quType;
// /**
// * 试题在题库中的排序顺序
// */
@ApiModelProperty(value = "排序", required=true)
private Integer sort;
}

@ -0,0 +1,86 @@
package com.yf.exam.modules.qu.dto.export;
import com.yf.exam.core.utils.excel.annotation.ExcelField;
import com.yf.exam.core.utils.excel.fieldtype.ListType;
import lombok.Data;
import java.util.List;
///**
// * 用于导出的数据结构
// * @author bool
// */
@Data
public class QuExportDTO {
private static final long serialVersionUID = 1L;
//
// /**
// * 问题题目的唯一标识ID
// */
private String qId;
// /**
// * 题目序号
// */
@ExcelField(title="题目序号", align=2, sort=1)
private String no;
// /**
// * 题目类型
// */
@ExcelField(title="题目类型", align=2, sort=2)
private String quType;
// /**
// * 题目内容
// */
@ExcelField(title="题目内容", align=2, sort=3)
private String qContent;
// /**
// * 整体解析
// */
@ExcelField(title="整体解析", align=2, sort=4)
private String qAnalysis;
// /**
// * 题目图片完整URL多个用逗号隔开限制10个
// */
@ExcelField(title="题目图片", align=2, sort=5)
private String qImage;
//
// /**
// * 题目视频完整URL只限一个
// */
@ExcelField(title="题目视频", align=2, sort=6)
private String qVideo;
// /**
// * 所属题库的ID列表
// */
@ExcelField(title="所属题库", align=2, sort=7, fieldType = ListType.class)
private List<String> repoList;
// /**
// * 是否为正确项0表示否1表示是
// */
@ExcelField(title="是否正确项", align=2, sort=8)
private String aIsRight;
//
// /**
// * 选项内容
// */
@ExcelField(title="选项内容", align=2, sort=9)
private String aContent;
// /**
// * 选项解析
// */
@ExcelField(title="选项解析", align=2, sort=10)
private String aAnalysis;
// /**
// * 选项图片完整URL只限一个
// */
@ExcelField(title="选项图片", align=2, sort=11)
private String aImage;
}

@ -0,0 +1,44 @@
package com.yf.exam.modules.qu.dto.export;
import com.yf.exam.modules.qu.dto.QuAnswerDTO;
import lombok.Data;
import java.util.List;
///**
// * 用于导入的数据结构
// * @author bool
// */
@Data
public class QuImportDTO {
private static final long serialVersionUID = 1L;
// /**
// * 题目类型
// */
private String quType;
// /**
// * 题目内容
// */
private String qContent;
// /**
// * 整体解析
// */
private String qAnalysis;
// /**
// * 题目图片完整URL
// */
private String qImage;
// /**
// * 所属题库名称
// */
private String repoName;
// /**
// * 答案列表
// */
private List<QuAnswerDTO> answerList;
}

@ -0,0 +1,34 @@
package com.yf.exam.modules.qu.dto.ext;
import com.yf.exam.modules.qu.dto.QuAnswerDTO;
import com.yf.exam.modules.qu.dto.QuDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
///**
// * <p>
// * 问题题目请求类
// * </p>
// *
// * @author 聪明笨狗
// * @since 2020-05-25 13:23
// */
@Data
@ApiModel(value="问题题目详情", description="问题题目详情")
public class QuDetailDTO extends QuDTO {
private static final long serialVersionUID = 1L;
// /**
// * 备选项列表
// */
@ApiModelProperty(value = "备选项列表", required=true)
private List<QuAnswerDTO> answerList;
// /**
// * 题库ID列表
// */
@ApiModelProperty(value = "题库列表", required=true)
private List<String> repoIds;
}

@ -0,0 +1,45 @@
package com.yf.exam.modules.qu.dto.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
///**
// * <p>
// * 题目查询请求类
// * </p>
// *
// * @author 聪明笨狗
// * @since 2020-05-25 13:23
// */
@Data
@ApiModel(value="题目查询请求类", description="题目查询请求类")
public class QuQueryReqDTO implements Serializable {
private static final long serialVersionUID = 1L;
// /**
// * 题目类型
// */
@ApiModelProperty(value = "题目类型")
private Integer quType;
// /**
// * 归属题库ID列表
// */
@ApiModelProperty(value = "归属题库")
private List<String> repoIds;
// /**
// * 题目内容的关键字
// */
@ApiModelProperty(value = "题目内容")
private String content;
// /**
// * 需要排除的题目ID列表
// */
@ApiModelProperty(value = "排除ID列表")
private List<String> excludes;
}

@ -0,0 +1,39 @@
package com.yf.exam.modules.qu.dto.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
///**
// * <p>
// * 试题题库批量操作类
// * </p>
// *
// * @author 聪明笨狗
// * @since 2020-05-25 13:23
// */
@Data
@ApiModel(value="试题题库批量操作类", description="试题题库批量操作类")
public class QuRepoBatchReqDTO implements Serializable {
private static final long serialVersionUID = 1L;
// /**
// * 题目ID列表
// */
@ApiModelProperty(value = "题目ID", required=true)
private List<String> quIds;
//
// /**
// * 题库ID列表
// */
@ApiModelProperty(value = "题目类型", required=true)
private List<String> repoIds;
// /**
// * 是否移除题目false表示新增true表示移除
// */
@ApiModelProperty(value = "是否移除,否就新增;是就移除", required=true)
private Boolean remove;
}

@ -0,0 +1,75 @@
package com.yf.exam.modules.qu.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import java.util.Date;
///**
//* <p>
//* 问题题目实体类
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
@Data
@TableName("el_qu")
public class Qu extends Model<Qu> {
private static final long serialVersionUID = 1L;
// /**
// * 题目ID
// */
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
// /**
// * 题目类型
// */
@TableField("qu_type")
private Integer quType;
// /**
// * 1普通,2较难
// */
private Integer level;
// /**
// * 题目图片
// */
private String image;
// /**
// * 题目内容
// */
private String content;
// /**
// * 创建时间
// */
@TableField("create_time")
private Date createTime;
// /**
// * 更新时间
// */
@TableField("update_time")
private Date updateTime;
// /**
// * 题目备注
// */
private String remark;
// /**
// * 整题解析
// */
private String analysis;
}

@ -0,0 +1,58 @@
package com.yf.exam.modules.qu.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
///**
//* <p>
//* 候选答案实体类
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
@Data
@TableName("el_qu_answer")
public class QuAnswer extends Model<QuAnswer> {
private static final long serialVersionUID = 1L;
// /**
// * 答案ID
// */
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
// /**
// * 问题ID
// */
@TableField("qu_id")
private String quId;
// /**
// * 是否正确
// */
@TableField("is_right")
private Boolean isRight;
// /**
// * 选项图片
// */
private String image;
// /**
// * 答案内容
// */
private String content;
/**
*
*/
private String analysis;
}

@ -0,0 +1,50 @@
package com.yf.exam.modules.qu.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
///**
//* <p>
//* 试题题库实体类
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
@Data
@TableName("el_qu_repo")
public class QuRepo extends Model<QuRepo> {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
// /**
// * 试题
// */
@TableField("qu_id")
private String quId;
// /**
// * 归属题库
// */
@TableField("repo_id")
private String repoId;
// /**
// * 题目类型
// */
@TableField("qu_type")
private Integer quType;
// /**
// * 排序
// */
private Integer sort;
}

@ -0,0 +1,26 @@
package com.yf.exam.modules.qu.enums;
///**
// * 题目类型
// * @author bool
// * @date 2019-10-30 13:11
// */
public interface QuType {
// /**
// * 单选题
// */
Integer RADIO = 1;
// /**
// * 多选题
// */
Integer MULTI = 2;
// /**
// * 判断题
// */
Integer JUDGE = 3;
}

@ -0,0 +1,16 @@
package com.yf.exam.modules.qu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yf.exam.modules.qu.entity.QuAnswer;
///**
//* <p>
//* 候选答案Mapper
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
public interface QuAnswerMapper extends BaseMapper<QuAnswer> {
}

@ -0,0 +1,56 @@
package com.yf.exam.modules.qu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yf.exam.modules.qu.dto.QuDTO;
import com.yf.exam.modules.qu.dto.export.QuExportDTO;
import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO;
import com.yf.exam.modules.qu.entity.Qu;
import org.apache.ibatis.annotations.Param;
import java.util.List;
///**
//* <p>
//* 问题题目Mapper
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
public interface QuMapper extends BaseMapper<Qu> {
// /**
// * 随机抽取题库的数据
// * @param repoId
// * @param quType
// * @param level
// * @param excludes 要排除的ID列表
// * @param size
// * @return
// */
List<Qu> listByRandom(@Param("repoId") String repoId,
@Param("quType") Integer quType,
@Param("excludes") List<String> excludes,
@Param("size") Integer size);
// /**
// * 查找导出列表
// * @param query
// * @return
// */
List<QuExportDTO> listForExport(@Param("query") QuQueryReqDTO query);
// /**
// * 分页查找
// * @param page
// * @param query
// * @return
// */
IPage<QuDTO> paging(Page page, @Param("query") QuQueryReqDTO query);
}

@ -0,0 +1,16 @@
package com.yf.exam.modules.qu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yf.exam.modules.qu.entity.QuRepo;
///**
//* <p>
//* 试题题库Mapper
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
public interface QuRepoMapper extends BaseMapper<QuRepo> {
}

@ -0,0 +1,48 @@
package com.yf.exam.modules.qu.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yf.exam.core.api.dto.PagingReqDTO;
import com.yf.exam.modules.qu.dto.QuAnswerDTO;
import com.yf.exam.modules.qu.entity.QuAnswer;
import java.util.List;
///**
//* <p>
//* 候选答案业务类
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
public interface QuAnswerService extends IService<QuAnswer> {
// /**
// * 分页查询数据
// * @param reqDTO
// * @return
// */
IPage<QuAnswerDTO> paging(PagingReqDTO<QuAnswerDTO> reqDTO);
//
// /**
// * 根据题目ID查询答案并随机
// * @param quId
// * @return
// */
List<QuAnswer> listAnswerByRandom(String quId);
// /**
// * 根据问题查找答案
// * @param quId
// * @return
// */
List<QuAnswerDTO> listByQu(String quId);
// /**
// * 保存试题
// * @param quId
// * @param list
// */
void saveAll(String quId, List<QuAnswerDTO> list);
}

@ -0,0 +1,59 @@
package com.yf.exam.modules.qu.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yf.exam.core.api.dto.PagingReqDTO;
import com.yf.exam.modules.qu.dto.QuRepoDTO;
import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO;
import com.yf.exam.modules.qu.entity.QuRepo;
import java.util.List;
///**
//* <p>
//* 试题题库业务类
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
public interface QuRepoService extends IService<QuRepo> {
// /**
// * 分页查询数据
// * @param reqDTO
// * @return
// */
IPage<QuRepoDTO> paging(PagingReqDTO<QuRepoDTO> reqDTO);
// /**
// * 保存全部列表
// * @param quId
// * @param quType
// * @param ids
// */
void saveAll(String quId, Integer quType, List<String> ids);
// /**
// * 根据问题查找题库
// * @param quId
// * @return
// */
List<String> listByQu(String quId);
// /**
// * 根据题库查找题目ID列表
// * @param repoId
// * @param quType
// * @param rand
// * @return
// */
List<String> listByRepo(String repoId, Integer quType, boolean rand);
// /**
// * 批量操作
// * @param reqDTO
// */
void batchAction(QuRepoBatchReqDTO reqDTO);
}

@ -0,0 +1,76 @@
package com.yf.exam.modules.qu.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yf.exam.core.api.dto.PagingReqDTO;
import com.yf.exam.modules.qu.dto.QuDTO;
import com.yf.exam.modules.qu.dto.export.QuExportDTO;
import com.yf.exam.modules.qu.dto.ext.QuDetailDTO;
import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO;
import com.yf.exam.modules.qu.entity.Qu;
import java.util.List;
///**
//* <p>
//* 问题题目业务类
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
public interface QuService extends IService<Qu> {
// /**
// * 分页查询数据
// * @param reqDTO
// * @return
// */
IPage<QuDTO> paging(PagingReqDTO<QuQueryReqDTO> reqDTO);
// /**
// * 删除试题
// * @param ids
// */
void delete(List<String> ids);
// /**
// * 随机抽取题库的数据
// * @param repoId
// * @param quType
// * @param excludes 要排除的ID列表
// * @param size
// * @return
// */
List<Qu> listByRandom(String repoId,
Integer quType,
List<String> excludes,
Integer size);
// /**
// * 问题详情
// * @param id
// * @return
// */
QuDetailDTO detail(String id);
// /**
// * 保存试题
// * @param reqDTO
// */
void save(QuDetailDTO reqDTO);
// /**
// * 查找导出列表
// * @param query
// * @return
// */
List<QuExportDTO> listForExport(QuQueryReqDTO query);
// /**
// * 导入Excel
// * @param dtoList
// * @return
// */
int importExcel(List<QuExportDTO> dtoList);
}

@ -0,0 +1,144 @@
package com.yf.exam.modules.qu.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.exam.core.api.dto.PagingReqDTO;
import com.yf.exam.core.utils.BeanMapper;
import com.yf.exam.modules.qu.dto.QuAnswerDTO;
import com.yf.exam.modules.qu.entity.QuAnswer;
import com.yf.exam.modules.qu.mapper.QuAnswerMapper;
import com.yf.exam.modules.qu.service.QuAnswerService;
import com.yf.exam.modules.qu.utils.ImageCheckUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
///**
//* <p>
//* 语言设置 服务实现类
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
@Service
public class QuAnswerServiceImpl extends ServiceImpl<QuAnswerMapper, QuAnswer> implements QuAnswerService {
@Autowired
private ImageCheckUtils imageCheckUtils;
@Override
public IPage<QuAnswerDTO> paging(PagingReqDTO<QuAnswerDTO> reqDTO) {
//创建分页对象
IPage<QuAnswer> query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
//查询条件
QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
//获得数据
IPage<QuAnswer> page = this.page(query, wrapper);
//转换结果
IPage<QuAnswerDTO> pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference<Page<QuAnswerDTO>>(){});
return pageData;
}
@Override
public List<QuAnswer> listAnswerByRandom(String quId) {
QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuAnswer::getQuId, quId);
wrapper.last(" ORDER BY RAND() ");
return this.list(wrapper);
}
@Override
public List<QuAnswerDTO> listByQu(String quId) {
QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuAnswer::getQuId, quId);
List<QuAnswer> list = this.list(wrapper);
if(!CollectionUtils.isEmpty(list)){
return BeanMapper.mapList(list, QuAnswerDTO.class);
}
return null;
}
// /**
// * 查找已存在的列表
// * @param quId
// * @return
// */
public List<String> findExistsList(String quId) {
//返回结果
List<String> ids = new ArrayList<>();
QueryWrapper<QuAnswer> wrapper = new QueryWrapper();
wrapper.lambda().eq(QuAnswer::getQuId, quId);
List<QuAnswer> list = this.list(wrapper);
if (!CollectionUtils.isEmpty(list)) {
for (QuAnswer item : list) {
ids.add(item.getId());
}
}
return ids;
}
@Override
public void saveAll(String quId, List<QuAnswerDTO> list) {
//最终要保存的列表
List<QuAnswer> saveList = new ArrayList<>();
//已存在的标签列表
List<String> ids = this.findExistsList(quId);
if(!CollectionUtils.isEmpty(list)){
for(QuAnswerDTO item: list){
// 校验图片地址
imageCheckUtils.checkImage(item.getImage(), "选项图片地址错误!");
//标签ID
String id = item.getId();
QuAnswer answer = new QuAnswer();
BeanMapper.copy(item, answer);
answer.setQuId(quId);
//补全ID避免新增
if(ids.contains(id)){
ids.remove(id);
}
saveList.add(answer);
}
//保存标签列表
if(!CollectionUtils.isEmpty(saveList)) {
this.saveOrUpdateBatch(saveList);
}
//删除已移除
if(!ids.isEmpty()){
this.removeByIds(ids);
}
}else{
QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuAnswer::getQuId, quId);
this.remove(wrapper);
}
}
}

@ -0,0 +1,175 @@
package com.yf.exam.modules.qu.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.exam.core.api.dto.PagingReqDTO;
import com.yf.exam.modules.qu.dto.QuRepoDTO;
import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO;
import com.yf.exam.modules.qu.entity.Qu;
import com.yf.exam.modules.qu.entity.QuRepo;
import com.yf.exam.modules.qu.mapper.QuMapper;
import com.yf.exam.modules.qu.mapper.QuRepoMapper;
import com.yf.exam.modules.qu.service.QuRepoService;
import com.yf.exam.modules.repo.service.RepoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
///**
//* <p>
//* 语言设置 服务实现类
//* </p>
//*
//* @author 聪明笨狗
//* @since 2020-05-25 13:23
//*/
@Service
public class QuRepoServiceImpl extends ServiceImpl<QuRepoMapper, QuRepo> implements QuRepoService {
@Autowired
private QuMapper quMapper;
@Autowired
private RepoService repoService;
@Override
public IPage<QuRepoDTO> paging(PagingReqDTO<QuRepoDTO> reqDTO) {
//创建分页对象
IPage<QuRepo> query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
//查询条件
QueryWrapper<QuRepo> wrapper = new QueryWrapper<>();
//获得数据
IPage<QuRepo> page = this.page(query, wrapper);
//转换结果
IPage<QuRepoDTO> pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference<Page<QuRepoDTO>>(){});
return pageData;
}
@Override
public void saveAll(String quId, Integer quType, List<String> ids) {
// 先删除
QueryWrapper<QuRepo> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuRepo::getQuId, quId);
this.remove(wrapper);
// 保存全部
if(!CollectionUtils.isEmpty(ids)){
List<QuRepo> list = new ArrayList<>();
for(String id: ids){
QuRepo ref = new QuRepo();
ref.setQuId(quId);
ref.setRepoId(id);
ref.setQuType(quType);
list.add(ref);
}
this.saveBatch(list);
for(String id: ids){
this.sortRepo(id);
}
}
}
@Override
public List<String> listByQu(String quId) {
// 先删除
QueryWrapper<QuRepo> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuRepo::getQuId, quId);
List<QuRepo> list = this.list(wrapper);
List<String> ids = new ArrayList<>();
if(!CollectionUtils.isEmpty(list)){
for(QuRepo item: list){
ids.add(item.getRepoId());
}
}
return ids;
}
@Override
public List<String> listByRepo(String repoId, Integer quType, boolean rand) {
QueryWrapper<QuRepo> wrapper = new QueryWrapper<>();
wrapper.lambda()
.eq(QuRepo::getRepoId, repoId);
if(quType!=null){
wrapper.lambda().eq(QuRepo::getQuType, quType);
}
if(rand){
wrapper.orderByAsc(" RAND() ");
}else{
wrapper.lambda().orderByAsc(QuRepo::getSort);
}
List<QuRepo> list = this.list(wrapper);
List<String> ids = new ArrayList<>();
if(!CollectionUtils.isEmpty(list)){
for(QuRepo item: list){
ids.add(item.getQuId());
}
}
return ids;
}
@Override
public void batchAction(QuRepoBatchReqDTO reqDTO) {
// 移除的
if(reqDTO.getRemove()!=null && reqDTO.getRemove()){
QueryWrapper<QuRepo> wrapper = new QueryWrapper<>();
wrapper.lambda()
.in(QuRepo::getRepoId, reqDTO.getRepoIds())
.in(QuRepo::getQuId, reqDTO.getQuIds());
this.remove(wrapper);
}else{
// 新增的
for(String quId : reqDTO.getQuIds()){
Qu q = quMapper.selectById(quId);
this.saveAll(quId, q.getQuType(), reqDTO.getRepoIds());
}
}
for(String id: reqDTO.getRepoIds()){
this.sortRepo(id);
}
}
// /**
// * 单个题库进行排序
// * @param repoId
// */
private void sortRepo(String repoId){
QueryWrapper<QuRepo> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuRepo::getRepoId, repoId);
List<QuRepo> list = this.list(wrapper);
if(CollectionUtils.isEmpty(list)){
return;
}
int sort = 1;
for(QuRepo item: list){
item.setSort(sort);
sort++;
}
this.updateBatchById(list);
}
}

@ -0,0 +1,283 @@
package com.yf.exam.modules.qu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.exam.ability.upload.config.UploadConfig;
import com.yf.exam.core.api.dto.PagingReqDTO;
import com.yf.exam.core.exception.ServiceException;
import com.yf.exam.core.utils.BeanMapper;
import com.yf.exam.modules.qu.dto.QuAnswerDTO;
import com.yf.exam.modules.qu.dto.QuDTO;
import com.yf.exam.modules.qu.dto.export.QuExportDTO;
import com.yf.exam.modules.qu.dto.ext.QuDetailDTO;
import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO;
import com.yf.exam.modules.qu.entity.Qu;
import com.yf.exam.modules.qu.entity.QuAnswer;
import com.yf.exam.modules.qu.entity.QuRepo;
import com.yf.exam.modules.qu.enums.QuType;
import com.yf.exam.modules.qu.mapper.QuMapper;
import com.yf.exam.modules.qu.service.QuAnswerService;
import com.yf.exam.modules.qu.service.QuRepoService;
import com.yf.exam.modules.qu.service.QuService;
import com.yf.exam.modules.qu.utils.ImageCheckUtils;
import com.yf.exam.modules.repo.service.RepoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
///**
// * <p>
// * 语言设置 服务实现类
// * </p>
// *
// * @author 聪明笨狗
// * @since 2020-05-25 10:17
// */
@Service
public class QuServiceImpl extends ServiceImpl<QuMapper, Qu> implements QuService {
@Autowired
private QuAnswerService quAnswerService;
@Autowired
private QuRepoService quRepoService;
@Autowired
private ImageCheckUtils imageCheckUtils;
@Override
public IPage<QuDTO> paging(PagingReqDTO<QuQueryReqDTO> reqDTO) {
//创建分页对象
Page page = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
//转换结果
IPage<QuDTO> pageData = baseMapper.paging(page, reqDTO.getParams());
return pageData;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void delete(List<String> ids) {
// 移除题目
this.removeByIds(ids);
// 移除选项
QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
wrapper.lambda().in(QuAnswer::getQuId, ids);
quAnswerService.remove(wrapper);
// 移除题库绑定
QueryWrapper<QuRepo> wrapper1 = new QueryWrapper<>();
wrapper1.lambda().in(QuRepo::getQuId, ids);
quRepoService.remove(wrapper1);
}
@Override
public List<Qu> listByRandom(String repoId, Integer quType, List<String> excludes, Integer size) {
return baseMapper.listByRandom(repoId, quType, excludes, size);
}
@Override
public QuDetailDTO detail(String id) {
QuDetailDTO respDTO = new QuDetailDTO();
Qu qu = this.getById(id);
BeanMapper.copy(qu, respDTO);
List<QuAnswerDTO> answerList = quAnswerService.listByQu(id);
respDTO.setAnswerList(answerList);
List<String> repoIds = quRepoService.listByQu(id);
respDTO.setRepoIds(repoIds);
return respDTO;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void save(QuDetailDTO reqDTO) {
// 校验数据
this.checkData(reqDTO, "");
Qu qu = new Qu();
BeanMapper.copy(reqDTO, qu);
// 校验图片地址
imageCheckUtils.checkImage(qu.getImage(), "题干图片地址错误!");
// 更新
this.saveOrUpdate(qu);
// 保存全部问题
quAnswerService.saveAll(qu.getId(), reqDTO.getAnswerList());
// 保存到题库
quRepoService.saveAll(qu.getId(), qu.getQuType(), reqDTO.getRepoIds());
}
@Override
public List<QuExportDTO> listForExport(QuQueryReqDTO query) {
return baseMapper.listForExport(query);
}
@Override
public int importExcel(List<QuExportDTO> dtoList) {
//根据题目名称分组
Map<Integer, List<QuExportDTO>> anMap = new HashMap<>(16);
//题目本体信息
Map<Integer, QuExportDTO> quMap = new HashMap<>(16);
//数据分组
for (QuExportDTO item : dtoList) {
// 空白的ID
if (StringUtils.isEmpty(item.getNo())) {
continue;
}
Integer key;
//序号
try {
key = Integer.parseInt(item.getNo());
} catch (Exception e) {
continue;
}
//如果已经有题目了,直接处理选项
if (anMap.containsKey(key)) {
anMap.get(key).add(item);
} else {
//如果没有,将题目内容和选项一起
List<QuExportDTO> subList = new ArrayList<>();
subList.add(item);
anMap.put(key, subList);
quMap.put(key, item);
}
}
int count = 0;
try {
//循环题目插入
for (Integer key : quMap.keySet()) {
QuExportDTO im = quMap.get(key);
//题目基本信息
QuDetailDTO qu = new QuDetailDTO();
qu.setContent(im.getQContent());
qu.setAnalysis(im.getQAnalysis());
qu.setQuType(Integer.parseInt(im.getQuType()));
qu.setCreateTime(new Date());
//设置回答列表
List<QuAnswerDTO> answerList = this.processAnswerList(anMap.get(key));
//设置题目
qu.setAnswerList(answerList);
//设置引用题库
qu.setRepoIds(im.getRepoList());
// 保存答案
this.save(qu);
count++;
}
} catch (ServiceException e) {
e.printStackTrace();
throw new ServiceException(1, "导入出现问题,行:" + count + "" + e.getMessage());
}
return count;
}
// /**
// * 处理回答列表
// *
// * @param importList
// * @return
// */
private List<QuAnswerDTO> processAnswerList(List<QuExportDTO> importList) {
List<QuAnswerDTO> list = new ArrayList<>(16);
for (QuExportDTO item : importList) {
QuAnswerDTO a = new QuAnswerDTO();
a.setIsRight("1".equals(item.getAIsRight()));
a.setContent(item.getAContent());
a.setAnalysis(item.getAAnalysis());
a.setId("");
list.add(a);
}
return list;
}
// /**
// * 校验题目信息
// *
// * @param qu
// * @param no
// * @throws Exception
// */
public void checkData(QuDetailDTO qu, String no) {
if (StringUtils.isEmpty(qu.getContent())) {
throw new ServiceException(1, no + "题目内容不能为空!");
}
if (CollectionUtils.isEmpty(qu.getRepoIds())) {
throw new ServiceException(1, no + "至少要选择一个题库!");
}
List<QuAnswerDTO> answers = qu.getAnswerList();
if (CollectionUtils.isEmpty(answers)) {
throw new ServiceException(1, no + "客观题至少要包含一个备选答案!");
}
int trueCount = 0;
for (QuAnswerDTO a : answers) {
if (a.getIsRight() == null) {
throw new ServiceException(1, no + "必须定义选项是否正确项!");
}
if (StringUtils.isEmpty(a.getContent())) {
throw new ServiceException(1, no + "选项内容不为空!");
}
if (a.getIsRight()) {
trueCount += 1;
}
}
if (trueCount == 0) {
throw new ServiceException(1, no + "至少要包含一个正确项!");
}
//单选题
if (qu.getQuType().equals(QuType.RADIO) && trueCount > 1) {
throw new ServiceException(1, no + "单选题不能包含多个正确项!");
}
}
}

@ -0,0 +1,31 @@
package com.yf.exam.modules.qu.utils;
import com.yf.exam.ability.upload.config.UploadConfig;
import com.yf.exam.core.exception.ServiceException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ImageCheckUtils {
@Autowired
private UploadConfig conf;
// /**
// * 进行图片校验!
// * @param image
// * @param throwMsg
// */
public void checkImage(String image, String throwMsg) {
if(StringUtils.isBlank(image)){
return;
}
// 校验图片地址
if(!image.startsWith(conf.getUrl())){
throw new ServiceException(throwMsg);
}
}
}
Loading…
Cancel
Save