简介:本资源是一套完整的基于Java开发的在线考试系统毕业设计项目,面向计算机专业本科生、Java初学者及教育类系统开发者,解决课程考核数字化、考试流程自动化与后台管理可视化等实际需求。压缩包共14个文件,包含5个MP4演示与部署视频(含项目演示、数据库设计、部署操作等)、3个ZIP源码包(适配MySQL 5/8双版本及原始项目)、1个SQL数据库脚本、3个文本类连接配置与说明文档,以及DOC/DOCX格式的数据库结构设计与部署文档,整体大小95.11MB,结构清晰、开箱即用。已有174人学习下载,所有模块均已通过验收并可稳定运行。读者可直接获取可编译运行的完整源码、双数据库兼容方案、分步骤部署指南、全流程操作录屏及关键表结构设计说明,特别适合课程设计参考、毕设快速启动与Java Web全栈实践。
1. 别急着跑 demo,先搞清你手里的这套 Java 考试系统到底“认”哪个 MySQL 版本
你下载的这个「基于Java的在线考试系统设计与实现」压缩包,表面看是毕业设计标配——源码+数据库+部署文档+演示视频,样样齐全。但实际解压后你会发现:里面塞了三套项目代码(1-源项目.zip、2-mysql5的项目.zip、3-mysql8的项目.zip),两份数据库连接说明(mysql5.txt / mysql8.txt),还有一份 db.sql 和一份独立的「数据库表结构设计.doc」。这不是冗余,是血泪经验堆出来的兼容性分叉——MySQL 5.7 和 MySQL 8.0 在认证插件、时区处理、JDBC URL 参数、甚至默认 SQL 模式上存在不可忽略的断裂点。我见过太多人直接用 MySQL 8.0 启动 mysql5 的项目,卡在Access denied for user十分钟查不出原因;也有人把 mysql8 的项目硬塞进本地 MySQL 5.7,登录页一刷就报Unknown system variable 'caching_sha2_password'。这套资源不是“拿来即用”,而是“选对版本才能用”。它适合正在做课程设计、毕设答辩倒计时两周、需要快速验证功能逻辑的 Java 初学者,也适合带学生做实训的某高校导师——但前提是,你得先看清自己环境里装的是哪一代 MySQL,再从三套代码里精准摘出匹配的那一套。别跳过这一步,否则后面所有配置都是玄学。
2. 环境准备:JDK、MySQL、Tomcat 三件套的版本锚点与安装实操
2.1 JDK 8u202 是这套系统的“黄金基线”
项目未明确声明 JDK 版本,但通过反编译 class 文件、检查 pom.xml 中 maven-compiler-plugin 的 source/target 设置(均为 1.8),以及部署文档中 Tomcat 版本指向 8.5.x,可确认其编译目标为 Java 8。JDK 11+ 会因模块化和移除 JAXB 等 API 导致启动失败;JDK 17 更会直接抛UnsupportedClassVersionError。推荐使用 OpenJDK 8u202(非最新版),因其与 MySQL Connector/J 5.1.x(项目所用)兼容最稳。
安装步骤:
# Linux/macOS 下推荐使用 SDKMAN!(避免手动配 PATH) curl -s "https://get.sdkman.io" | bash source "$HOME/.sdkman/bin/sdkman-init.sh" sdk install java 8.0.202-open sdk use java 8.0.202-open java -version # 输出应为 openjdk version "1.8.0_202"提示:Windows 用户请下载
OpenJDK8U-jdk_x64_windows_hotspot_8u202b08.zip,解压后将bin目录加入系统 PATH,并通过set JAVA_HOME=C:\path\to\jdk8显式声明。务必验证javac -version与java -version输出一致。
2.2 MySQL 5.7.33 或 8.0.33:两个分支必须严格隔离
项目提供两套 SQL 脚本与两套代码,本质是适配 MySQL 认证机制变更:
- MySQL 5.7 分支:使用
mysql_native_password插件,JDBC URL 形如jdbc:mysql://localhost:3306/exam?useSSL=false&serverTimezone=GMT%2B8 - MySQL 8.0 分支:默认
caching_sha2_password,需显式指定authenticationPlugins或降级用户插件,URL 需追加allowPublicKeyRetrieval=true
安装建议(以 Ubuntu 22.04 为例):
# 安装 MySQL 5.7(官方 apt 源已移除,需手动添加) wget https://dev.mysql.com/get/mysql-apt-config_0.8.24-1_all.deb sudo dpkg -i mysql-apt-config_0.8.24-1_all.deb # 安装时选择 5.7 sudo apt update && sudo apt install mysql-server-5.7 sudo mysql_secure_installation # 设定 root 密码,禁用匿名用户# 或安装 MySQL 8.0(更推荐,长期维护有保障) sudo apt install mysql-server # 启动后立即执行降级命令(适配项目 JDBC 驱动) sudo mysql -u root -p -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password'; FLUSH PRIVILEGES;"注意:
db.sql文件本身不区分版本,但其中CREATE USER语句在 MySQL 8.0 中需配合IDENTIFIED WITH子句,否则导入会报错。部署文档中数据库连接-mysql5.txt与数据库连接-mysql8.txt的差异,正是源于此。
2.3 Tomcat 8.5.94:Servlet 3.1 兼容性与端口避让
项目web.xml声明为version="3.1",且未使用 Jakarta EE 命名空间(仍为javax.servlet),故必须使用 Tomcat 8.5.x(支持 Servlet 3.1 + JSP 2.3)。Tomcat 9+ 已切换至jakarta.servlet,会导致ClassNotFoundException: javax.servlet.http.HttpServlet。
下载与配置:
wget https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.94/bin/apache-tomcat-8.5.94.tar.gz tar -xzf apache-tomcat-8.5.94.tar.gz cd apache-tomcat-8.5.94/conf # 修改 server.xml:将默认 8080 改为 8081(避免与本地其他服务冲突) sed -i 's/port="8080"/port="8081"/' server.xml # 修改 context.xml:启用 session 持久化(防重启丢数据) echo '<Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true"/>' >> context.xml关键参数说明:
saveOnRestart="true"确保 Tomcat 重启后考生未交卷的 session 不丢失;port="8081"是为后续 Nginx 反向代理或本地调试留出端口弹性。
3. 数据库初始化:从 db.sql 到用户权限的完整链路
3.1 执行 db.sql 前必须做的三件事
db.sql是核心数据脚本,但直接source db.sql会失败——它不包含CREATE DATABASE语句,且假设用户已存在。必须按顺序执行:
- 创建数据库并指定字符集(关键!否则中文乱码):
CREATE DATABASE exam CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;- 创建应用专用用户并授权(禁止用 root 连接 Web 应用):
-- MySQL 5.7 写法 CREATE USER 'exam_user'@'localhost' IDENTIFIED BY 'Exam@2024'; GRANT ALL PRIVILEGES ON exam.* TO 'exam_user'@'localhost'; -- MySQL 8.0 写法(需指定插件) CREATE USER 'exam_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Exam@2024'; GRANT ALL PRIVILEGES ON exam.* TO 'exam_user'@'localhost'; FLUSH PRIVILEGES;- 验证用户能否登录并建表:
mysql -u exam_user -pExam@2024 -D exam -e "SHOW TABLES;" # 应返回空结果集3.2 导入 db.sql 的两种安全方式
方式一:命令行管道(推荐,避免编码问题)
mysql -u exam_user -pExam@2024 -D exam --default-character-set=utf8mb4 < db.sql方式二:MySQL 客户端内执行(需先USE exam;)
SET NAMES utf8mb4; SOURCE /path/to/db.sql;注意:
--default-character-set=utf8mb4参数强制客户端与服务端使用统一编码,否则INSERT INTO question VALUES (1,'单选题','下列...')中的中文可能存为????。若导入后SELECT * FROM user;显示乱码,请立即检查my.cnf中[client]和[mysqld]段的default-character-set是否均为utf8mb4。
3.3 表结构文档与实际 SQL 的一致性校验
数据库表结构设计.doc是 Word 文档,而db.sql是可执行脚本。二者必须一致,否则前端页面字段会报Unknown column 'xxx' in 'field list'。重点核对三处:
| 文档位置 | SQL 实际字段 | 必须一致项 |
|---|---|---|
user表 doc 中 | user_id | db.sql中是否为id INT PRIMARY KEY AUTO_INCREMENT? |
exam_record表 doc | start_time DATETIME | db.sql中是否含DEFAULT CURRENT_TIMESTAMP? |
question表 doc | type ENUM('single','multi') | db.sql中是否用VARCHAR(10)替代了ENUM?(MySQL 5.7 兼容性考虑) |
若发现不一致,优先以db.sql为准修改文档——因为它是真实运行的依据。例如某次部署中,文档写answer TEXT NOT NULL,而db.sql是answer VARCHAR(1000),导致多选题答案超长被截断,考生提交后显示“答案不完整”。
4. 项目部署:三套代码的选择逻辑与 WAR 包构建细节
4.1 为什么必须三选一?版本锁死的底层原因
1-源项目.zip是原始工程,但未适配任何 MySQL 版本;2-mysql5的项目.zip和3-mysql8的项目.zip是分别修改后的分支。差异集中在:
pom.xml中mysql-connector-java依赖版本:5.7 分支用5.1.47,8.0 分支用8.0.28src/main/resources/jdbc.properties中 JDBC URL 参数:5.7 分支无allowPublicKeyRetrieval,8.0 分支必须有src/main/java/com/xxx/dao/impl/UserDaoImpl.java中密码加密逻辑:5.7 分支用MD5,8.0 分支改用BCrypt(因 MySQL 8.0 默认密码哈希强度提升)
提示:不要试图“混搭”——比如用 5.7 的代码连 8.0 的数据库。
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.这类错误就是典型版本错配信号。
4.2 构建 WAR 包:Maven 打包的四个关键参数
项目为 Maven 结构,需在对应分支根目录执行:
# 清理旧包,跳过测试(毕业设计通常无单元测试) mvn clean package -Dmaven.test.skip=true # 若提示 “The packaging for this project did not assign a file to the build artifact”: # 检查 pom.xml 中 <packaging> 是否为 war(而非 jar) # 并确认 <build><plugins> 下有 maven-war-plugin 配置生成的 WAR 包路径为target/exam-system.war(具体名以pom.xml中<finalName>为准)。
参数说明:
-Dmaven.test.skip=true跳过测试编译,避免因缺少测试依赖(如 junit 4.12)导致打包失败;clean强制清除target目录,防止旧 class 文件残留引发NoSuchMethodError。
4.3 部署到 Tomcat:WEB-INF/lib 的隐性依赖陷阱
将exam-system.war复制到tomcat/webapps/后,Tomcat 会自动解压。但需检查WEB-INF/lib/目录:
- 必须存在
mysql-connector-java-5.1.47.jar(5.7 分支)或mysql-connector-java-8.0.28.jar(8.0 分支) - 不能同时存在两个版本,否则类加载器会随机选择一个,导致
java.lang.NoClassDefFoundError: com/mysql/cj/jdbc/Driver - 若缺失,手动复制对应 JAR 包至此目录,再重启 Tomcat
验证命令:
ls -l tomcat/webapps/exam-system/WEB-INF/lib/ | grep mysql # 正确输出应只有一行,如:mysql-connector-java-5.1.47.jar5. 避坑指南:五个高频翻车现场与后悔药
5.1 现象:首页能打开,但登录时提示 “用户名或密码错误”,控制台无报错
原因:数据库user表中password字段存储的是明文或 MD5 加密串,但项目代码中UserDaoImpl.login()方法调用了BCryptPasswordEncoder.encode()进行比对。这是 5.7 与 8.0 分支密码策略不一致导致的——5.7 分支用MD5(password),8.0 分支用BCrypt.hashpw(password, BCrypt.gensalt())。
解决:
- 若用 5.7 分支,确保
db.sql中INSERT INTO user的密码是MD5('123456')计算结果(如e10adc3949ba59abbe56e057f20f883e) - 若用 8.0 分支,用在线 BCrypt 工具生成
123456的哈希值(如$2a$10$KQVZzX...),替换db.sql中的密码字段
5.2 现象:考试页面空白,浏览器 F12 查看 Network,exam/list接口返回 404
原因:web.xml中servlet-mapping的url-pattern与 Controller 类上的@RequestMapping注解不匹配。常见于1-源项目.zip,其ExamController.java使用@RequestMapping("/exam"),但web.xml中DispatcherServlet映射为/,导致实际访问路径为/exam/exam/list。
解决:
- 方案一(推荐):修改
web.xml,将DispatcherServlet的url-pattern改为*.do,并在 Controller 中改为@RequestMapping("/exam.do") - 方案二:保持
url-pattern为/,但 Controller 改为@RequestMapping("/exam/list"),前端 AJAX 请求地址同步调整
5.3 现象:MySQL 8.0 下登录成功,但进入考试页报java.sql.SQLException: Unknown system variable 'query_cache_size'
原因:MySQL 8.0 移除了查询缓存(Query Cache)相关变量,但项目jdbc.properties中jdbc.url包含&cachePrepStmts=true等过时参数。
解决:
删除jdbc.properties中所有以cache开头的参数,URL 简化为:
jdbc.url=jdbc:mysql://localhost:3306/exam?useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true5.4 现象:Tomcat 启动后访问http://localhost:8081/exam-system重定向到http://localhost:8081/login.jsp,但该页面 404
原因:项目采用Filter实现登录拦截,web.xml中LoginFilter的url-pattern配置为/admin/*,但实际登录页路径是/login.jsp,未被拦截规则覆盖。
解决:
修改web.xml:
<filter-mapping> <filter-name>LoginFilter</filter-name> <url-pattern>*.jsp</url-pattern> <!-- 改为此行 --> <!-- 或更精确:<url-pattern>/login.jsp</url-pattern> --> </filter-mapping>5.5 现象:演示视频中点击“开始考试”弹出试卷,但本地部署后点击无反应,Console 报Uncaught ReferenceError: startExam is not defined
原因:exam.jsp中调用的startExam()函数定义在js/exam.js,但该 JS 文件路径在2-mysql5的项目.zip中为js/exam.js,而在3-mysql8的项目.zip中被移至static/js/exam.js,HTML 中<script src="js/exam.js">路径未同步更新。
解决:
检查exam.jsp头部的 script 标签,将其改为:
<script src="${pageContext.request.contextPath}/static/js/exam.js"></script> <!-- 或根据实际路径调整,确保浏览器 Network 面板中该 JS 返回 200 -->6. 验证跑通:从登录到交卷的全链路自测清单与日志定位法
6.1 四步闭环验证:每个环节都必须看到预期响应
部署完成后,不要只点开首页就认为成功。按顺序执行以下四步,每步都需观察三个维度:浏览器表现、Tomcat 日志、数据库状态。
| 步骤 | 操作 | 预期浏览器表现 | Tomcat catalina.out 关键日志 | 数据库验证 SQL |
|---|---|---|---|---|
| 1. 登录 | 输入 admin/123456 | 跳转至index.jsp,右上角显示“欢迎,管理员” | INFO [http-nio-8081-exec-1] c.x.c.LoginController.login - 用户 admin 登录成功 | SELECT login_time FROM user WHERE username='admin';(时间应为当前) |
| 2. 创建考试 | 管理员后台 → 考试管理 → 新增考试 | 页面提示“添加成功”,列表出现新考试 | DEBUG [http-nio-8081-exec-2] c.x.s.ExamService.addExam - 考试ID: 1001 | SELECT COUNT(*) FROM exam WHERE name='模拟测试';(应为 1) |
| 3. 开始考试 | 学生账号登录 → 点击“开始考试” | 加载试卷页,显示题目、倒计时、选项 | INFO [http-nio-8081-exec-3] c.x.c.ExamController.startExam - 生成试卷ID: 2001 | SELECT COUNT(*) FROM exam_record WHERE user_id=2 AND exam_id=1001;(应为 1,记录考试开始) |
| 4. 提交试卷 | 点击“交卷”按钮 | 弹出“成绩:95分”,跳转至成绩页 | INFO [http-nio-8081-exec-4] c.x.c.ExamController.submitExam - 用户2提交试卷,得分95 | SELECT score FROM exam_record WHERE user_id=2 AND exam_id=1001;(应为 95) |
提示:
catalina.out日志默认不打印 DEBUG 级别。如需查看 Service 层日志,需修改conf/logging.properties:将org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO改为DEBUG。
6.2 日志定位法:三类错误的秒级排查路径
当某一步失败时,按此顺序查日志,90% 问题可 2 分钟内定位:
第一类:HTTP 500 错误(服务器内部异常)
- 直接搜索
catalina.out中Caused by:后的第一行异常类名 - 若为
SQLException,看前一行SQLState:值:08S01是连接超时,42S02是表不存在,23000是主键冲突 - 若为
ClassNotFoundException,检查WEB-INF/lib/是否缺失对应 JAR(如spring-webmvc-5.2.22.RELEASE.jar)
第二类:HTTP 404 错误(资源未找到)
- 检查浏览器 Network 面板中请求的Full Path(如
/exam-system/exam/list) - 对照
web.xml中servlet-mapping的url-pattern和 Controller 的@RequestMapping,确认路径拼接逻辑 - 验证
webapps/exam-system/目录下是否存在对应 JSP 或静态资源(如exam/list.jsp)
第三类:页面渲染异常(空白/乱码/JS 报错)
- 浏览器按 F12 → Console 标签,复制报错信息(如
Uncaught TypeError: Cannot read property 'length' of null) - 搜索
exam.jsp中调用该属性的 JS 代码,检查其依赖的数据是否为空(如var questions = ${requestScope.questions};,需确认后端是否真的 setAttribute 了questions) - 查看 Network → All 标签,过滤
js、css,确认所有静态资源返回 200,无 404
6.3 终极验证:用 curl 模拟全流程(脱离浏览器干扰)
当界面操作不稳定时,用命令行绕过前端,直击后端接口:
# 1. 模拟登录,获取 JSESSIONID LOGIN_RESP=$(curl -s -X POST "http://localhost:8081/exam-system/login" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=admin" -d "password=123456" -i) SESSION_ID=$(echo "$LOGIN_RESP" | grep 'JSESSIONID=' | sed -r 's/.*JSESSIONID=([^;]+).*/\1/') # 2. 携带 Cookie 获取考试列表 curl -s -X GET "http://localhost:8081/exam-system/exam/list" \ -H "Cookie: JSESSIONID=$SESSION_ID" | head -20 # 3. 模拟交卷(需构造 JSON) curl -s -X POST "http://localhost:8081/exam-system/exam/submit" \ -H "Cookie: JSESSIONID=$SESSION_ID" \ -H "Content-Type: application/json" \ -d '{"examId":1001,"answers":[{"questionId":1,"answer":"A"},{"questionId":2,"answer":"B"}]}'如果 curl 返回正常 JSON(如
{"code":200,"msg":"提交成功","data":{"score":95}}),证明后端逻辑完全 OK,问题一定出在前端资源路径、JS 逻辑或浏览器缓存上。从那以后我每次部署完 Java Web 项目,都强制走一遍这四步闭环验证 + 一次 curl 全流程,哪怕只是本地调试——因为线上环境不会给你第二次机会。希望帮到你。
本文还有配套的精品资源,点击获取