简介这是一套基于SpringBoot与MySQL开发的上机考试系统完整项目包面向计算机、数学、电子信息等专业的学生与教师适合作为课程设计、期末大作业或毕业设计的参考资料。系统通过绑定IP地址控制学生登录确保考生独立完成并提交程序涵盖管理员、教师、学生三类角色支持教师管理、考试清理、系统配置、试卷上传、学生名单导入、考试开启与结束、提交文件打包下载及通知消息推送等完整业务流程。压缩包共218个文件约8.42MB包含52个Java源文件、23个HTML页面、22个JavaScript脚本、6个JSP页面及配套CSS样式另有数据库SQL脚本、需求分析与总体设计报告文档以及layui等前端框架资源结构清晰便于二次开发。目前已有91人学习下载读者可获取可直接运行的源码、数据库脚本与设计文档对照用例图、类图和顺序图理解系统架构快速完成项目搭建与功能调试。1. 上机考试系统为什么总在期末周翻车从一份 SpringBootMySQL 源码说起每到期末周机房管理员和任课老师最怕的不是学生不会做题而是考试系统本身先崩了。我见过太多“上机考试系统”在 200 人同时登录时数据库连接池被打满也见过交卷瞬间因为一条没加索引的查询把 MySQL 拖到 CPU 100%。这份基于 SpringBootMySQL 开发的上机考试系统含源码数据库设计报告本质上要解决的就是三件事考生身份与考试场次的绑定、考试过程中的实时状态管理、以及交卷后成绩与答卷的可靠落库。它适合两类人一类是课程设计或毕设需要一套完整可跑系统的学生另一类是中小机房想自建轻量考试平台的运维或老师。热词里反复出现的 springboot、mysql、上机考试系统、源码、数据库恰好对应了这套系统的四个核心面框架选型、数据存储、业务建模、可交付代码。下面我不讲空泛的架构图直接按“拿到这份源码后怎么跑起来、怎么改、怎么不翻车”的顺序拆。2. 把源码跑起来之前SpringBoot 与 MySQL 的版本对齐2.1 为什么 springboot 版本太高反而跑不动老代码热搜里“springboot版本太高”是个高频痛点。这份上机考试系统的源码如果基于 SpringBoot 2.x 编写你直接换成 3.x 大概率启动就报错原因集中在三处javax.*包被替换成jakarta.*、Spring Security 配置写法变更、以及 MyBatis 与 SpringBoot 3 的兼容版本要求。我一般会先看pom.xml里的parent版本再决定本地 JDK 用 8 还是 17。常见做法是源码写的是 2.7.x就老老实实用 JDK 8 或 11别为了追新把整个依赖树搅乱。MySQL 侧同理热词里“mysql 5.7.44 安装过程详细”“mysql安装教程8.0”说明大家版本跨度大而 5.7 和 8.0 在驱动类名、时区参数、默认认证插件上都有差异跑之前必须对齐。2.2 数据库导入与连接配置的最小步骤拿到源码和数据库文件后第一步不是急着mvn spring-boot:run而是先把库建好、把连接串改对。下面是我常用的导入与配置流程命令按 MySQL 8.0 写5.7 把认证相关行去掉即可。# 1. 登录 MySQL创建考试系统专用库字符集用 utf8mb4 防止学生姓名生僻字乱码 mysql -u root -p -e CREATE DATABASE exam_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 2. 导入随源码附带的 .sql 文件注意路径换成你本地的实际位置 mysql -u root -p exam_system /path/to/exam_system.sql # 3. 确认表结构和初始数据是否进去重点看用户表和试卷表 mysql -u root -p exam_system -e SHOW TABLES; SELECT COUNT(*) FROM sys_user;导入完成后改application.yml核心就四行url、username、password、driver-class-name。MySQL 8.0 的驱动类是com.mysql.cj.jdbc.Driver连接串要带serverTimezoneAsia/ShanghaiuseUnicodetruecharacterEncodingutf8否则中文题干和时区时间会出玄学问题。spring.datasource.hikari.maximum-pool-size默认 10机房 100 人考试时这个值偏小建议先调到 30 再压测。参数说明maximum-pool-size是最大连接数connection-timeout是拿不到连接时的等待毫秒数考试场景下后者别设太大否则学生点交卷会一直转圈。2.3 启动类与静态资源的落位检查SpringBoot 项目结构里启动类必须在所有 Controller 的上级包否则扫描不到。热词“springboot项目结构”“vue打包放进springboot中”提示了一个常见组合前端 Vue 打包后放进src/main/resources/static。如果你拿到的是前后端分离版先确认static下有没有index.html没有就单独起前端。启动前用mvn clean package -DskipTests打一次包能提前暴露依赖冲突。启动成功看到 Tomcat 端口和Started Application才算过第一关别看到日志刷屏就以为好了。3. 考试系统的数据建模从数据库增删改查到交卷落库3.1 核心表结构与字段设计取舍上机考试系统的数据库设计决定了后面所有业务好不好写。常见做法是围绕五张主表展开用户表、角色表、试卷表、题目表、答卷/成绩表。下面这张表是我从这类源码里总结的字段要点不是让你照抄而是对照检查你手里的库有没有埋雷。表名关键字段设计意图与注意点sys_userid, username, password, role_id密码必须加盐哈希别存明文exam_paperid, title, start_time, end_time, duration时间字段用 datetime别用字符串exam_questionid, paper_id, type, content, scoretype 区分单选/多选/编程题exam_recordid, user_id, paper_id, start_time, submit_time, statusstatus 标记进行中/已交卷exam_answerid, record_id, question_id, answer, score编程题答案字段要够长用 text热词“mysql数据库修改结构”在这里很实用如果源码给的库缺了status字段你补ALTER TABLE exam_record ADD COLUMN status TINYINT DEFAULT 0;就能让“进行中/已交卷”逻辑跑通。字段类型上分数用decimal(5,1)比int更稳编程题可能给 0.5 分。3.2 用 MyBatis 写交卷事务的完整代码交卷是整个系统最不能出错的动作要同时写答卷、更新考试记录状态、可能还要算客观题分数。这三步必须在一个事务里否则学生交了卷但成绩没落库就是血泪事故。下面是一段典型的 Service 层代码基于 MyBatis 注解方式逻辑说明和参数说明跟在后面。Service public class ExamSubmitService { Autowired private ExamRecordMapper recordMapper; Autowired private ExamAnswerMapper answerMapper; // Transactional 保证三步要么全成功要么全回滚 Transactional(rollbackFor Exception.class) public void submitExam(Long recordId, ListExamAnswer answers) { // 1. 先更新考试记录状态为已交卷并写入交卷时间 int updated recordMapper.updateStatusAndSubmitTime(recordId, 1, new Date()); if (updated ! 1) { throw new RuntimeException(考试记录状态更新失败recordId recordId); } // 2. 批量写入学生答案answer 字段可能很长 for (ExamAnswer ans : answers) { ans.setRecordId(recordId); answerMapper.insert(ans); } // 3. 客观题自动判分主观题留空待老师批阅 answerMapper.autoScoreObjective(recordId); } }逻辑说明第一步用updateStatusAndSubmitTime做乐观更新返回影响行数不是 1 就抛异常触发回滚防止重复交卷。第二步循环插入答案数据量大时建议改批量insertBatch。第三步autoScoreObjective是一条 SQL 把单选题与标准答案比对后写分数。参数说明recordId是考试记录主键answers是前端提交的答案列表rollbackFor Exception.class确保任何异常都回滚别只写默认的RuntimeException。3.3 考试进行中的状态查询与防重复交卷学生考试过程中前端会定时拉取剩余时间后端要能快速返回该场次是否还在进行。这里最容易踩的坑是“同一学生重复交卷”。常见做法是在exam_record上加唯一索引(user_id, paper_id)并在交卷前先查状态。查询语句要利用索引别全表扫。热词“mysql排序”“mysql锁的分类”在这里有实际意义如果并发交卷多可以用SELECT ... FOR UPDATE锁住该行再判断状态但要注意别把整张表锁死。我一般先用唯一索引兜底再用应用层判断双保险。4. 避坑与排查上机考试系统上线前必须过的五道坎4.1 现象启动报 Unknown database 或 Access denied原因通常是数据库没建、用户名密码不对或者 MySQL 8.0 的caching_sha2_password认证插件与老驱动不兼容。解决先mysql -u root -p手动登录确认库存在连接串里加allowPublicKeyRetrievaltrueuseSSLfalse实在不行把用户认证改成mysql_native_password。别一上来就怀疑源码有问题八成是环境没对齐。4.2 现象中文题干在页面上显示成问号原因是数据库、连接串、表字段三处字符集不一致。解决库用utf8mb4连接串带characterEncodingutf8建表时字段也显式CHARACTER SET utf8mb4。已经建好的表用ALTER TABLE exam_question CONVERT TO CHARACTER SET utf8mb4;补救。这个坑在热词“mysql安装配置教程”里被反复提到但很多人只改一处就以为好了。4.3 现象考试中途所有学生卡住日志显示连接池耗尽原因是maximum-pool-size太小或者有慢查询长时间占用连接。解决先把池调到 30 到 50再打开 MySQL 慢查询日志slow_query_logON和long_query_time1找出没走索引的 SQL。常见元凶是答卷表按record_id查询却没建索引补CREATE INDEX idx_record ON exam_answer(record_id);即可。4.4 现象交卷后成绩为 0 或答案丢失原因是交卷事务没生效或者前端提交的答案列表为空。解决检查Transactional是否被同类内部方法调用绕过Spring 代理失效确认前端answers数组非空并在 Service 入口打日志记录recordId和答案条数。这个坑我踩过最后发现是 Controller 里把异常吞了事务根本没触发回滚。4.5 现象考试时间到了学生还能继续答题原因是后端没有校验end_time只靠前端倒计时。解决在提交答案和拉取题目两个接口里都加服务端时间判断if (new Date().after(paper.getEndTime())) throw new RuntimeException(考试已结束);。前端时间可以被改服务端才是唯一可信源。5. 让这套源码真正可用的三个进阶技巧5.1 用数据库同步思路做考试数据备份热词里“数据库同步软件”“使用flink 实现mysql同步到clickhouse”提醒我考试系统的成绩数据其实值得做一份实时备份。轻量做法是用 MySQL 主从复制把从库放在另一台机器考试期间主库压力大时从库还能顶查询。配置上主库开binlog从库CHANGE MASTER TO指向主库即可。如果不想搞复制至少每天凌晨用mysqldump导一份成绩表到独立目录命令是mysqldump -u root -p exam_system exam_record exam_answer /backup/exam_$(date %F).sql。别等数据丢了才想起后悔药。5.2 把编程题判分从字符串比对升级为用例校验很多上机考试系统的编程题只做字符串比对学生多一个空格就判错体验极差。进阶做法是引入代码沙箱或至少用测试用例跑一遍。轻量方案把学生代码写入临时文件用ProcessBuilder调用编译器执行预设输入比对输出。注意必须限制执行时间和内存否则一个死循环就能拖垮服务器。下面是一个最小校验思路的代码片段。// 简化示例仅说明思路生产环境必须加超时和资源限制 public boolean runTestCase(String code, String input, String expected) throws Exception { // 将学生代码写入临时 .java 文件并编译此处省略文件操作细节 Process process new ProcessBuilder(java, StudentMain) .redirectErrorStream(true) .start(); // 写入测试输入 process.getOutputStream().write(input.getBytes()); process.getOutputStream().close(); // 等待最多 3 秒超时强制销毁 boolean finished process.waitFor(3, TimeUnit.SECONDS); if (!finished) { process.destroyForcibly(); return false; } String output new String(process.getInputStream().readAllBytes()).trim(); return output.equals(expected.trim()); }逻辑说明启动子进程执行学生代码写入输入后等待超时直接杀掉。参数说明3是超时秒数按题目难度调整expected是标准输出。这个方案不是让你直接上生产而是告诉你编程题判分有比字符串比对更靠谱的路值得投入。5.3 用 SpringBoot 自定义配置管理考试参数考试系统里有很多可调参数单场人数上限、自动交卷提前提醒分钟数、是否允许切屏。别把这些硬编码在 Java 里用ConfigurationProperties抽到application.yml改参数不用重新编译。定义一个ExamProperties类前缀exam字段maxStudents、remindMinutes、allowSwitchScreen在需要的地方注入即可。这样机房老师自己就能改配置不用找你重新打包。我现在的习惯是凡是可能随考试场次变化的数字一律进配置文件源码里只留默认值兜底。这套上机考试系统能不能扛住真实期末周往往不取决于功能多全而取决于这些参数和边界有没有提前想到。希望帮到你。本文还有配套的精品资源点击获取