在线考试系统的设计与实现

·  阅读 3906

这是我参与更文挑战的第3天,活动详情查看: 更文挑战

1、设计背景

近日有用户提出需求,需要在原网站中实现一套视频学习模块及在线考试模块,在这里我先介绍以下在线考试模块的设计思路。

实现一个基本功能的在线考试系统,需要以下几个要素:

1、题库管理【可能需要针对不同的考试设计不同的题库,比如驾考科目一、道路运输资格证】

2、章节管理【对应的是考试培训资料的章节】

3、考题管理【题库中包含的所有考题】

4、考题选项【每一道题的选择项】

5、准确答案【每一道考题的准确答案】

6、考试管理【在网站上发布最新的考试连接,用户可以通过链接进入考试】

7、考试结果查看【完成考试后,实时查看考试成绩及错题】 实现以上功能后,基本上算是一个比较完整的考试系统了,接下来我们针对这些功能点进行表结构设计。

2、表结构设计

根据以上细化的内容,我们先设计以下数据库,这里直接贴图了,注释写的很清晰

image.png

3、部分功能的实现过程及关键代码片段

代码写的也比较乱,小功能也没讲究太多,将就看吧。

架构环境介绍:整体是基于jfinal_cms开发,以jfinal为基础mvc框架,模板引擎是beetl,前台还是传统的bootstrap和jquery

3.1题库管理

这里比较简单,没什么逻辑

image.png

3.2题目管理

image.png

image.png

下面是设置正确选项的代码,这里单独加了多选题的处理逻辑,把准确选项的id用逗号分隔拼接后保存

	private void  set_right(TbExamAnswer model,TbExamQuestions questionsModel) {
		if(questionsModel.getQuestionsType()!=111) {//单选和判断题准确答案设置
			questionsModel.setRightAnswerId(model.getId().toString());
			questionsModel.setRightAnswerTitle(model.getAnswerTitle());
		}else {
			List<TbExamAnswer> answerList=TbExamAnswer.dao.findByWhere(" where questions_id=? and answer_right=1 order by id asc",questionsModel.getId());
			StringBuffer right_ids=new StringBuffer("");
			StringBuffer right_title=new StringBuffer("");
			for(int i=0;i<answerList.size();i++) {
				TbExamAnswer answer=answerList.get(i);
				right_ids.append(answer.getId().toString());
				right_title.append(answer.getAnswerTitle());
				if(i<answerList.size()-1) {
					right_ids.append(",");
					right_title.append(",");				
				}
			}
			questionsModel.setRightAnswerId(right_ids.toString());
			questionsModel.setRightAnswerTitle(right_title.toString());
		}
		questionsModel.update();
	}
复制代码

3.3 考试发布

image.png

image.png

这里是考试发布后的前台页面,用户可以通过这个连接进入考试页面

image.png

