前言:顾名思义,随机组合试卷是区别于固定试卷的,固定试卷里面的题目都是规定好,不会产生变化;而随机组合试卷是事先定义好一套组合的规则,每次根据规则来随机产生不重复的试题组合。
一、背景意义:随机试卷功能的开发有效遏制了考场上作弊的不良风气,也有利于为所有考生提供公平、公正的考试环境,因此随机组卷功能的开发将成为考试界线上考试的一种主流。
二、需求分析:就像前言一样,本人在实际开发过程中开发了固定试卷和随机组卷这两个模块,在随机组卷模块里主要是制定各类型试题组合规则,包括每个类型题目数量多少,每个题目分值多少,还有该随机组合试卷名称和考试限时等等,具体效果图以及该模块表结构对应的实体类如下:
public class TRandomPaper implements Serializable {
private static final long serialVersionUID=1L;
/** 随机试卷ID */
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 随机试卷名称 */
@Excel(name = "随机试卷名称")
private String paperName;
/** 考核类别ID */
@Excel(name = "考核类别ID")
private Long subjectId;
/** 单选题数量 */
@Excel(name = "单选题数量")
private Long singleNum;
/** 每个单选题分值 */
@Excel(name = "每个单选题分值")
private Long perSingleScore;
/** 多选题数量 */
@Excel(name = "多选题数量")
private Long multipleNum;
/** 每个多选题分值 */
@Excel(name = "每个多选题分值")
private Long perMultipleScore;
/** 判断题数量 */
@Excel(name = "判断题数量")
private Long judgeNum;
/** 每个判断题分值 */
@Excel(name = "每个判断题分值")
private Long perJudgeScore;
/** 简答题数量 */
@Excel(name = "简答题数量")
private Long shortNum;
/** 每个简答题的分值 */
@Excel(name = "每个简答题的分值")
private Long perShortSocre;
/** 应用题数量 */
@Excel(name = "应用题数量")
private Long applyNum;
/** 每个应用题分值 */
@Excel(name = "每个应用题分值")
private Long perApplyScore;
/** 试卷总分 */
@Excel(name = "试卷总分")
private Long totalScore;
/** 考试限时(以分钟为单位) */
@Excel(name = "考试限时(以分钟为单位)")
private Long limitTime;
/** 试卷说明 */
@Excel(name = "试卷说明")
private String paperIntroduce;
/** 及格分数线*/
@Excel(name = "及格分数线")
private Long passSocre;
/** 考试开始时间 */
@Excel(name = "考试开始时间" , width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/** 考试结束时间 */
@Excel(name = "考试结束时间" , width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/** 试题难度星数 */
@Excel(name = "试题难度星数")
private Long difficultStartNum;
/** 是否删除(false代表未删除) */
@Excel(name = "是否删除(false代表未删除)")
private boolean deleted;
}
三、各类型试题根据规则随机进行不重复组合,代码如下:
/**
* 微信小程序根据规则进行不重复试题随机组卷
* @param qRequest
* @return
*/
@ApiOperation(value = "WX小程序根据规则进行不重复试题随机组卷",notes = "不重复试题随机组卷")
@RequestMapping(value = "/wxRandomQComByRule", method = RequestMethod.POST)
public Response<List<Question>> wxRandomQComByRule(@RequestBody Questionparam qRequest) {
//questionDetail.getList()可获取该考核类型下所有的试题集合
//获取questionDetail的相关方法代码此处省略,直接从此处开始
List<Question> qList = questionDetail.getList();
//根据考核类型subjectId查询该类别随机组卷规则详情
QueryWrapper<TRandomPaper> randomWrapper = new QueryWrapper<TRandomPaper>();
//qRequest.getSubjectId()可获取考核模块subjectId
randomWrapper.lambda().eq(TRandomPaper::getSubjectId, qRequest.getSubjectId());
TRandomPaper tRandomPaper = iTRandomPaperService.getOne(randomWrapper);
//预定义各种类型的题目的集合
List<Question> qSingelList = new ArrayList<Question>();
List<Question> qMultipleList = new ArrayList<Question>();
List<Question> qJudgeList = new ArrayList<Question>();
List<Question> qShortList = new ArrayList<Question>();
List<Question> qApplylList = new ArrayList<Question>();
//遍历该考核模块下先前拿到的试题总集合
for(Question Question : qList) {
//由于QuestionType是数值类型,此处转成字符串,要不然switch/case 用不了
switch (Question.getQuestionType().toString()) {
//1代表单选题
case "1":
qSingelList.add(Question);
break;
//2代表多选题
case "2":
qMultipleList.add(Question);
break;
//3代表判断题
case "3":
qJudgeList.add(Question);
break;
//5代表简答题
case "5":
qShortList.add(Question);
break;
//6代表应用题
case "6":
qApplylList.add(Question);
break;
default:
break;
}
}
//预定义各类型试题随机结果集合
List<Question> singeRQList = null;
List<Question> multiRQList = null;
List<Question> judgeRQList = null;
List<Question> shortRQList = null;
List<Question> applyRQList = null;
//单选题:如题库题数小于等于需要的题数,即返回现有的题目集合
if(qSingelList.size() <= tRandomPaper.getSingleNum().intValue()) {
singeRQList = qSingelList;
}else {
//此处随机拿到该类型的试题的HashSet<Question>格式,需转成ArrayList<Question>,才能用singeRQList接收
singeRQList = new ArrayList<Question>(this.getQTypeHashSet(qSingelList, tRandomPaper.getSingleNum().intValue()));
}
//多选题:如题库题数小于等于需要的题数,即返回现有的题目集合
if(qMultipleList.size() <= tRandomPaper.getMultipleNum().intValue()) {
multiRQList = qSingelList;
}else {
//此处随机拿到该类型的试题的HashSet<Question>格式,需转成ArrayList<Question>,才能用multiRQList接收
multiRQList = new ArrayList<Question>(this.getQTypeHashSet(qMultipleList, tRandomPaper.getMultipleNum().intValue()));
}
//判断题:如题库题数小于等于需要的题数,即返回现有的题目集合
if(qJudgeList.size() <= tRandomPaper.getJudgeNum().intValue()) {
judgeRQList = qJudgeList;
}else {
//此处随机拿到该类型的试题的HashSet<Question>格式,需转成ArrayList<Question>,才能用judgeRQList接收
judgeRQList = new ArrayList<Question>(this.getQTypeHashSet(qJudgeList, tRandomPaper.getJudgeNum().intValue()));
}
//简答题:如题库题数小于等于需要的题数,即返回现有的题目集合
if(qShortList.size() <= tRandomPaper.getShortNum().intValue()) {
shortRQList = qShortList;
}else {
//此处随机拿到该类型的试题的HashSet<Question>格式,需转成ArrayList<Question>,才能用shortRQList接收
shortRQList = new ArrayList<Question>(this.getQTypeHashSet(qShortList, tRandomPaper.getShortNum().intValue()));
}
//应用题:如题库题数小于等于需要的题数,即返回现有的题目集合
if(qApplylList.size() <= tRandomPaper.getApplyNum().intValue()) {
applyRQList = qApplylList;
}else {
//此处随机拿到该类型的试题的HashSet<Question>格式,需转成ArrayList<Question>,才能用applyRQList接收
applyRQList = new ArrayList<Question>(this.getQTypeHashSet(qApplylList, tRandomPaper.getApplyNum().intValue()));
}
//调用合并各类型随机试题集合的方法
List<Question> finalList = this.mergeQList(singeRQList, multiRQList, judgeRQList, shortRQList, applyRQList);
questionDetail.setList(finalList);
return Response.ok(questionDetail);
}
/**
* 根据不同类型的试题集合和规则中该类型题目制定的数量返回随机不重复的HashSet集合
* @param qList qMumber
* @return
*/
public Set<Question> getQTypeHashSet(List<Question> qList, int qMumber){
Set<Question> questionSet = new HashSet<>();
while (numSet.size() < qMumber) {
int index = (int) (Math.floor(Math.random() * qList.size()));
if(!questionSet.contains(qList.get(index))) {
questionSet.add(qList.get(index));
}
}
//此处打印随机生成的结构
for(Question Question : questionSet){
System.out.println("试题类型:"+Question.getQuestionType()+"// 试题Id:"+Question.getId());
}
System.out.println("--------------------------------------");
return questionSet;
}
/**
* 把随机生成各种类型试题进行合并
* @param singeRQList multiRQList judgeRQList shortRQList applyRQList
* @return
*/
public List<Question> mergeQList(List<Question> singeRQList, List<Question> multiRQList, List<Question> judgeRQList, List<Question> shortRQList, List<Question> applyRQList ){
List<Question> mergeList = new ArrayList<Question>();
mergeList.addAll(singeRQList);
mergeList.addAll(multiRQList);
mergeList.addAll(judgeRQList);
mergeList.addAll(shortRQList);
mergeList.addAll(applyRQList);
return mergeList;
}
四、根据规则各类型试题随机不重复组合效果图如下:
五、谢谢您的浏览,希望能帮到您或者稍微的启发到您!