ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

JavaWeb考试系统源码解析:MD5加密、分页与权限实战

JavaWeb考试系统源码解析:MD5加密、分页与权限实战 简介这是一套面向高校计算机相关专业学生的JavaWeb课程设计大作业完整项目主题为Web电脑考试系统适合初学者作为课程设计参考也便于有基础的开发者进行二次开发。项目采用JavaWeb技术栈实现涵盖登录认证、权限过滤、考试管理、成绩统计等核心业务模块代码结构规范、易于维护与拓展。压缩包共345个文件约46.27MB包含45个java源文件、29个jsp页面、27个jar依赖包、27个js脚本以及大量docx项目文档另附sql数据库脚本、war部署包与xls导入模板覆盖从源码到文档的完整交付内容。系统功能较为丰富支持双层MD5加密、过滤器权限保护、管理员与老师身份一键切换、老师评分评语、成绩报表与及格率统计、分页展示与模糊查询、学生名单表格导入、考试倒计时及Ajax通知提醒等并配有详细使用说明。目前已有2955人学习下载可作为课程设计选题落地的实用参考。1. 从一份 JavaWeb 考试系统源码说起它到底能跑出什么效果如果你正在找一份能直接跑起来、结构清晰、还带数据库的 JavaWeb 课程设计那这份「web 电脑考试系统」源码包值得先看一眼。它不是那种只有登录页和空壳后台的演示项目而是把管理员、老师、学生三种角色的完整业务链路都串了起来老师出题、学生在线答题、系统倒计时收卷、老师评分写评语、成绩报表按区间统计及格率甚至连学生文件打包下载和 xls 名单导入都做了。技术栈是经典的 Servlet JSP JDBC MySQL配合 Filter 做权限拦截DaoFactory 做数据访问层解耦PageInfo 封装分页。对初学者来说这是一份能照着理解 MVC 分层和请求流转的完整案例对熟手来说它的权限模型、加密方案和分页封装都有可二次开发的余地。源码包里带了数据库脚本和项目文档解压后按说明导入就能跑适合课程设计答辩、JavaWeb 期末大作业或者单纯想拆一个真实项目练手的人。2. 环境搭建与数据库导入把项目从 zip 跑到登录页2.1 运行环境选型与依赖确认这份源码是典型的「老派但稳」的 JavaWeb 项目没有用 Spring Boot 那套自动装配所以环境配置反而更透明。我一般会先确认三件事JDK 版本、Tomcat 版本、MySQL 版本。源码里的 class 文件是编译过的但项目文档里通常附了源码目录建议直接用源码重新编译避免 class 版本和本地 JDK 不匹配导致UnsupportedClassVersionError。推荐组合是 JDK 8 或 JDK 11、Tomcat 8.5 或 9.0、MySQL 5.7 或 8.0。为什么不用 JDK 17 以上因为老项目里如果用了javax.servlet而不是jakarta.servletTomcat 10 会直接报类找不到这是最常见的翻车点。MySQL 8.0 要注意驱动包版本com.mysql.cj.jdbc.Driver和老的com.mysql.jdbc.Driver写法不同连接串还要加时区和 SSL 参数。在 IDEA 里导入时选「Existing Sources」或直接 Open 项目根目录然后手动配置 Artifacts 和 Tomcat Server。具体步骤是File → Project Structure → Modules 确认源码目录标记为 SourcesWeb 目录标记为 Web Resource Directory然后在 Run/Debug Configurations 里新增 Tomcat LocalDeployment 里加上war exploded。这一步做完项目基本就能识别了。2.2 数据库导入与连接配置数据库是这份项目的核心所有题目、用户、成绩、通知都存在 MySQL 里。源码包里的.sql文件一般包含建库、建表和初始数据。导入时我习惯先用命令行确认字符集避免中文乱码# 登录 MySQL注意 -p 后面不要跟密码回车后再输入 mysql -u root -p # 创建数据库并指定 utf8mb4兼容性比 utf8 好 CREATE DATABASE exam_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 退出后用 source 导入 sql 文件路径换成你解压后的实际位置 exit mysql -u root -p exam_system /path/to/exam_system.sql导入完成后用SHOW TABLES;确认表数量通常会有student、teacher、admin、exam、question、score、notice、file这几张核心表。接着改项目里的数据库配置文件一般在src/db.properties或src/c3p0-config.xml里。如果是 properties 文件重点改这四项jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/exam_system?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse jdbc.usernameroot jdbc.password你的密码参数说明useUnicode和characterEncoding保证中文不乱码serverTimezone解决 MySQL 8.0 时区报错useSSLfalse去掉本地开发时的 SSL 警告。改完配置后启动 Tomcat访问http://localhost:8080/项目名/看到登录页就说明数据库连通了。如果报Access denied检查密码和远程权限如果报Unknown database说明库名写错或没导入成功。2.3 登录页与权限过滤器的初始化验证登录页是这份项目的门面摘要里提到「精美炫酷」实际看下来是用了 CSS 渐变和背景图不算复杂但足够体面。真正要验证的是登录后的权限流转。项目里有个PermissionFilter.class它拦截所有请求根据 session 里的角色判断能不能访问目标资源。测试时我建议按这个顺序走一遍用管理员账号登录确认能进后台、能切换老师身份用老师账号登录确认能出题、评分、看报表用学生账号登录确认能答题、看通知、下载文件直接访问未登录状态下的/admin/xxx路径确认被踢到nopriviliage页面。这一步能过说明 Filter 配置和 web.xml 里的映射没问题。常见坑是 Filter 的url-pattern写成/*后把登录页也拦了导致死循环需要在 Filter 里放行登录和静态资源路径。3. 核心模块拆解MD5 加密、分页封装与 DaoFactory3.1 32 位字段截取式双层 MD5 加密的实现逻辑摘要里写的「32 位 字段截取式 双层 MD5 加密」听起来玄乎拆开看其实是一个很实用的密码存储方案。普通 MD5 直接对密码做一次哈希容易被彩虹表撞库这份项目做了两层第一层对原始密码加盐后 MD5第二层对第一层结果再截取部分字段拼接后二次 MD5。这样即使数据库泄露攻击者拿到的也不是标准 MD5 值反查成本高很多。核心代码逻辑大概是这样public class MD5Util { // 第一层原始密码 固定盐值做一次 MD5 public static String encodeOnce(String password, String salt) { String base password salt; return DigestUtils.md5Hex(base); // 返回 32 位小写十六进制 } // 第二层截取第一层结果的前 16 位和后 16 位交叉拼接再 MD5 public static String encodeTwice(String password, String salt) { String first encodeOnce(password, salt); // 字段截取前 16 位 后 16 位反转拼接 String mixed first.substring(0, 16) new StringBuilder(first.substring(16)).reverse(); return DigestUtils.md5Hex(mixed); } }逻辑说明encodeOnce负责加盐哈希盐值可以存在配置文件里每个项目不同encodeTwice做字段截取和反转目的是打乱哈希结构让第二层结果和第一层没有直观对应关系。参数上盐值建议用固定字符串加用户注册时间戳但这份源码里为了简化用的是全局固定盐。验证时可以在注册和登录两处都调用encodeTwice对比结果是否一致。注意 MD5 本身不是加密而是摘要这套方案提升的是撞库难度不是绝对安全课程设计够用生产环境建议换 BCrypt。3.2 PageInfo 分页封装与模糊查询的配合分页是这份项目里复用率最高的模块。PageInfo.class一般封装了当前页、每页条数、总记录数、总页数、数据列表这几个字段。所有展示处支持分页所有搜索处支持模糊查询这两句话落到代码里就是Dao 层先用COUNT(*)查总数再用LIMIT查当前页数据Service 层把结果塞进 PageInfo 返回给 JSP。一个典型的分页查询方法public PageInfoStudent getStudentPage(int pageNum, int pageSize, String keyword) { PageInfoStudent page new PageInfo(); page.setPageNum(pageNum); page.setPageSize(pageSize); // 模糊查询条件keyword 为空时查全部 String like (keyword null || keyword.isEmpty()) ? % : % keyword %; // 第一步查总记录数 String countSql SELECT COUNT(*) FROM student WHERE name LIKE ? OR sno LIKE ?; int total queryRunner.count(countSql, like, like); // 第二步查当前页数据LIMIT 第一个参数是偏移量 String dataSql SELECT * FROM student WHERE name LIKE ? OR sno LIKE ? LIMIT ?, ?; ListStudent list queryRunner.query(dataSql, new BeanListHandler(Student.class), like, like, (pageNum - 1) * pageSize, pageSize); page.setTotal(total); page.setList(list); page.setTotalPage((int) Math.ceil(total * 1.0 / pageSize)); return page; }参数说明pageNum从 1 开始(pageNum - 1) * pageSize是 SQL 偏移量写错会导致第一页重复或跳页pageSize建议 10 到 20太大影响渲染速度。模糊查询的LIKE两边加%是全模糊如果数据量大建议改成右模糊keyword %以命中索引。JSP 页面里用 JSTL 遍历page.list分页条根据page.totalPage和page.pageNum渲染上一页、下一页和页码。3.3 DaoFactory 与过滤器权限保护的分工DaoFactory.class是这份项目结构清晰的关键。它用工厂模式统一创建 Dao 实例避免在 Servlet 里到处new StudentDao()。常见实现是读配置文件或反射简单点就是静态方法返回单例public class DaoFactory { private static final StudentDao studentDao new StudentDao(); private static final TeacherDao teacherDao new TeacherDao(); private static final ExamDao examDao new ExamDao(); public static StudentDao getStudentDao() { return studentDao; } public static TeacherDao getTeacherDao() { return teacherDao; } public static ExamDao getExamDao() { return examDao; } }这样做的价值是以后换 ORM 框架或加缓存只改工厂内部Servlet 不用动。PermissionFilter则负责在请求进入 Servlet 之前做角色校验它和 DaoFactory 一个管「谁能进来」一个管「进来后怎么取数据」职责分开后代码就好维护。测试权限时重点看 Filter 里对 session 为空的处理以及nopriviliage页面的跳转路径是否正确。4. 考试流程与成绩报表倒计时、评分、区间统计怎么落地4.1 考试倒计时与 Ajax 通知提醒考试结束倒计时是学生端的核心体验。实现方式一般是后端在考试记录里存start_time和duration前端页面加载时算出剩余秒数用setInterval每秒刷新显示。关键点是时间以服务器为准不能信客户端本地时间否则改系统时间就能作弊。常见做法是后端返回剩余秒数前端只做递减展示到 0 自动提交试卷。// 后端在页面渲染时注入 remainingSeconds let remaining parseInt(document.getElementById(remaining).value); const timer setInterval(function () { if (remaining 0) { clearInterval(timer); // 倒计时结束自动提交试卷 document.getElementById(examForm).submit(); return; } remaining--; let min Math.floor(remaining / 60); let sec remaining % 60; document.getElementById(countdown).innerText min 分 sec 秒; }, 1000);Ajax 通知提醒通常用在老师发布新考试或管理员发通知时前端定时轮询一个接口有新消息就弹窗。轮询间隔建议 30 秒以上太频繁会给服务器压力。这份项目里通知和考试是分开的模块NoticeDao负责通知的增删查学生登录后能看到未读通知数量。4.2 老师评分、评语与成绩区间统计老师评分模块的流程是老师进入某场考试的学生列表看到学生提交的答案逐题给分或给总分再写评语提交后更新score表。这里要注意事务评分和更新考试状态要么一起成功要么一起回滚否则会出现「分数存了但状态没变」的脏数据。成绩报表是这份项目的亮点。区间人数统计和及格率统计本质上是 SQL 聚合查询-- 按分数区间统计人数区间可以按需调整 SELECT CASE WHEN score 90 THEN 优秀 WHEN score 80 THEN 良好 WHEN score 60 THEN 及格 ELSE 不及格 END AS level, COUNT(*) AS num FROM score WHERE exam_id ? GROUP BY level; -- 及格率统计 SELECT SUM(CASE WHEN score 60 THEN 1 ELSE 0 END) / COUNT(*) AS pass_rate FROM score WHERE exam_id ?;参数说明exam_id是考试场次标识CASE WHEN划分区间GROUP BY按区间聚合。前端拿到数据后用 ECharts 或简单表格展示摘要里说的「炫酷成绩报表」一般就是柱状图加饼图。注意SUM和COUNT的除法在 MySQL 里默认是浮点如果结果是 0 要检查是否有成绩记录。4.3 学生文件打包下载与 xls 名单导入学生文件自动打包下载用的是 ZIP 流。后端把学生上传的文件从磁盘或数据库读出用ZipOutputStream边读边写设置响应头Content-Disposition触发浏览器下载。常见坑是文件名中文乱码需要URLEncoder.encode(fileName, UTF-8)处理。xls 名单导入用的是 Apache POI 或 jxl。读取每一行校验学号姓名批量插入student表。导入前建议先查重学号已存在就跳过或更新避免主键冲突导致整个导入失败。这份项目里导入功能配合StudentDao的批量插入方法效率比逐条插入高很多。5. 避坑与常见问题排查从乱码到权限死循环5.1 中文乱码请求、响应、数据库三处都要管现象登录后页面显示问号或者导入的学生姓名变成乱码。原因通常是三处编码不统一JSP 页面pageEncoding、请求体编码、数据库连接编码。解决JSP 顶部统一写% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %在 Filter 里加request.setCharacterEncoding(UTF-8)和response.setContentType(text/html;charsetUTF-8)数据库连接串加useUnicodetruecharacterEncodingutf8。三处都改完再重启 Tomcat基本能解决。5.2 权限过滤器死循环登录页被拦住了现象访问任何页面都跳转到nopriviliage包括登录页本身导致永远登不进去。原因PermissionFilter的url-pattern配了/*但没有放行登录请求和静态资源。解决在 Filter 里判断请求路径如果是login.jsp、LoginServlet、css/、js/、images/开头直接chain.doFilter放行不校验 session。5.3 数据库连接池耗尽连接没关或配置太小现象用一会儿就报Cannot get a connection或页面卡死。原因Dao 里手动拿的连接没有在 finally 里关闭或者连接池最大连接数设得太小。解决检查每个Connection、PreparedStatement、ResultSet是否在 finally 中关闭如果是 c3p0 或 Druid把maxPoolSize调到 20 以上并开启连接泄漏检测。这份项目里如果用了 DBUtils通常会自动关但手写 JDBC 的地方要重点看。5.4 class 文件与源码不一致改了没生效现象改了 Java 代码重启 Tomcat 后行为没变。原因项目里同时存在.class和.javaIDEA 编译输出路径和 Tomcat 部署路径不一致或者直接部署了旧的 war 包。解决在 Project Structure 里确认 Output 目录重新 Build → Rebuild Project然后检查 Tomcat Deployment 里用的是war exploded而不是旧 war。最稳妥的办法是删掉out目录和 Tomcat 的work目录再重启。5.5 考试倒计时归零后没自动交卷现象倒计时显示 0 但试卷没提交学生还能继续答。原因前端setInterval被浏览器节流或者自动提交的 form action 路径写错。解决倒计时以服务器时间为准前端每秒同步一次剩余秒数自动提交用form.submit()并确认 action 指向正确的 Servlet后端在接收提交时再校验一次考试是否已结束双重保险。6. 二次开发与验证技巧从能跑到能改把项目跑起来只是第一步真正有价值的是知道怎么改、怎么验证改对了。我一般会先做一次「最小改动验证」改登录页的标题文字重新部署看页面有没有变。这一步能确认编译和部署链路是通的后面改业务代码才不会白费功夫。接着是数据库层验证。用SHOW CREATE TABLE score;看字段类型和索引如果exam_id没索引成绩报表在数据量大时会很慢加一个普通索引就能明显提速。分页查询的LIMIT偏移量在深分页时性能差如果数据超过几万条建议改成基于游标的WHERE id ? LIMIT ?。权限模块的验证有个技巧在PermissionFilter里临时加一行日志打印请求路径和 session 里的角色然后分别用三种角色访问同一批 URL看日志输出是否符合预期。这比反复点页面快得多。评分模块要测边界0 分、满分、评语为空、重复提交看后端有没有做校验和事务回滚。报表模块我习惯用一组构造数据验证插入 10 条成绩其中 6 条及格、4 条不及格看及格率是不是 60%区间人数是不是对得上。数字对不上就回去查 SQL 的CASE WHEN边界比如 60 分到底算及格还是不及格这种边界最容易写错。最后说一个血泪经验改任何和数据库相关的代码之前先备份一份 sql 文件。我有次调分页把LIMIT参数写反导致数据看起来「丢了」其实是查询偏移量错了但当时慌了直接改表结果更乱。从那以后我每次动 Dao 层之前都强制走一遍「备份 → 改代码 → 构造数据验证 → 对比备份」的流程。这份考试系统源码结构清楚适合拿来练这种完整闭环改坏了也能从备份恢复。希望帮到你。本文还有配套的精品资源点击获取
返回列表