考试发布操作需要设置基础信息题目总数字段用来控制每一个用户答题试卷的抽题数量,规则里需要设置每一章节的抽题数量,以下是抽题部分的代码。

	public void index() {
		// 数据列表
		SysUser user = (SysUser) getSessionUser();
		if (user == null) {
			redirect(CommonController.firstPage);
			return;
		}
		int examPublishId = getParaToInt();
		TbExamPublish examPublish=TbExamPublish.dao.findById(examPublishId);
		TbExamPaper paper=new TbExamPaper();
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar nowTime=Calendar.getInstance();
		if(examPublish.getExamTimeLength()==null) {
			nowTime.add(Calendar.MINUTE, 60);
		}else {
			nowTime.add(Calendar.MINUTE, examPublish.getExamTimeLength());
		}

		paper.setUserId(user.getUserid());//用户id
		paper.setUserName(user.getUserName());//用户名称
		paper.setExamPublishId(examPublish.getId());//考试发布id
		paper.setExamName(examPublish.getExamName());
		paper.setExamCode(examPublish.getExamCode());//考试编号
		paper.setExamStatus(1);//考试中
		paper.setExamStartDate(sdf.format(new Date()));
		paper.setExamEndDate(sdf.format(nowTime.getTime()));
		paper.save();
		
		List<TbExamPublishRule> ruleList =TbExamPublishRule.dao.findByWhere(" where exam_publish_id="+examPublish.getId());
		String questionWhere="tb_exam_questions where tk_id=? and chapter_id=? and questions_type=? ORDER BY RAND() LIMIT ?";
		for(int i=0;i<ruleList.size();i++) {
			TbExamPublishRule rule=ruleList.get(i);
			List<TbExamQuestions> singleChoiceQuestions=TbExamQuestions.dao.findByWhere(questionWhere, rule.getExamTkId(),rule.getExamChapterId(),109,rule.getSingleChoiceCount());//抽取单选题
			List<TbExamQuestions> multipleChoiceQuestions=TbExamQuestions.dao.findByWhere(questionWhere, rule.getExamTkId(),rule.getExamChapterId(),111,rule.getMultipleChoiceCount());//抽取多选题
			List<TbExamQuestions> judgeQuestions=TbExamQuestions.dao.findByWhere(questionWhere, rule.getExamTkId(),rule.getExamChapterId(),110,rule.getJudgeCount());//抽取判断题
			singleChoiceQuestions.addAll(multipleChoiceQuestions);//合并单选和多选list
			for(TbExamQuestions q:singleChoiceQuestions) {
				TbExamPaperQuestions paperQuestion=new TbExamPaperQuestions();
				paperQuestion.setPaperId(paper.getId());//试卷id
				paperQuestion.setQuestionsId(q.getId());//题目id
				paperQuestion.setQuestionsTitle(q.getQuestionsTitle());//题目
				paperQuestion.setQuestionsType(q.getQuestionsType());//题目类型
				paperQuestion.setRightAnswerId(q.getRightAnswerId());//准确选项id
				paperQuestion.setRightAnswerTitle(q.getRightAnswerTitle());//准确选项标题
				paperQuestion.save();
				List<TbExamAnswer> answers=TbExamAnswer.dao.findByWhere(" where questions_id=? order by id asc", q.getId());//查询选项列表
				for(TbExamAnswer a:answers) {
					TbExamPaperAnswer paperAnswer=new TbExamPaperAnswer();
					paperAnswer.setPaperId(paper.getId());//试卷id
					paperAnswer.setQuestionsId(q.getId());//题目id
					paperAnswer.setAnswerId(a.getId().toString());//选项id
					paperAnswer.setAnswerTitle(a.getAnswerTitle());//选项标题
					paperAnswer.setAnswerContent(a.getAnswerContent());//选项内容
					paperAnswer.setAnswerRight(a.getAnswerRight()==null?null:a.getAnswerRight().toString());//是否正确答案
					paperAnswer.save();
				}
			}
			
			for(TbExamQuestions q:judgeQuestions) {
				TbExamPaperQuestions paperQuestion=new TbExamPaperQuestions();
				paperQuestion.setPaperId(paper.getId());//试卷id
				paperQuestion.setQuestionsId(q.getId());//题目id
				paperQuestion.setQuestionsTitle(q.getQuestionsTitle());//题目
				paperQuestion.setQuestionsType(q.getQuestionsType());//题目类型
				paperQuestion.setRightAnswerId(q.getRightAnswerId());//准确选项id
				paperQuestion.setRightAnswerTitle(q.getRightAnswerTitle());//准确选项标题
				paperQuestion.save();
			}
				//BeanUtils.copyProperties(q,choiceQuestions.get(0));
			//log.info(rule.getExamChapterName()+ " 选择题--"+choiceQuestions.size()+"判断题--"+judgeQuestions.size());
		}
		redirect("/front/onlineExam/toExam/"+paper.getId());
		return;
	}

	public void toExam() {
		log.info("开始考试啦");
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		SimpleDateFormat sdf1=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		int paperId = getParaToInt();
		TbExamPaper paper=TbExamPaper.dao.findById(paperId);//试卷实体
		List<TbExamPaperQuestions> questionsList=TbExamPaperQuestions.dao.findByWhere(" where paper_id=? order by questions_type desc", paperId);//查询题目列表
		Map<Integer,List<TbExamPaperAnswer>> answerMap=new HashMap<Integer,List<TbExamPaperAnswer>>();//试题选项map
		for(TbExamPaperQuestions q:questionsList) {
			List<TbExamPaperAnswer> answers=TbExamPaperAnswer.dao.findByWhere(" where paper_id=? and questions_id=?", paperId,q.getQuestionsId());
			answerMap.put(q.getQuestionsId(), answers);
		}
		//try {
		Date d=paper.getExamEndDate();
		setAttr("examEndDate",sdf1.format(d));
		setAttr("paper",paper);
		setAttr("questionsList",questionsList);
		setAttr("answerMap",answerMap);
		renderAuto(path + "exam_page.html");
	}
