题库和试卷模块分为题库分类、题库管理、试卷管理
题库分类
分类是否存在
方法的返回值是false,参数是分类名称,该方法就是判断分类名称是否重复
以分类名称为参数,在题库分类表中查询,生成一个list,list不为空返回true,否则返回false
/**
* 分类是否存在
* 返回值是boolean 参数是分类名称
* @param questionCategoryName
* @return
*/
boolean exists(String questionCategoryName);
/**
* 分类是否存在
* 就是根据分类名称在分类列表中查询,看是否能查到相关的分类记录列表
* boolean exists(String questionCategoryName);
* 参数是分类名称 返回值是boolean
* @param questionCategoryName
* @return
*/
@Override
public boolean exists(String questionCategoryName) {
if(StrUtil.isEmpty(questionCategoryName)) {
throw new BerryException("请输入分类名称");
}
QueryWrapper<CourseQuestionCategory> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(CourseQuestionCategory::getQuestionCategoryName,queryWrapper);
List<CourseQuestionCategory> list = list(queryWrapper);
//根据分类名称查到分类列表之后,看列表中是否有数据,列表不为空,返回true,列表为为空,返回false
if(CollUtil.isNotEmpty(list)) {
return true;
}
return false;
}
新增题库分类
/**
* 新增题库分类
* @param courseQuestionCategoryVO
* @return
* @throws BerryException
*/
boolean addQuestionCategory(CourseQuestionCategoryVO courseQuestionCategoryVO) throws BerryException;
//先判断参数,然后创建对象,赋值属性,调用新增方法
@Override
public boolean addQuestionCategory(CourseQuestionCategoryVO courseQuestionCategoryVO) throws BerryException {
if(courseQuestionCategoryVO==null){
throw new BerryException("请输入分类参数!");
}
if(StrUtil.isEmpty(courseQuestionCategoryVO.getQuestionCategoryName())){
throw new BerryException("请输入题库分类名称");
}
if (exists(courseQuestionCategoryVO.getQuestionCategoryName())) {
throw new BerryException("分类已存在");
}
try {
CourseQuestionCategory questionCategory = new CourseQuestionCategory();
BeanUtils.copyProperties(courseQuestionCategoryVO,questionCategory);
return save(questionCategory);
} catch (BerryException e) {
throw new BerryException(e.getMessage());
}
}
更新题库分类
判断参数不为空,判断题库分类名称不能重复(条件是主键不相等,名称相等),然后创建要更新的分类的对象,赋值属性之后进行更新
/**
* 更新题库分类
* @param courseQuestionCategoryVO
* @return
* @throws BerryException
*/
boolean updateQuestionCategory(CourseQuestionCategoryVO courseQuestionCategoryVO) throws BerryException;
/**
* 更新题库分类
* courseQuestionCategoryVO: 分类id ,分类名称,分类说明,分类父id
* @param courseQuestionCategoryVO
* @return
* @throws BerryException
*/
@Override
public boolean updateQuestionCategory(CourseQuestionCategoryVO courseQuestionCategoryVO) throws BerryException {
//先判断参数
if(courseQuestionCategoryVO == null) {
throw new BerryException("请输入分类参数");
}
if(courseQuestionCategoryVO.getQuestionCategoryId() == null) {
throw new BerryException("请输入分类id");
}
if(StrUtil.isEmpty(courseQuestionCategoryVO.getQuestionCategoryName())) {
throw new BerryException("请输入分类名称");
}
//先从数据库中取数据,看具体的分类对象是否存在
CourseQuestionCategory courseQuestionCategory = getById(courseQuestionCategoryVO.getQuestionCategoryId());
if(courseQuestionCategory == null) {
throw new BerryException("题库分类不存在");
}
//判断题库分类名称是否已经存在
//就是查一下去掉我们修改的这个对象,还有没有别的分类叫这个名称
QueryWrapper<CourseQuestionCategory> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().ne(CourseQuestionCategory::getQuestionCategoryId,courseQuestionCategoryVO.getQuestionCategoryId());
queryWrapper.lambda().eq(CourseQuestionCategory::getQuestionCategoryName,courseQuestionCategoryVO.getQuestionCategoryName());
List<CourseQuestionCategory> list = list(queryWrapper);
if(CollUtil.isNotEmpty(list)) {
throw new BerryException("该题库分类名称已经存在");
}
BeanUtils.copyProperties(courseQuestionCategoryVO,courseQuestionCategory);
return updateById(courseQuestionCategory);
}
删除题库分类
1参数是分类id,先根据分类id查询题库,若该分类下面有题库不能删除
2该分类id为父id,查询二级分类列表,然后构建List<Long> categoryIdList,用于存放二级分类的id
循环二级分类列表,同上判断每个子分类下面是否有题库,把分类id装到categoryIdList,循环外删除子分类列表(removeByIds(categoryIdList))
3,没有二级分类列表直接删除
/**
* 删除题库分类
* @param id
* @return
* @throws BerryException
*/
boolean deleteQuestionCategory(Long id) throws BerryException;
/**
* 删除题库分类
* 如果该分类下面有题库,先清除分类下的题库
* 如果该分类的子分类下面有题库,先清除子分类下面的题库
* 参数:分类id
* @param id
* @return
* @throws BerryException
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteQuestionCategory(Long id) throws BerryException {
if(id == null) {
throw new BerryException("请输入id");
}
//创建QuestionDbVo对象,这个是查询题库列表方法的参数,
//创建对象之后,还需要传入分类id
QuestionDbVo questionDbVo = new QuestionDbVo();
questionDbVo.setCategoryId(id);
//根据题库分类id查询对应的题库分类列表
List<CourseQuestionDb> courseQuestionDbs = courseQuestionDbService.getDbList(questionDbVo);
if(CollUtil.isNotEmpty(courseQuestionDbs)) {
throw new BerryException("该分类下存下题库,请先删除分类下面的题库");
}
//以参数id为父id,查询对应的题库分类列表,循环该分类列表,就可以通过每个子分类的id,看每个子分类下面是否有对应的题库
QueryWrapper<CourseQuestionCategory> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(CourseQuestionCategory::getParentId,id);
List<CourseQuestionCategory> list = list(queryWrapper);
if(list != null && list.size() > 0) {
//初始化子分类id列表
List<Long> categoryIdList = new ArrayList<>();
list.forEach(obj-> {
QuestionDbVo childDbVo = new QuestionDbVo();
childDbVo.setCategoryId(obj.getQuestionCategoryId());
List<CourseQuestionDb> dbList = courseQuestionDbService.getDbList(childDbVo);
if(CollUtil.isNotEmpty(dbList)) {
throw new BerryException("该子分类下面存在题库,请先删除子分类下面的题库");
}
categoryIdList.add(obj.getQuestionCategoryId());
});
//若子分类下面没有题库了,批量删除子分类列表
removeByIds(categoryIdList);
}
return removeById(id);
}
分类树形二级列表展示
package com.rong.resourcestudy.question.dto;
/**
* QuestionCategoryTreeDto 有 CourseQuestionCategory的全部属性
* List<QuestionCategoryTreeDto> children; 是另外设置的属性
*
*/
@Data
public class QuestionCategoryTreeDto1 extends CourseQuestionCategory {
/**
* 子菜单
*/
List<QuestionCategoryTreeDto1> children;
/**
* 把数据库中普通的分类列表转换成树形列表
* * 1判断参数分类列表是否为空
* * 2new HashMap<>()创建map<Long,树形类>,new ArrayList<>()创建树形类的数组列表
* * 3对参数列表进行循环,可以使用list.stream.forEach,也可以使用for(:)
* * 在循环里面创建树形类的对象,把实体类对象的属性赋值给树形类对象,再把树形类对象拿去给创建的map赋值
* * 4赋值完成之后,还是对参数列表进行增强for循环,通过map.get(parentId/主键)得到树形类对象
* * if (parentId == null) 如果父id为空,直接把主键对象放在创建的树形数组列表,
* * 父id 不为空,通过map和父id获取父对象,父对象为空,也是当前对象直接添加
* * 父对象不为空判断父对象的chirdren是否为空,
* * 为空的话,需要初始化children, List<FileCategoryTreeVo> children = new ArrayList<>();把当前对象放在children中,
* * 再把children放入父节点之中,
* *不为空,不用创建对象,直接放入就行
* @param categoryList
* @return
*/
public static List<QuestionCategoryTreeDto1> convertCategoryList2Tree(List<CourseQuestionCategory> categoryList) {
//先判断参数列表不能为空
if(CollUtil.isEmpty(categoryList)) {
return ListUtil.empty();
}
//2new HashMap<>()创建map<Long,树形类>
Map<Long,QuestionCategoryTreeDto1> menuTreeDtoMap = new HashMap<>();
categoryList.stream().forEach(item-> {
//属性赋值
QuestionCategoryTreeDto1 questionCategoryTreeDto1 = new QuestionCategoryTreeDto1();
//这样子继承于父类的属性就可以完成赋值
BeanUtils.copyProperties(item,questionCategoryTreeDto1);
//把得到的树形类对象封装成map,键是分类id,值是树形类对象
menuTreeDtoMap.put(item.getQuestionCategoryId(),questionCategoryTreeDto1);
});
//初始化树形类列表
List<QuestionCategoryTreeDto1> questionCategoryTreeDto1s = new ArrayList<>();
for(CourseQuestionCategory category:categoryList) {
//循环分类列表,获取分类对象的父id,根据分类id获取对应的dto
Long parentId = category.getParentId();
QuestionCategoryTreeDto1 currentCategoryDto = menuTreeDtoMap.get(category.getQuestionCategoryId());
//若该对象的父id为空,自己就是父对象,直接把自己放入初始化的树形列表之中
if(parentId == null) {
questionCategoryTreeDto1s.add(currentCategoryDto);
} else {
//下面对应的都是当前对象有父id的情况
//若该对象的父id不为空,那么先通过父id获得该对象的父树形对象
QuestionCategoryTreeDto1 parentCategory = menuTreeDtoMap.get(parentId);
if(parentCategory == null) {
//若获取的该对象的父树形对象为空,那么自己还是父对象,直接把自己放入初始化的树形列表之中
questionCategoryTreeDto1s.add(currentCategoryDto);
continue;
}
//父对象不为空了,现在一级栏目是父对象,现在看是否有二级栏目
if(parentCategory.getChildren() == null) {
//二级栏目列表为空
//初始化二级列表
List<QuestionCategoryTreeDto1> children = new ArrayList<>();
children.add(currentCategoryDto);
parentCategory.setChildren(children);
} else {
//二级栏目列表不为空,直接把当前的对象添加进去作为二级栏目
parentCategory.getChildren().add(currentCategoryDto);
}
}
}
return questionCategoryTreeDto1s;
}
}
题库管理
新增题库
判断参数,然后判断题库名称是否已经存在,然后创建对象,赋值分类id、题库名称、题库状态为1
/**
* 新增题库
* boolean addQuestionDb(QuestionDbVo questionDbVo);
* @param questionDbVo
* @return
*/
@Override
public boolean addQuestionDb(QuestionDbVo questionDbVo) {
if(questionDbVo == null) {
throw new BerryException("参数不能为空");
}
if(questionDbVo.getCategoryId() == null) {
throw new BerryException("分类id不能我空!");
}
if(StrUtil.isBlank(questionDbVo.getDbName())) {
throw new BerryException("请输入题库名称");
}
QueryWrapper<CourseQuestionDb> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(CourseQuestionDb::getDbName,questionDbVo.getDbName());
if(count(queryWrapper) > 0) {
throw new BerryException("该题库名称已经存在");
}
CourseQuestionDb courseQuestionDb = new CourseQuestionDb();
courseQuestionDb.setCategoryId(questionDbVo.getCategoryId());
courseQuestionDb.setDbName(questionDbVo.getDbName());
courseQuestionDb.setDbStatus(1);
return save(courseQuestionDb);
}
}
删除题库
removeById(id);
/**
* 删除题库
* boolean deleteQuestionDb(Long id) throws BerryException;
* @param id
* @return
* @throws BerryException
*/
@Override
public boolean deleteQuestionDb(Long id) throws BerryException {
if(id == null) {
throw new BerryException("id不能为空");
}
return removeById(id);
}
题库详情
/**
* 查询题库详情
* CourseQuestionDb queryQuestionDbInfo(Long id) throws BerryException;
* @param id
* @return
* @throws BerryException
*/
@Override
public CourseQuestionDb queryQuestionDbInfo(Long id) throws BerryException {
if(id == null) {
throw new BerryException("id不能为空");
}
return getById(id);
}
题库列表
需要连带着查出来题库分类名称,我们先根据条件查出来题库列表
循环题库列表,在循环中根据分类id查询到具体的题库分类对象,然后根据对象获得分类名称,复赋值给题库对象
/**
* 查询题库列表
* * 题库列表(不分页,可以根据题库分类id,或者题库名称查询)
* * 在查询列表的时候需要把题库分类名称查出来(在循环中赋值)
* @param questionDbVo
* @return
*/
@Override
public List<CourseQuestionDb> getDbList(QuestionDbVo questionDbVo) {
if(questionDbVo == null) {
throw new BerryException("参数列表不为空");
}
QueryWrapper<CourseQuestionDb> queryWrapper = new QueryWrapper<>();
if(!StrUtil.isEmpty(questionDbVo.getDbName())) {
queryWrapper.lambda().like(CourseQuestionDb::getDbName,questionDbVo.getDbName());
}
if(questionDbVo.getCategoryId() != null) {
queryWrapper.lambda().eq(CourseQuestionDb::getCategoryId,questionDbVo.getCategoryId());
}
List<CourseQuestionDb> list = list(queryWrapper);
list.forEach(obj -> {
//想要获取对应分类的名称,得先获取到题库分类对象
CourseQuestionCategory questionCategory = questionCategoryService.getById(obj.getCategoryId());
obj.setCategoryName(questionCategory.getQuestionCategoryName());
});
return list;
}
更新题库信息
/**
* 修改题库
* boolean updateQuestionDbInfo(CourseQuestionDb courseQuestionDb) throws BerryException;
* @param courseQuestionDb
* @return
* @throws BerryException
*/
@Override
public boolean updateQuestionDbInfo(CourseQuestionDb courseQuestionDb) throws BerryException {
if(courseQuestionDb.getDbId() == null) {
throw new BerryException("题库id不存在");
}
//根据id查一下该题库是否存在
CourseQuestionDb questionDb = getById(courseQuestionDb.getDbId());
if(questionDb == null) {
throw new BerryException("该题库不存在");
}
QueryWrapper<CourseQuestionDb> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(CourseQuestionDb::getDbName,courseQuestionDb.getDbName());
queryWrapper.lambda().ne(CourseQuestionDb::getDbId,courseQuestionDb.getDbId());
if(count(queryWrapper) > 0) {
throw new BerryException("该题库名称已经存在");
}
return updateById(courseQuestionDb);
}
更新题库状态
就是判断参数,然后创建题库对象,传题库id和状态两个参数之后,调用修改方法就可
/**
* 更改题库状态
* boolean updateQuestionDbStatus(Long dbId, Integer status);
* @param dbId
* @param status
* @return
*/
@Override
public boolean updateQuestionDbStatus(Long dbId, Integer status) {
if(dbId == null) {
throw new BerryException("请输入题库id !");
}
if(status == null) {
throw new BerryException("请输入题库状态");
}
CourseQuestionDb courseQuestionDb = new CourseQuestionDb();
courseQuestionDb.setDbStatus(status);
courseQuestionDb.setDbId(dbId);
return updateById(courseQuestionDb);
}
题库试题管理
题库添加试题
/**
* 题库添加试题
* @param questionReqVO
*/
void addQuestion(QuestionReqVO questionReqVO);
1先判断参数
2判断该题目是否已将在该题库
3初始化选项列表,因为我们在新增问题的时候会顺带把选项添加到选项列表
4如果是判断题,创建两个选项对象,分别赋值对和错对应的选项名和选项值,然后把赋值后对象添加到初始化的选项列表
5如果是选择题,选项列表从参数获得,optionList = questionReqVO.getOptionList();
6双层循环该参数中的选项列表,就可以判断选项中是否有选项值为空,是否有重复的选项值
7创建问题对象,从参数中对对象赋值,保存问题对象
8批量保存选项,先循环选项列表,把每个每个选项对象都复制上题目id,调用saveOrUpdateBatch
9改变题库题目数量
/**
* 题库添加试题
* @param questionReqVO
*/
void addQuestion(QuestionReqVO questionReqVO);
/**
* 题库添加试题
* @param questionReqVO
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void addQuestion(QuestionReqVO questionReqVO) {
if(questionReqVO == null) {
throw new BerryException("参数错误");
}
if(StrUtil.isEmpty(questionReqVO.getQuestionName())) {
throw new BerryException("题干不能为空");
}
if(StrUtil.isEmpty(questionReqVO.getQuestionAnswerRight()) && questionReqVO.getQuestionType() != 5) {
throw new BerryException("正确答案不能为空");
}
if(questionReqVO.getQuestionType() == null || questionReqVO.getQuestionType() == 0) {
throw new BerryException("题目类型不能为空");
}
if ((questionReqVO.getQuestionType() != 3 && questionReqVO.getQuestionType() != 4 && questionReqVO.getQuestionType() != 5) && (questionReqVO.getOptionList() == null || questionReqVO.getOptionList().size() == 0)) {
throw new BerryException("选项不能为空");
}
if(questionReqVO.getQuestionDbId() == null || questionReqVO.getQuestionDbId() == 0) {
throw new BerryException("题库id不能为空");
}
//判断该题目是否已经存在,需要指定题库
QueryWrapper<CourseQuestions> questionsQueryWrapper = new QueryWrapper<>();
questionsQueryWrapper.lambda().eq(CourseQuestions::getQuestionDbId,questionReqVO.getQuestionId());
questionsQueryWrapper.lambda().eq(CourseQuestions::getQuestionName,questionReqVO.getQuestionName());
int count = count(questionsQueryWrapper);
if(count > 0) {
throw new BerryException("该题目已经存在");
}
//判断选项,类型3代表判断题
//初始化选项列表,为了向列表中封装数据
List<CourseQuestionsOption> optionList = new ArrayList<>();
if(questionReqVO.getQuestionType() == 3) {
//创建选项对象,封装属性,那对象添加到选项列表中,下面的操作相当于会添加两条记录
CourseQuestionsOption option = new CourseQuestionsOption();
option.setOptionName("A");
option.setOptionValue("对");
optionList.add(option);
CourseQuestionsOption optionB = new CourseQuestionsOption();
option.setOptionName("B");
option.setOptionValue("错");
optionList.add(optionB);
} else {
optionList = questionReqVO.getOptionList();
for(CourseQuestionsOption option :optionList) {
if(StrUtil.isBlank(option.getOptionValue())) {
throw new BerryException("问题选项里有选项值为空,请重新配置并提交");
}
//判断选项值是否重复
String optionValue = option.getOptionValue().trim();
for (CourseQuestionsOption nextOption:optionList) {
if(StrUtil.isBlank(nextOption.getOptionValue())) {
throw new BerryException("问题选项里有选项值为空,请重新配置并提交");
}
String nextOptionValue = nextOption.getOptionValue().trim();
if(option != nextOption) {
if(optionValue.equals(nextOptionValue)) {
throw new BerryException("问题选项中有重复选项值,请重新输入");
}
}
}
}
}
CourseQuestions courseQuestions = new CourseQuestions();
BeanUtils.copyProperties(questionReqVO,courseQuestions);
save(courseQuestions);
//批量保存选项
if(optionList != null) {
for(CourseQuestionsOption option:optionList) {
option.setQuestionId(courseQuestions.getId());
}
if(optionList.size() > 0) {
courseQuestionsOptionService.saveOrUpdateBatch(optionList);
}
}
//最后改变题库的问题数量
updateDbQuestionCount(questionReqVO.getQuestionDbId(),1);
}
题库查询题目列表(分页查询)
参数
返回参数
public class CourseQuestionPageResVo {
@ApiModelProperty("分页数据")
public PageResVO pageResVo;
@ApiModelProperty("题库题目")
public List<CourseQuestions> courseQuestionsList;
}
@ApiModel(value = "题库题目请求VO")
@Data
public class CourseQuestionPageReqVo {
@ApiModelProperty(value = "题库ID(非必传)")
private Long questionDbId;
@ApiModelProperty(value = "题目(非必传)")
private String questionName;
@ApiModelProperty(value = "分页请求参数")
private PageReqVO pageReqVO;
@ApiModelProperty(value = "题型列表")
private List<Integer> questionTypes;
/**
* 题库查询题目列表
* @param courseQuestionPageReqVo
*/
CourseQuestionPageResVo listQuestion(CourseQuestionPageReqVo courseQuestionPageReqVo);
1判断参数和分页请求参数
2使用PageHelper.startPage完成分页,参数传 的是第几页和一页几条数据
3查询,参数:题库id,题干名称,题目类型()查询结果会生成一个列表
4创建PageInfo对象,把查询出的列表封装到里面
5循环查询到的列表,根据题目id查询选项列表,把查询到的选项列表赋值给题目
6创建返回对象,赋值分页返回参数和题目列表,最后返回返回对象
/**
* 题库查询题目列表(分页查询)
* @param courseQuestionPageReqVo:private Long paperId;private PageReqVO pageReqVO;
CourseQuestionPageResVo:分页参数,题目列表public List<CourseQuestions> courseQuestionsList;
* @return
*/
@Override
public CourseQuestionPageResVo listQuestion(CourseQuestionPageReqVo courseQuestionPageReqVo) {
if(courseQuestionPageReqVo == null) {
courseQuestionPageReqVo = new CourseQuestionPageReqVo();
}
if(courseQuestionPageReqVo.getPageReqVO() == null) {
courseQuestionPageReqVo.setPageReqVO(new PageReqVO());
}
PageHelper.startPage(courseQuestionPageReqVo.getPageReqVO().getCurrent(),courseQuestionPageReqVo.getPageReqVO().getPageSize());
QueryWrapper<CourseQuestions> questionsQueryWrapper = new QueryWrapper<>();
//题库id是最主要的查询条件
if(courseQuestionPageReqVo.getQuestionDbId() != null) {
questionsQueryWrapper.lambda().eq(CourseQuestions::getQuestionDbId,courseQuestionPageReqVo.getQuestionDbId());
}
if(StrUtil.isNotBlank(courseQuestionPageReqVo.getQuestionName())) {
questionsQueryWrapper.lambda().like(CourseQuestions::getQuestionName,courseQuestionPageReqVo.getQuestionName());
}
if(CollUtil.isNotEmpty(courseQuestionPageReqVo.getQuestionTypes())){
questionsQueryWrapper.lambda().in(CourseQuestions::getQuestionType, courseQuestionPageReqVo.getQuestionTypes());
}
List<CourseQuestions> courseQuestionsList = list(questionsQueryWrapper);
PageInfo<CourseQuestions> pageInfo = new PageInfo<>(courseQuestionsList);
CourseQuestionPageResVo courseQuestionPageResVo = new CourseQuestionPageResVo();
//需要把查到的问题列表附带上选项,需要使用循环
pageInfo.getList().forEach(item-> {
item.setOptionList(courseQuestionsOptionService.getOptionsByQuestionId(item.getId()));
});
courseQuestionPageResVo.setCourseQuestionsList(pageInfo.getList());
PageResVO pageResVO = new PageResVO();
pageResVO.setCurrent(pageInfo.getPageNum());
pageResVO.setPageSize(pageInfo.getPageSize());
pageResVO.setTotal(pageInfo.getTotal());
courseQuestionPageResVo.setPageResVo(pageResVO);
return courseQuestionPageResVo;
}
分页查询试卷所选题库中尚未使用的试题列表
请求参数
@ApiModel(value = "试题添加题库剩余题目请求VO")
@Data
public class ExamPaperOtherQuestionPageReqVo {
@ApiModelProperty(value = "paperId")
private Long paperId;
@ApiModelProperty(value = "分页请求参数")
private PageReqVO pageReqVO;
}
返回参数
public class CourseQuestionPageResVo {
@ApiModelProperty("分页数据")
public PageResVO pageResVo;
@ApiModelProperty("题库题目")
public List<CourseQuestions> courseQuestionsList;
}
/**
* 查询试卷所选题库中尚未使用的试题列表
* @param courseQuestionPageReqVo
*/
CourseQuestionPageResVo listQuestionDbOtherQuestions(ExamPaperOtherQuestionPageReqVo courseQuestionPageReqVo);
1开启分页条件,创建queryWrapper查询
2我们用试卷id作为参数,在试卷问题映射表中查询映射列表,循环映射列表就可以拿到对应的试题id列表
3查询条件就是在题库中查询,指定题库id,试题id不在2查询的试题id列表里面
4查询到的列表用pageInfo封装,然后创建返回对象,赋值分页参数和试题列表,最后 返回返回对象
/**
* 查询试卷所选题库中尚未使用的试题列表
* 查询条件就是题库id 和 问题id不在现在已将使用过的问题列表中
* @param examPaperOtherQuestionPageReqVo
*/
@Override
public CourseQuestionPageResVo listQuestionDbOtherQuestions(ExamPaperOtherQuestionPageReqVo examPaperOtherQuestionPageReqVo) {
PageHelper.startPage(examPaperOtherQuestionPageReqVo.getPageReqVO().getCurrent(),examPaperOtherQuestionPageReqVo.getPageReqVO().getPageSize());
QueryWrapper<CourseQuestions> queryWrapper = new QueryWrapper<>();
ExamPaper examPaper = examPaperService.getById(examPaperOtherQuestionPageReqVo.getPaperId());
if(examPaper == null) {
return null;
}
if(examPaper.getQuestionDbId() != null) {
queryWrapper.lambda().eq(CourseQuestions::getQuestionDbId,examPaper.getQuestionDbId());
}
//从试卷问题映射表中拿到已有的问题id列表
List<ExamPaperQuestionMap> examPaperQuestionMaps = examPaperQuestionMapService.paperQuestionList(examPaper.getId());
if(CollUtil.isNotEmpty(examPaperQuestionMaps)) {
List<Long> hasAddedQuestions = examPaperQuestionMaps.stream().map(obj -> {
return obj.getQuestionId();
}).collect(Collectors.toList());
queryWrapper.lambda().notIn(CourseQuestions::getId,hasAddedQuestions);
}
List<CourseQuestions> courseQuestionsList = list(queryWrapper);
PageInfo<CourseQuestions> pageInfo = new PageInfo<>(courseQuestionsList);
CourseQuestionPageResVo courseQuestionPageResVo = new CourseQuestionPageResVo();
courseQuestionPageResVo.setCourseQuestionsList(pageInfo.getList());
PageResVO pageResVO = new PageResVO();
pageResVO.setCurrent(pageInfo.getPageNum());
pageResVO.setPageSize(pageInfo.getPageSize());
pageResVO.setTotal(pageInfo.getTotal());
courseQuestionPageResVo.setPageResVo(pageResVO);
return courseQuestionPageResVo;
}
查询试卷下所有题目及选项,按照已有顺序排序或者随机排序
参数
@ApiModel("试卷题目Dto")
@Data
public class ExamPaperQuestionDto {
@ApiModelProperty(value = "试卷题目映射表Id")
private Long id;
@ApiModelProperty(value = "问题Id")
private Long questionId;
@ApiModelProperty(value = "题干内容")
private String questionName;
@ApiModelProperty(value = "题库ID")
private Long questionDbId;
@ApiModelProperty(value = "题目类型 1 单选题 2 多选题 3 判断题 ")
private Integer questionType;
@ApiModelProperty(value = "是否为关键知识点 ")
private Integer isCrucial;
@ApiModelProperty(value = "答案解析")
private String questionAnalization;
@ApiModelProperty(value = "难度 1 简单 2 一般 3 略难 4 非常难")
private Integer difficultLevel;
@ApiModelProperty(value = "分值")
private Integer score;
@ApiModelProperty(value = "题目选项")
private List<CourseQuestionsOption> optionList;
/**
* 查询试卷下所有题目及选项
* @param paperId
* @return
*/
List<ExamPaperQuestionDto> listPaperQuestions(Long paperId);
调用试卷问题映射表中的方法就能的得到我们想要的列表了,重点是我们想要的两种排序方式
如果选项默认排序,就能直接循环列表,赋值一下选项列表就可以
如果是随机排序,就调用随机工具类ListObjectRandomUtil.randomHandler
/**
* 查询试卷下所有题目及选项
* 按照已有顺序排序或者随机排序
* 我们现在查询的返回是List<> 若参数为空,可以先返回ListUtil.empty();
* @param paperId
* @return
*/
@Override
public List<ExamPaperQuestionDto> listPaperQuestions(Long paperId) {
if(paperId == null) {
return ListUtil.empty();
}
ExamPaper examPaper = examPaperService.getById(paperId);
if(examPaper == null) {
return ListUtil.empty();
}
List<ExamPaperQuestionDto> examPaperQuestionDtos = examPaperQuestionMapService.listPaperQuestions(paperId);
if(CollUtil.isEmpty(examPaperQuestionDtos)) {
return ListUtil.empty();
}
/**
* 未设置或者0 为 默认,按照已有顺序排序
* 1 随机排序
*/
boolean questionOptionDefaultSort = (examPaper.getQuestionOptionSortWay() == null || examPaper.getQuestionOptionSortWay() == 0) ? true : false;
examPaperQuestionDtos.stream().forEach(item-> {
//若为真,默认排序
if(questionOptionDefaultSort) {
item.setOptionList(courseQuestionsOptionService.getOptionsByQuestionId(item.getQuestionId()));
} else {
item.setOptionList(ListObjectRandomUtil.randomHandler(courseQuestionsOptionService.getOptionsByQuestionId(item.getQuestionId())));
}
});
return examPaperQuestionDtos;
}
把列表随机展示的工具类
就是按照列表长度进行循环,然后生成[0,listSize)之间的随机数,若i和随机数不相等,就按照二者为索引交换位置
public static List randomHandler1(List list) {
if(CollUtil.isNotEmpty(list)) {
Random random = new Random();
int listSize = list.size();
for (int i = 0; i < listSize; i++) {
//生成的数在[0,listSize)之间
int randomIndex = random.nextInt(listSize);
if(i != randomIndex) {
//将列表中索引i对应的数据和随机索引对调位置
Object temp = list.get(i);
list.set(i,list.get(randomIndex));
list.set(randomIndex,temp);
}
}
}
return list;
}
查询试卷下的所有题目和选项
查询试题列表(不带选项,不分页)
/**
* 查询试题
* @param questionDbId
*/
List<CourseQuestions> listQuestionByDbId(Long questionDbId, boolean isCrucial);
1创建查询,查询条件题库id
2把查询到的试题列表循环,然后调用获得选项列表的方法给每个试题赋值选项
3最后返回试题列表
/**
* 查询试题列表(带选项,不分页)
* @param questionDbId
* @param isCrucial
* @return
*/
@Override
public List<CourseQuestions> listQuestionByDbId(Long questionDbId, boolean isCrucial) {
QueryWrapper<CourseQuestions> questionsQueryWrapper = new QueryWrapper<>();
if(questionDbId != null) {
questionsQueryWrapper.lambda().eq(CourseQuestions::getQuestionDbId,questionDbId);
if(isCrucial) {
questionsQueryWrapper.lambda().eq(CourseQuestions::getIsCrucial,1);
} else {
questionsQueryWrapper.lambda().eq(CourseQuestions::getIsCrucial,0);
}
}
List<CourseQuestions> list = list(questionsQueryWrapper);
list.forEach(item -> {
item.setOptionList(courseQuestionsOptionService.getOptionsByQuestionId(item.getId()));
});
return list;
}
查询单个问题的详情
/**
* 查看问题详细信息
* @param questionId
* @return
*/
CourseQuestions questionDetail(Long questionId);
根据试题id拿到试题对象,然后查询选项列表给试题赋值,最后返回试题对象
/**
* 查看单个问题详细信息
*就是问题带选项
* @param questionId
* @return
*/
@Override
public CourseQuestions questionDetail(Long questionId) {
CourseQuestions courseQuestions = getById(questionId);
if(courseQuestions != null) {
courseQuestions.setOptionList(courseQuestionsOptionService.getOptionsByQuestionId(questionId));
}
return courseQuestions;
}
更新试题
/**
* 更新试题
* @param questionReqVO
*/
void updateQuestion(QuestionReqVO questionReqVO);
1 判断 参数,判断修改的时候题干不要重复
2对选项判断,如果是判断题,初始化选项列表,创建两个选择对象,把对和错分别对应的选项名和选项值赋值后,选项对象添加到选项列表,若果不是判断题,选项列表就从前端拿到,双层循环选项列表,判断选项值不能为空,选项值不能重复
3更新操作,创建问题对象,复制属性
4对选项列表的更新,典型的对列表的多个数据进行更新操作(
先查询库中的选项列表数据
初始化新的选项列表,为了存放新的数据,初始化id列表,为了删除数据做准备
循环参数中的选项列表,把数据放入初始化的新的选项列表
找出需要删除的选项id,外城循环库中原始列表数据,定义一个初始值为0,内层循环参数列表数据,如果内城的选项id不为空(说明它是在原有数据上修改)而且 外层数据id和内层id一样,初始值自增,如果这个初始值还是0,说明原来库中的选项已经没用,把他的id添加到初始化的要删除的选项列表
添加或修改新的,删除没用的选项saveOrUpdateBatch(optionListNew); .removeByIds(optionListDel);
)
5更新问题
/**
* 更新试题
* @param questionReqVO
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void updateQuestion(QuestionReqVO questionReqVO) {
//先判断参数
if(questionReqVO == null) {
throw new BerryException("参数不能为空");
}
if (questionReqVO.getQuestionDbId() == null) {
throw new BerryException("题库不能为空");
}
if (StrUtil.isBlank(questionReqVO.getQuestionName())) {
throw new BerryException("题干不能为空");
}
if (StrUtil.isBlank(questionReqVO.getQuestionAnswerRight()) && questionReqVO.getQuestionType() != 5) {
throw new BerryException("正确答案不能为空");
}
if (questionReqVO.getQuestionType() == null) {
throw new BerryException("题目类型不能为空");
}
if ((questionReqVO.getQuestionType() != 3 && questionReqVO.getQuestionType() != 4 && questionReqVO.getQuestionType() != 5) && (questionReqVO.getOptionList() == null || questionReqVO.getOptionList().size() == 0)) {
throw new BerryException("选项不能为空");
}
//判断题干不能重复
QueryWrapper<CourseQuestions> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(CourseQuestions::getQuestionDbId,questionReqVO.getQuestionDbId());
queryWrapper.lambda().eq(CourseQuestions::getQuestionName,questionReqVO.getQuestionName());
queryWrapper.lambda().ne(CourseQuestions::getId,questionReqVO.getQuestionId());
List<CourseQuestions> list = list(queryWrapper);
if(list.size() > 0) {
throw new BerryException("该题目已经存在,请重新设置");
}
//初始化选项列表,为了封装好数据之后批量添加
List<CourseQuestionsOption> optionList = new ArrayList<>();
if(questionReqVO.getQuestionType() == 3) {
//如果是判断题的话,向选项列表中封装数据
CourseQuestionsOption optionA = new CourseQuestionsOption();
optionA.setOptionName("A");
optionA.setOptionValue("对");
CourseQuestionsOption optionB = new CourseQuestionsOption();
optionB.setOptionName("B");
optionB.setOptionValue("错");
optionList.add(optionA);
optionList.add(optionB);
} else {
//如果是选择题需要对选项做判断
optionList = questionReqVO.getOptionList();
for (CourseQuestionsOption option:optionList) {
if(StrUtil.isEmpty(option.getOptionValue())) {
throw new BerryException("选项中有选项值为空,请重新设置")
}
String optionValue = option.getOptionValue().trim();
for (CourseQuestionsOption optionNext:optionList) {
if(StrUtil.isEmpty(optionNext.getOptionValue())) {
throw new BerryException("选项中有选项值为空。请重新配置");
}
String nextOptionValue = optionNext.getOptionValue().trim();
if(option != optionNext) {
if(optionValue == nextOptionValue) {
throw new BerryException("选项中有重复的选项值,请重新输入");
}
}
}
}
}
//前面都是参数的判断,后面是具体的操作
CourseQuestions courseQuestions = new CourseQuestions();
BeanUtils.copyProperties(questionReqVO,courseQuestions);
courseQuestions.setId(questionReqVO.getQuestionId());
//下面的操作是对列表的多个数据的更新操作
//1 先从库中查询之前对应的列表
List<CourseQuestionsOption> oldOptionList = courseQuestionsOptionService.getOptionsByQuestionId(questionReqVO.getQuestionId());
//2初始化一个新的选项列表为了存放新数据,初始化一个id列表,为了删除旧数据
List<CourseQuestionsOption> optionListNew = new ArrayList<>();
List<Long> optionListDel = new ArrayList<>();
//3循环参数给的选项列表数据,把它放到新的列表之中
for (CourseQuestionsOption option : optionList) {
option.setQuestionId(questionReqVO.getQuestionId());
optionListNew.add(option);
}
//4 找出需要删除的选项记录
List<CourseQuestionsOption> finalOptionList = optionList;
//外层循环库中原始列表数据,定义个初始值为0,内层循环参数中的列表数据,若参数列表中的选项id不为空且和原始列表选项id一样,初始值自增,若初始值还是0,说明库中的这个选项在页面被删掉了,把它放入到要删除的列表之中
oldOptionList.forEach(item -> {
int haveCount = 0;
for (CourseQuestionsOption courseQuestionsOption:finalOptionList) {
if(courseQuestionsOption.getOptionId() != null && courseQuestionsOption.getOptionId().equals(item.getOptionId())) {
haveCount ++;
}
}
if(haveCount == 0) {
optionListDel.add(item.getOptionId());
}
});
if(optionListNew.size() > 0) {
courseQuestionsOptionService.saveOrUpdateBatch(optionListNew);
}
if(optionListDel.size() > 0) {
courseQuestionsOptionService.removeByIds(optionListDel);
}
//最后更新问题
updateById(courseQuestions);
}
删除试题
/**
* 删除试题
* @param questionId
*/
void deleteQuestion(Long questionId);
需要删除问题,更新题库问题数量。用map删除试卷和问题的映射关系
/**
* 删除试题
* @param questionId
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void deleteQuestion(Long questionId) {
//先看试题是否还存在
CourseQuestions questions = getById(questionId);
if(questions == null) {
throw new BerryException("题目已经删除");
}
removeById(questionId);
//更新题目数量
updateDbQuestionCount(questions.getQuestionDbId(),-1);
Map<String, Object> map = new HashMap<>();
map.put("question_id",questionId);
List<ExamPaperQuestionMap> list = examPaperQuestionMapService.listByMap(map);
if(list != null && list.size() > 0) {
throw new BerryException("题目关联试卷,抢先删除试卷关联");
} else {
courseQuestionsOptionService.removeByMap(map);
}
}
题库导入题目
@SysLogAnnotation("题库导入题目")
@ApiOperation("题库导入题目")
@PostMapping("/batchImport/{questionDbId}")
public BaseResponse importQuestion(@PathVariable Long questionDbId, @RequestParam("file") MultipartFile uploadFile) {
try {
List<CourseQuestionExcelModel> list = EasyExcelFactory.read(new BufferedInputStream(uploadFile.getInputStream())).head(CourseQuestionExcelModel.class).sheet(0).headRowNumber(1).doReadSync();
courseQuestionsService.importQuestion(questionDbId, list);
return BaseResponse.success();
} catch (Exception ex) {
ex.printStackTrace();
log.info("exception:{}", ex.getMessage());
return BaseResponse.fail(ex.getMessage());
}
}
/**
* 题库导入题目
* @param questionDbId
* @param importList
* @return
*/
List<Long> importQuestion(Long questionDbId, List<CourseQuestionExcelModel> importList);
1参数是题库id,列表数据,根据题库id获得题库,看题库是否还存在 ,循环列表,如列表中有题干为空,移除该题目
2判断导入的题目和库中的题目是否有重复,先通过循环参数列表,抽取出来题干列表,我们拿题干列表做为参数,对实体进行in查询,若能拿到试题列表,这些试题列表中的数据就是库中已经存在,循环我们拿到的试题列表,抽取题干属性,把导入的课表中有该题干的都移除importList.removeIf(obj -> obj.getQuestionName().equals(questionName));
3正式的导入操作,循环我们的导入列表,(
//创建QuestionReqVO对象,它是新增问题的参数,下面需要封装属性,先赋值已有的题库id,从导入数据中可以知道题目类型,赋值给vo对象
//也需要给选项表赋值,先初始化选项列表,若不是判断题,初始化一个选项数组
String[] optionNameArray = "a,b,c,d,e,f,g,h,i,j,k".toUpperCase().split(",");,该数组提供选项名,循环该数组,根据选项名获取选项值,若选项值不为空,创建选项对象,把选项名和选项值都赋值进去,然后选项添加到选项列表
//如果是多选题,需要拼接正确选项:创建StringBuilder对象,用于拼接,如果导入对象的正确答案不包括(","),不包括(", "),那正确答案按照空格分割,生成数组,循环数组,把数组中的空格去掉,然后把正确答案和,拼接
//如果包含(",");正确答案按照(",")分割,循环数组,进行正确答案的拼接
//拼接之后把最后一个逗号去掉,
String nextAnswer = finalAnswer.substring(0, finalAnswer.length() - 1); 然后赋值正确答案
//如果是判断题,给选项列表赋值,设定正确答案,不是判断题的话,循环选项列表,判断选项
//把选项列表赋值给vo对象,给vo赋值正确答案,答案解析,分数,然后作为参数调用添加问题方法
)
最后更新问题数量
/**
* 题库导入题目
* 数据导入
* @param questionDbId
* @param importList
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public List<Long> importQuestion(Long questionDbId, List<CourseQuestionExcelModel> importList) {
CourseQuestionDb db = courseQuestionDbService.getById(questionDbId);
if(db == null) {
throw new BerryException("题库不存在");
}
//初始化一个id列表
List<Long> idList = new ArrayList<>();
//判断 导入列表若有空的题干,去除
importList.forEach(obj -> {
if(obj.getQuestionName().trim().equals("")) {
importList.remove(obj);
}
});
//获得题干列表
List<String> questionTitleList = importList.stream().map(obj ->
obj.getQuestionName()
).collect(Collectors.toList());
//判断导入的题目和库中的题目重复需要移除,我们拿导入的题干列表作为参数,查询数据库看是否有一样的题干,若有的话直接把导入的列表中重复的题移除
QueryWrapper<CourseQuestions> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().in(true,CourseQuestions::getQuestionName,questionTitleList);
List<CourseQuestions> courseQuestionsList = list(queryWrapper);
for (CourseQuestions courseQuestions : courseQuestionsList) {
String questionName = courseQuestions.getQuestionName();
importList.removeIf(obj -> obj.getQuestionName().equals(questionName));
//这些是和导入的题干有重的问题id
idList.add(courseQuestions.getId());
}
//正式的导入操作
for(CourseQuestionExcelModel questionModel : importList) {
//创建QuestionReqVO对象,它是新增问题的参数,下面需要封装属性
QuestionReqVO questionReqVO = new QuestionReqVO();
questionReqVO.setQuestionDbId(questionDbId);
//也需要给选项表赋值,先初始化选项列表
List<CourseQuestionsOption> optionList = new ArrayList<>();
questionReqVO.setQuestionType(COURSE_QUESITION_TYPE.getTypeByName(questionModel.getQuestionType()));
String[] optionNameArray = "a,b,c,d,e,f,g,h,i,j,k".toUpperCase().split(",");
if(questionReqVO.getQuestionType() != 3) {
//题目不是判断题
for (String optionName : optionNameArray) {
String optionValue = questionModel.getOptionValue(optionName);
if(optionValue != null && optionValue.length() > 0) {
CourseQuestionsOption option = new CourseQuestionsOption();
option.setOptionName(optionName);
option.setOptionValue(optionValue);
optionList.add(option);
}
}
}
//多选题
if(questionReqVO.getQuestionType().equals(2)) {
StringBuilder finalAnswer = new StringBuilder();
if(!questionModel.getQuestionAnswerRight().contains(",")) {
if(!questionModel.getQuestionAnswerRight().contains(", ")) {
String[] answerArray = questionModel.getQuestionAnswerRight().split("");
for(String answerOption: answerArray) {
if(!answerOption.trim().equals("")) {
finalAnswer.append(answerOption).append(",");
}
}
} else {
String[] answerArray = questionModel.getQuestionAnswerRight().split(",");
for (String answerOption : answerArray) {
if (!answerOption.trim().equals("")) {
finalAnswer.append(answerOption).append(",");
}
}
}
//就是把正确答案去掉最后一个逗号
if(finalAnswer.length() > 0) {
String nextAnswer = finalAnswer.substring(0, finalAnswer.length() - 1);
questionModel.setQuestionAnswerRight(nextAnswer);
}
}
}
//判断题
if(questionReqVO.getQuestionType() == 3) {
String answerValue = "";
if(optionList.size() == 0) {
CourseQuestionsOption option = new CourseQuestionsOption();
option.setOptionName("A");
option.setOptionValue("对");
optionList.add(option);
CourseQuestionsOption optionB = new CourseQuestionsOption();
optionB.setOptionName("B");
optionB.setOptionValue("错");
optionList.add(optionB);
}
//设定正确答案呢
if (questionModel.getQuestionAnswerRight().equals("对")
|| questionModel.getQuestionAnswerRight().equals("1")
|| questionModel.getQuestionAnswerRight().equals("A")) {
answerValue = "A";
} else {
answerValue = "B";
}
questionModel.setQuestionAnswerRight(answerValue);
} else {
for(CourseQuestionsOption option:optionList) {
if(StrUtil.isEmpty(option.getOptionValue())) {
throw new BerryException("问题选项中有选项值为空,请重新配置")
}
String optionValue = option.getOptionValue().trim();
for (CourseQuestionsOption nextOption : optionList) {
if(StrUtil.isEmpty(nextOption.getOptionValue())) {
throw new BerryException("问题选项中有选项值为空,请重新配置并提交");
}
String nextOptionValue = nextOption.getOptionValue().trim();
if(option != nextOption) {
if(optionValue.equals(nextOptionValue)) {
throw new BerryException("选项中有选项值重复,请重新配置并且提交");
}
}
}
}
}
if(optionList.size() > 0) {
questionReqVO.setOptionList(optionList);
}
questionReqVO.setQuestionAnswerRight(questionModel.getQuestionAnswerRight());
questionReqVO.setQuestionAnalization(questionModel.getQuestionAnalysis());
questionReqVO.setScore(questionModel.getScore());
addQuestion(questionReqVO);
idList.add(questionReqVO.getQuestionId());
}
updateDbQuestionCount(questionDbId,importList.size());
return idList;
}
题库导出题目
@SysLogAnnotation("题库题目导出")
@ApiOperation("题库题目导出")
@GetMapping("/exportQuestion/{bookId}")
public void exportQuestion(HttpServletResponse response,@PathVariable Long bookId) {
try {
List<CourseQuestionExcelModel> resultList = courseQuestionsService.exportData(bookId);
ExcelUtil.writeExcel(response,resultList,"QuestionDb","课程题库模板",CourseQuestionExcelModel.class);
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 题库题目导出
* @param questionDbId
* @return
*/
List<CourseQuestionExcelModel> exportData(Long questionDbId);
1先根据题库id为条件,查询该题库的所有试题列表
2我们要返回的是ExcelModel列表,所以先初始化ExcelModel列表
3循环试题列表,在循环中创建ExcelModel对象,用来接收相关的属性,
4返回ExcelModel列表
/**
* 题库题目导出
* 是根据题库id为条件,查出该题库所有的问题列表,然后把该问题列表转换成对应的ExcelModel列表
* @param questionDbId
* @return
*/
@Override
public List<CourseQuestionExcelModel> exportData(Long questionDbId) {
//1先通过题库id为条件,查询该题库对应的所有问题列表
QueryWrapper<CourseQuestions> questionsQueryWrapper = new QueryWrapper<>();
questionsQueryWrapper.lambda().eq(CourseQuestions::getQuestionDbId,questionDbId);
List<CourseQuestions> voList = list(questionsQueryWrapper);
//2我们要返回的是ExcelModel列表,所以先初始化ExcelModel列表
List<CourseQuestionExcelModel> resultList = new ArrayList<>();
for(CourseQuestions vo : voList) {
//3 循环问题列表,在循环中创建ExcelModel对象,用来接收相关的属性
//4属性赋值,把ExcelModel对象加入到ExcelModel列表之中
CourseQuestionExcelModel excelModel = new CourseQuestionExcelModel();
List<CourseQuestionsOption> optionList = courseQuestionsOptionService.getOptionsByQuestionId(vo.getId());
if(optionList.size() > 0) {
for (CourseQuestionsOption option : optionList) {
excelModel.setOptionValue(option.getOptionName(),option.getOptionValue());
}
}
excelModel.setQuestionAnswerRight(vo.getQuestionAnswerRight());
excelModel.setQuestionName(vo.getQuestionName());
excelModel.setQuestionType(COURSE_QUESITION_TYPE.getNameByType(vo.getQuestionType()));
resultList.add(excelModel);
}
return resultList;
}
随机生成试题列表,指定试题的个数
@SysLogAnnotation("题库随机题目")
@ApiOperation("题库随机题目")
@GetMapping("/randomQuestion/{questionDbId}")
public BaseResponse< List<CourseQuestions> > getNextQuestion(@PathVariable("questionDbId") Long questionDbId){
try {
List<CourseQuestions> randomQuestions = courseQuestionsService.getRandomQuestionByDbId(questionDbId,10);
return BaseResponse.success(randomQuestions);
} catch (BerryException e) {
log.info("exception:{}", e.getMessage());
return BaseResponse.fail(e.getMessage());
} catch (Exception e) {
log.info(" createQuestion exception:{}", "题库随机题目失败");
return BaseResponse.fail("题库随机题目失败");
}
}
参数是题库id,题目数量
1判断题库是否存在,根据题库Id查询试题列表
2随机有两种情况,一种是库中的试题够用,那么初始化一个接收问题的列表,创建Random对象,按照指定试题数量进行循环,生成随机数的范围为0-list.size()-1,把随机数作为问题id获得问题独享,添加的初始化的问题列表中,然后循环初始化后的列表,天骄选项,最后返回该列表
3另一种情况就是库中题目不够用,就不用随机了,直接用就行
/**
* 随机生成下一题
* 随机生成试题列表,指定试题的个数
*
* @param questionDbId
* @param randomNum
* @return、
*/
@Override
public List<CourseQuestions> getRandomQuestionByDbId(Long questionDbId,int randomNum) {
//先判断参数,看看题库是否还存在
if(questionDbId == null) {
throw new BerryException("题库id不能为空");
}
//随机个数不能 < 0
if(randomNum < 0 ) {
throw new BerryException("随机个数必须大于0");
}
CourseQuestionDb courseQuestionDb = courseQuestionDbService.getById(questionDbId);
if(courseQuestionDb == null) {
throw new BerryException("题库不存在");
}
//查询该题库中的所有问题列表
QueryWrapper<CourseQuestions> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(CourseQuestions::getQuestionDbId,questionDbId);
List<CourseQuestions> courseQuestionsList = list(queryWrapper);
if(CollUtil.isNotEmpty(courseQuestionsList)) {
//随机的时候有两种情况,一个是指定的随机数小于 现有的题目数,也就是现有题目够用,初始化一个接收问题的列表,然后循环,在循环中用随机数作为问题的id,然后获得问题呢对象,把问题添加到初始化的问题列表之中
if(courseQuestionsList.size() > randomNum) {
List<CourseQuestions> backSum = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < randomNum ; i++) {
//随机数的范围为0-list.size()-1
int target = random.nextInt(courseQuestionsList.size());
CourseQuestions courseQuestions = courseQuestionsList.get(target);
courseQuestions.setQuestionAnswerRight(null);
courseQuestions.setQuestionAnalization(null);
backSum.add(courseQuestions);
//删除掉已经被选择的
courseQuestionsList.remove(target);
}
//给生成的题目赋值选项
if(backSum.size() > 0) {
backSum.forEach(item -> {
item.setOptionList(courseQuestionsOptionService.getOptionsByQuestionId(item.getId()));
});
}
return backSum;
} else {
//现有题目不够用,就不随了
courseQuestionsList.forEach(item -> {
item.setQuestionAnswerRight(null);
item.setQuestionAnalization(null);
item.setOptionList(courseQuestionsOptionService.getOptionsByQuestionId(item.getId()));
});
return courseQuestionsList;
}
} else {
return ListUtil.empty();
}
}
课程题目作答
参数
/**
* 学生课程试题练习作答测试
*/
@Data
@ApiModel(value = "课程练习学生作答结果VO" ,description = "课程练习学生作答结果VO")
public class StudentQuestionApplyResultVO {
/**
* 问题Id
*/
@ApiModelProperty("问题ID")
private Long questionId;
/**
* 学生作答答案
*/
@ApiModelProperty("学生答案")
private String studentAnswer;
@ApiModelProperty("作答结果 true正确 false错误")
private Boolean answerResult;
@ApiModelProperty("问题详情")
private CourseQuestions courseQuestions;
}
/**
* 学生课程试题练习作答测试
*/
@Data
@ApiModel(value = "课程练习学生作答VO" ,description = "课程练习学生作答VO")
public class StudentQuestionApplyVO {
/**
* 问题Id
*/
@NotNull(message = "请输入问题ID")
@ApiModelProperty("问题ID")
private Long questionId;
/**
* 学生作答答案
*/
@NotNull(message = "请输入问题学生作答")
@ApiModelProperty("学生答案")
private String studentAnswer;
}
@SysLogAnnotation("题库题目作答")
@ApiOperation("题库题目作答")
@PostMapping("/questionApply")
public BaseResponse<StudentQuestionApplyResultVO> questionApply(@Valid @RequestBody StudentQuestionApplyVO studentQuestionApplyVO,BindingResult bindingResult){
if (bindingResult.hasErrors()) {
throw new BerryException(bindingResult.getFieldError().getDefaultMessage());
}
try {
StudentQuestionApplyResultVO studentQuestionApplyResultVO = courseQuestionsService.studentQuestionApply(studentQuestionApplyVO);
return BaseResponse.success(studentQuestionApplyResultVO);
} catch (BerryException e) {
log.info("exception:{}", e.getMessage());
return BaseResponse.fail(e.getMessage());
} catch (Exception e) {
log.info(" createQuestion exception:{}", "题库题目作答失败");
return BaseResponse.fail("题库题目作答失败");
}
}
/**
* 课程题目作答
* @param studentQuestionApplyVO
* @return
*/
StudentQuestionApplyResultVO studentQuestionApply(StudentQuestionApplyVO studentQuestionApplyVO);
/**
* 课程题目作答
* StudentQuestionApplyResultVO:课程练习学生作答结果VO,包括问题id,学生答案,作答结果(true正确 false错误) 问题详情
*
* StudentQuestionApplyVO:问题id ,学生答案
* @param studentQuestionApplyVO
* @return
*/
@Override
public StudentQuestionApplyResultVO studentQuestionApply(StudentQuestionApplyVO studentQuestionApplyVO) {
if(studentQuestionApplyVO == null) {
throw new BerryException("请输入作答内容");
}
Long questionId = studentQuestionApplyVO.getQuestionId();
CourseQuestions courseQuestions = getById(questionId);
if(courseQuestions == null) {
throw new BerryException("问题不存在");
}
//创建StudentQuestionApplyResultVO 对象,用来封装作答情况
StudentQuestionApplyResultVO studentQuestionApplyResultVO = new StudentQuestionApplyResultVO();
studentQuestionApplyResultVO.setStudentAnswer(studentQuestionApplyVO.getStudentAnswer());
studentQuestionApplyResultVO.setQuestionId(studentQuestionApplyVO.getQuestionId());
//判断是否答对
if(courseQuestions.getQuestionAnswerRight().equals(studentQuestionApplyVO.getStudentAnswer())) {
//回答正确
studentQuestionApplyResultVO.setAnswerResult(true);
} else {
studentQuestionApplyResultVO.setAnswerResult(false);
}
studentQuestionApplyResultVO.setCourseQuestions(courseQuestions);
return studentQuestionApplyResultVO;
}
试卷题目分页列表
@Data
@ApiModel(value = "试卷题目列表请求VO")
public class QuestionPageDataReqVo {
@ApiModelProperty(value = "分页参数")
private PageReqVO pageReqVO;
@ApiModelProperty(value = "试卷ID")
private Long paperId;
@ApiModelProperty(value = "题库ID")
private Long questionDbId;
}
@Data
@ApiModel(value = "试卷题目分页列表Vo")
public class QuestionPageVo {
@ApiModelProperty(value = "返回分页配置")
private PageResVO pageResVO;
@ApiModelProperty(value = "题目列表")
private List<PaperQuestionData> questionList;
@Data
public class PaperQuestionData {
@ApiModelProperty(value = "题目ID")
private Long questionId;
@ApiModelProperty(value = "题目题干")
private String questionName;
@ApiModelProperty(value = "题目类型")
private Integer questionType;
@ApiModelProperty(value = "题目分数")
private Integer score;
@ApiModelProperty(value = "是否为试卷题目")
private boolean isSelected;
}
@SysLogAnnotation("试卷题目分页列表")
@ApiOperation("试卷题目分页列表")
@PostMapping("/paperQuestionList")
public BaseResponse<QuestionPageVo> paperQuestionList(@RequestBody QuestionPageDataReqVo reqVo) {
QuestionPageVo questionPageVo =courseQuestionsService.listQuestionPageData(reqVo);
return BaseResponse.success(questionPageVo);
}
/**
* 试卷题目分页列表
* @param reqVo
* @return
*/
QuestionPageVo listQuestionPageData(QuestionPageDataReqVo reqVo);
/**
* 试卷题目分页列表
* PaperQuestionData: 题目ID、题目题干、题目类型、题目分数、是否为试卷题目
* QuestionPageVo 分页返回:分页参数、题目列表private List<PaperQuestionData> questionList;
* 试卷题目列表请求VO:分页参数、试卷id、题库id
* @param reqVo
* @return
*/
@Override
public QuestionPageVo listQuestionPageData(QuestionPageDataReqVo reqVo) {
//先根据题库id查询所有的问题列表
PageHelper.startPage(reqVo.getPageReqVO().getCurrent(),reqVo.getPageReqVO().getPageSize());
QueryWrapper<CourseQuestions> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(CourseQuestions::getQuestionDbId,reqVo.getQuestionDbId());
queryWrapper.orderByDesc("id");
List<CourseQuestions> resultQuestion = list(queryWrapper);
//把查询结果封装到PageInfo
PageInfo<CourseQuestions> pageInfo = new PageInfo<>(resultQuestion);
//创建返回对象
QuestionPageVo courseQuestionPageResVo = new QuestionPageVo();
List<PaperQuestionData> resultList = pageInfo.getList().stream().map(item -> {
PaperQuestionData paperQuestionData = new PaperQuestionData();
paperQuestionData.setQuestionId(item.getId());
paperQuestionData.setQuestionName(item.getQuestionName());
paperQuestionData.setQuestionType(item.getQuestionType());
//看试题是否和试卷有关系,从映射表中看
ExamPaperQuestionMap examPaperQuestionMap = examPaperQuestionMapService.getDetailQuestionByPaperIdAndQuestionId(reqVo.getPaperId(), item.getId());
if (examPaperQuestionMap != null) {
paperQuestionData.setSelected(true);
paperQuestionData.setScore(examPaperQuestionMap.getScore());
} else {
paperQuestionData.setSelected(false);
paperQuestionData.setScore(item.getScore());
}
return paperQuestionData;
}).collect(Collectors.toList());
courseQuestionPageResVo.setQuestionList(resultList);
PageResVO pageResVO = new PageResVO();
pageResVO.setCurrent(pageInfo.getPageNum());
pageResVO.setPageSize(pageInfo.getPageSize());
pageResVO.setTotal(pageInfo.getTotal());
courseQuestionPageResVo.setPageResVO(pageResVO);
return courseQuestionPageResVo;
}
课程问题映射表
批量添加记录
参数是问题列表,课程id
先判断参数和判断课程是否存在
批量添加就是参数列表转为目标列表,然后批量保存列表,我们循环参数列表,循环里面创建目标对象,对目标对象赋值之后,返回目标对象,然后就可以生成目标列表
/**
* 向课程问题映射表中批量添加记录
* * 参数是topicId 课程id,问题列表
* 批量添加的思路就是循环问题列表,把关联关系添加到映射表中
* * 需要创建映射表对象,赋值属性,返回映射对象
* @param list
* @param topicId
* @return
*/
@Override
public boolean addBatchMap(List<CourseQuestions> list, Long topicId) {
if(topicId == null) {
return false;
}
CourseBasicInfo courseBasicInfo = courseBasicInfoService.getById(topicId);
if(courseBasicInfo == null) {
return false;
}
//循环参数列表生成映射列表,就可以直接用列表做参数批量添加
List<CourseQuestionsMap> courseQuestionsMapList = list.stream().map(obj -> {
CourseQuestionsMap courseQuestionsMap = new CourseQuestionsMap();
courseQuestionsMap.setQuestionId(obj.getId());
courseQuestionsMap.setCourseId(topicId);
return courseQuestionsMap;
}).collect(Collectors.toList());
return saveOrUpdateBatch(courseQuestionsMapList);
}
根据课程id批量删除映射关系
根据课程id查询对应的映射列表数据,循环该列表拿到主键id列表,然后removeByIds(ids);
/**
* 根据课程id批量删除映射表记录
* 先通过课程id拿到在映射表中与该课程相关的记录List,再从list的循环中拿到主键列表
* 根据removeByIds(ids)即可达到目的
* @param courseId
* @return
*/
@Override
public boolean removeList(Long courseId) {
List<CourseQuestionsMap> list = getListByCourseId(courseId);
List<Long> ids = list.stream().map(obj ->
obj.getId()
).collect(Collectors.toList());
boolean success = removeByIds(ids);
return success;
}
根据问题id批量删除映射关系
/**
* 根据问题id批量删除映射表记录
* @param questionId
* @return
*/
@Override
public boolean removeByQuestionId(Long questionId) {
List<CourseQuestionsMap> list = getListByQuestionId(questionId);
List<Long> ids = list.stream().map(obj -> obj.getId()).collect(Collectors.toList());
if (ids.size() == 0) {
return true;
}
boolean success = removeByIds(ids);
return success;
}
单个删除
/**
* 单个删除
* @param id
* @return
*/
@Override
public boolean removeQuestion(Long id) {
return removeById(id);
}
通过问题id获得映射关系列表
/**
* 通过问题ID获得课程和问题映射列表
* @param questionId
* @return
*/
@Override
public List<CourseQuestionsMap> getListByQuestionId(Long questionId) {
QueryWrapper<CourseQuestionsMap> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(CourseQuestionsMap::getQuestionId, questionId);
return list(queryWrapper);
}
通过课程id获得映射关系列表
/**
* 通过课程ID获得课程和问题映射列表
* @param courseId
* @return
*/
@Override
public List<CourseQuestionsMap> getListByCourseId(Long courseId) {
QueryWrapper<CourseQuestionsMap> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(CourseQuestionsMap::getCourseId, courseId);
return list(queryWrapper);
}
试卷管理
新增试卷