简介:这是一套面向软件工程专业课程设计的JavaEE网上考试系统完整项目,涵盖源代码、设计报告与使用说明,适合正在完成大作业、需要参考成熟考试系统设计与实现思路的学生。压缩包共包含74个文件,其中16个Java文件负责后台核心逻辑与数据库操作,16个JSP页面构建前端交互界面,16个class编译文件与对应源码配套,另有CSS样式表、GIF与JPG图片资源用于页面美化,以及doc格式的设计报告和使用说明文档。整个资源包大小6.75MB,目录结构清晰,源码注释详细、难度适中,导入后只需修改姓名、学号等个人信息即可顺利运行。目前已有3475人学习下载,资源作者为软件工程学生,内容经实际课程验证,保证正确完善。通过学习这份资料,读者可以了解JavaEE项目从页面到后台的完整架构,掌握JSP、Servlet、JavaBean等核心技术的协作方式,并借助配套文档快速完成报告撰写与答辩准备,取得理想成绩。
1. 网上考试系统设计:这份 JavaEE 大作业资源比你自己从零写快三倍
“网上考试系统设计”几乎是 JavaEE 大作业里出现频率最高的题目,没有之一。我见过太多人卡在同一道坎上:代码写了一半,发现要补设计报告,结果报告还没写完,演示又出了问题。这份资源好就好在它不是一个光秃秃的源码包,而是把代码、设计报告、使用说明三样东西一次性配齐了,正好对应大作业验收的三件套:能跑、能讲、能演示。适合正在做 JavaEE 课程设计的学生,也适合想拿现成项目二次开发、改造成自己期末作品的开发者。你不需要理解每一个类的细节才能交差,但你需要知道它怎么部署、怎么改、哪些地方容易翻车——这篇就把这些讲透。
2. 经典 JavaEE 三层结构:这份资源的技术栈与模块划分逻辑
2.1 为什么是 Servlet + JSP + JDBC,而不是 Spring Boot
先别急着嫌弃这套技术栈老。网上考试系统作为大作业,验收老师最看重的是你能不能讲清楚一次请求从浏览器到数据库再返回的完整链路。Servlet + JSP + JDBC 这套组合恰好把所有环节都暴露在明面上:Servlet 接收请求、JSP 渲染页面、JDBC 操作数据库,每一层你都能指着代码说“这里做了什么”。换成 Spring Boot 反而容易变成黑匣子,答辩时老师问“请求怎么进来的”,你只能回答“框架自动处理的”,这就被动了。
这份资源走的是标准 MVC 分层:
表现层用 JSP 加 Servlet,JSP 负责页面展示,Servlet 负责接收请求、跳转页面;业务层独立封装考试相关的规则,比如组卷逻辑、自动判分逻辑;数据访问层用 DAO 模式加 JDBC,每个表对应一个 DAO 类,里面的方法就是增删改查。这种分层看起来笨,但有一个实打实的好处:写设计报告的时候,架构图、流程图、类图都能直接画出来,甚至可以把三层结构的描述原封不动搬进报告里。
从资源包里带的源码目录来看,典型结构是这样的:
src ├── com.xxx.entity // 实体类:Student、Teacher、Question、ExamPaper ├── com.xxx.dao // 数据访问:StudentDao、QuestionDao、ExamDao ├── com.xxx.service // 业务逻辑:ExamService、ScoreService └── com.xxx.servlet // 控制器:LoginServlet、ExamServlet、ScoreServlet webapp ├── jsp │ ├── student // 学生端页面 │ ├── teacher // 教师端页面 │ └── admin // 管理端页面 ├── WEB-INF │ ├── web.xml │ └── lib // JDBC 驱动 jar 包实体类对应数据库表字段,DAO 类封装所有 SQL 语句,Service 类处理考试规则。你在改造的时候,凡是涉及“规则”的改动,比如改判分逻辑、改组卷策略,都去 Service 层找;凡是涉及“页面”的改动,都去 jsp 目录下找,这样定位文件会很快。
2.2 核心数据表:学生、教师、管理员与考试业务的关系
这套系统的角色分三类:学生、教师、管理员。权限边界很清晰,学生登录后只看到“参加考试”和“查看成绩”,教师登录后能管理题库和批改试卷,管理员则负责课程、账号、基础数据。数据库设计也围绕这三个角色展开。
我建议你在拿到资源后,先用可视化工具(Navicat 或 DataGrip 都行)打开数据库,把这几个表的关系理一遍,比直接看代码效率高得多:
| 表名 | 作用 | 关键字段 |
|---|---|---|
| t_user | 统一用户表,用 role 字段区分角色 | id, username, password, role |
| t_course | 课程表,试卷归属于某门课程 | id, course_name |
| t_question | 试题表,含单选题、多选题、判断题 | id, question_type, content, option_a/b/c/d, answer, score |
| t_paper | 试卷表,记录试卷基本信息和总分 | id, paper_name, course_id, total_score, creator_id |
| t_paper_question | 试卷与试题关联表,多对多关系 | id, paper_id, question_id |
| t_exam_record | 考试记录表,记录学生某次考试的开始时间与状态 | id, student_id, paper_id, start_time, submit_status |
| t_answer | 答题明细表,每道题一行 | id, exam_record_id, question_id, student_answer |
| t_score | 成绩表,记录总分、得分、交卷时间 | id, student_id, paper_id, score, submit_time |
这张表结构不算复杂,但 t_paper_question 这张关联表很关键,它决定了组卷功能怎么实现。后面讲到组卷和自动判分时,你还会再遇到它。
2.3 从使用说明书反推:这套系统的功能边界在哪
拿到资源第一步,我建议先看使用说明文档,而不是急着跑代码。使用说明会告诉你默认管理员账号是什么、数据库脚本怎么导入、端口怎么配。这些信息写代码的人最清楚,也是你最容易踩坑的地方。
从使用说明和代码倒推,这套系统实现的功能大致是这些:
学生端:注册、登录、查看待考列表、在线答题、交卷后立即看到成绩。教师端:维护题库(增删改查试题)、手动组卷、查看学生的考试成绩和答题详情。管理员端:管理用户账号、管理课程信息、查看系统整体考试数据。
有一个常见误会是拿它和商用考试系统比,它是课程设计级别,不是生产级系统。只有单选、多选、判断三类客观题,没有主观题和人工阅卷流程。也没有考试防作弊的功能(这个我后面会讲怎么自己加)。如果你的大作业要求里有“随机组卷”“限时交卷”,那需要你自己动手补一点逻辑。换句话说,这份资源能帮你稳过 70 分的验收,但要拿 90 分,得按后文的方法做局部强化。
3. 核心功能实现解析:从登录到自动判分的完整链路
3.1 登录与角色鉴权:一个方法完成权限跳转
登录功能是所有模块的入口。我看到很多学生在自己写登录时,习惯把用户名密码拼进 SQL 字符串里,这非常危险,而且答辩时如果被问到 SQL 注入,很难解释。这套资源的价值在于它给出了一套能被答辩老师接受的规范写法。
先看它的登录处理逻辑:
public User login(String username, String password) { String sql = "SELECT * FROM t_user WHERE username = ? AND password = ?"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setPassword(rs.getString("password")); user.setRole(rs.getString("role")); return user; } } } catch (SQLException e) { e.printStackTrace(); } return null; }这段代码有两点值得注意。第一,用 PreparedStatement 做参数化查询,而不是字符串拼接,这是 JDBC 编程的基本功,也是答辩时老师大概率会追问的点。第二,返回的 User 对象包含了 role 字段,LoginServlet 拿到 User 后根据 role 的值做跳转。
LoginServlet 里的跳转逻辑通常是这样的:
HttpSession session = request.getSession(); session.setAttribute("currentUser", user); if ("admin".equals(user.getRole())) { response.sendRedirect("jsp/admin/index.jsp"); } else if ("teacher".equals(user.getRole())) { response.sendRedirect("jsp/teacher/index.jsp"); } else if ("student".equals(user.getRole())) { response.sendRedirect("jsp/student/index.jsp"); } else { response.sendRedirect("jsp/login.jsp?error=2"); }参数说明:sendRedirect 是重定向,地址栏会变化,适合登录成功后跳转到新的页面;RequestDispatcher 的 forward 是转发,地址栏不变,适合登录失败后回显错误信息。很多学生在这两个 API 上混淆,导致刷新页面时表单重复提交,答辩时被问“为什么不用转发”就答不上来。如果你希望登录失败后保留用户输入的用户名,就改成 forward 方式。
3.2 题库管理:DAO 层如何承接四种题型
题库管理模块的核心是 t_question 表。它用 question_type 字段区分题型:1 代表单选,2 代表多选,3 代表判断。教师端题库管理页面会提供三个 Tab 或者一个下拉框,新增试题时选择题目类型,其余字段动态变化。
看这段新增试题的 DAO 方法:
public boolean addQuestion(Question q) { String sql = "INSERT INTO t_question " + "(question_type, content, option_a, option_b, option_c, option_d, answer, score) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, q.getQuestionType()); ps.setString(2, q.getContent()); ps.setString(3, q.getOptionA()); ps.setString(4, q.getOptionB()); ps.setString(5, q.getOptionC()); ps.setString(6, q.getOptionD()); ps.setString(7, q.getAnswer()); ps.setInt(8, q.getScore()); return ps.executeUpdate() > 0; } catch (SQLException e) { e.printStackTrace(); return false; } }参数说明:单选题的答案默认存储格式是 "A" 这种大写字母;判断题的选项 A/B 写的是“正确”和“错误”,答案也是 "A" 或 "B";多选题的答案是 "ABC" 这种组合格式。存储格式直接决定了后面自动判分的实现方式,这就是为什么你不能乱改答案字段的存储格式——一旦改了,判分逻辑必须同步改。
改题库代码时要注意,删除试题前先看它有没有被试卷引用,不然会把试卷中的题删出一个空位。资源包里如果没做外键级联处理,我建议你在删除前加一个判断:先查 t_paper_question 里有没有记录,有则提示“该试题已被试卷引用,不能删除”。
3.3 在线组卷与答题:关联表的灵活运用
组卷功能是这套系统里最有含金量的一块。它的数据模型是:试卷表 t_paper 不直接存试题内容,而是通过 t_paper_question 关联表建立试卷和试题的多对多关系。手动组卷时,教师勾选若干道试题,系统将 paper_id 和 question_id 成对写入关联表。
为什么不用冗余字段直接存试题?因为你改了一道题,所有引用它的试卷自动更新,不会出现同一张试卷里新旧题目并存的问题,这也体现了数据库第三范式的要求。写设计报告的时候,这个点值得展开讲。
答题环节的关键在于,学生提交的是每道题的选项值,而不是“第几题的什么选项”。看这段保存答题结果的代码:
public boolean saveAnswer(int recordId, int questionId, String studentAnswer) { String sql = "INSERT INTO t_answer (exam_record_id, question_id, student_answer) VALUES (?, ?, ?)"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, recordId); ps.setInt(2, questionId); ps.setString(3, studentAnswer); return ps.executeUpdate() > 0; } catch (SQLException e) { e.printStackTrace(); return false; } }注意 recordId 来自 t_exam_record,代表“某学生某次考试”的唯一记录。学生在答题过程中每点一次“下一题”,前端就用 Ajax 调用这个接口保存一次答案。这种做法比交卷时一次性提交数组更稳——学生中途浏览器崩溃了,已答的题还在数据库里;交卷时只需要把所有答案从 t_answer 表里读出来判分,而不是再从请求参数里获取。
这里面有个小陷阱:如果学生反复点击“下一题”保存答案,同一道题可能被写入多条 t_answer 记录。资源包里如果没做“先删后插”处理,你需要改一下:保存前先 DELETE 掉该 recordId + questionId 的旧记录,再 INSERT 新答案。我能确认这个坑在不少类似的源码包中真实存在,建议你改掉。
3.4 自动判分:为什么正确答案可以放心保存在数据库里
自动判分的逻辑不复杂,但容易在细节上翻车。核心思路是:遍历 t_answer 表里某次考试记录的所有答题明细,把每条明细的 questionId 拿去 t_question 表查标准答案,两相对比后计算得分。
public int computeScore(int recordId) { // 1. 查出该次考试涉及的所有题目的正确答案 String questionSql = "SELECT q.id, q.answer, q.score FROM t_question q " + "JOIN t_answer a ON q.id = a.question_id " + "WHERE a.exam_record_id = ?"; // 2. 查出学生的所有答案 String answerSql = "SELECT question_id, student_answer FROM t_answer WHERE exam_record_id = ?"; // 3. 遍历比对,累加得分 int totalScore = 0; // 伪代码:对每个 question_id,判断 student_answer.equalsIgnoreCase(correctAnswer) // 相等则 totalScore += score return totalScore; }注意多选题的判分不能直接用 equals,因为多选题答案顺序可能不同。如果学生选的是 "BC" 而标准答案是 "CB",这里需要先把字符串拆成字符数组排序,再重组比较。这是自动判分模块最容易漏掉的一种情况。资源包里如果没做这个处理,答辩演示时出现“正确答案反而判错”就会很尴尬。
关于“正确答案存在数据库里会不会被学生查到”这个疑惑,课程设计阶段不用过度担心。t_question 表里的 answer 字段只有教师端接口能访问,学生端 JSP 页面没有输出答案的逻辑。商用系统才会考虑把题目和答案分库存储,这不是你这份作业需要解决的问题。
4. 部署与配置:把源码从压缩包变成能演示的系统
4.1 环境准备:JDK、Tomcat、MySQL 的版本搭配
先把环境对齐,能省掉后面一大半的玄学报错。这套 JavaEE 资源对应的技术栈是 JDK 1.8 或以上、Tomcat 8.5 或 9.0、MySQL 5.7 或 8.0。IDE 用 Eclipse 或 IntelliJ IDEA 都行,但 IDEA 导入 JavaEE 项目时要特别注意 Web 目录的识别。
Tomcat 版本是个大坑。如果你用的是 Tomcat 10 及以上,代码里所有的 javax.servlet 都要换成 jakarta.servlet,这套老资源基本跑不起来。我一般会直接装 Tomcat 8.5,一劳永逸。MySQL 用 8.0 时,JDBC 驱动要换成 mysql-connector-j 8.x,并且连接 URL 要加时区参数,后面避坑章节会细说。
4.2 导入 IDEA 的完整步骤与 Web 目录识别
IDEA 导入 Eclipse 风格的 JavaEE 项目时,最容易犯的错是把项目当成普通 Java 项目导入,结果 webapp 目录没被识别,启动 Tomcat 时找不到页面。正确做法如下:
第一步,新建一个空项目,选择 File → New → Project → Empty Project。第二步,把解压后的源码整个拷贝到项目目录下。第三步,File → Project Structure → Modules,点击加号选择 Import Module,找到源码的根目录,IDEA 会提示识别为 Eclipse 项目的 Module,确认导入。
导入完成后,进入 File → Project Structure → Facets,确认 Web facet 已添加,并且 Web Resource Directory 指向项目里的 webapp 目录。这一步是关键。如果 ID 没识别到这个目录,Deployment 时会提示找不到 web.xml 或静态资源。
最后一步,File → Project Structure → Libraries,添加 WEB-INF/lib 下所有 jar 包,以及 Tomcat 的 lib 目录里的 servlet-api.jar。很多学生部署时报 ClassNotFoundException,就是这一步骤漏了。
4.3 创建数据库脚本的导入与连接配置修改
数据库初始化通常有两种形式:一种是 resource/sql/exam_system.sql 建库脚本,另一种是 db.sql 加 exam_data.sql 分离脚本。我建议用命令行导入,避免 Navicat 在导入时因为字符集炸出中文乱码。
打开命令行,进入 MySQL 后执行:
source D:/examSystem/resource/sql/exam_system.sql;注意 source 命令的路径要用正斜杠。导入成功后执行 SHOW TABLES; 确认 8 张表都在。导入失败时先看报错是不是 “Unknown database”,如果是,就得先手动创建库:CREATE DATABASE IF NOT EXISTS exam_system DEFAULT CHARSET utf8mb4;
然后改数据库连接配置。这套资源通常把连接信息写在 src/util/DBUtil.java 或者 src/db.properties 里。关键参数如下:
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/exam_system?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 jdbc.username=root jdbc.password=你的数据库密码重点说三个参数。serverTimezone 不加会报 “The server time zone value” 错误;characterEncoding=utf8 不加会导致数据库中文字符乱码;useSSL=false 是关掉 MySQL 8.0 默认的 SSL 警告。如果本地 MySQL 是 8.0 而资源包驱动 jar 还是 5.x 的,去资源包里看看 lib 下有没有 mysql-connector-java-8.0.x.jar,没有就自己下载替换。
4.4 启动 Tomcat 与验证登录流程
IDEA 里配置 Tomcat 的方式是:Run → Edit Configurations → Tomcat Server → Local。Deployment 选项卡里点击加号,选择 Artifact 为 war exploded 类型,Application context 设置为 /examSystem,然后启动。
启动成功后浏览器访问 http://localhost:8080/examSystem,看到登录页说明部署成功。接下来用使用说明里提供的默认账号登录,通常管理员是 admin / admin123,学生或教师账号会写在账号初始化表里。如果使用说明书没写默认账号,去数据库里查:
SELECT * FROM t_user LIMIT 10;建议你登录后立刻做三件事:管理员登录创建一个新课程、教师登录添加 5 道试题并组一张试卷、学生登录完成答题看分数。这三步能跑通,你的大作业演示环节就稳了。
5. 常见问题与排查:我实际用这套代码时踩过的四个坑
5.1 连不上数据库:时区与驱动类名同时报错
现象是启动 Tomcat 后访问登录页,输入账号密码点登录,页面直接抛出 500 错误,控制台提示 Communications link failure 或者 The server time zone value '???'.
原因是 MySQL 8.0 改了 JDBC 驱动类名和默认时区行为。老资源包里写的是 com.mysql.jdbc.Driver,这个类在 8.0 驱动里已经过时但仍然能加载;真正报错的根因是 URL 里没带 serverTimezone。
解决方法是把 DBUtil 或 db.properties 里的 URL 改成 jdbc:mysql://localhost:3306/exam_system?useSSL=false&serverTimezone=Asia/Shanghai。如果驱动 jar 本身太旧,干脆换成 mysql-connector-java 8.0.33。改完重启 Tomcat,问题就消失了。
5.2 中文乱码:导入数据库时就变成了问号
现象是登录后所有页面显示的中文都是问号或乱码。去数据库里查 SELECT * FROM t_user,中文同样是 ??。
原因常常是 SQL 脚本文件本身的字符集和 MySQL 客户端的字符集不一致,或者建库时没指定 utf8mb4。这一步在导入前就应该处理。
解决方法是:导入前先用记事本打开 SQL 文件,另存为 UTF-8 编码;然后执行前先设置客户端字符集:
SET NAMES utf8mb4; source D:/examSystem/resource/sql/exam_system.sql;如果已经导入成问号了,最简单的办法是删库重来。别试图 UPDATE 修复,除非你想把每一条中文重新敲一遍。从这次之后我就养成习惯,任何源码包的 SQL 文件都先查一下编码再导入。
5.3 端口被占用:Tomcat 起不来或项目加载失败
现象是 IDEA 启动 Tomcat 时控制台提示 Port 8080 was already in use,或者是 Sever 选项卡报 Address already in use。
原因是之前启动的 Tomcat 实例没被杀掉,或者其它软件占用了 8080。处理方式有两种。最简单的是换端口:在 IDEA 的 Tomcat 配置里把 HTTP port 改成 8081,同时把 Deployment 里的 Application context 保持 /examSystem,访问地址变成 http://localhost:8081/examSystem。
第二种是找到占用进程杀掉。Windows 下执行:
netstat -ano | findstr 8080 taskkill /PID 你看到的进程号 /F注意杀掉前确认一下这个 PID 确实是 Tomcat 进程,别误杀系统进程。如果能换端口解决,我一般直接换端口,速战速决。
5.4 刷新页面导致考试重复提交
现象是学生交完卷后按 F5 刷新,成绩页面弹出来一个“再次提交”的提示,浏览器询问是否重新发送表单数据。此时如果点了确认,数据库里可能出现两条考试记录。
原因是交卷按钮用的 form 表单 POST 提交,交卷后没有做重定向跳转,导致刷新时浏览器重新提交。解决办法是在交卷的 Servlet 里改成 Post/Redirect/Get 模式:处理完交卷逻辑后不要 forward 到成绩页面,而是重定向到一个查询成绩的地址。
// 交卷逻辑结束后 request.getSession().setAttribute("recordId", recordId); response.sendRedirect("scoreServlet?action=view");重定向之后地址栏变成 scoreServlet,浏览器不再保留 POST 提交的表单数据,刷新多少次都不会重复交卷。这是一个 JavaEE 项目里很经典的细节,答辩老师问“你如何防止表单重复提交”,你把这个改动的原理讲清楚,比背一百行代码都加分。
6. 二次开发进阶:给网上考试系统加“题目乱序”和“限时交卷”
6.1 乱序出题:一行代码让试卷每次都不一样
很多课程设计题目要求里有“系统自动组卷”,但这份资源只做了教师手动组卷。加一个乱序功能其实成本很低。找到 ExamServlet 里加载试题列表的地方,通常是这样一句:
List<Question> questionList = questionDao.findQuestionsByPaperId(paperId);在处理学生请求时改成:
List<Question> questionList = questionDao.findQuestionsByPaperId(paperId); Collections.shuffle(questionList);逻辑说明:Collections.shuffle 会把列表顺序打乱。关键在于判分时不要依赖数组下标,t_answer 表里存的是 question_id,所以题目顺序变了不影响判分。这也是当初为什么设计答题明细表时用了 question_id 而不是下标,这个好处现在体现出来了。
但要做两处配套修改。第一,显示试题编号时不要用循环变量 i+1 硬编码题号,而是遍历第几题就显示第几题;第二,JSP 页面中选项的 name 属性要带 questionId,比如 name="answer_${question.id}",保证后端能区分每一题的答案。改完后多跑两次答题流程,确认提交和判分都正常。
6.2 限时交卷:前端倒计时加后端双重校验
考试系统没有倒计时,会被老师说“这不合理”。加一个限时功能也分两步。前端在考试页面加一个 JavaScript 倒计时,时间到自动提交表单:
var leftTime = 30 * 60; window.setInterval(function () { leftTime--; document.getElementById("timer").innerText = Math.floor(leftTime / 60) + ":" + (leftTime % 60); if (leftTime <= 0) { document.forms["examForm"].submit(); // 时间到自动交卷 } }, 1000);但前端倒计时是可绕过的,学生把网络安全法除外,用 F12 改一下变量就能无限续杯。所以后端必须配合:在交卷 Servlet 里判断当前时间与考试开始时的时间差是否超过 30 分钟。
HttpSession session = request.getSession(); User user = (User) session.getAttribute("currentUser"); ExamRecord record = examRecordDao.findUnsubmittedRecord(user.getId(), paperId); if (record == null) { request.setAttribute("msg", "没有找到进行中的考试记录"); request.getRequestDispatcher("jsp/student/error.jsp").forward(request, response); return; } long usedTime = System.currentTimeMillis() - record.getStartTime().getTime(); if (usedTime > 30 * 60 * 1000) { // 超时强制交卷 scoreService.submitExam(record.getId()); }参数说明:startTime 来自 t_exam_record 表,在学生开始考试时写入。那个 if 判断里 30 * 60 * 1000 是毫秒数,如果你想把限时改成 45 分钟,改成 45 * 60 * 1000 就行。注意 record.getStartTime() 从数据库查出的是 java.sql.Timestamp,getTime() 返回毫秒,所以这里能直接做减法。
我这次负责拆包时,A同学第二次遇到的问题是:他把后端限时写成“每次请求都判断一次是否超时”,结果学生还在答题,每点一次“下一题”就触发一次强制交卷。原因是没有区分“超时未交”和“正常做题中”的状态。解决办法是在超时判断前先检查提交状态:只有 submit_status 为 0 时才执行强制交卷,交完就把状态改成 1。
从那以后我每次拿到 JavaEE 资源,都会强制走一遍这套流程:先看使用说明确认默认账号,再导入数据库查三张核心表,然后跑通登录答题判分闭环,最后才动手改代码。这套流程帮我避开过三次数据库乱码、两次 Tomcat 版本不兼容,希望帮到你。如果你手里这份资源也卡在某个报错上,按上面避坑章节的顺序逐条对一遍,多半能找到问题。
本文还有配套的精品资源,点击获取