复制代码
以下是考试页面,实现方式主要是遍历所以试题,根据题目类型渲染不同的dom标签。
复制代码

image.png

这个js方法主要是为了在答题过程中,实时保存答题数据,防止页面刷新时丢失数据
复制代码
		function commitAnswer(paperId,questionsId,questionsType,answerId,domName){
			if(questionsType==111){
				var selAnswerId="";
				$("input:checkbox[name='"+domName+"']:checked").each(function(index) { // 遍历name=test的多选框
					size=$("input:checkbox[name='"+domName+"']:checked").length;
					if(index==size-1){
						selAnswerId+=$(this).val();  // 每一个被选中项的值
					}else{
						selAnswerId+=$(this).val()+",";  // 每一个被选中项的值	
					}
				});
				answerId=selAnswerId;
			}
			var url = '${BASE_PATH }front/onlineExam/saveAnswer';
			$.ajax({
				type:'POST',
				dataType:'json',
				data:{
					"paperId":paperId,
					"questionsId":questionsId,
					"questionsType":questionsType,
					"answerId":answerId
				},
				url:url,
				success:function(data){
					//$("#chapter_id").empty();
					//for(var i=0;i<data.length;i++){
					//	var item=data[i];
				  //  $("#chapter_id").append("<option value='"+item.id+"'>"+item.chapterName+"</option>");
					//}
					
				},
				error:function(html){
				}
			});
		}
复制代码

这段代码是确认提交后,计算分数的方法,逻辑很简单,就通过比对答题选项与准确答案选项

	public void commitPaper() {
		int paperId = getParaToInt();
		int score=0;
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		TbExamPaper paper=TbExamPaper.dao.findById(paperId);//试卷实体
		List<TbExamPaperQuestions> list=TbExamPaperQuestions.dao.findByWhere(" where paper_id=?",paperId);
		for(int i=0;i<list.size();i++) {
			TbExamPaperQuestions q=list.get(i);
			if(q.getRightAnswerId()==null)continue;
			if(q.getRightAnswerId().equals(q.getUserAnswerId()))score++;
		}
		
		int examTimeLength=getBetweenMinutes(paper.getExamStartDate(),new Date());
		paper.setExamScore(score);
		paper.setExamTimeLength(examTimeLength);
		paper.setExamEndDate(sdf.format(new Date()));
		paper.setExamStatus(-1);//置为交卷状态
		paper.update();
		log.info("总分数"+score);
		redirect("/front/onlineExam/viewPaperResult/"+paper.getId());
	}
复制代码

这里是考试结果页面,页面中可以显示答对题目及错题

image.png

这里是管理员查看考试列表的页面,可以完善筛选条件或其他个性功能,这里只实现了查询功能

image.png

至此,基本完成了一套完整的在线考试系统,但是从设计思路上还是代码实现上都有诸多问题,在这里抛砖引玉一下,如果大家有更好的思路也可以在评论区一起交流。

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改