ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SpringBoot+Vue在线考试与学习交流平台毕设完整实战

SpringBoot+Vue在线考试与学习交流平台毕设完整实战 每年到这个节点都会有大批人为了毕设焦头烂额。如果你正在搜索SpringBootVue能做什么项目在线考试系统大概率是结果里最常见的那个。我当初也躲不开这个经典选题但真正做完才发现这套语言在线考试与学习交流网页平台远没有表面上看着那么套路——它既要搞定考试流程里的随机组卷、自动判分、防切屏又得兼顾学习社区里的发帖、评论、视频播放前后端加起来二十多个接口数据库初始化脚本一跑就是十几张表。这篇文章就当是给自己的项目复盘也顺便给正在做同类毕设的同学一份可以直接参考的完整经验从选题逻辑、技术选型、数据库设计到前后端实现、安全加固、启动部署全部过一遍踩过的坑也都标出来照着走能少折腾很多天。1. 毕业设计选题复盘为什么在线考试学习交流是个好方向毕设选题这件事本质上是在三个维度里找平衡能不能写出论文、系统能不能达到工作量要求、答辩时有没有东西可讲。市面上很多图书管理宿舍管理之类的系统做完发现只有一个 CRUD论文写到第三章就开始硬凑字数答辩时评委一问你这个系统的难点是什么就直接卡壳。在线考试系统则完全不同题库、组卷、答题、判分、成绩管理天然是一整条业务链路随便拆一块出来都有足够的建模深度。学习交流模块的价值在于它让这个项目从考试工具升级成了学习平台。单纯做考试系统功能再完整也只是孤立的工具属性加上课程视频、学习笔记、讨论帖、问答互动之后系统就有了用户黏性场景上也能往在线教育平台方向靠。对于语言类课程来说尤其合理——用户学完一节课程视频去题库做对应的测评再回到社区里讨论错题和背词心得整个闭环是完整的。这不仅仅是功能堆叠它让论文可以围绕基于前后端分离的在线学习平台设计与实现去展开需求分析、功能设计、系统测试每个环节都有实际内容支撑。另一个现实优势是工程量可控。SpringBootVue 这套组合是 Java Web 领域最成熟的搭配开发效率高踩坑资料多一个人两三个月完全可以从零做完。不管是管理员端的题库管理、试卷管理、用户管理还是学生端的在线考试、成绩查询、社区交流所有的功能点都建立在标准的前后端分离架构上代码量不会大到失控也不会少到没东西写。1.1 考试模块的含金量在于随机组卷与自动判分考试系统表面上是几套增删改查但真正让它有技术含量的是考试过程中的业务规则。随机组卷就是一个典型学生点击开始考试时系统需要根据试卷模板的配置从题库里按照题型和难度随机抽取题目组成一份同卷不同题的试卷。这里涉及概率抽取、题目数量校验、难度比例控制逻辑写清楚之后论文里的系统详细设计部分会非常充实。自动判分也是同样的道理。客观题单选、多选、判断可以直接比对标准答案但多选题还有少选、错选是否给分的规则判断题要考虑字符串归一化。主观题则需要支持教师人工评分并且成绩要能合并计算。这些规则如果只能靠文档描述评委是不太认的最好直接在代码里有清晰的策略实现比如用策略模式处理不同题型的判分规则。1.2 学习交流模块让系统的平台感成立有了考试功能为什么不直接结束因为评委大概率会问你的系统和其他考试系统有什么区别如果回答不上来项目就少了差异化亮点。我的做法是加入学习交流模块用户可以浏览课程视频、查看学习资料还可以在社区发帖提问、回帖讨论、点赞收藏。这个模块还有一个隐性好处——它让数据库设计必须涵盖帖子表、评论表、点赞表、收藏表关联查询的场景立刻变多分页、模糊搜索、多表联查这些 Java Web 面试常问的知识点也都有地方落地。到了答辩环节你说说这个社区首页的分页是怎么做的点赞是怎么防止重复的搜索帖子时的 SQL 是怎么优化的——每一个问题都是你亲手实现过的答起来自然有底气。2. 技术选型与版本取舍SpringBoot 2.7 Vue 2.7 的实战理由技术选型不能只看新不新要看你有没有能力在一个可控的周期内把项目做出来并且稳定跑起来。这个项目我最终选的是SpringBoot 2.7 MyBatis-Plus MySQL 8.0前端是Vue 2.7 Element UI Axios鉴权用JWT。这个组合看起来很保守但每一项选择都有具体原因。2.1 后端为什么锁 SpringBoot 2.7 而不是 3.x这两年搜 SpringBoot 相关的帖子经常看到springboot版本太高导致启动失败springboot版本太高项目跑不起来这类问题。原因在于 SpringBoot 3.x 强制要求 JDK 17而很多学校机房、评委电脑、甚至是教程里的老项目都还是 JDK 8。如果你选了 SpringBoot 3.x写完代码本地能跑到了演示环境装不上 JDK 17或者答辩时老师直接打开你的项目说我这边环境跑不了那场面会非常难受。SpringBoot 2.7.x 是 2.x 系列的最后一个版本也是 JDK 8 下能享受到的最完整特性集合。它兼容性最好网上百分之九十的教程和问题帖都基于 2.x遇到报错随手就能搜到解法。而且 MyBatis-Plus、PageHelper、EasyExcel 这类主流组件的 starter 也都对 2.x 做了完整适配不用去处理版本兼容的连环坑。核心依赖大致长这样parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency /dependencies2.2 前端选型Vue 2.7 加 Element UI 的理由前端框架的选择上Vue 3 确实是当前的主流趋势但如果你的毕设时间紧、前期没有 Vue 3 的使用基础Vue 2.7 加 Element UI 是更稳的选择。Element UI 的组件文档齐全表格、表单、弹窗、分页、树形控件直接拿来用开发速度极快。Vue 2.7 是官方在 2.x 里对齐了不少 Composition API 语法但项目里我还是以 Options API 为主原因只有一个方便。传统写法的教程多脑子不需要切换答辩时也容易讲清楚。当然如果你本身对 Vue 3 的 Composition API 和script setup已经很熟直接用 Vue 3 加 Element Plus 也完全可以甚至答辩时还能多一个亮点。但别忘了评估 Node 环境和脚手架版本的兼容性很多时候你花两小时建项目模板一小时在装依赖最后一小时在解决依赖版本冲突这就得不偿失了。我这里为了少折腾选的就是最经典的Vue CLI 脚手架 Vue 2.7 Element UI。2.3 标准目录结构是一开始就要定好的事java web 项目 标准目录结构也是高频搜索词说明很多人真正动手前是懵的。后端目录我建议一开始就按这个结构建好后面写代码只是往里面填文件exam-backend/ ├── src/main/java/com/example/exam/ │ ├── common/ # 通用返回结果、状态码、常量 │ ├── config/ # 跨域配置、拦截器注册、MyBatis-Plus配置 │ ├── controller/ # 接口层 │ ├── entity/ # 数据库实体 │ ├── mapper/ # MyBatis-Plus Mapper接口 │ ├── service/ # 业务逻辑层 │ ├── utils/ # JWT工具、日期工具等 │ └── ExamApplication.java └── src/main/resources/ ├── application.yml └── mapper/ # XML文件复杂SQL时使用这一套结构不是随便定的它是分层架构在 Java Web 项目里的落地方式。Controller 只负责接收参数和返回结果Service 处理业务规则Mapper 负责数据访问各层职责单一出了问题知道去哪排查。这个结构本身在论文里就可以作为系统的分层架构设计来写。3. SQL 脚本与数据库设计八张核心表撑起整个平台拿到项目源码的人第一件事肯定是先跑 SQL 脚本初始化数据库。但看脚本之前我更建议先理解表结构为什么要这么设计。这套平台的所有数据最后落在 MySQL 里核心是八张表用户表、课程表、题库表、试卷表、答题记录表、帖子表、评论表、点赞表外加几张关联表。3.1 用户与角色一张表加字段还是 RBAC 三张表很多人纠结用户权限要不要用 Shiro 或者 Spring Security 的 RBAC 模型。我的建议是毕设项目用一张 user 表加一个 role 字段就够了管理员 admin、教师 teacher、学生 student理由很简单——系统里只有三种固定角色权限控制就三种粒度用三张表的 RBAC 反而是在给自己造复杂度。答辩时如果老师问到你的权限是怎么设计的你只需要答基于角色字段做拦截器级别的访问控制管理员接口、教师接口、学生接口各自用注解或路径规则隔离。当然角色权限判断一定要放在后端做不能前端隐藏按钮就算完事。接口层面要有一个登录拦截器校验 JWT 是否有效、用户角色是否有权访问这样用接口工具直接调后台地址也进不来。CREATE TABLE user ( id bigint NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 登录名, password varchar(100) NOT NULL COMMENT BCrypt加密后的密码, nickname varchar(50) DEFAULT NULL, role tinyint NOT NULL DEFAULT 3 COMMENT 1管理员 2教师 3学生, avatar varchar(255) DEFAULT NULL, status tinyint NOT NULL DEFAULT 1, create_time datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 COMMENT用户表;密码字段一定要是加密后的值前端传原始密码后端用 BCrypt 加密后存库。这样即使数据库泄露拿到手的也是密文。很多毕设项目直接把密码明文存进去这属于答辩时会被当场扣分的硬伤。3.2 考试域从题库到答题记录的流转考试相关的表是整个库的核心我设计了四张question题库、exam_paper试卷、paper_question试卷与题目关联表、exam_record答题记录。题库表要存题型和难度还要存选项和答案。语言类题目可能出现阅读题这类带大段文本的题型所以题干字段用 text 类型选项和答案用 JSON 字符串存储这样单选的 A/B/C/D 、多选的一组选项都能在一个字段里表达解析时用 JSON 工具转一下就行不用为了选项单独建一堆列。试卷表存的是试卷的基本信息标题、总分、时长、组卷规则真正跟题库连接的是 paper_question 表它记录这份试卷需要单选题多少道、多选题多少道、每题多少分。这样设计的好处是组卷逻辑非常清晰——根据 paper_question 里的配置从 question 表按 type 和 difficulty 随机取对应数量的题目。答题记录表 record 记录的是每个学生每次考试的情况关联考试 ID、用户 ID、试卷快照、答案 JSON、客观题得分、状态未交卷/已交卷/已判分。这里特别注意交卷后要保存试卷快照因为题库里的题目随时可能被老师修改历史成绩必须能还原到当时的题目内容。3.3 社区域帖子、评论、点赞的防重复设计社区部分我建了 post帖子表、comment评论表、like_record点赞表。帖子表包含标题、内容、发布人、浏览数、回复数评论表通过 parent_id 字段支持二级回复点赞表用 user_id post_id 的唯一索引保证一个人只能点赞一次这就是最简单的防重复设计。CREATE TABLE like_record ( id bigint NOT NULL AUTO_INCREMENT, user_id bigint NOT NULL, post_id bigint NOT NULL, create_time datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_user_post (user_id,post_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT点赞记录表;这个唯一索引就是防重关键。前端即使连续点了十次数据库层面也会把第二条插入直接挡住比前端加 flag 或者后端用 set 去重都可靠得多。3.4 SQL 脚本里的初始化数据和字符集SQL 脚本里最容易被忽略的是字符集。所有字符串类型的表、字段都要统一用 utf8mb4不能用 utf8因为 utf8 在 MySQL 里存不了 emoji而社区模块的用户昵称、帖子内容完全可能出现 emoji。如果你在导入脚本后插入中文时看到乱码或者incorrect string value的报错九成是这个原因。初始化数据我放了一个管理员账号、一个教师账号、两个学生账号、一整套演示用的课程、题目和帖子数据。这些数据不是随便填的它们有两个作用一是让项目跑起来之后立刻有内容可看演示效果好二是给自测接口提供数据基础没有题目数据考试流程根本走不通。4. Vue 前端从环境配置到核心页面前端这块是很多人的第一道坎卡住的大多不是写代码而是环境。搜一下vue安装及环境配置出来的问题帖子能翻好几页。我把项目的实际配置过程和遇到过的坑写清楚。4.1 环境配置Node 版本、依赖安装、vue devtools项目用的是 Vue CLI 4.x要求 Node 版本在 10 以上但不要太高。有一段时间我用 Node 18 去跑一个老项目的依赖直接就报 OpenSSL 的 hash 错误后来才知道是 Node 17 的 OpenSSL 3 跟 webpack 4 不兼容需要在 package.json 里加一句serve: vue-cli-service serve --openssl-legacy-provider才绕过去。所以如果你用的是 Vite 创建的新项目Node 版本新一点没关系如果用 Vue CLINode 16 是比较稳妥的版本。依赖装好之后强烈建议装 Vue DevTools 浏览器插件。表单调试、Vuex 状态查看、组件层级检查全靠它了。尤其排查页面数据没渲染这类问题的时候打开 DevTools 看组件里 data 和计算属性一眼就能定位到是接口没返回还是渲染逻辑写错。4.2 路由参数与登录守卫的组合用法项目里典型的路由参数场景是从课程列表页跳转到课程详情页携带课程 ID以及点击开始考试携带试卷 ID 跳转到考试页。用 Vue Router 的 query 或者 params 都行但刷新页面时 params 参数可能会丢失所以我统一用 query 传参this.$router.push({ path: /exam/start, query: { paperId: row.id } }) // 考试页面里读取 const paperId this.$route.query.paperId路由守卫这块也是必做的。全局前置守卫里判断有没有 token没有就跳登录页有 token 但访问的是管理员页面再根据用户角色判断权限没权限就提示无访问权限并回到首页。这一套做完前端层面的权限控制就成型了。4.3 考试页面的倒计时与防切屏实现在线考试最怕什么学生开两个页面互相抄。虽然毕设系统不需要真的做到人脸识别级别的防作弊但基本的防切屏是应该有的。我做了三重机制一是考试计时倒计时时间到了自动交卷二是监听 visibilitychange 事件切出页面超过三次就提醒超过五次强制交卷三是在答题过程中周期性向后端发送心跳更新剩余时间。倒计时的实现尤其要注意不能只在前端 setTimeout 里减还必须结合后端返回的交卷截止时间来计算剩余秒数。否则学生把前端时钟改一下或者页面卡住倒计时就乱了。正确做法是后端返回endTime前端每个秒级 tick 都用endTime - Date.now()重新计算剩余时间保证时间基准在后端。4.4 学习视频播放与 m3u8 的支持学习交流平台里课程视频是很自然的需求这里有同学会卡在格式问题上。我们平时手里的 mp4 是可以直接用 HTML5 video 播放的但有些课程视频为了做切片分发采用的是 HLS 协议的 m3u8 索引文件这种情况下浏览器原生 video 是播不了的需要引入 hls.js 这个库。import Hls from hls.js if (Hls.isSupported()) { const hls new Hls() hls.loadSource(videoUrl) // videoUrl 指向 xxx.m3u8 hls.attachMedia(this.$refs.video) }装依赖阶段记得把 hls.js 一并装好别等到页面白屏才反应过来。如果测试时发现 hls.js 报跨域错误通常是视频文件存储的域名跟前端域名不一致需要后端在响应头里加上跨域允许配置。4.5 Axios 请求封装与 401 统一跳转项目里所有接口请求统一走封装好的 Axios 实例而不是每个页面单独import axios。封装的目的有三个统一加 token、统一处理错误、统一处理接口状态码。最核心的一段逻辑是响应拦截器里对 401 的处理——token 过期时清掉本地登录信息跳转到登录页并弹出登录已过期请重新登录的提示。service.interceptors.request.use(config { if (token) { config.headers[Authorization] token } return config }) service.interceptors.response.use( response { const res response.data if (res.code 401) { localStorage.removeItem(token) router.push(/login) } return res }, error { Message.error(网络异常请稍后重试) return Promise.reject(error) } )统一错误处理的好处是页面里写接口时不再需要反复 try-catch网络错误、后端业务错误都能在拦截器里兜住页面代码干净很多。5. 后端关键模块登录鉴权、随机组卷、自动判分后端代码量最大的几个模块写的时候要带着接口文档可维护的意识来做。我这边给每个接口都定义了统一的返回格式和状态码这也是项目里附带的接口文档能直接用的前提。5.1 JWT 登录鉴权与拦截器登录接口做的事很简单接收用户名和密码先判用户是否存在、状态是否正常然后用 BCrypt 的 matches 方法验证密码通过后生成 JWT 返回。JWT 里放 userId、username、role 这三个字段过期时间设置为 24 小时。后端拦截器是所有需要登录的接口的守门员。继承 HandlerInterceptor在 preHandle 里取出请求头里的 token解析成功就放行解析失败或者过期就返回 401。配置的时候注意把登录接口、注册接口这些放行其余接口统一拦截。Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token null || !jwtUtils.validateToken(token)) { response.setStatus(401); response.setContentType(application/json;charsetUTF-8); response.getWriter().write({\code\:401,\message\:\未登录或登录已过期\}); return false; } // 从token中解析用户信息存入ThreadLocal供后续业务使用 UserContext.set(jwtUtils.parseToken(token)); return true; }这里有个细节容易被忽略拦截器注册时要设置排除路径不然 Swagger、静态资源、以及登录接口全部会被拦截一启动项目先挂一片。5.2 随机组卷算法按配置抽题组卷接口的逻辑我分了三步。第一步根据 paperId 查到 paper_question 关联配置拿到每种题型、难度需要抽多少题以及每题分值第二步遍历配置从 question 表里用带条件的随机查询抽题第三步校验抽取结果如果某类题型题库数量不够配置要求直接返回题库不足请补充题目。随机抽题的 SQL 可以用 MyBatis-Plus 的orderByAsc(RAND()).last(limit count)实现但要注意数据量大时 RAND() 排序会有性能问题。毕设阶段题库数据量一般不大用这种方式最简单清晰如果题库达到几十万题就需要改成先查 ID 再 IN 查询的方式了。5.3 自动判分策略模式和状态流转自动判分我是用策略模式实现的定义了一个ScoreStrategy接口每种题型一个实现类单选、判断直接比对答案多选实现少选得部分分、错选零分的规则主观题不参与自动判分标记为待教师评分。交卷时遍历答题记录客观题当场判分并累加最终成绩里区分客观题得分和主观题得分教师评分后汇总。public interface ScoreStrategy { double score(String correctAnswer, String studentAnswer, double fullScore); }这种设计的另一个好处是可以直接写单元测试把每种题型的判分规则都测一遍。答辩时能演示测试用例印象分会好很多。5.4 MyBatis-Plus 分页插件与模糊搜索项目里列表页很多课程列表、题库列表、帖子列表、用户列表清一色要用分页。用 MyBatis-Plus 的话只需要在配置类里注册一个分页插件Service 层直接用page()方法连 XML 都不用写。Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }模糊搜索用 LambdaQueryWrapper 的 like 方法即可但这里必须说一下直接用wrapper.like(post.title, keyword)是安全的因为 MyBatis-Plus 会把参数预编译成占位符不存在 SQL 注入问题。真正危险的是自己拼接 SQL 字符串的方式这个下一节单独讲。5.5 文件上传、XSS 过滤器与全局异常处理上传 PDF、图片这类需求在课程资料模块是少不了的。实现方案是本地磁盘存储路径通过 application.yml 配置一个可写目录上传成功后把文件的相对访问路径返回给前端。这里提醒一句上传目录不要放在项目源码目录里单独放在服务器某个盘符或者目录下并配置一个静态资源映射来访问这样项目重新部署时文件不会丢。XSS 过滤这块建议做一个全局过滤器。前端表单里输入的内容如果不做转义贴一段带script的内容发到帖子里其他用户浏览时脚本就可能被执行。我在项目里用 Hutool 工具库的 HTML 过滤器把请求参数里的危险标签统一转义一遍存储和展示时都是安全内容。至于上传 PDF 时也要注意文件后缀校验和大小限制防止有人传一个伪装成 PDF 的可执行文件上来。全局异常处理用 RestControllerAdvice 统一兜底业务异常返回 code 500 加具体错误信息未捕获的异常记日志并返回系统繁忙。这样前端拿到的永远是一个规范结构的 JSON不会因为某个 bug 直接把异常堆栈吐给用户。6. 安全与性能SQL 注入、慢查询、SSL 连接的三个坑毕设项目如果只跑通流程就交差大概率会在测试环节被老师问住。安全性和性能虽然不是功能需求但它们是质量需求反而是答辩时最容易出彩的地方。这个项目里我实际处理过三个高频问题分享下整个过程。6.1 SQL 注入从万能密码开始排查sql注入万能密码绕过是一个非常经典的攻击测试。最简单的演示就是登录接口如果 SQL 是这样拼的SELECT * FROM user WHERE username username AND password password 那输入用户名admin --就能把后面的密码条件直接注释掉等于不用密码就能登录。这就是为什么我一再强调要用 MyBatis-Plus 的 LambdaQueryWrapper 或者 XML 里的#{}占位符因为 MyBatis 的#{}底层就是 PreparedStatement 预编译机制用户输入永远只是参数不可能变成 SQL 指令。项目里所有涉及用户输入拼查询条件的地方我都检查过一遍包括登录、搜索、排序凡是需要动态拼 SQL 的全部改成参数化查询。如果你拿到一个老项目或者帮别人改代码可以先全项目搜一遍${}逐个人工确认有没有被用户可控的数据传进去。6.2 慢 SQL 优化社区列表页的排查过程项目联调阶段我遇到过一次社区首页打开很慢的问题页面要卡一到两秒。当时第一反应是打开 MySQL 慢查询日志再加EXPLAIN分析。定位后发现卡点不在帖子表本身而在统计回复数和点赞数的子查询上——帖子列表每查一页就要对每个帖子执行两次 count 子查询数据量一上来就撑不住了。优化方案是在 post 表上增加reply_count和like_count两个冗余字段发评论、点赞、取消赞时用事务去更新这两个字段。列表查询直接 select 冗余字段不再实时 count。这是非常典型的用空间换时间优化改完以后列表页响应时间降到一百毫秒以内。另外给 post 表的 create_time 加了普通索引排序分页性能也有了明显提升。6.3 数据库连接 SSL 报错与连接池参数第一次把项目部署到同学的电脑上时报了一段错误大意是驱动程序无法通过使用安全套接字层(SLL)加密与数据库建立安全连接。查了下才知道MySQL 8.0 的 JDBC 驱动默认开启了 SSL 连接而本地 MySQL 又没有配置 SSL 证书所以握手失败。解决办法是在 jdbc url 上加两个参数spring: datasource: url: jdbc:mysql://localhost:3306/exam_db?useUnicodetruecharacterEncodingutf8useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaiuseSSLfalse关闭 SSLallowPublicKeyRetrievaltrue是配合 MySQL 8 的 caching_sha2_password 认证用的。这两个参数不加上本地连接数据库必报错属于从零搭建项目时第一个要踩的坑。还有一个连接池参数值得注意max-active和initial-size建议显式配置默认值在并发考试场景下不太够用。我这边把 HikariCP 的核心参数调了一下最大连接数设为 20超时时间设为 30 秒跑下来稳定很多。7. 从导入 SQL 到联调跑通完整启动手册这部分是给拿到源码或者准备照着做的人准备的。一个项目不管代码写得多漂亮启动不起来就什么都不是。我按从头开始的顺序把每一步说清楚照着做基本十分钟内能把环境跑起来。7.1 环境准备清单JDK 1.8确认java -version输出是 1.8.xMaven 3.6配置好国内镜像源不然依赖下载能急死人MySQL 8.05.7 也行但字符集必须是 utf8mb4Node.js 16.x后端 IDEIDEA装 Lombok 插件前端VSCode 或 IDEA 都行7.2 导入 SQL 脚本初始化数据库用 Navicat 或者命令行新建一个数据库比如叫exam_db字符集选 utf8mb4然后导入项目里附带的exam_db.sql脚本。脚本开头我写了创建数据库的语句但为了避免本地库名冲突建议只执行表和数据部分库名自己定。导入成功后打开表列表能看到全部核心表和初始化数据就说明脚本没问题。7.3 后端启动步骤IDEA 里直接 File - Open 打开后端项目目录等 Maven 把依赖拉完修改 application.yml 里的数据库账号密码然后启动。启动成功后控制台会打印 Tomcat 端口号默认 8080。如果端口被占用改成 8081 或者其他可用端口同时记得让前端代理指向新端口。常见的启动报错一个是本文前面说的 SSL 连接问题另一个是Table xxx doesnt exist——这种基本就是 SQL 脚本没导入成功或者连错数据库了。先检查配置里的 jdbc url 是不是指向你建的那个库。7.4 前端启动与代理配置前端项目打开后先npm install装完依赖修改根目录下vue.config.js里的 devServer 代理配置把/api开头的请求代理到后端地址devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }npm run serve启动浏览器访问http://localhost:3000用脚本里初始化的管理员账号登录整个系统就跑起来了。7.5 联调自测清单项目跑通之后别急着觉得完事了建议按照下面这个清单自测一遍这一套流程走下来基本就把核心功能覆盖了管理员创建一个课程导入几道单选、多选、判断、主观题管理员创建一个试卷模板配置每种题型的抽题数量学生账号进入考试做几道题后交卷检查客观题自动得分是否正确教师账号进入阅卷给主观题打分检查总分汇总学生发布一个帖子另一个账号评论并点赞检查社区数据切换账号、退出登录检查 token 失效逻辑清空浏览器缓存后直接访问某个后台页面地址验证路由守卫是否生效8. 答辩亮点与进阶扩展项目做完只是第一步答辩能不能讲出东西才是决定分数的关键。这里分享几个我实际用过的思路以及如果时间充裕这个项目还能往哪些方向扩展。8.1 答辩时建议主动秀的三个点第一个是随机组卷的规则设计。讲清楚试卷模板 题目关联 随机抽取这三层结构评委立刻能感受到你不是在做一个简单的 CRUD。第二个是安全设计。BCrypt 密码加密、参数化查询防 SQL 注入、全局 XSS 过滤器、JWT 过期校验、上传文件校验随便展开两个都能讲三分钟。第三个是性能优化。社区列表的慢 SQL 优化案例从现象到 EXPLAIN 分析到冗余字段方案这是一条非常完整的发现问题-定位问题-解决问题链路比直接背八股文有说服力得多。8.2 时间充裕时的进阶扩展方向如果做完基础功能还剩时间可以考虑往这几个方向扩展。考试流程可以用 Flowable 工作流引擎来做把创建考试-审批-发布-考试-阅卷-发布成绩定义成一条流程工作量不大但技术含量很明显。社区内容更新场景可以用 ActiveMQ 或者 RabbitMQ 做异步通知比如有人回复你的帖子时发站内信提高系统响应速度。搜索功能可以做中文分词用 HanLP 对帖子标题分词后建索引这样用户搜英语四级也能匹配到标题含四级英语的帖子体验比 MySQL 的 LIKE 搜索好很多。8.3 最后说几句实在话做完这个项目最大的感触是毕设的价值不在于用了多新的技术而在于把一套完整的东西做扎实。SpringBootVue 这套组合确实旧但它让你把注意力集中在业务逻辑、数据库设计、前后端交互、安全与性能这些真正通用的能力上。等你把考试流程调通、把社区功能跑顺、把部署文档写清楚答辩的自信不是靠背稿子装出来的是来自你亲手解决过的每一个问题。如果再让我重做一次我会把接口文档维护得更规范一点每个接口都标注请求参数示例和返回示例也会在数据库初始化脚本里加一个清库脚本方便反复测试环境。这些小细节看起来不起眼但在演示环节能帮你省掉很多尴尬。项目本身只是一个开始你在调试、排错、优化过程中建立起来的工程习惯才是它留给你的真正价值。
返回列表