资讯详情

资讯详情

JavaEE网上考试系统:零Spring Boot的可部署实战项目

简介本资源是一套面向软件工程专业本科生的JavaEE课程设计实践项目——网上考试系统适用于JavaWeb基础扎实、正开展企业级Web应用开发实训的学习者。系统采用JSPServletJavaBean经典三层架构涵盖用户管理、题库维护、在线考试、自动阅卷与成绩统计等核心功能模块代码结构清晰、注释详尽便于理解与二次定制。压缩包共74个文件含16个Java源码业务逻辑与DAO层、16个JSP页面前端交互、16个Class字节码编译验证可用、8个GIF图标及CSS/JPG等静态资源整体6.75MB开箱即用仅需替换姓名、学号等基础信息即可部署运行。已有3474人学习下载配套提供完整设计报告、详细使用说明文档及MyEclipse项目工程含.project、.classpath等元数据助读者快速掌握JavaEE项目开发全流程与典型部署规范。1. 这不是又一个“学生交差项目”一套能真跑起来的 JavaEE 网上考试系统含完整部署链路、防刷新作弊逻辑与可调试源码包你手头那份标着“JavaEE大作业”的网上考试系统压缩包大概率正躺在某个课程资料群的聊天记录底部被标注为“含代码报告说明”但点开后发现Tomcat 启动报 404、MySQL 连不上、登录页空白、管理员账号密码全写死在 JSP 里——这不是资源质量差而是绝大多数教学级项目根本没走完「从开发到可验证运行」这一环。我拆过不下二十个同名资源真正能不改一行配置就完成「创建试卷→学生作答→自动判分→导出成绩」闭环的不到三成。这套资源不同它基于 Servlet 3.0 JSP JDBC 原生栈零 Spring Boot 魔法数据库脚本带初始化数据所有路径硬编码已替换为 contextPath 动态获取关键环节如“同一IP限制单次考试”“页面关闭前强制提交”“选择题答案比对防空格干扰”都有可验证的实现逻辑。适合两类人一是需要交作业但不想被老师问住底层细节的学生二是想用最小技术栈理解 Web 考试系统状态管理本质的初学者。它不炫技但每行代码都经得起System.out.println打桩。2. 从解压到首页可见四步完成本地可运行环境搭建2.1 环境依赖清单与版本锚定逻辑该系统严格限定在 JavaEE 传统生态内回避了任何现代构建工具的黑盒封装。这意味着你必须手动确认三个核心组件的版本兼容性JDK必须为 JDK 8u202 或更高低于 u191 的某些 SecurityManager 行为会导致request.getRemoteAddr()返回 nullServlet 容器仅验证通过 Tomcat 8.5.93注意Tomcat 9 默认禁用 JSP EL 表达式需额外修改conf/web.xml中el-ignored为false数据库MySQL 5.7.33MySQL 8.0 的caching_sha2_password认证插件会导致 JDBC 连接失败除非显式指定useSSLfalseserverTimezoneUTC。提示不要用 IDE 内置 Tomcat 插件直接运行 WAR 包。IDE 插件常会覆盖web.xml中的session-config设置导致考试倒计时失效。务必使用独立解压的 Tomcat 实例。2.2 数据库初始化执行脚本前必须做的三件事资源包中sql/目录下的exam_system_init.sql不是普通建表语句它包含业务强约束逻辑。执行前请按顺序完成创建专用数据库非 rootCREATE DATABASE exam_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;创建应用用户并授权CREATE USER exam_userlocalhost IDENTIFIED BY Exam2024; GRANT SELECT, INSERT, UPDATE, DELETE ON exam_db.* TO exam_userlocalhost; FLUSH PRIVILEGES;修改脚本中的INSERT INTO admin (username, password)密码字段原始值为明文admin123需替换为 MD5 加密后的21232f297a57a5a743894a0e4a801fc3这是系统登录校验逻辑硬编码的哈希值不匹配则管理员无法登录。2.3 Tomcat 配置文件关键修改项将war/exam_system.war解压至webapps/后必须编辑WEB-INF/web.xml将session-config中的session-timeout从默认30改为60考试场景下 30 分钟 session 过期会中断作答在welcome-file-list下添加welcome-filelogin.jsp/welcome-file否则访问http://localhost:8080/exam_system会返回 404检查filter标签是否包含EncodingFilter其init-param中encoding值必须为UTF-8否则中文试卷题目显示为乱码。2.4 启动验证用 curl 做最小化连通性测试不要依赖浏览器刷新判断是否成功。在 Tomcat 启动后执行以下命令验证服务层可达性# 测试登录接口基础响应绕过前端 JS curl -X POST http://localhost:8080/exam_system/LoginServlet \ -H Content-Type: application/x-www-form-urlencoded \ -d usernameadmin -d passwordadmin123 \ -i | head -n 10预期返回中应包含HTTP/1.1 302及Location: /exam_system/admin/index.jsp。若返回404检查LoginServlet是否在web.xml中正确映射若返回500查看logs/catalina.out中java.lang.ClassNotFoundException: com.mysql.jdbc.Driver—— 此时需将mysql-connector-java-5.1.47.jar复制到lib/目录注意不是WEB-INF/lib/是 Tomcat 根目录的lib/。3. 核心业务流程拆解从试卷生成到成绩导出的七层调用链3.1 试卷动态组装PaperGenerator.java的三层过滤逻辑系统未采用预设试卷表而是每次考试前实时生成。PaperGenerator.generatePaper(int subjectId, int questionCount)方法执行时会按优先级顺序筛选题目难度权重过滤先从question表中WHERE difficulty IN (1,2,3)1简单3困难随机抽取但要求最终试卷中三类难度题数量比例固定为4:4:2知识点去重对抽中的题目knowledge_point字段做GROUP_CONCAT聚合若同一知识点出现超过 2 次则丢弃该题并重抽历史错题加权查询student_answer表中当前学生WHERE is_correct0的错题 ID 列表将这些 ID 加入新试卷的概率提升 300%通过ORDER BY RAND() * IF(id IN (错题ID列表), 3, 1)实现。逻辑说明这种设计避免了“题库越刷越窄”的问题。参数subjectId对应科目表主键questionCount必须为 10 的倍数系统硬编码限制否则抛出IllegalArgumentException。3.2 考试状态机ExamSession.java如何用 HttpSession 维护原子性整个考试过程被抽象为有限状态机状态流转完全绑定HttpSession属性Session 属性名类型作用currentExamIdInteger当前考试唯一标识由ExamService.startExam()生成并存入 DBremainingTimeLong剩余秒数初始值 试卷设置的duration_minutes * 60前端每秒 AJAX 请求/CheckTimeServlet更新submittedQuestionsMapInteger, Stringkey题号value学生答案选择题存选项字母填空题存原文防止页面刷新丢失作答isSubmittedBooleantrue后禁止任何AnswerServlet提交强制跳转至成绩页关键点在于CheckTimeServlet它不依赖前端 JavaScript 计时器而是每次请求时计算session.getAttribute(remainingTime) - (System.currentTimeMillis() - startTime)若结果 ≤ 0 则自动触发submitExam()并清除 session 属性。这解决了学生禁用 JS 后无限拖时间的问题。3.3 自动判分引擎Scorer.java的答案标准化处理判分逻辑藏在Scorer.calculateScore(Exam exam, MapInteger, String answers)中其核心是答案清洗选择题将学生答案toUpperCase().trim()后与数据库correct_answer字段比对数据库中存的是A而非A.填空题调用normalizeBlankAnswer(String raw)方法该方法执行public static String normalizeBlankAnswer(String s) { return s.replaceAll(\\s, ) // 合并连续空格 .trim() // 去首尾空格 .replaceAll([。\], ) // 清除中文标点 .toLowerCase(); // 统一小写 }例如学生输入 苹果 会被标准化为苹果与标准答案苹果匹配成功。参数说明Exam对象包含试卷所有题目及标准答案answers是学生实际提交的答案 Map。该方法返回ScoreResult对象含totalScore、correctCount、detailList每题得分详情。3.4 成绩导出模块ExportService.java的 Excel 兼容性陷阱ExportService.exportToExcel(HttpServletResponse response, ListScoreRecord records)生成的.xls文件刻意避开 Apache POI 的高版本 API因教学环境常受限于 JDK 8。它使用jxl库jxl-2.6.12.jar但存在两个隐藏坑日期格式错误若ScoreRecord.submitTime为java.util.Date直接写入会显示为数字Excel 序列号。必须转换WritableCellFormat dateFmt new WritableCellFormat(new DateFormat(yyyy-MM-dd HH:mm)); DateTime dateTime new DateTime(col, row, record.getSubmitTime(), dateFmt); sheet.addCell(dateTime);中文乱码jxl默认用ISO-8859-1编码需在创建工作簿时指定WritableWorkbook workbook Workbook.createWorkbook(outputStream, new WritableWorkbookSettings()); workbook.setEncoding(Encoding.UTF_8); // 关键4. 避坑指南五个让开发者凌晨三点还在看 catalina.out 的真实问题4.1 现象登录成功后跳转到http://localhost:8080/login.jsp路径丢失上下文原因LoginServlet中重定向代码写为response.sendRedirect(admin/index.jsp)而非response.sendRedirect(request.getContextPath() /admin/index.jsp)。当应用部署路径不是/如/exam_system时相对路径重定向会丢失上下文。解决全局搜索所有sendRedirect(将字符串拼接改为request.getContextPath() /xxx。特别注意LogoutServlet和AnswerServlet中的跳转逻辑。4.2 现象创建试卷时提示“数据库连接超时”但 Navicat 可正常连接原因DBUtil.java中getConnection()方法使用DriverManager.getConnection(url, user, pwd)但url字符串中未包含connectTimeout30000参数。MySQL 默认连接超时为 8 小时但在高并发测试时连接池耗尽会导致此错误。解决修改url为jdbc:mysql://localhost:3306/exam_db?useSSLfalseserverTimezoneUTCconnectTimeout30000socketTimeout60000并确保mysql-connector-java-5.1.47.jar版本与 MySQL 5.7 兼容5.1.x 系列。4.3 现象学生作答时点击“下一题”无反应浏览器控制台报Uncaught ReferenceError: gotoQuestion is not defined原因exam.jsp中的 JavaScript 函数gotoQuestion(qid)被包裹在script typetext/javascript标签内但该标签位于/body之后HTML 结构错误导致函数未加载。解决将script块移至/body标签内部并在函数定义前添加window.onload function(){...}确保 DOM 加载完成。同时检查exam.jsp中是否有未闭合的div导致后续脚本解析失败。4.4 现象导出 Excel 后打开提示“文件损坏”用记事本打开显示乱码原因ExportService.java中设置了response.setContentType(application/vnd.ms-excel)但未设置response.setCharacterEncoding(UTF-8)且OutputStreamWriter未指定编码。解决在getOutputStream()后立即添加response.setCharacterEncoding(UTF-8); response.setHeader(Content-Disposition, attachment; filenameexam_scores.xls);并在创建WritableWorkbook前确保输出流以 UTF-8 编码写入。4.5 现象同一台电脑用 Chrome 登录管理员Firefox 登录学生学生考试时管理员后台看到“当前在线人数”为 0原因OnlineUserListener.java实现了HttpSessionListener但统计逻辑只监听sessionCreated事件未在sessionDestroyed时减计数。当学生关闭浏览器session 超时销毁但计数未减少。解决在sessionDestroyed(HttpSessionEvent se)方法中添加Integer count (Integer) se.getSession().getServletContext() .getAttribute(onlineUserCount); if (count ! null count 0) { se.getSession().getServletContext() .setAttribute(onlineUserCount, count - 1); }并初始化ServletContext属性在contextInitialized(ServletContextEvent sce)中设置sce.getServletContext().setAttribute(onlineUserCount, 0)。5. 防刷新与防切屏两个被 90% 教学项目忽略的考试安全实践5.1 页面卸载拦截beforeunload的双重保险机制单纯用window.addEventListener(beforeunload, ...)无法阻止学生通过任务管理器强制结束浏览器。本系统采用双层防御前端层在exam.jsp中window.addEventListener(beforeunload, function(e) { if (!window.examSubmitted) { // 全局标志位 e.preventDefault(); e.returnValue 考试尚未提交离开将导致成绩丢失; } });后端层AnswerServlet接收答案时校验session.getAttribute(currentExamId)是否存在且有效。若学生强制关闭页面下次重新打开考试页时currentExamId已因 session 失效而为空系统会拒绝继续作答并提示“考试已终止”。注意window.examSubmitted在点击“提交试卷”按钮时设为true且该按钮onclicksubmitExam(); return false;阻止默认行为确保beforeunload不被触发。5.2 屏幕切换检测visibilitychange事件的考场级应用为防止学生 AltTab 切换到其他窗口搜答案系统在exam.jsp中注入document.addEventListener(visibilitychange, function() { if (document.hidden) { // 页面不可见时记录时间戳 sessionStorage.setItem(switchOutTime, Date.now()); } else { // 页面恢复可见 const outTime sessionStorage.getItem(switchOutTime); if (outTime (Date.now() - outTime) 5000) { // 超过5秒视为作弊 alert(检测到长时间切出考试界面本次考试将被标记为异常); // 向后端发送警告 fetch(/exam_system/ReportSwitchServlet?examId examId, {method: POST}); } } });后端ReportSwitchServlet将该事件写入exam_cheat_log表字段包括exam_id,switch_time,ip_address,user_agent。教师可在后台“异常考试报告”中查看。5.3 数据库层面的防重复提交answer表唯一索引设计answer表结构中除主键外必须建立复合唯一索引ALTER TABLE answer ADD UNIQUE INDEX uk_student_exam_question (student_id, exam_id, question_id);当学生网络抖动多次点击“下一题”时重复的INSERT INTO answer语句会因违反唯一约束而抛出SQLIntegrityConstraintViolationException。AnswerServlet捕获此异常后不报错而是返回{status:success,message:答案已保存}保证用户体验不中断。这是比前端按钮置灰更可靠的防重手段。5.4 试卷加密传输JSP 中的动态 Token 机制为防止学生抓包后伪造AnswerServlet请求系统在exam.jsp渲染时生成一次性的examToken% String token UUID.randomUUID().toString().replace(-, ); session.setAttribute(examToken, token); % input typehidden nametoken value% token %AnswerServlet验证逻辑String clientToken request.getParameter(token); String serverToken (String) session.getAttribute(examToken); if (!clientToken.equals(serverToken)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, 非法请求); return; }该 token 在学生提交答案后立即失效session.removeAttribute(examToken)。即使 token 被截获也无法用于第二次提交。6. 从“能跑”到“可交付”一份经得起答辩追问的报告撰写要点与代码注释规范6.1 报告中必须回答的五个灵魂问题附答辩话术你的报告不能只写“实现了登录功能”要直击评审老师最可能追问的点。以下是每个模块对应的答辩话术模板模块评审可能问你应该答精简版数据库设计“为什么question表不把选项 A/B/C/D 存为单独字段”“为支持不定长选项如多选题最多 8 个选项我们采用options TEXT字段存储 JSON 数组[{id:A,content:...},{id:B,content:...}]用JSON_EXTRACT查询兼顾灵活性与查询效率。”会话管理“如何保证 100 人同时考试时不出现 session 冲突”“每个考试实例生成唯一exam_id所有答案提交均携带该 ID。HttpSession仅存储轻量级状态剩余时间、已答题目核心数据落库session 本身不承担业务一致性。”判分逻辑“填空题答案有多种表述如‘TCP/IP’和‘TCP IP’怎么处理”“我们在Scorer.normalizeBlankAnswer()中加入了正则清洗replaceAll([\\s\\p{Punct}], )将所有空白符和标点统一替换为空格再 trim最后比对。”安全性“如何防止学生用 Postman 直接调AnswerServlet”“除了examToken一次性校验我们还检查request.getRemoteAddr()是否与登录时一致且session.getAttribute(currentExamId)必须存在——Postman 无法继承浏览器 session。”扩展性“如果要增加视频监考架构上怎么改”“当前ExamSession已预留monitoring_status字段。新增MonitoringServlet接收摄像头帧存入exam_monitoring表前端用WebRTC推流后端不做实时分析只存档供回溯。”6.2 代码注释的“三线原则”让老师一眼看出你懂底层教学项目最忌讳“写了代码但不知道为什么”。我在DBUtil.java的getConnection()方法旁加了这样的注释/** * 获取数据库连接此处不使用连接池如 DBCP因教学项目需暴露 JDBC 原理。 * 1. Class.forName(com.mysql.jdbc.Driver) 显式加载驱动JDBC 4.0 可省略但为兼容性保留 * 2. URL 中 ?useSSLfalse 是因 MySQL 5.7 默认启用 SSL而本地开发未配置证书 * 3. catch SQLException 时打印堆栈但不 throw因上层 Service 已做事务控制 */ public static Connection getConnection() { ... }这种注释告诉老师你清楚每一行代码的取舍理由不是复制粘贴。6.3 使用说明文档的致命细节必须写清“第一次启动后要做什么”很多同学把README.md写成“下载、解压、启动”却漏掉最关键的初始化动作。正确的写法是首次启动必做三件事登录管理员账号admin/admin123进入【系统设置】→【初始化题库】点击“导入样例题目”此操作将sql/sample_questions.sql写入数据库进入【考试管理】→【新建考试】设置科目、题量、时长点击“生成试卷”——此时系统才真正开始工作用学生账号stu001/123456登录进入【我的考试】找到刚创建的考试点击“开始考试”。没有这三步系统就是一堆静态页面。我见过太多同学卡在第二步因为报告里只写了“管理员可创建考试”没写“创建考试前必须先有题目”。从那以后我每次交付教学项目都会在README.md顶部加一行加粗警告“请严格按‘首次启动必做三件事’顺序操作跳过任意一步将导致功能不可用”。这不是怕老师刁难是尊重自己写的每一行代码——它值得被正确地跑起来。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →