简介:这是一套面向高校计算机相关专业毕业设计场景的在线考试系统完整项目包,采用Java语言与Spring Boot框架开发,基于B/S架构并以MySQL作为数据存储,适合正在准备毕设的学生或需要教学案例的开发者参考。系统按管理员、教师、学生三类角色划分权限:管理员负责学生与教师管理、课程分类与课程信息维护、在线考试与试题习题管理等;教师可管理课程信息、试题、在线考试与考试安排;学生端则提供课程信息浏览、在线考试、通知公告与个人中心等功能。压缩包共791个文件,约42.13MB,包含107个Java源码、46个Vue组件、164个JavaScript脚本、53个CSS样式及36个HTML页面,另有SQL脚本、配置文件与演示视频等,覆盖前后端完整工程结构。资源同时附带开发说明文档与演示视频,便于快速理解项目架构、数据库设计与功能实现思路。目前已有1106人学习下载,可作为毕设选题、课程设计或Spring Boot实战练习的参考方案。
1. 从一份能跑起来的 SpringBoot 在线考试系统说起
毕业设计选题里,教育/考试方向一直是高频选项,但真正能跑通、能讲清楚、能扛住答辩追问的工程并不多。这份基于 SpringBoot 框架的在线考试系统,交付物是源码加开发说明再加演示视频,定位很明确:给需要交毕业设计、又不想从零搭架子的人一个可复现的起点。它解决的不是"考试系统是什么"这种概念问题,而是"我拿到手能不能编译、能不能登录、能不能出一份卷子、答辩时老师问到我能不能答上来"这一串具体问题。适合计算机相关专业做毕设的学生,也适合想拿一个完整 SpringBoot 项目练手、熟悉前后端分离和权限控制的初级开发者。整套东西围绕考试这个核心业务展开,题库、组卷、答题、判分、成绩管理这些环节都在里面,不是那种只有登录页和空壳首页的"演示级"工程。
2. 拆开工程看结构:SpringBoot 分层与考试业务怎么对应
2.1 拿到源码先看目录,别急着点运行
很多人拿到压缩包第一反应是双击启动类,结果报一堆错,然后开始怀疑人生。血泪经验是先把目录结构过一遍,搞清楚这是个什么形态的工程。常见的 SpringBoot 毕设项目结构大致是这样:
exam-system/ ├── src/main/java/com/xxx/exam/ │ ├── ExamApplication.java // 启动类 │ ├── controller/ // 接口层 │ ├── service/ // 业务逻辑 │ ├── mapper/ 或 dao/ // 数据访问 │ ├── entity/ 或 model/ // 实体类 │ ├── config/ // 配置类 │ └── common/ // 工具、统一返回 ├── src/main/resources/ │ ├── application.yml // 主配置 │ ├── mapper/ // MyBatis XML(如果用了) │ └── static/ 或 templates/ // 前端资源 ├── pom.xml // Maven 依赖 └── sql/ // 建库脚本看到controller / service / mapper / entity这套分层,基本能判断是标准的 SSM 思路套在 SpringBoot 上。考试业务通常对应几个核心实体:用户(学生/教师/管理员三种角色)、题目、试卷、考试记录、答题详情。组卷逻辑一般放在 service 层,判分逻辑要么在提交时同步算,要么异步跑。先把这个映射关系在脑子里建起来,后面看代码就不会迷路。
2.2 环境与依赖:版本对不上是最常见的翻车点
SpringBoot 项目跑不起来,八成是环境问题。先确认三件事:JDK 版本、Maven 版本、数据库版本。这份工程如果用的是 SpringBoot 2.x,那 JDK 8 或 11 都能带;如果是 3.x,JDK 必须 17 起步。热搜里"springboot版本太高"这个词不是白来的,很多人本地装了 JDK 17,结果项目是 2.3 的老工程,编译直接炸。
pom.xml里重点看这几块:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.0</version> <!-- 记住这个版本号 --> </parent> <properties> <java.version>1.8</java.version> <!-- 和本地 JDK 对齐 --> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> <!-- 和本地 MySQL 对齐 --> </dependency> <!-- MyBatis 或 MyBatis-Plus --> </dependencies>逻辑说明:parent里的版本决定了整个 SpringBoot 的依赖树,改它等于改全局。java.version必须和本地JAVA_HOME指向的 JDK 一致,否则编译期就报invalid target release。MySQL 驱动版本要和数据库服务端匹配,8.0 的驱动连 5.7 的库一般没问题,反过来容易出时区或认证插件的坑。
参数怎么改:如果本地是 JDK 17,把java.version改成 17,同时确认 SpringBoot 版本在 2.5 以上(2.7 对 17 支持较好)。如果数据库是 MySQL 8,驱动用8.0.x,连接串里加serverTimezone=Asia/Shanghai。
2.3 数据库初始化:脚本顺序和字符集别搞反
sql/目录下的脚本一般分建库和插数据两部分。常见做法是先执行建表脚本,再执行初始化数据脚本。执行前先建库:
CREATE DATABASE exam_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;字符集用utf8mb4而不是utf8,因为题目里可能有特殊符号或 emoji,utf8存不下会报错。建完库再use exam_system;然后跑建表脚本。
application.yml里的数据源配置要对应上:
spring: datasource: url: jdbc:mysql://localhost:3306/exam_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver逻辑说明:useUnicode和characterEncoding保证中文不乱码,serverTimezone不加的话 MySQL 8 驱动会报时区错误。driver-class-name用com.mysql.cj.jdbc.Driver是 8.0 驱动的写法,老版本是com.mysql.jdbc.Driver,写错会提示驱动加载失败。
2.4 启动与验证:看到什么才算真的跑起来了
配置改完,在项目根目录执行:
mvn clean package -DskipTests java -jar target/exam-system-0.0.1-SNAPSHOT.jar或者直接在 IDE 里跑启动类。控制台出现Started ExamApplication in x.xxx seconds才算启动成功。然后浏览器访问http://localhost:8080(端口看application.yml里的server.port),能看到登录页就说明前后端通了。
验证顺序建议这样走:先用管理员账号登录,看能不能进后台;再建一道题,看能不能存进库;然后组一张卷子,用学生账号考一次,看判分对不对。这一圈走下来,整个业务链路就验证完了。如果卡在某一步,看控制台报错和浏览器 F12 的网络请求,基本能定位到是后端接口问题还是前端调用问题。
3. 核心业务怎么落地:组卷、答题、判分的实现思路
3.1 组卷逻辑:随机抽题和手动选题的差别
考试系统的组卷一般有两种模式:手动选题和随机抽题。手动选题就是教师从题库里勾题,逻辑简单,一张试卷对应一个题目 ID 列表。随机抽题要复杂些,通常按题型和知识点分布来抽,比如"单选题抽 10 道、多选题抽 5 道、判断题抽 5 道"。
随机抽题的 SQL 常见写法:
SELECT * FROM question WHERE type = #{type} AND subject_id = #{subjectId} ORDER BY RAND() LIMIT #{count};逻辑说明:ORDER BY RAND()是 MySQL 的随机排序,配合LIMIT实现随机抽取。参数type是题型,subjectId是科目或知识点,count是抽取数量。
注意:ORDER BY RAND()在数据量大时性能很差,因为要对全表做随机排序。题库几千条以内无所谓,上万条就要换思路,比如先查出 ID 范围再随机取,或者用WHERE id >= (SELECT FLOOR(RAND() * MAX(id)) FROM question)这种方式。毕设场景题库一般不大,直接用RAND()没问题,但答辩时如果老师问到性能,能说出这个边界就是加分项。
组卷完成后,试卷和题目的关联关系存到中间表,比如paper_question,字段包括paper_id、question_id、score、sort_order。这样一张卷子每道题的分值和顺序都能单独控制。
3.2 答题与提交:前端状态和后端校验要配合
学生答题时,前端一般用一个数组或对象维护当前答案,提交时整体发给后端。后端接收的数据结构大致是:
{ "paperId": 1, "answers": [ {"questionId": 101, "answer": "A"}, {"questionId": 102, "answer": "B,D"} ] }后端处理时,先根据paperId查出这张卷子的所有题目和标准答案,再逐题比对。这里有个容易忽略的点:多选题的答案顺序。学生提交的"B,D"和标准答案"D,B"如果不做排序处理,直接字符串比较就会判错。常见做法是提交前把答案按字母排序,或者后端比对时先拆分再排序。
// 多选题判分:先排序再比较 String[] studentArr = studentAnswer.split(","); String[] correctArr = correctAnswer.split(","); Arrays.sort(studentArr); Arrays.sort(correctArr); boolean isCorrect = Arrays.equals(studentArr, correctArr);逻辑说明:split(",")把答案拆成数组,Arrays.sort排序后Arrays.equals比较,这样顺序不同也能判对。参数上要注意分隔符统一,前端传逗号,后端就按逗号拆,别一会儿逗号一会儿分号。
3.3 判分与成绩:同步算还是异步算
判分逻辑放在提交接口里同步执行是最简单的,学生点提交,后端算完直接返回分数。但如果有主观题需要教师批改,就不能同步出总分,得把客观题分数先算出来,主观题标记为待批改,等教师批完再汇总。
成绩表一般设计成exam_record,字段包括user_id、paper_id、score、submit_time、status(已批改/待批改)。客观题判分后更新score,主观题批改后再累加。这里要注意并发问题:如果同一个学生重复提交,要么做幂等控制(同一张卷子只能提交一次),要么允许重考但每次生成新的记录。毕设里常见做法是限制一次提交,提交后按钮置灰,后端也做校验。
3.4 权限控制:三种角色怎么隔离
考试系统至少三种角色:管理员、教师、学生。权限控制常见两种做法:一种是 Spring Security 或 Shiro 做认证授权,另一种是简单的拦截器加角色判断。毕设项目用拦截器的居多,因为配置简单、代码直观。
拦截器思路:
public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token = request.getHeader("token"); if (token == null || !tokenService.validate(token)) { response.setStatus(401); return false; } return true; } }逻辑说明:preHandle在请求进入 Controller 前执行,校验 token 是否有效。无效就返回 401,前端收到后跳登录页。参数上token放在请求头里比放 URL 里安全,避免被日志记录。
角色隔离则在接口层面做,比如/admin/**只允许管理员访问,/teacher/**只允许教师访问。可以在拦截器里根据 token 解析出的角色判断请求路径,也可以在每个 Controller 方法上加自定义注解。毕设场景用路径前缀加拦截器判断就够了,不用上太重的框架。
4. 避坑与排查:那些让项目跑不起来的常见问题
4.1 启动报数据库连接失败
现象:控制台报Communications link failure或Access denied for user。
原因:数据库没启动、连接串地址端口不对、用户名密码错、或者 MySQL 8 的认证插件问题。
解决:先确认 MySQL 服务在跑,telnet localhost 3306能通。再看application.yml里的用户名密码和实际是否一致。如果是Access denied且密码确认没错,可能是 MySQL 8 默认用caching_sha2_password插件,老驱动不认,要么升级驱动,要么改用户认证方式:ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';。
4.2 页面能打开但接口全部 404
现象:登录页正常显示,但点登录没反应,F12 看请求返回 404。
原因:前端请求的接口路径和后端实际路径对不上,或者后端有统一前缀(如server.servlet.context-path)而前端没加。
解决:看application.yml里有没有配context-path,有的话前端请求要带上这个前缀。再看 Controller 上的@RequestMapping路径和前端axios的baseURL是否一致。常见做法是前端配baseURL: '/api',后端 Controller 加@RequestMapping("/api"),两边对齐。
4.3 中文乱码
现象:题目或用户名显示成问号或方块。
原因:数据库字符集、连接串字符集、或者前端页面编码不一致。
解决:数据库建库时用utf8mb4,连接串加characterEncoding=utf8,前端 HTML 加<meta charset="UTF-8">。三处都对齐基本不会乱码。如果已经建了库且字符集不对,改库字符集:ALTER DATABASE exam_system CHARACTER SET utf8mb4;,但已有数据可能还是乱的,需要重新导入。
4.4 打包后运行报找不到主类
现象:java -jar执行时报no main manifest attribute或找不到启动类。
原因:pom.xml里没配 SpringBoot 的打包插件,或者配了但没执行repackage。
解决:确认pom.xml里有这个插件:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>然后重新mvn clean package,生成的 jar 才是可执行的 fat jar。如果用的是 IDE 自带打包,注意选对方式。
4.5 前端资源打包后访问不到
现象:本地 IDE 跑正常,打成 jar 后页面样式丢失或 404。
原因:前端资源没被打进 jar,或者路径引用方式不对。
解决:如果前端是独立工程,打包后要把dist目录内容拷到 SpringBoot 的src/main/resources/static/下再打包。如果前端资源直接在static里,确认pom.xml的resources配置没有排除这些文件。路径引用用相对路径,别用绝对路径。
5. 二次开发与答辩加分:把这份源码用出差异化
拿到一份能跑的毕设源码只是起点,真正拉开差距的是你能不能在它基础上做出自己的东西。答辩时老师最怕听到"这就是网上下的",所以你得有改动、有思考、能说出为什么这么改。
一个成本低但效果好的方向是加日志和监控。SpringBoot 集成 Actuator 只要加个依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>然后在application.yml里放开端点:
management: endpoints: web: exposure: include: health,info,metrics这样访问/actuator/health就能看到应用状态,答辩时演示一下,比干说"系统运行稳定"有说服力。参数上include控制暴露哪些端点,毕设场景放开health和info就够了,别全放开,有安全风险。
另一个方向是优化判分逻辑。原始代码如果是逐题查库比对,可以改成提交时一次性查出所有题目,在内存里比对,减少数据库交互。改动不大,但能讲出"减少 IO 次数、提升响应速度"这个点。还可以加一个错题本功能,把学生答错的题记录下来,这个功能实现简单但演示效果好,老师一看就知道是你自己加的。
验证改动是否生效,我一般会走一遍完整流程:启动应用、登录、组卷、答题、提交、看成绩、看错题本。每一步都确认数据正确,尤其是判分结果和数据库里的记录要对得上。从那以后我每次改完代码,都强制走一遍这个全链路,不跳过任何一步。希望这份源码能帮你把毕设稳稳落地,也希望你在它基础上做出自己的东西。
本文还有配套的精品资源,点击获取