
简介压缩包提供了一套完整的Java在线考试系统源码面向需要快速搭建考试平台或学习SSM整合与前后端分离开发的Java开发者。系统后台基于Spring MVC、MyBatis、FreeMarker构建前端采用Bootstrap、jQuery及Vue.js实现页面交互涵盖题库管理、组卷、在线答题等典型考试环节适合课程设计、毕业设计及企业内训场景。包体共332个文件包含47个Java核心类、14个XML配置、82张页面图片、69个CSS样式与58个JS脚本配合22个HTML页面组成完整可运行的前端资源另附SQL数据库脚本及Eclipse工程配置方便导入后直接调试。整体压缩包仅10.33MB轻量易用目录按后台逻辑与前端资源分层检索便捷。资源已有1111人学习下载。通过阅读源码可掌握Spring MVC与MyBatis的整合方式、Vue.js在FreeMarker模板页面中的引入方法以及考试业务核心表结构设计思路是积累Java Web实战经验的高性价比参考。1. 先说清楚“Java在线考试系统源码.zip”到底是什么玩意你先别急着解压。这个标题在 GitHub 上、在各大源码站里、在闲鱼上出现的频率高得吓人。但凡是 Java 课程设计、Java 毕业设计、Java 实训项目十个里头有七个是“在线考试系统”剩下三个是“学生管理系统”和“图书管理系统”。所以当你下载到一个叫“Java在线考试系统源码.zip”的包时你拿到的很可能不是某个特定开源项目的唯一命名而是一类项目的通用打包名。这类源码包到底能干什么往小了说就是一套支持管理员管理题库、老师出卷阅卷、学生在线答题和查看成绩的 Web 应用。往大了说它涵盖了 Spring Boot 的后端接口、MySQL 的表结构设计、前端页面的表单交互、会话管理和角色权限控制。对于正在学 Java 基础、想刷 java 面试题里“项目经验”的人或者马上要交课程设计的人这个包是一个能改能跑的完整骨架不是一堆没法落地的 demo。但我要给你打个反直觉的预防针这种包十有八九不是解压就能跑的。你会发现缺数据库脚本、JDK 版本对不上、Maven 依赖拉不下来、Tomcat 端口被占、Redis 没装、文件上传路径不存在——这些不是运气差是这类“课程设计源码”的常态。这篇文章我会按“拿到压缩包之后怎么一步步盘它”的顺序把它是什么、怎么跑起来、参数怎么改、坑在哪一次讲完。适合谁看适合你手里刚拿到这种包、准备在本地把它跑起来并且改成自己东西的人。新手能跟着落地熟手能直接跳到第 5 章看避坑。2. 解压之后先盘它技术栈识别、目录结构和模块划分2.1 怎么从文件结构判断它是不是 Spring Boot 项目解压之后不要急着找“启动类”。你先打开根目录看有没有 pom.xml。有 pom.xml说明是 Maven 项目再往下看如果 src/main/java 下面有个带 SpringBootApplication 注解的启动类那就是标准 Spring Boot 工程。这是最常见的情况我在本地跑过的“Java在线考试系统源码.zip”里90% 是这个结构。剩下 10% 是早期的 SSM 项目也就是 Spring Spring MVC MyBatis靠 web.xml 和 lib 目录里的 jar 包运行这种包我建议你直接放弃因为依赖版本太老JDK 8 以上经常跑不起来修复成本比重新写一个还高。除了 pom.xml还有几个关键信号。看有没有 src/main/resources/application.yml 或 application.properties这是 Spring Boot 的配置入口看有没有 src/main/webapp 目录有的话前端大概率是 JSP没有的话可能是 Thymeleaf 模板或前后端分离的静态页面。我拿到这种项目包一般先执行一条命令把整个目录树拉出来看比你一个个点开快得多find . -maxdepth 4 -type f | grep -E (pom.xml|application.*\.(yml|properties)|*.sql|*.jsp)$ | sort这条命令的作用是列出项目里的核心文件。-maxdepth 4控制扫描深度太深了会把 target 目录里编译出来的 class 文件也扫出来干扰判断。grep 的四个模式分别对应 Maven 配置、Spring Boot 配置文件、数据库初始化脚本和 JSP 页面。看到输出里有 .sql 文件说明数据库脚本就在包里如果一条 sql 都没有那你得先去数据库手工建表这个坑后面会专门讲。2.2 在线考试系统的三层角色与六张核心表看技术栈只是第一步更重要的判断是这个系统的业务完整度到底够不够。在线考试系统最常见的角色划分是三种管理员、教师、学生。管理员管用户和系统配置教师管题库和阅卷学生管考试和查成绩。如果源码里只有“管理员”和“学生”两种角色那它的业务边界大概率很窄改造空间也小。对应到数据库层面我用 Navicat 或 DBeaver 打开它自带的 .sql 脚本后会重点核对六张表用户表user 或 sys_user、角色表role、课程表course、试题表question、试卷表paper、考试记录表exam_record。如果这六张表都在这个项目的业务闭环是完整的可以往下走如果缺了试卷表或者试题表那说明这是个半成品。我见过不少“源码包”里只有一张 user 表和一张 question 表页面上的“在线考试”只是个静态路由根本没有逻辑闭环。这种包不值得花时间。表格我放这儿你可以对照自己的源码包勾一下表名常见命名核心字段作用sys_user / t_userid, username, password, role_id统一登录账号区分管理员/教师/学生sys_role / t_roleid, role_name角色定义决定登录后的菜单和接口权限course / t_courseid, course_name课程维度考试按课程归类question / t_questionid, course_id, type, content, answer题库题型一般分单选/多选/判断paper / t_paperid, course_id, title, total_score, duration试卷绑定课程和考试时长exam_record / t_exam_recordid, user_id, paper_id, score, submit_time考试记录记录谁考了哪套卷、得分多少2.3 前后端是否分离要不要预留联调窗口看这个源码包里的在线考试系统是 JSP 为主还是前后端分离决定了你改代码的方式。老一点的课程设计项目几乎全是 JSP页面写在 src/main/webapp/WEB-INF/views 下面服务端渲染Java 代码里直接返回 ModelAndView。这种项目的优点是打开就能看到完整页面不用起前端工程缺点是前后端耦合死你想把页面改成 Vue 或 React等于重写。新一些的源码包会用 Spring Boot 写纯粹的后端接口返回 JSON前端是独立的静态页面或者 Vite 工程。判断方法很简单如果 controller 里的方法大量用了 RestController 或 ResponseBody那就是接口风格如果用的是 Controller 加 return xxx那是模板渲染风格。我从实际改包的经验看如果你要拿这套代码去应付课程设计答辩JSP 风格的项目更好讲因为老师一眼能看到页面和代码的完整链路如果你要拿它去写简历项目前后端分离的风格更好写“技术亮点”比如“采用 RESTful 接口设计前端通过 Axios 调用后端 API”。这个选择题你要先想清楚因为它直接决定你后面要花多少时间改前端。3. 在本地跑通它从 JDK 配置到数据库导入的最小操作流3.1 环境核对JDK 8 还是 JDK 11Maven 版本别用错拿到源码包第一步先核对 JDK 版本。打开 pom.xml看 java.version 标签。我看到的绝大多数这种课程设计项目是 1.8也就是 JDK 8。如果你机器上装的是 JDK 17 甚至更高直接跑大概率报 UnsupportedClassVersionError 或者 Spring 容器启动到一半就挂。这不是代码问题是编译和运行环境不匹配。如果你还没有配置过 JDK去搜“java环境变量配置详细教程”那类文章足够帮你装好 JDK 8 并把 JAVA_HOME、PATH 配好。配完之后在命令行确认版本java -version mvn -version这两条命令分别确认 JDK 和 Maven 是否可用。java -version要看输出里是否有 1.8 字样或者 8.xxx。mvn -version的输出里会有 Java version 一栏这里显示的 Java 版本其实取决于你 PATH 里指向的 JDK。如果输出显示的是 17 而你 pom.xml 里写的是 1.8那就是 PATH 优先级的问题去把 JAVA_HOME 改成 JDK 8 的安装目录就行。Maven 本身版本倒不用太在意3.6 以上都能用。但要注意 Maven 的 settings.xml 里有没有配阿里云镜像。国内网络环境直接拉中央仓库依赖慢到怀疑人生。后面第 5 章我会专门讲这个。3.2 导入数据库用自带 SQL 脚本还是手工建库数据库这块常见有两种情况包里有 .sql 脚本或者没有。有脚本的话直接用 MySQL 命令行导入。我一般先建一个空的数据库再指向它执行脚本CREATE DATABASE IF NOT EXISTS exam_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE exam_system; SOURCE /你的路径/exam.sql;这三行 SQL 的作用依次是建库、切换库、执行脚本。SOURCE后面要写绝对路径而且注意 MySQL 命令行里的路径分隔符用正斜杠Windows 上写C:/Users/xxx/Desktop/exam.sql别写成反斜杠否则会报语法错误。执行完SOURCE之后你要做一个验证动作USE exam_system; SHOW TABLES;如果看到 10 张以上的表说明脚本是完整的。如果只有三五张表或者干脆报错说某个表已存在这里很可能有坑脚本可能是从别人库里导出的里面带了创建表以外的数据或者脚本开头有 DROP TABLE IF EXISTS你把它执行到自己的库里会把已有表删掉。这时候我建议你打开 .sql 文件用记事本或 VS Code 看一眼开头如果有 DROP TABLE说明它可以安全重复执行如果没有那你每执行一次就会叠加报错。学习用的源码我一般还是先看脚本再执行不盲目跑。如果你的包里没有 .sql 文件那就麻烦了。你得根据实体类反推建表语句。这种活很累但也不是不能做打开 src/main/java 下面的 entity 或 pojo 目录每个实体类对应一张表字段名和类型就是表的列。我接过一个这样的包光反推表结构花了一个下午。所以这里也建议你拿到源码包先别急着删自带的 sql 文件那个东西是这套代码的“后悔药”。3.3 配置文件application.yml 里的数据源和 MyBatis 路径数据库导进去之后打开 src/main/resources/application.yml大概率你要改的就是 spring.datasource 这一段。最常见的错误写法是 URL 里的数据库名不对、密码不对或者 driver-class-name 跟实际数据库版本不匹配。server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/exam_system?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.exam.entity这里几个参数要解释一下。serverTimezoneAsia/Shanghai是必加的MySQL 8 的时区设置默认是 UTC不加这个你插入考试时间、答题时间的时候数据会差 8 个小时。useSSLfalse是本地开发建议加的不然 MySQL 8 会拿 SSL 握手消耗性能。mapper-locations指向 MyBatis 的 XML 文件位置如果你的包用的是注解 SQL 而不是 XML Mapper这一段可以不写。driver-class-name 要注意MySQL 5.x 用的是com.mysql.jdbc.DriverMySQL 8.x 用的是com.mysql.cj.jdbc.Driver配错了启动直接报 Cannot load driver class。如果你看到项目里用的是 MyBatis-Plus那 application.yml 里还要多加一段 mybatis-plus 的配置区别主要在 mapper 路径的写法是mapper-locations放在 mybatis-plus 节点下面而不是 mybatis 节点下面。这俩位置写混了运行的时候会报 Invalid bound statement但是项目又能启动特别迷惑人。3.4 启动项目三种方式对比和最小启动命令配置改完接下来就是把项目跑起来。有三种方式IDE 里直接跑启动类、命令行mvn spring-boot:run、打包成 jar 再跑。对于拿源码学习的人来说我推荐第一种断点好打、报错好查。但为了验证打包链路命令行方式也得会。mvn spring-boot:run这条命令会先触发 Maven 编译再执行 Spring Boot 插件启动。如果你在前面加了阿里云镜像第一次跑会把几百 MB 的依赖下载下来耐心等就好。启动成功的标志是日志里出现Tomcat started on port(s): 8080然后你在浏览器打开http://localhost:8080看到登录页这事就成了。如果启动失败不要慌看日志的前三行报错而不是看最后三行。Spring Boot 的报错信息会把根本原因放在最上面下面跟着一大串 Caused by。常见失败我放在第 5 章详细讲这里先带过端口被占用、数据库连不上、Mapper XML 找不到、Redis 没启动这四个占了这类项目 80% 的启动失败原因。4. 三个必调参数与一组核心接口把在线考试的骨架改顺手4.1 端口和上下文路径一台机器跑两套系统的必备调整如果你本机已经有一个项目占着 8080那你得改端口。这个改动很简单server: port: 8081 servlet: context-path: /examport改成 8081 就能错开端口。context-path是上下文路径加了/exam之后登录页地址就变成http://localhost:8081/exam。这里有个很容易被忽略的细节如果你的前端页面或者 JavaScript 里写死了绝对路径比如$.post(/user/login)那么加了 context-path 之后这个请求会变成http://localhost:8081/user/login404。要么你 Logout、Login 之类的请求路径全部带上前缀要么前端统一用相对路径。这个坑我在改一套 JSP 项目的时候踩过页面能打开但登录按钮点了没反应排查了半天发现是 context-path 导致请求路径全部错位了。4.2 数据库密码和连接池参数区分开发环境与生产环境很多这种源码包里面写的密码是 root 或者 123456。你要是只在自己电脑上跑确实不用改。但如果要写到简历里、部署到服务器上这个密码必须改。同时我建议你把连接池参数也加上不然后端接口并发一起来数据库连接不够用会出现诡异的偶发超时。spring: datasource: url: jdbc:mysql://localhost:3306/exam_system?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: ${DB_PASSWORD:123456} hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000这里${DB_PASSWORD:123456}是 Spring Boot 的占位符语法意思是优先读环境变量 DB_PASSWORD没配就用默认值 123456。这个方法在你部署服务器的时候特别有用你不用把真实密码写进代码、提交到 Git只需要在服务器上 export 一个环境变量即可源码包里泄露密码也不会连上生产库。HikariCP 是 Spring Boot 2.x 默认的数据库连接池maximum-pool-size控制最大连接数20 对一个课程设计项目够用了connection-timeout是拿连接的超时时间 30 秒。4.3 文件和富文本上传路径最容易在 Windows 和 Linux 之间翻车的设置在线考试系统里老师上传图片题、Excel 批量导入试题都会用到文件上传。很多源码包写死了本地绝对路径比如D:/upload/这种代码换一台机器直接废。正确做法是配置一个相对路径并且在代码里做兜底创建目录的逻辑。常见做法是先在 application.yml 里定义一个自定义属性exam: upload-path: ./upload-files/然后在代码里通过 Value 注入并在上传服务里判断目录是否存在不存在就创建Value(${exam.upload-path}) private String uploadPath; public String saveFile(MultipartFile file) { File dir new File(uploadPath); if (!dir.exists()) { dir.mkdirs(); } String fileName System.currentTimeMillis() _ file.getOriginalFilename(); file.transferTo(new File(dir, fileName)); return uploadPath fileName; }这段逻辑里最关键的是dir.mkdirs()很多新手只写mkdir()父目录不存在的时候直接返回 false文件保存失败还不报错。用mkdirs()会递归创建父目录。System.currentTimeMillis()拼在文件名前面是为了防止重名覆盖。Windows 和 Linux 在路径分隔符上的差异也经常造成上传后图片打不开我一般建议全部用相对路径加 File 类拼接而不是把D:/、/root/这种写死。这是这个章节里最值得抄的一段代码。4.4 核心接口链从登录鉴权到交卷算分的四组接口跑通项目之后你肯定要把它改成自己的。改之前先看懂核心接口链。在线考试系统最少要有四组接口登录与鉴权、题库管理、考试进行、交卷判分。登录接口一般是 POST /user/login接收用户名密码成功后把 userId 放进 Session 或者返回 Token。如果是 JSP 项目多用 Session如果是前后端分离项目可能用了 JWT。你打开 Controller 层看一眼就知道。题库管理接口是 POST /question/add 和 POST /question/import负责新增试题和 Excel 导入。有些系统里这个接口没有任何校验任何人调一下就能往库里塞题这就是典型的越权漏洞你自己改的时候要注意加上角色校验。考试接口 GET /exam/start 的作用是生成一份试卷。这个接口我专门提醒一下它到底是一次性把试题查出来返回给前端还是只返回试卷 ID、前端逐个请求题目前者有风险用户打开浏览器 F12 能看到所有题目和答案后者更安全但实现复杂。这类源码包大多是前者因为好写。交卷接口 POST /exam/submit 会把用户答题的 JSON 提交上来后端解析后逐题比对答案算分。有些包的算分逻辑是写在前端的那这就很荒唐了用户把请求改一下就能得满分。你拿到源码包之后务必确认这个算分接口在后端不要用前端传来的分数直接入库。5. 避坑与排查这类源码包最常见的七个启动和运行问题5.1 现象Tomcat 启动成功却访问报 404问题出在上下文路径和拦截器这是我接到的“在线考试系统源码.zip”里出现频率最高的问题。启动日志显示 Tomcat started浏览器打开首页却 404。原因分两种一是你加了 context-path 但没带前缀访问二是 Spring Boot 的拦截器把静态资源和登录页都拦掉了。你先看地址栏是不是少了上下文路径再看 WebMvcConfigurer 的 addInterceptors 里 excludePathPatterns 配了哪些路径。我看到过一套源码拦截器把/login、/css/**、/js/**全部拦截放行列表里漏了/api/login导致登录接口 404。解决方法是把静态资源和登录接口加进放行名单这种问题卡你一小时都是少的。5.2 现象Invalid bound statement (not found)MyBatis 的 Mapper XML 没被扫描到项目能启动但一调用任何涉及数据库的接口就报 Invalid bound statement (not found)。这是因为 Mapper 接口有了但 MyBatis 没找到对应的 XML 文件。原因有两个application.yml 里的 mapper-locations 路径不对或者包名不一致。我建议你直接检查编译后的 target/classes 目录看看 mapper 文件夹在不在那里。如果不在大概率是 Maven 默认不会把 src/main/resources 之外的文件打进 classpath。这时候在 pom.xml 加一段资源声明build resources resource directorysrc/main/resources/directory includes include**/*.xml/include include**/*.properties/include /includes /resource /resources /build这段配置的作用是把 resources 目录下所有 XML 和 properties 文件都打进编译产物。很多课程设计源码包的 pom.xml 里漏了这一段导致别人一 clone 就报错你自己补上即可。这也是一个高频面试点问“MyBatis 的 Mapper XML 为什么找不到”时答这个原因加验证步骤比背概念强多了。5.3 现象Maven 依赖下载极慢或直接失败换阿里云镜像加版本锁定这类源码包里 pom.xml 经常写一堆你没见过的依赖版本而且中央仓库在国内下载非常痛苦。解决方法是修改 Maven 的 settings.xml在 mirrors 节点加上阿里云镜像mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirrormirrorOf写central表示只有中央仓库走这个镜像你本地其他私有仓库不受影响。改完 settings.xml 之后在项目根目录执行mvn clean install -DskipTests观察下载速度。如果还是慢检查是不是 IDE 里内置的 Maven 和命令行用的不是同一个 settings.xml。IDEA 里 File - Settings - Build Tools - Maven 可以看到 User settings file 的路径这地方经常被覆盖成默认配置。5.4 现象数据库中文乱码问题源头不是代码而是连接串和建表字符集页面上显示的中文全是问号。新手第一反应是加过滤器但这类课程设计项目乱码的根源几乎都是数据库连接串少了 characterEncoding。前面给的 URL 里characterEncodingutf8是关键参数。还有另一种情况你的表是 utf8mb4但字段是 latin1或者 .sql 脚本在执行时用的客户端字符集不对。我处理这种问题的方式是三步走先看数据库连接串再看表字段的 collation最后执行一条 SQL 验证当前会话字符集SHOW VARIABLES LIKE character_set_%;如果返回结果里 character_set_server 是 latin1说明 MySQL 服务端默认字符集不对需要改 my.cnf 里的character-set-serverutf8mb4并重启 MySQL。这个环节看不到什么显眼报错全是显示层面的问题所以很多人会忽略。搞在线考试系统题目里可能有数学符号、希腊字母utf8mb4 比 utf8 更稳妥建议建库时用我前面给的标准写法。5.5 现象端口被占用Tomcat 启动失败但日志不明显Tomcat 启动失败报 Port 8080 was already in use。这种情况在你有多个 Java 项目在本地测试时非常常见。解决方式有两种改端口或者把占用端口的进程杀掉。Windows 上先查占用进程再定向清理netstat -ano | findstr 8080 taskkill /PID 12345 /F第一条命令会输出占用 8080 的进程 PID第二条把它强制结束。注意 taskkill 后面的 /F 是强制结束如果你的机器上跑着别的 Java 服务杀错了要自己负责。我建议用改端口的方式更安全。也提醒你如果你同时打开两个 IDEA 项目两个都在启动 Spring Boot它们抢 8080 也是这个现象别误以为是代码问题。这是笨办法也是最快的排查路径不要一开始就怀疑源码。5.6 现象启动时连接 Redis 超时但你的项目根本没写 Redis 代码这是最容易摔的坑。有些源码包引入了 spring-boot-starter-data-redis 依赖但你没装 Redis启动的时候 Spring Boot 会自动尝试连接 Redis 来缓存会话或验证码连接超时导致启动失败。解决方法是定位引用 Redis 的地方打开启动类看有没有 EnableCaching 或注入 RedisTemplate 的配置类。如果有最快的方法是装一个 Redis 服务端Windows 可以用 Memurai 或 WSL 里跑 Linux 的 Redis。如果你只想快速跑通项目不想装就把 Redis 相关配置类注释掉同时把依赖从 pom.xml 里删掉重新 clean。注意有些源码包用 Redis 存验证码你注释掉的后果是验证码功能失效要能接受这个代价再动手。5.7 现象跨域报错前端 8081 调用后端 8080 被拦截前后端分离的在线考试系统里前端起在 8081后端在 8080前端发请求时报 CORS 错误。这类源码包十有八九没配跨域过滤器。解决方式是在后端加一个配置类Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }这个配置的作用是允许所有来源跨域调用接口。allowCredentials(true)表示允许携带 Cookie这对基于 Session 的登录状态很重要。maxAge(3600)是预检请求的有效期单位秒设大一点能减少 OPTIONS 请求次数。这个配置类加到 Spring Boot 项目里会自动生效适合课程设计阶段的联调。但放到生产环境allowedOriginPatterns 不建议写*换成你自己的前端域名更好。6. 拿来改造成的经验加防作弊、随机抽题与压测验证源码包跑通只是起点。你要把它写进简历或者交课程设计必须做出“不是原版”的痕迹。我的习惯是挑三个点来改防作弊、随机抽题、交卷判分性能。这三个点也恰好是 java 面试题和“java开发工程师面试题”里常被追问的项目细节。第一个点是防作弊。大多数源码包里学生进入考试页面后可以切走浏览器查资料系统完全不管。你可以在后端加一个简单的交卷时间校验前端在考试开始时把开始时间发给后端记录在 Redis 或数据库里每次请求下一题时后端比对当前时间和考试总时长超过时长就强制交卷。这个逻辑不复杂但能体现出你是真的考虑过在线考试的业务风险。如果你不想引 Redis用数据库字段加内存 ConcurrentHashMap 也行但要注意多实例部署时内存方案失效。第二个点是随机抽题。很多包的试卷是固定题目你只要改 service 层的查询逻辑即可。核心是把 “查全部题目” 改成 “按课程和题型分组、每组随机取 N 条”。用 MyBatis 的注解或 XML 都可以实现public ListQuestion generatePaper(Integer courseId, Integer singleCount, Integer judgeCount) { ListQuestion singleList questionMapper.selectRandomByType(courseId, 1, singleCount); ListQuestion judgeList questionMapper.selectRandomByType(courseId, 2, judgeCount); singleList.addAll(judgeList); return singleList; }这里的前提是selectRandomByType对应的 SQL 用了ORDER BY RAND() LIMIT #{count}。RAND()在题目量小的时候没问题但题库有几万条时性能很差你可以改成WHERE id (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM question)))这种主键随机偏移写法或者把题目提前缓存起来再内存随机。我说到这种程度你在答辩时已经有足够细节可讲了。第三个点是验证。不要只靠浏览器手点两下就说项目完成。我一般用 JMeter 或者直接写一个简单的 Python 脚本压一下交卷接口看并发 50 个学生同时交卷时数据库连接池会不会被打满、接口响应时间会不会超过 2 秒。这个验证动作在课程设计里属于加分项老师看到你做了压测数据会比只看界面完成度要认可得多。最后说一下我自己的教训。以前我拿到这种源码包第一件事是删掉里面的 README、改掉版权信息、把登录页的 Logo 换成自己学校然后直接提交。后来发现答辩时老师问了几个表结构设计的问题我支支吾吾答不上来因为从来没打开过数据库脚本。从那以后我改任何源码项目都养成了一个习惯先看 SQL 脚本里的字段注释再画一遍 ER 图再动手改代码。画完 ER 图你会知道为什么 exam_record 表要同时存 paper_id 和 question_id为什么成绩字段要允许带小数为什么题库表要有一个 type 字段区分单选多选。这些细节才是你真正学到东西的地方。在线考试系统看着简单但“考试”两个字背后有考场纪律、题目随机、倒计时、判分规则、成绩统计这些真实业务逻辑能把它讲清楚的人写进简历里比堆一堆框架名有用得多。希望这篇笔记能帮你把手里那个 zip 变成真正跑得起来、讲得出口的项目别再把时间浪费在“解压即吹”的空壳上了。本文还有配套的精品资源点击获取