基于Servlet、JSP技术的学生在线考试系统
我们一路前行,不是为了能改变世界,而是为了不让世界改变我们!
一、引言
随着网络技术的发展,教育和学习的方式也在不断地改变。在线考试系统是一种利用网络技术实现的无纸化考试系统,可以大大提高考试效率,降低考试成本,同时也可以提高考试的公正性和公平性。本文将对在线考试系统的需求进行分析,以期为在线考试系统的设计和实现提供参考。
二、相关技术
本系统使用MVC架构模式,持久化层使用JDBC技术,前端页面主要使用JSP、AJAX、JavaScript等技术实现,为了界面更加美观,使用了lay-ui前端框架的一些组件如页面布局、按钮、表格等。控制层使用Servlet技术。
三、系统需求分析
整个系统主要面向两类用户设计:学生和教师。
其中教师的主要功能模块包括:题库管理模块,主要负责对题库进行增删改查等操作,确保题库中题目能得到实时更新,方便教师进行查阅;试卷生成与发布模块,该模块主要用于帮助教师快速创建试卷,教师可以的从题库中选择需要的题目,并将其添加到指定试卷中,此外还提供了一键发布功能,系统会显示还未发布的试卷,教师可以一键发布试卷,发布试卷后,系统将通过选课记录自动匹配需要参加考试的考生,考生也可以看到待考试信息,实现了教师端和学生端的同步。学生成绩管理模块,该模块主要用于协助教师完成学生成绩的录入。考虑到目前大多数高校采用过程化考核方式对学生进行成绩认定,该模块还实现了供教师修改平时成绩在总评成绩的占比。此外,如果考试类型是期末考试,学生考试完毕后,该模块支持自动提交学生的期末成绩,只需要教师录入平时成绩即可自动计算学生的总评成绩,减轻了教师的工作量。
对于学生而言,学生的主要模块包括查看考试信息模块,该模块负责向学生展示考试信息,包括考试科目、时间、考试时长等。考试模块,考试模块主要负责向学生展示试卷中的试题并存储学生的作答记录,收到学生作答记录后,该模块还会负责计算学生的考试成绩,提交给相应教师供教师进行学生成绩分析。查看成绩模块,当考试结束,且教师将学生成绩录入完毕后,学生即可查看自己的成绩信息。
四、开发运行环境
(1)开发终端:LAPTOP-V3D33N24(64位)
(2)开发工具:IntelliJ IDEA 2022.1.2,Navicat Premium 16
(3)JDK版本:1.8
(4)数据库: 8.0.26 MySQL Community Server - GPL
(5)服务器:apache-Tomcat 8.0.50
(6)操作系统:Windows10
五、核心模块的实现
1. 登录模块与题库管理模块
//***************View: QuestionManageTable.jsp
<table class="layui-table" lay-even>
<tr>
<th>编号</th><th>学科</th><th>命题人</th><th>类型</th><th>题目</th>
<th>A</th><th>B</th><th>C</th><th>D</th><th>E</th><th>答案</th> <th>操作</th>
</tr>
<c:forEach items="${questions}" var="question">
<tr><td>${question.questionNumber}</td>//...
<td>${question.correctAnswer}</td>
<td><div class="layui-btn-group">
<button type="button" data-type="editbut"><a href="${pageContext.request.contextPath}/teacher.editQuestion?qid=${question.questionNumber}"></a></i>
</div></td></tr>
</c:forEach>
</table>
var qid = $(this).find('a').attr('href');//筛选用户点击动态绑定的url
$.ajax({//发送ajax请求到后端
type: 'get',//get post 请求类型
url: qid.toString(),//通讯地址
dataType: "text",//服务器传回来的数据text json
success: function (res) {
if (res == "success") {
alert("删除成功!")
window.location.href='${pageContext.request.contextPath}/teacher.questionManage'
} else {
alert("删除失败!")
}}})
//***************Controller:TeacherServlet
case "/teacher.questionManage": {
String qType = request.getParameter("type");
String qSubject = request.getParameter("subject");
ArrayList<Question> questions = questionService.queryQuestion(qType, qSubject);
session.setAttribute("questions", questions);
response.sendRedirect("/exam/tView/QuestionManageTable.jsp");//重定向
}
break;
//***************pojo:Question
public class Question {
private Integer questionNumber;
private String subject;
private String type;
private String author;
private String question;
private String optionA;
private String optionB;
private String optionC;
private String optionD;
private String optionE;
private String correctAnswer;
}
//***************DAO:QuestionDaoImpl
public class QuestionDaoImpl implements QuestionDao {
@Override
public int addQuestion(Question q) {
int i = 0;
try {
i = JDBCUtils.updateDate("insert into 题库(考察科目, 题目类型, 命题人, 题目, A, B, C, D, E, 正确答案)" +"values(?,?,?,?,?,?,?,?,?,?)", q.getSubject(), q.getType(), q.getAuthor(),
q.getQuestion(), q.getOptionA(), q.getOptionB(), q.getOptionC(), q.getOptionD(), q.getOptionE(), q.getCorrectAnswer());
return i; }
public int updateQuestion(Question q, Integer id)//...
关键代码实现说明:为题库增删改按钮绑定事件,当点击按钮时会发送请求调用后端Controller中的相关方法,Controller间接调用调用DAO中的方法,将数据同步到数据库中。对题库的增删改查功能均已实现。
实际界面
登录界面
题库管理界面
2. 试卷生成与发布模块
//***************View: QuestionManageTable.jsp
<tr>
<th>编号</th><th>试卷名称</th><th>考试科目</th><th>课号</th><th>组卷老师</th> <th>组卷时间</th>
<th>开考时间</th><th>考试时长</th><th>满分</th><th>试卷类型</th> <th>试卷状态</th><th>操作</th>
</tr>
<c:forEach items="${paperInfos}" var="paper">
<tr>
<td>${paper.paperId}</td>
//...此处代码省略
<td>${paper.paperState}</td>
<td><a href="${pageContext.request.contextPath}/teacher.editPaper?paperId=${paper.paperId}"></a></i
</td>
</c:forEach>
//***************Controller:TeacherServlet
case "/teacher.delPaper": {//以删除试卷为例
String paperId = request.getParameter("paperId");
int i = paperService.deletePaperByPid(Integer.valueOf(paperId));
if (i == 1) {
response.getWriter().write("success");
} else {
response.getWriter().write("false");
}
}
//***************pojo:
public class PaperInfo {
private Integer paperId;
private String paperName;
private String examSubject;
private String cno;
private String tName;
private Date paperFormationDate;
private Timestamp examStartTime;
private Time examContinue;
private Integer examFullCredit;
private String paperState;}
//***************DAO:QuestionDaoImpl
public int deletePaperByPid(Integer pid) {
return JDBCUtils.updateDate("delete from 试卷 where 试卷编号 = ?",pid);
}
}
关键代码实现说明:为试卷增删改按钮绑定事件,当点击按钮时会发送请求调用后端Controller中的相关方法,Controller间接调用调用DAO中的方法,将数据同步到数据库中。点击查看试卷后,会跳转到添加题库的页面,在该页面可以管理试卷上的试题,包括增删改查等功能。点击发布试卷后,选课学生即可看到试卷信息,并参与考试。上图示按钮的功能均已实现。
实际界面
试卷管理界面
试卷题目管理界面
3. 学生成绩管理模块
//***************View: GradeManageTable.jsp
<tr>
<th>学年</th><th>学期</th><th>学号</th><th>姓名</th><th>课号</th><th>课名</th><th>班级</th>
<th>考试成绩</th><th>总评成绩</th> <th>GPA</th><th>平时成绩</th><th>操作</th>
</tr>
<c:forEach items="${choiceCourseInfos}" var="choiceCourseInfo">
<tr>
<td>${choiceCourseInfo.academicYear}</td>
//...此处代码省略
<td><input type="text" placeholder="请输入" class="layui-input" value="${choiceCourseInfo.regularScore}"
cid="${choiceCourseInfo.courseId}" studentId="${choiceCourseInfo.studentId}"></td>
<td>
<button type="button" class="layui-btn" data-type="putInDataBase">录入</button>
</td>
</tr>
</c:forEach>
$("button[data-type='putInDataBase']").on("click", function () {
var input = $(this).parent().parent().find("input");//jquery获取父级的父级元素下的input
var url = "${pageContext.request.contextPath}/teacher.updatePsGrade?studentId=" +
$(input).attr("studentId") + "&courseId=" + $(input).attr("cid") + "&psGrade=" + $(input).val();
$.ajax({
type: 'get',
url: url,
dataType: "text",
success: function (res) {
if (res == "success") {
alert("录入成功!")
} else {
alert(("录入失败!"))
window.location.href = "${pageContext.request.contextPath}/teacher.gradeManage"//重定向
}
},
error:function (){
alert("录入失败,平时成绩不能为NULL!")
}
})
})
//***************Controller:TeacherServlet
case "/teacher.updatePsGrade":{
String studentId = request.getParameter("studentId");
String courseId = request.getParameter("courseId");
Integer psGrade = null;
if(request.getParameter("psGrade")!=null) {
psGrade = Integer.valueOf(request.getParameter("psGrade"));
}
int i = gradeManageService.updatePsGrade(studentId, courseId, psGrade);
if(i>=1){
response.getWriter().write("success");
}else {
response.getWriter().write("false");}}
//***************DAO:ChoiceCourseDaoImpl
@Override//查询所有学生成绩信息
public List<ChoiceCourse> getChoiceCourseByFilter(String academicYear, String semester, String classNo, String studentId, String courseId, String sName) {
return choiceCourseDao.getChoiceCourseByFilter(academicYear,semester,classNo,studentId,courseId,sName);}
@Override//更新学生成绩信息
public int gradeManageService (String studentId, String courseId, Integer psGrade) {
return choiceCourseDao.updatePsGrade(studentId,courseId,psGrade);
}
关键代码实现说明:教师可以修改平时成绩占总成绩的比例,底层通过调用ChoiceCourseManageService的updatePsRate方法修改,如果考试类型是期末考试,学生考试完毕后,自动将考试成绩插入考试成绩字段。教师录入平时成绩即可自动计算学生的总评成绩,底层使用数据库的触发器实现。录入平时成绩时,教师只需要输入成绩并点击录入即可调用gradeManageService方法,向数据库中添加学生成绩信息。同时系统为教师提供了多条件查询、模糊查询等功能,方便教师的使用。上述所有功能均已实现。
实际界面
修改平时成绩界面
学生成绩录入界面
4. 考试模块的实现
//***************View: Paper.jsp
<div class="container">
<div class="question-container">
<h1>${paperName}</h1>
<div class="timer">
<!-- 倒计时 -->
考试倒计时 <span id="countdown"></span>
</div>
<form id="qfrom">
<%--设置qid变量--%>
<c:forEach items="${questions}" var="question">
<c:if test="${question.type=='单选题'}"> <!-- 单选题 -->
<div class="question" id="question${question.qIdInPaper}">
<h2>第${question.qIdInPaper}题:</h2>
<p>${question.question}</p>
<input type="radio" name="q${question.qIdInPaper}"
value="A">A ${question.optionA}<br>
<input type="radio" name="q${question.qIdInPaper}"
value="B">B ${question.optionB}<br>
<input type="radio" name="q${question.qIdInPaper}"
value="C">C ${question.optionC}<br>
<input type="radio" name="q${question.qIdInPaper}"
value="D">D ${question.optionD}<br>
</div>
</c:if>
<c:if test="${question.type=='多选题'}"> //... <%--多选题--%>
<c:if test="${question.type=='判断题'}"> //... <!-- 判断题 -->
</c:forEach>
</form>
<c:forEach items="${questions}" var="question">
<button onclick="goToQuestion(${question.qIdInPaper})">Q${question.qIdInPaper}</button>
</c:forEach>
</div>
</div>
<div class="container">
<div class="submit-btn-container">
<button class="submit-btn" onclick="prevQuestion()" id="left">上一题</button>
<button class="submit-btn" onclick="nextQuestion()" id="right">下一题</button>
<button class="submit-btn" onclick="submitExam()">交卷</button>
</div>
</div>
//***************Controller:StudentServlet
switch (servletPath) {
case "/student.openThePaper": {
List<PaperQuestion> questions = getAllQuestionInPaperService.getAllPaperQuestionByPid(Integer.valueOf(pid));
request.setAttribute("questions", questions);
request.setAttribute("paperName", paperName);
request.setAttribute("examEndTime", examEndTime);
request.getRequestDispatcher("/sView/Paper.jsp").forward(request,response);
}
//***************pojo:PaperQuestion
public class PaperQuestion {
private Integer qIdInPaper;//试题在试卷上的编号
private Integer paperId;//试卷编号
private String type;//题目类型
private Integer qIdInRepository;//试题在试卷上的编号
private Integer qGrade;//题目分值
private String subject;//科目
private String author;//命题人
private String question;//题目
private String optionA; //... A-E选项
//正确答案
private String correctAnswer;
private Map<String,String> beforeFlushOptionAnswerMap;//
//***************DAO:PaperContextDaoImpl
public List<PaperContext> showPaperContextByPid(Integer paperNumber,String type) {
ArrayList<PaperContext> paperQuestions = new ArrayList<>();//存储试卷中的所有题目信息的集合
String sql = "select * from 试卷题目视图 where 试卷编号=? ";
if(type!=""&&type!=null){ sql = sql + " and 题目类型='"+ type +"'"; }
sql +=" order by 题目类型 asc";
Connection conn = null;
PreparedStatement pre = null;
ResultSet rs = null;
//...代码省略
paperQuestion.setCorrectAnswer(rs.getString("正确答案"));
paperQuestions.add(paperQuestion);
}//...释放资源 return paperQuestions
}
关键代码实现说明:在PaperQuestion实体类中调用Collections工具类的shuffle()方法,随机刷新选项顺序。问题类中存储添加Map集合(key:选项信息,value:选项)beforeFlushOptionAnswerMap数据结构,存储刷新选项顺序前(即数据库中的选项顺序)的选项信息。学生答题后,将所选选项内容与上述Map集合做映射,映射为数据库中存储的选项。实现了不同学生的题目顺序一致而选项顺序不一致的效果。
实际界面
考试信息展示界面
学生进入考试界面
学生查看成绩界面
个人小结
虽然已经2024年了,servlet、jsp技术几乎不再被使用了,但迫于应试教育,不得不学一些过时的技术,希望路过的各位朋友分清主次,不要在这上面花费太多时间,这是我的第一篇博文,希望能给各位朋友提供帮助!
学生在线考试系统项目是对本学期所学内容的综合,它综合了servlet、jsp、html、css、js相关技术,同时项目中为了更好的与用用户交互,还用到了AJAX技术,使用传统的java script对DOM元素的筛选颇为繁琐,所以还用到了一些JQuery框架提供的一些功能函数。在开始着手做界面时,原本打算自己进行前端界面的设计,但由于成品非常难看,调节CSS样式时又非常耗时,效率极低,所以使用了layui框架提供的一些组件,如按钮、表格等,把主要精力放在后端的程序实现上。在后端程序设计上,由于之前已经做了Java SE相同题目的课程设计,所以对系统的结构有了一个初步的认识。在实现过程中,使用了MVC的架构模式,由于之前的一些课程设计代码量不大,没有意识到架构模式的重要性,但这次由于代码量较大,业务逻辑也较多,所以我深刻体会到采用架构模式的优点,例如,系统的结构更加清晰,维护起来也更加容易。关于jsp、servlet方面,这是这个学期的核心内容,学生考试系统中大量使用,此外还有session域、request域、request转发,response重定向等,在系统的实现过程中也得到了广泛应用。在编程过程中,我对这些知识点也有了更深刻的认识。
完整代码或技术交流联系邮箱:3214541099@qq.com