毕业设计选题里,管理系统这一类年年有人做,但真正能拿出来演示、能讲清楚技术点、还能经得住老师追问的并不多。这次看的是一个基于 SpringBoot + Vue 的羽毛球比赛管理系统,属于典型的 Java 前后端分离毕设项目:后端 SpringBoot 提供 REST 接口,前端 Vue 负责页面渲染和交互,数据落在 MySQL 里,整体结构清晰、功能边界明确,既不会像纯增删改查那样单薄,也没有复杂到答辩十分钟讲不完。
这个项目最值得关注的点有三个。一是业务贴近真实场景,羽毛球赛事本身就包含报名、抽签、分组、赛程编排、比分录入、积分排名这条完整链路,比"图书管理""学生管理"这类题目更有得聊;二是技术栈主流,SpringBoot + MyBatis-Plus + Vue + Element UI + MySQL 这套组合几乎是 Java 毕设的标配,答辩时技术选型这一块不容易被问住;三是项目通常附带源码、数据库脚本、文档报告和代码讲解,对基础一般的同学比较友好,能省掉大量从零搭架子的时间。
硬件门槛方面要说清楚:这类项目不吃显卡,也不需要 CUDA。一台普通笔记本,装好 JDK、Maven、MySQL 和 Node.js 就能跑起来,内存在 8G 以上基本够用,磁盘留出几个 G 放依赖和数据库就行。真正会卡住新手的从来不是性能,而是环境版本对不上、数据库没导入、前后端端口没对齐这些琐碎问题。本文就按"环境准备 → 数据库初始化 → 前后端启动 → 功能验证 → 接口调试 → 排错"这条线,把这类项目从头到尾跑一遍,顺带把毕设答辩和二次开发要注意的地方一起说清楚。
适合的读者也很明确:正在选毕设题目的计算机相关专业学生、需要一套可运行 Java 项目做课设的同学、想拿这套代码做二次开发练手的前后端初学者,以及需要快速判断"这套源码值不值得下载"的人。
1. 项目核心能力速览
先把关键信息摆出来,方便快速判断是否符合自己的需求。下面这张表里的技术项属于这类项目的通用形态,具体版本和模块请以实际拿到的pom.xml、package.json和数据库脚本为准,不同作者整理的项目会有出入。
| 能力项 | 说明 |
|---|---|
| 项目类型 | Java Web 前后端分离管理系统,赛事业务方向 |
| 技术栈 | SpringBoot + MyBatis-Plus/MyBatis + MySQL + Vue + Element UI + Axios |
| 后端语言/运行时 | Java,需要 JDK 与 Maven 环境 |
| 前端构建 | Node.js + npm,Vue CLI 或 Vite 构建 |
| 数据库 | MySQL,需要导入项目自带的.sql初始化脚本 |
| 推荐硬件 | 普通笔记本即可,8G 内存起步,无需独立显卡 |
| 显存占用 | 不涉及,纯 CPU 业务系统 |
| 启动方式 | 后端main方法或 Maven 插件启动,前端npm run serve/npm run dev |
| 是否支持 API | 是,标准 RESTful 接口,可用 Postman 或 curl 直接调试 |
| 是否支持批量任务 | 支持批量数据导入、批量审核、批量导出等业务级操作,具体看项目实现 |
| 主要业务模块 | 用户与角色、比赛项目、报名审核、赛程编排、比分录入、积分排名、场地管理、公告通知、数据统计 |
| 适合场景 | 毕业设计、课程设计、Java Web 入门实战、二次开发练手 |
| 交付物 | 源码、数据库脚本、文档报告、代码讲解(以实际分享内容为准) |
从表格能看出来,这个项目的定位很清楚:它不是拿来炫技的,而是拿来完整跑通一套真实业务的。对毕设来说,这一点比技术堆料更重要,因为答辩老师最常问的往往就是"你这个赛程是怎么排的""积分规则怎么算的""多人报名同一个项目怎么处理",这些才是这套代码真正的价值所在。
1.1 角色与权限划分
这类系统一般会做多角色区分,常见的是管理员、裁判、运动员(或普通用户)三类,部分项目还会拆出赛事组织方。管理员拥有最高权限,负责用户管理、比赛项目发布、报名审核、赛程编排和成绩公示;裁判主要负责比赛过程中的比分录入与结果确认;运动员侧则聚焦在注册登录、查看赛事、提交报名、查询自己的赛程和成绩。
权限控制这块,常见做法是登录后由后端签发 Token(JWT 或自定义 token),前端把 token 存到 localStorage 或 Vuex/Pinia 里,每次请求通过 Axios 拦截器塞进请求头,后端再用拦截器或 Spring Security 做校验。理解这条链路很重要,因为一旦出现"登录成功但所有接口都返回 401"这类问题,排查方向基本就锁定在拦截器、Token 过期时间、请求头字段名这三处。毕设答辩时如果被问到"你怎么做权限控制的",能把这条链路讲清楚,比背概念有用得多。
1.2 赛事业务主线
羽毛球比赛管理和普通信息管理系统最大的区别,在于它有一条真实的业务主线。一场比赛从发布到出成绩,通常要走完"创建比赛项目 → 开放报名 → 报名审核 → 分组抽签 → 生成对阵 → 安排场地与时间 → 录入比分 → 计算积分 → 更新排名 → 成绩公示"这么多步。
这条链路里,赛程编排是技术含量最高的部分。单淘汰赛的对阵树生成、小组循环赛的轮次安排、种子选手的分布,都是可以深入讲的地方。如果项目里做了这部分逻辑,答辩时完全可以把它当作亮点展开;如果只是手工录入对阵,那也没关系,重点讲清楚数据表怎么设计、外键怎么关联、状态怎么流转,同样成立。积分排名则相对简单,一般是胜场数、净胜局、净胜分这几个维度排序,用一条 SQL 或者一段 Java 排序就能搞定。
2. 适用场景与使用边界
这套代码最适合的场景就是毕业设计和课程设计。原因很实在:题目不空洞,业务有纵深,技术栈主流,代码量适中。老师看到"羽毛球比赛管理系统"这种题目,第一反应是"这个有具体业务",比看到"基于 XX 的 XX 管理系统"要正面得多。而且赛事业务的复杂度天然存在,报名截止怎么控制、重复报名怎么拦截、弃赛怎么处理、比分打平怎么算,这些都是可以展开写的点。
第二个场景是 Java Web 入门实战。对刚学完 SpringBoot 和 Vue、但没做过完整项目的人来说,一套能跑起来的前后端分离代码,比看十篇教程都管用。你可以顺着一个请求从浏览器点按钮开始,一路跟到 Controller、Service、Mapper、SQL,最后看数据怎么回传到页面渲染出来,这个完整的闭环走一遍,对 MVC 分层和前后端协作的理解会明显不一样。
第三个场景是二次开发练手。拿到源码之后改点东西,比如加一个"比赛直播比分"页面、加一个"裁判评分"模块、把积分算法从简单排序换成更复杂的规则,甚至把前端从 Element UI 换成别的组件库,这些都是很好的练习。改动过程中会踩到各种坑,而踩坑本身就是学习。
不适合的场景也要说清楚。这套代码不适合直接商用,原因很简单:毕设项目普遍缺少完整的异常处理、并发控制、数据校验、日志审计和安全防护,报名接口如果没有做幂等,高并发下很容易出现重复记录;数据库连接池、缓存、事务边界这些也大多是默认配置。真要上线,得做一轮相当彻底的工程化改造。
合规方面有几条要提醒。第一,源码和文档的使用要遵守原作者声明的许可范围,如果是付费或授权分享的内容,不要二次分发。第二,系统里会涉及用户手机号、身份证号一类信息(报名场景常见),本地测试时不要用真实身份信息,测试数据建议造假的。第三,如果要把项目部署到公网做在线演示,务必修改默认管理员密码、关闭数据库远程访问、限制接口访问来源,别让一套练手代码变成安全漏洞。
3. 技术架构与目录结构梳理
拿到一套 Java 毕设源码,别急着双击启动,先花十分钟把目录结构和分层看清楚,后面出问题时能少走很多弯路。典型的项目根目录一般分成后端和前端两个文件夹,后端是标准的 Maven 结构,前端是 Vue CLI 或 Vite 生成的工程。
后端目录大致是这样:src/main/java下面按包名分层,通常有controller(接口层)、service与service/impl(业务层)、mapper(数据访问层)、entity或pojo(实体类)、config(配置类)、utils(工具类)、interceptor或filter(拦截器),有些项目还会单独拆出vo、dto、common。src/main/resources下放application.yml或application.properties、MyBatis 的mapper/*.xml,有的项目还会把前端打包产物丢进static做一体化部署。
前端目录一般有src/api(接口封装)、src/views(页面)、src/components(公共组件)、src/router(路由配置)、src/store(状态管理)、src/utils(请求封装和工具函数)。src/utils/request.js这个文件值得单独看一眼,Axios 实例的 baseURL、超时时间、请求拦截器和响应拦截器都在里面,前后端联调 90% 的问题都能在这个文件里找到线索。
3.1 分层职责与请求链路
理解分层职责比记住目录名更重要。一次典型请求是这样的:用户在 Vue 页面点击"提交报名",页面调用src/api里封装的方法,方法内部用 Axios 发 POST 请求,请求经过拦截器加上 token 后打到后端;后端先过拦截器校验登录状态,再进Controller接收参数并做基础校验,然后调Service处理业务逻辑(比如检查是否已报名、名额是否已满、报名时间是否截止),Service调Mapper执行 SQL 落库,最后统一封装成Result对象返回。
这条链路里任何一环断了,表现都是"点了没反应"。所以排查顺序建议固定下来:先看浏览器 Network 面板的请求状态码和响应体,再看后端控制台有没有异常堆栈,再看 SQL 日志有没有执行,最后才去怀疑业务逻辑。养成这个顺序,能让排错效率提升一大截。
3.2 统一返回结构与异常处理
大多数这类项目会定义一个统一返回体,形如code、msg、data三个字段,前端拦截器根据code判断成功失败。有的项目还会配一个全局异常处理器@RestControllerAdvice,把业务异常统一转成友好提示。看代码时留意这两处,能快速理解项目的错误处理风格。
// 统一返回体示例,实际字段名以项目中的 Result 类为准 public class Result<T> { private Integer code; private String msg; private T data; public static <T> Result<T> success(T data) { Result<T> r = new Result<>(); r.setCode(200); r.setMsg("操作成功"); r.setData(data); return r; } public static <T> Result<T> error(String msg) { Result<T> r = new Result<>(); r.setCode(500); r.setMsg(msg); return r; } }上面这段只是示意结构,实际项目里可能是R、AjaxResult、ResponseData之类的命名。关键在于:前端拦截器判断的字段名,必须和后端返回的字段名完全一致,大小写都不能错,这是新手最容易忽略的低级问题。
4. 环境准备与数据库初始化
环境这块,先把需要装的东西列清楚:JDK、Maven、MySQL、Node.js。版本方面不建议追新,SpringBoot 2.x 项目用 JDK 8 或 JDK 11 最稳,SpringBoot 3.x 项目则要求 JDK 17 以上,这一点务必先看pom.xml里的java.version和spring-boot-starter-parent版本再决定,装错了就是一堆看不懂的编译错误。Maven 建议配好国内镜像源,不然拉依赖能等到怀疑人生。
MySQL 建议 5.7 或 8.0,具体看建表脚本里的语法。Node.js 版本要和前端工程匹配,Vue CLI 老项目用 Node 14/16 比较稳,Vite 新项目则需要 Node 16 以上,版本过高有时会报OpenSSL相关的构建错误。
# 环境自检,四条命令都能输出版本号说明基础环境就绪 java -version mvn -v mysql --version node -v && npm -v四条命令跑完,缺哪个装哪个。这里有个经验:如果java -version输出的是 17 而项目是 SpringBoot 2.x,编译阶段大概率报Unsupported class file major version,解决办法不是改代码,而是换 JDK 或升级 SpringBoot 版本,二选一。
4.1 数据库创建与脚本导入
数据库这一步是新手最容易翻车的地方。标准流程是先建库、再导脚本、最后改配置。建库时字符集一定要指定utf8mb4,否则中文赛事名称、运动员姓名很容易出现乱码或插入失败。
-- 创建数据库,字符集必须指定,排序规则按 MySQL 版本选择 CREATE DATABASE badminton_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE badminton_db; -- 建表脚本一般由项目提供,例如 badminton_db.sql -- 导入方式一:命令行 -- mysql -u root -p badminton_db < badminton_db.sql -- 导入方式二:Navicat / DataGrip 里右键"运行 SQL 文件"导入完成后,一定要验证表和数据是否真的进去了,别只看工具提示"执行成功"就完事。
-- 验证:查看表数量、关键表数据量 SHOW TABLES; SELECT COUNT(*) FROM sys_user; SELECT COUNT(*) FROM match_project;如果SELECT报"表不存在",说明脚本没导进当前库,八成是导入时没选中badminton_db。如果报"Unknown column",说明脚本版本和代码版本不匹配,需要回头确认源码和 SQL 是不是同一批。
4.2 配置文件修改要点
application.yml里有几个配置必须改,改完再启动。
server: port: 8080 # 后端端口,被占用就换一个 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/badminton_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: 你的数据库密码 servlet: multipart: max-file-size: 10MB # 涉及图片上传时按需调整 max-request-size: 20MB mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 调试期打开,能看到执行的 SQLurl里的三个参数值得说明:serverTimezone不配在某些 MySQL 8 环境下会直接报时区错误;useSSL=false是为了避免本地连接时的证书告警;useUnicode和characterEncoding关系到中文能否正常存取。这三个几乎是本地部署的必备项,缺一个都可能出问题。
log-impl那行打开后,控制台会打印每条执行的 SQL 和参数,调试期非常有用,但正式演示前建议关掉,不然日志刷得太快看不清异常。
5. 后端与前端启动方式
数据库就绪、配置改完,就可以启动后端了。两种方式:IDEA 里找到带@SpringBootApplication注解的主类,点绿色三角运行;或者命令行用 Maven 插件跑。命令行方式更容易看到完整的启动日志,排错推荐用它。
# 进入后端项目根目录(有 pom.xml 的那一层) cd backend # 方式一:Maven 插件启动 mvn spring-boot:run # 方式二:先打包再运行 mvn clean package -DskipTests java -jar target/xxx-0.0.1-SNAPSHOT.jar启动成功的标志很明确:控制台出现 Spring Boot 的 banner 图案,随后打印 Tomcat 的启动端口,最后一行类似Started XxxApplication in 5.2 seconds。看到这一行才算真的起来了,如果卡在HikariPool或者报Communications link failure,那就是数据库连不上,回去检查地址、账号、密码、库名四要素。
后端起来之后,先在浏览器直接访问一下接口,确认服务真的通。
# 验证后端服务是否存活,路径以项目实际 controller 为准 curl http://127.0.0.1:8080/ # 如果接口需要登录,一般会返回 {"code":401,"msg":"未登录"},这也说明服务是通的前端这边,进入前端目录,先装依赖再启动。
cd frontend # 安装依赖,国内网络建议先配置镜像源 npm config set registry https://registry.npmmirror.com npm install # 启动开发服务,Vue CLI 项目用 serve,Vite 项目用 dev npm run serve # 或 npm run dev启动成功后控制台会输出本地访问地址,通常是http://localhost:8081或http://localhost:5173,具体看项目配置。打开浏览器访问,能看到登录页就说明前端通了。
5.1 前后端端口与代理配置
前后端分离项目有个必踩的坑:跨域。前端跑在 8081,后端跑在 8080,浏览器同源策略直接拦截请求,控制台一片红色 CORS 报错。
处理方式有两种。一是后端加跨域配置,用@CrossOrigin注解或者全局WebMvcConfigurer配置;二是前端配代理,把/api开头的请求转发到后端端口。第二种更常见也更干净,因为生产环境通常由 Nginx 统一处理。
// vue.config.js 代理配置示例,Vite 项目对应 vite.config.js 的 server.proxy module.exports = { devServer: { port: 8081, proxy: { '/api': { target: 'http://127.0.0.1:8080', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }配置完记得重启前端服务,热更新有时候不生效。改完之后如果还报跨域,重点检查src/utils/request.js里的baseURL是不是/api,如果写成了完整地址http://127.0.0.1:8080,代理就绕过去了,等于白配。
6. 核心功能测试与效果验证
服务跑起来只是第一步,接下来要按业务主线把功能一个个点过去。测试要有顺序,从基础到复杂,这样出问题时能快速定位是哪一层的问题。
6.1 登录与权限验证
测试目的:确认认证链路和角色权限是否正常。
操作步骤:先用项目文档里提供的管理员账号登录(一般在 SQL 脚本的sys_user表里,密码通常是加密后的固定值),登录成功后观察浏览器 localStorage 里是否写入了 token;再点几个只有管理员能访问的菜单,确认能正常加载;最后用普通用户账号登录,确认管理菜单不可见。
预期结果:三种角色登录后看到的菜单不同,访问越权接口时返回 401 或 403。
判断成功的标准:刷新页面后登录状态不丢失,说明 token 持久化正常;退出登录后再次访问受保护页面会跳回登录页,说明拦截生效。
常见失败原因:密码加密方式和数据库里存的不一致(比如代码用 BCrypt 而库里是明文);token 过期时间设得太短,测试过程中就失效了;前端路由守卫没配,导致直接输 URL 能绕过菜单权限。
6.2 比赛项目与报名流程
测试目的:验证赛事发布到报名的主链路。
操作步骤:管理员登录后新建一个比赛项目,填写项目名称(如"男子单打")、赛制(淘汰赛/循环赛)、报名起止时间、人数上限、比赛场地;保存后切换到运动员账号,在赛事列表里找到刚发布的项目,点击报名并提交;再切回管理员,在报名审核列表里通过该条报名。
预期结果:报名记录状态从"待审核"变为"已通过",赛事列表的人数统计同步更新。
判断成功的标准:重复提交报名时,后端应拦截并提示"您已报名该项目",这是判断幂等有没有做好的直接方式。报名截止时间之后再提交,应该被拒绝。
常见失败原因:时间字段前后端格式不一致(后端用Date、前端传字符串),导致截止校验永远通过;人数上限的判断用了>=而不是>,导致最后一个名额被挡。
6.3 赛程编排与比分录入
测试目的:验证赛程生成和成绩计算。
操作步骤:报名审核通过若干人后,触发赛程生成(有的项目是自动抽签生成对阵,有的是手动添加对阵记录);在裁判账号下打开对应场次,录入比分,保存;回到成绩页面查看积分排名是否更新。
预期结果:对阵表按轮次正确展示,比分保存后胜方晋级或积分增加,排名列表顺序变化。
判断成功的标准:比分录入后刷新页面数据不丢,说明落库正常;修改比分后排名能重新计算,说明积分逻辑是实时算的而不是写死的。
常见失败原因:抽签算法对人数不是 2 的幂次时没做轮空处理,导致对阵表缺人;比分字段用了字符串类型,排序时出现10 < 9这种字典序错误。
6.4 数据统计与图表展示
不少项目会用 ECharts 做数据看板,比如各项目报名人数分布、场地使用率、历史战绩趋势。测试时重点看两件事:图表数据是否和列表页一致,图表在数据为空时会不会报错崩掉。
判断标准很直接:手动在数据库里加几条测试数据,刷新看板看图表有没有跟着变;把某张表清空,看页面是否显示"暂无数据"而不是白屏报错。后者是很多毕设项目的通病,答辩演示时如果正好点到空数据页面直接报错,观感会很差,提前发现提前改。
7. 接口 API 调用与批量数据处理
前后端分离项目的好处就是接口是独立的,可以用任何工具直接调。调试接口这一步建议一定要做,因为答辩时如果被问到"你的接口是怎么设计的",能当场打开 Postman 演示一遍,说服力比口头描述强得多。
7.1 接口调试基本流程
先登录拿 token,再带着 token 调业务接口。这是所有需要鉴权的系统的通用套路。
# 第一步:登录获取 token,路径和参数以实际 controller 为准 curl -X POST http://127.0.0.1:8080/api/user/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"123456"}' # 返回示例(字段名以项目实际为准) # {"code":200,"msg":"登录成功","data":{"token":"eyJhbGciOiJIUzI1NiJ9..."}} # 第二步:带 token 查询比赛项目列表 curl -X GET "http://127.0.0.1:8080/api/matchProject/page?pageNum=1&pageSize=10" \ -H "token: eyJhbGciOiJIUzI1NiJ9..." # 第三步:新增一条报名记录 curl -X POST http://127.0.0.1:8080/api/registration/add \ -H "Content-Type: application/json" \ -H "token: eyJhbGciOiJIUzI1NiJ9..." \ -d '{"projectId":1,"userId":3,"remark":"测试报名"}'注意请求头里 token 的字段名,有的项目叫token,有的叫Authorization,还有的带Bearer前缀,这个必须和拦截器里读取的字段名完全对应,写错了就是 401。
7.2 用 Python 做批量数据导入
做演示或者压测时,手工点太慢,写个脚本批量造数据效率高得多。下面是一个通用的批量报名脚本模板,路径和字段需要按实际接口调整。
import requests import time BASE_URL = "http://127.0.0.1:8080/api" TOKEN = "登录后拿到的token" headers = { "Content-Type": "application/json", "token": TOKEN } def batch_register(project_id, user_ids): success, failed = 0, [] for uid in user_ids: payload = {"projectId": project_id, "userId": uid} try: resp = requests.post( f"{BASE_URL}/registration/add", json=payload, headers=headers, timeout=10 ) data = resp.json() if data.get("code") == 200: success += 1 else: failed.append((uid, data.get("msg"))) except Exception as e: failed.append((uid, str(e))) # 控制请求频率,避免把本地服务打满 time.sleep(0.1) return success, failed if __name__ == "__main__": user_ids = list(range(1, 51)) ok, bad = batch_register(project_id=1, user_ids=user_ids) print(f"成功 {ok} 条,失败 {len(bad)} 条") for item in bad[:10]: print("失败明细:", item)这个脚本的价值在于把"批量"和"失败重试"两件事分开了:成功计数、失败明细分开记录,失败了能看到具体原因而不是一笔糊涂账。真实业务里做批量导入,日志必须记到这个粒度,否则出问题根本没法回溯。
7.3 批量操作的工程化建议
如果项目里本身就有批量导入功能(比如 Excel 批量导入运动员名单),测试时要重点关注三件事。一是文件解析容错,表头少一列、某行是空行、手机号格式不对,程序应该给出明确的第几行出错,而不是整个导入直接 500。二是事务边界,一批 100 条里第 80 条失败,是全部回滚还是前 79 条保留,这个行为必须明确,通常建议整批回滚并提示失败行号。三是重复数据处理,同一个身份证号导入两次,应该跳过还是更新,得有清晰策略。
这三点如果项目里没做好,其实是个很好的改进点,改完写进论文的"系统优化"章节,比空谈"性能优化"实在得多。
8. 常见问题与排查方法
下面这张表是这类项目最高频的故障集合,按出现概率从高到低排。遇到问题先对表,能省掉大量瞎试的时间。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 后端启动报数据库连接失败 | 地址/库名/账号密码错误,或 MySQL 未启动 | 看控制台异常堆栈,确认Communications link failure还是Access denied | 核对application.yml四要素,先命令行mysql -u root -p验证连通性 |
启动报Table doesn't exist | 数据库脚本没导入或导入到了错误的库 | SHOW TABLES检查表是否存在 | 选中正确库重新导入脚本 |
| 中文显示乱码或插入失败 | 数据库或连接字符集不是 utf8mb4 | 查库和表的字符集设置 | 建库时指定 utf8mb4,连接串加characterEncoding=utf8 |
前端npm install卡住或报错 | 网络问题或 Node 版本不匹配 | 看报错关键词是ETIMEDOUT还是node-sass | 配国内镜像源,按项目要求切换 Node 版本 |
| 页面能开但接口全 401 | Token 未携带、字段名不一致、Token 过期 | 浏览器 Network 看请求头有没有 token 字段 | 对齐前后端 token 字段名,检查拦截器放行路径 |
| 接口报 CORS 跨域错误 | 代理未生效或 baseURL 写成了完整地址 | 看请求 URL 是相对路径还是绝对路径 | 修正request.js的 baseURL 为/api,重启前端 |
| 端口被占用启动失败 | 8080/8081 已被其他进程占用 | `netstat -ano | findstr 8080(Windows)或lsof -i:8080`(macOS/Linux) |
| 比分保存后排名不变 | 积分未实时计算或缓存未刷新 | 查数据库积分字段是否更新 | 检查积分计算触发时机,改为保存后重算 |
| 图片上传失败 | 上传大小超限或静态资源映射未配置 | 看响应体提示和文件大小 | 调整max-file-size,配置静态资源访问路径 |
| 打包后前端页面空白 | 静态资源路径配置错误 | 浏览器控制台看 404 的资源路径 | 配置publicPath,或前后端分开部署 |
这张表里的每一条都值得单独拿出来讲两句。以"页面空白"为例,这是打包部署环节的经典问题。开发环境用npm run serve一切正常,npm run build之后丢到后端static目录,打开一片白,控制台全是 404。原因通常是publicPath默认是/,而实际部署在子路径下,或者路由模式用了 history 但服务器没配 fallback。改成publicPath: './'、路由换成 hash 模式,问题基本就解决了。
{"code":401,"msg":"未登录"} 这个返回其实是个好消息,说明服务活着、接口通着、拦截器工作正常,问题只在认证这一层。反过来,如果返回的是 404,那才是路径不对;返回 500 是代码异常;连不上则是服务根本没起来。把这几种状态码和对应含义记熟练,排错时能快速缩小范围。
关于显存和性能这个话题,这套系统不涉及 GPU,所以不存在显存占用的问题。真正需要关注的性能点是数据库查询和接口响应时间。当比赛项目列表数据量变大之后,如果分页查询每次都全表扫描,响应会明显变慢。优化方向很朴素:给常用查询字段加索引、避免SELECT *、列表接口只查必要字段、关联查询用JOIN而不是循环里查库(也就是常说的 N+1 问题)。这些改动量小、效果直观,很适合写进论文的性能测试章节。
9. 二次开发与答辩准备建议
跑到这一步,系统算是完整跑通了。如果目标只是完成毕设,接下来重点转向文档和答辩;如果想拿它继续练手,可以从几个方向下手。
第一个方向是补工程化能力。这类项目普遍缺少的参数校验、统一异常处理、接口限流、操作日志,都是很好的切入点。比如给报名接口加上@Valid注解配合@NotBlank、@Min做参数校验,把校验逻辑从 Controller 里搬出来;再比如用 AOP 做一个操作日志切面,把"谁在什么时候改了哪场比赛的比分"记下来,这个改动不大,但答辩时讲出来很有分量,因为它体现的是工程思维而不是业务堆砌。
第二个方向是完善业务闭环。很多毕设项目的报名审核是单向的,只能通过不能驳回;赛程编排依赖手工录入;成绩公示没有生成对外可看的页面。把这些补上,系统的完整度会上一个台阶。特别是"驳回并填写理由"这种小功能,实现简单但很贴近真实产品,答辩老师一看就知道你认真想过用户场景。
第三个方向是技术升级。把 MyBatis 换成 MyBatis-Plus 减少 XML 配置,把 Session 认证换成 JWT,把前端从 Vue2 迁到 Vue3 + Composition API,把打包从 Webpack 换成 Vite 提升构建速度。这些升级每一项都能单独写一节,也都能在答辩时作为"技术选型演进"来聊。
9.1 答辩时的讲解重点
答辩时间通常很短,讲什么比讲多少重要。建议按这个顺序组织:先用一句话说清楚系统解决什么问题,然后演示一条完整业务主线(发布比赛 → 报名 → 审核 → 编排 → 录分 → 排名),再讲技术架构和分层设计,最后讲一个你解决过的具体问题。
那个"具体问题"是拉开差距的地方。比如"报名接口重复提交导致重复记录,我用唯一索引 + 业务层校验双重拦截解决了",或者"比分排序时发现字符串类型导致10排在9前面,改成数值类型并用多字段组合排序解决"。这种有现象、有定位、有方案的叙述,比罗列技术名词有力得多。
9.2 合规与使用边界提醒
最后再强调几点。源码里的第三方依赖要留意开源协议,商用前必须逐一确认;系统里的用户信息、联系方式属于个人信息,测试和演示一律用虚构数据,不要拿真实名单跑;如果要部署到公网做在线演示,务必改掉默认管理员密码、关闭数据库外网访问、把application.yml里的数据库密码换成环境变量注入,别把配置连同密码一起传到公开仓库。
10. 收尾:这套代码值得怎么用
回到最开始的判断:这个羽毛球比赛管理系统值不值得试,答案取决于你要什么。如果你要的是一套结构完整、业务真实、技术栈主流的 Java 毕设项目,它能省掉你从零搭建脚手架和设计表结构的时间,让精力集中在业务逻辑和文档上;如果你要的是学 SpringBoot 和 Vue 的完整链路,顺着一条请求从页面点到 SQL,是效率最高的学习方式。
上手时最先验证的三件事,按顺序是:数据库脚本能不能一次导入成功,后端能不能在控制台打印出Started,前端登录页能不能正常打开并登录成功。这三步过了,后面基本就是一马平川。最容易踩的坑也集中在三处:JDK 版本和 SpringBoot 版本不匹配、application.yml的数据库配置没改、前端代理和 token 字段名对不上。
后续可以扩展的方向,前面已经提了不少,挑一个做深比全都碰一遍要好。真要选一个性价比最高的,我建议是"报名链路的完整性"——把报名截止校验、重复报名拦截、名额控制、审核驳回、报名取消全部补齐,这条链路打通之后,整个系统的业务完整度会有明显提升,答辩时也有现成的东西可以讲。
代码跑起来只是起点,把它改成自己能讲清楚、能改得动的样子,才是这套源码真正的用法。