恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
基于SpringBoot+Vue的健美操评分系统:数据库设计、评分算法与权限管理
首页
资讯中心
/
基于SpringBoot+Vue的健美操评分系统:数据库设计、评分算法与权限管理
基于SpringBoot+Vue的健美操评分系统:数据库设计、评分算法与权限管理
发布时间:2026/10/10 15:46:01
先交代一下背景这次分享的是一个基于 SpringBoot Vue 的前后端分离项目——健美操评分系统管理平台技术栈是 Java MySQL。乍一看是个常见的“管理系统”但往里走会发现评分类系统在业务上有个很特殊的点它既要承接传统的增删改查又必须处理一套完整的评分规则、裁判角色权限、成绩汇总和排名逻辑。这些细节做好了项目的含金量才会真正上去。如果你的目标是毕业设计、课程设计或者想找一个能练手完整业务闭环的源码项目这个题目选得挺合适。它比普通的“XX管理系统”多了一层业务深度又没有复杂到让人望而却步。把评分规则、角色权限、前端交互捋清楚你的答辩和技术积累都会扎实不少。我把整个项目从架构到落地从数据库设计到核心代码实现再到我踩过的坑按实操顺序完整拆给你。1. 项目整体设计与思路拆解1.1 为什么评分类系统更适合做毕设课设平时网上能找到的项目大多是图书管理、班级管理、新闻发布这类纯 CRUD 系统。它们有一个共同的问题业务逻辑太浅做完以后除了“会调用框架”之外很难体现出更深的设计能力。而健美操评分系统天然带了一套完整业务流程赛事创建后需要设置参赛项目比如单人操、三人操、集体操运动员或者说参赛队伍要报名、分组、上场排序裁判按项目打分每个裁判的独立评分要落库系统根据规则剔除最高分和最低分计算最终得分最终得分用于排名、生成成绩单。这整条链路里权限控制的复杂度上来了计算逻辑也有了前端展示也有看点——裁判录入页面需要实时计算、成绩发布页面需要动态刷新。作为毕设课设它的“技术展示面”非常完整。更重要的是场景贴近真实赛事你毕业答辩的时候能讲清楚业务而不是停留在“这是张表那是张表”的层面。1.2 技术选型背后的真实考量前后端分离选 SpringBoot Vue这几年几乎是国内 Java 方向项目的主流标配了热度一直在线。你去看招聘要求也好看开源项目也好这套组合的覆盖率非常高。选它不只是为了“随大流”而是有几个实打实的好处。后端部分SpringBoot 最大的价值在于自动配置。做这种中小型管理系统你不太想花大量时间折腾 XML 配置和依赖版本兼容问题SpringBoot 能直接让你把精力放到业务代码上。配合 Spring MVC 做 RESTful 接口、Spring Data JPA 或 MyBatis 做数据访问一个项目的骨架很快就能跑起来。Java 作为主语言加上强类型特性和成熟的生态做这种业务逻辑明确的项目稳定性和可维护性都有保证。前端部分Vue 的响应式数据绑定在处理评分录入这种场景时非常舒服。裁判每输入一个分数页面可以立刻计算当前的平均分、待剔除的分数等这种实时反馈如果用传统 jQuery 来写逻辑会散落在各种 DOM 操作里项目一大就非常痛苦。而 Vue 组件化的方式可以把评分表、成绩单、报名表拆成独立的组件开发和维护都更清晰。数据库方面MySQL 依然是这类项目最稳妥的选择。它的 SQL 支持完善事务机制成熟而且网上资料多遇到问题搜起来方便。评分系统里成绩汇总涉及多表关联和聚合查询MySQL 在这个量级下完全够用。1.3 系统核心角色与边界划分我在最初梳理需求时发现很多人容易把角色设计弄得很乱。这里我理清一下这个平台的核心角色你照着做就不会糊涂系统管理员管理用户、管理赛事、管理项目类型拥有最高权限裁判负责录入分数、查看自己提交的评分但不能修改最终成绩和排名教练或运动员选手方查看赛事信息、查看自己的成绩和排名系统游客可选只能浏览公告和已发布的成绩。注意一个关键点裁判不能既打分别改结果成绩计算和排名是系统自动完成的。比赛评分最讲究公平这种权限边界是刚需不然你的系统在业务上站不住脚。放在答辩里这也是一个很好的设计亮点。2. 数据库设计与核心模块解析2.1 建表思路从业务流程反推表结构数据库设计是这种项目的门面也是面试官和答辩老师特别爱问的部分。我习惯从业务流程的每个动作出发反推需要什么表、哪些字段。这个项目里的核心动作有哪些创建赛事、创建项目、选手报名、裁判打分、成绩汇总每个动作对应一张或两张表。最终我的设计分成两大部分先看基础信息相关的表用户表 userid, username, password, real_name, role0管理员/1裁判/2运动员, phone, created_at赛事表 competitionid, name, start_date, end_date, location, status0未开始/1进行中/2已结束项目表 eventid, competition_id, name, type单人操/双人操/集体操等, sort_order, status报名表 registrationid, event_id, user_id运动员id, team_name, member_names, group_name组别然后是评分相关的表这里稍微绕一点评分表 scoreid, registration_id关联报名记录, judge_id裁判id, event_id, difficulty_score, artistry_score, execution_score, total_score, comment, created_at成绩表 resultid, registration_id, event_id, final_score, rank, statusscore 表里存的是每个裁判对每个参赛记录的原始评分result 表里存的是规则运算后的最终成绩。为什么要分成两张表因为原始分一旦被篡改或者需要复核得留底。成绩表只是最终快照可以随时从 score 表重新计算。2.2 评分字段拆分与评分规则设计这里我故意把 score 表的字段拆成了难度分、艺术分、完成分三个维度。健美操评分不是只给一个总分就完了裁判实际上会从这几个维度分别打分最后合计。系统层面这样设计有三个好处贴近真实比赛规则项目的真实性大大提升后续可以根据不同赛事类型灵活调整每个维度的权重统计层面可以做更细的分析比如某裁判对艺术分普遍打得偏高这些都能审计出来。字段长度方面分数我用 decimal(4,2)也就是 99.99 封顶大多数比赛满分 10 分或者 20 分这个精度足够了。如果你用 float 来存后续计算浮点误差会很烦decimal 是金钱和分数类数据的稳妥选择。2.3 用户权限设计的落地实现权限这块我没有引入 Spring Security 或者 Shiro直接用了最简单的方案JWT 拦截器。理由很实在这个项目角色就三种接口量也就几十个引入一套完整安全框架反而增加学习和调试成本。但如果你想要研究深度上更进一步把 Spring Security 换成自己实现也不是不行看你的时间。实现思路是这样的用户登录接口校验账号密码后用 jjwt 生成一个 tokentoken 里携带 user_id 和 role 信息。前端拿到 token 存在 localStorage后续请求在 axios 拦截器里统一加上 Authorization 头。后端写一个拦截器拦截除登录接口外的所有请求从 token 里解析出角色再配合自定义注解做接口级权限校验。这里有个容易被忽略的细节token 过期时间。很多人做项目图省事把过期时间设成 7 天甚至 30 天这是不对的。评分系统属于赛事管理系统一场比赛最多一两天token 过期时间设置 24 小时就足够。时间太长万一 token 泄露别人把成绩改了都不知道是谁干的。2.4 连接池与数据库配置的推荐方案数据库连接池我推荐用 HikariCP。SpringBoot 2.x 之后默认就是它几乎零配置就能获得不错的性能。在 application.yml 里设置一下最大连接数、连接超时时间即可。很多初学者会忽略这些配置默认值在本地开发没问题但如果你部署到服务器上并发一上来就会出现获取连接超时的报错。spring: datasource: url: jdbc:mysql://localhost:3306/aerobics_score?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 10 minimum-idle: 5 connection-timeout: 30000timezone 一定要显式指定不然 MySQL 8.x 下日期时间会差 8 个小时。这是个非常经典的坑网上搜一下全是被这个坑折磨的人。3. 后端核心功能实现与难点攻克3.1 赛事与项目管理接口项目的基础管理模块没什么好特别炫技的但我要强调一点接口设计必须规范RESTful 风格要贯彻到底。比如赛事接口GET /api/competitions 查询赛事列表支持分页和关键字检索GET /api/competitions/{id} 查询赛事详情POST /api/competitions 创建赛事仅管理员PUT /api/competitions/{id} 修改赛事信息DELETE /api/competitions/{id} 删除赛事仅管理员一个小细节是删除赛事之前要检查有没有关联的报名记录和成绩记录否则会直接把数据库外键约束给干翻了。这里就能看出你考不考虑数据完整性。实现方式很简单先 count 一下关联表有数据就接口直接返回错误提示前端弹窗告知用户“存在报名记录无法删除”。3.2 评分录入与分数汇总算法的实现这是整个项目里最核心的业务逻辑没有之一。评分的具体过程是这样的一个项目下有若干个报名记录每个记录会有多个裁判给它打分。录入时裁判选择某个项目下的报名记录录入难度分、艺术分、执行分系统自动算出该裁判给出的总分。不同裁判之间互相看不到评分这就是典型的评分独立性要求。汇总阶段也就是计算 final_score 的规则我实现的是经典方案去掉一个最高分和一个最低分剩余分数取平均。这个规则在体育赛事里非常常见目的是削弱极端评分对选手的影响。用 Java 实现时我用 Stream 一行就搞定了核心计算public BigDecimal calculateFinalScore(ListBigDecimal scores) { if (scores null || scores.size() 3) { throw new IllegalArgumentException(至少需要3个裁判评分才能计算); } ListBigDecimal sorted scores.stream() .sorted() .collect(Collectors.toList()); BigDecimal sum BigDecimal.ZERO; // 去掉第一个最低分和最后一个最高分 for (int i 1; i sorted.size() - 1; i) { sum sum.add(sorted.get(i)); } return sum.divide(BigDecimal.valueOf(sorted.size() - 2), 2, RoundingMode.HALF_UP); }这里有几个关键细节你必须注意用 BigDecimal 而不是 double 做运算double 在浮点计算时会有精度问题除法必须指定保留位数和舍入模式否则可能因为除不尽直接抛 ArithmeticException参数校验要先做裁判人数少于 3 时这个规则本身就是不成立的。3.3 排名计算与成绩发布排名算法反而简单在计算出 finalScore 之后按同一个 event_id 分组分数从高到低排序就能得到 Rank。批量排名我用 Java 8 的 Stream 流就可以搞定将报名记录按照 final_score 倒序排列然后依次给 rank 字段赋值。成绩发布这里我做了个状态控制比赛进行中选手和教练看不到别人的成绩只能看到自己的临时分数管理员手动点击“发布成绩”之后所有人才能看到完整排名。这个设计在企业级项目里叫“灰度发布”的简化版。它防止了比赛还在进行时后出场选手提前知道分数从而影响心态。这种细节放答辩里讲出来老师会觉得你真的理解了业务。3.4 事务控制与并发防线评分提交、成绩重算这些操作涉及多个步骤必须加事务控制。在 SpringBoot 里就是加一个 Transactional 注解的事。但真正要注意的是一个 update 操作里同时更新多条记录时事务的边界要画对。比如重算排名先要删除该项目中所有选手的旧成绩再重新计算插入新成绩。如果删除成功了插入过程中数据库突然报错没有事务的话比赛成绩就出现“查无此分”的情况了。加上 Transactional 之后要么全部成功要么全部回滚这才是一个靠谱的评分系统该有的底线。并发问题也不能忽视。同一个项目下多个裁判同时提交评分怎么办我在 score 表上加了唯一索引字段组合是 registration_id judge_id event_id这就保证了一个裁判对同一个选手同一个项目只能打一次分。就算两个请求同时到达数据库层面的约束也能挡住不会出现覆盖更新的问题。4. 前端 Vue 设计与交互方案4.1 页面结构与路由设计前端页面不需要太多关键页面就六个左右登录页 /login首页仪表盘 /dashboard展示赛事概况、参赛人数、最新成绩赛事管理页 /competitions管理赛事和项目报名管理页 /registration选手报名与分组评分录入页 /scoring裁判评分界面成绩发布页 /results成绩查询与排名展示路由我用了 vue-router 的动态路由方案根据用户角色在登录后动态添加可访问的路由表。管理员登录后左侧菜单有“赛事管理、用户管理、成绩发布、系统设置”裁判登录后只有“评分录入、我的评分”运动员登录后只有“赛事报名、我的成绩”。这样设计的直接好处是前端也能做到权限控制后端 JWT 校验再加一层双重保险。4.2 评分录入界面的实时计算逻辑评分录入页我强烈建议做成上下两栏布局上栏是当前项目的选手列表点击任意一个选手下栏是评分表单。这个页面有个体现 Vue 优势的点实时计算总分和已录入状态。裁判输入三个维度分之后前端立刻计算总分并显示在界面上。同时如果某个选手已录入过分数列表这一行要打上标记。这些交互看起来不难但如果用 jQuery 写你得手动维护大量 DOM 状态而 Vue 的 computed 属性天然就解决了template div classscoring-panel h3选手{{ currentPlayer.name }} - {{ currentPlayer.teamName }}/h3 el-form label-width100px el-form-item label难度分 el-input-number v-modelscoreForm.difficultyScore :min0 :max10 :step0.1 / /el-form-item el-form-item label艺术分 el-input-number v-modelscoreForm.artistryScore :min0 :max10 :step0.1 / /el-form-item el-form-item label完成分 el-input-number v-modelscoreForm.executionScore :min0 :max10 :step0.1 / /el-form-item el-form-item el-tag :typetotalScore 0 ? success : info 总分{{ totalScore }} /el-tag el-button typeprimary clicksubmitScore提交评分/el-button /el-form-item /el-form /div /template script export default { data() { return { scoreForm: { difficultyScore: 0, artistryScore: 0, executionScore: 0 } }; }, computed: { totalScore() { return Number( this.scoreForm.difficultyScore this.scoreForm.artistryScore this.scoreForm.executionScore ).toFixed(2); } } }; /script注意提交时要校验总分不能超过大赛规定上限一般 IT 项目里的评分都是 10 分制或 20 分制我这边设计的是每项 10 分总分最高 30 分。4.3 axios 封装与接口联调前端接口调用我没直接用 axios 裸调而是封装了一个 request.js统一配置了 baseURL、超时时间、请求拦截器自动携带 token和响应拦截器统一处理 401 跳转登录、错误信息提示。import axios from axios; import { Message } from element-ui; import router from /router; const request axios.create({ baseURL: /api, timeout: 10000 }); request.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers.Authorization Bearer ${token}; } return config; }); request.interceptors.response.use( response { const res response.data; if (res.code ! 200) { Message.error(res.message || 系统异常); return Promise.reject(new Error(res.message)); } return res.data; }, error { if (error.response error.response.status 401) { localStorage.removeItem(token); router.push(/login); Message.error(登录状态已过期请重新登录); } else { Message.error(error.message || 网络异常); } return Promise.reject(error); } ); export default request;这个封装在前后端分离的项目里是标配人手一份。我最想强调的反而是开发环境下代理配置。前后端分离必然存在跨域问题你可以在后端写 CORS 配置但我推荐更简单的方案用 Vue CLI 或 Vite 的 devServer 代理。在 vue.config.js 里配置const { defineConfig } require(vue/cli-service); module.exports defineConfig({ devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } });用代理的话前端代码里所有请求路径都写成相对路径 /api/xxx开发环境和生产环境可以无缝切换不用改任何代码。4.4 成绩展示页的数据刷新方案成绩发布页有一个需求比赛进行中管理员发布了某个项目的成绩裁判或选手端要能及时看到。最简单的方案是前端加一个定时器每隔 30 秒轮询一次接口获取最新数据。这个方案实现简单作为毕业设计完全够用。如果调研了 WebSocket这里其实是一个加分的扩展点管理员发布成绩时用 WebSocket 推送给前端前端收到消息后自动更新页面。这个项目如果引入 WebSocket也就多 100 行左右代码但对你的答辩亮点提升是很大的。我最初实现的也是轮询后来为了写进简历换成了 WebSocket 推送实际体验确实顺滑不少。你可以根据自己的时间安排决定用哪种方案但至少要把轮询机制做到无感体验不然成绩发布了用户还在看旧数据就很减分。5. 项目实操过程与踩坑记录5.1 从零搭建项目骨架的实操流程一套完整跑下来的流程我按顺序写给你第一步创建数据库。在你的 MySQL 里执行CREATE DATABASE aerobics_score DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;utf8mb4 一定要用它才能完整支持中文和特殊符号。以前用 utf8 编码存 emoji 或者部分生僻字会直接乱码血的教训。第二步创建 SpringBoot 项目。在 IDEA 里用 Spring Initializr 创建选择依赖Spring Web、MyBatis Framework、MySQL Driver。注意如果你用 MyBatis 而不是 JPA我记得当初用 JPA 写关联查询挺痛苦后来换回 MyBatis。MyBatis 写复杂 SQL 更顺手而且 XML 文件里调整 SQL 不需要重新编译。第三步准备前端项目。用 Vue CLI 创建推荐选 Vue2对新手更稳妥第三方组件库 ElementUI 的兼容性也最好。虽然 Vue3 ElementPlus 是新方向但你在网上找到的多数评分系统源码例子还在用 Vue2踩坑时更容易查到答案。第四步编写后端实体类、Mapper、Service、Controller。实体类对应每一张表字段类型要和数据库严格对齐尤其 decimal 对应 Java 里就是 BigDecimal。第五步前端页面开发。按“登录→主框架→列表页→表单页”的顺序来做。做登录页时先手动写死一个账号测试登录逻辑通了再接后端。第六步前后端联调。这一步最深坑。最容易出的问题是返回的数据格式不一致后端的 Result 包装类里 jsonKey 是 data前端取的是 content怎么都对不上。建议第一步就统一约定好格式public class ResultT { private Integer code; // 200成功500失败 private String message; // 提示信息 private T data; // 业务数据 }前后端开发前先把这个空接口调通了能省下后面大量不必要的调试时间。5.2 Maven 依赖冲突与版本老掉牙问题SpringBoot 版本不同依赖差异很大。我最早在本地跑的时候因为 pom.xml 里引入了过旧的 jjwt 版本和 SpringBoot 2.7 的安全机制冲突导致启动直接报错。这个很影响心情处理办法说简单也简单用最新稳定版不要从随手找的教程里复制版本号。举个例子jjwt 推荐用 0.9.1 之后的版本dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency但这里有个兼容性问题jjwt 0.9.1 依赖的 JAXB 在 JDK 11 之后被移除了。如果你用的是 JDK 11 以上的版本运行时会报 ClassNotFoundException: javax.xml.bind.DatatypeConverter。解决方案有两个一是引入 JAXB 依赖二是换成更现代的 jjwt 0.11.5 并使用其新的 API。我更推荐后者API 稍微变了一下其实文档很清晰。MyBatis 也经常出这个问题启动时报 Invalid bound statement (not found)也就是 BindingException。90% 的原因是 Mapper 接口和 XML 文件没有正确关联。我检查的顺序通常是XML 文件里的 namespace 是否等于 Mapper 接口的全限定名XML 里的方法 id 是否等于接口方法名mapper-locations 配置是否指向了 XML 所在目录target/classes 目录下编译产物里有没有把 XML 打进去。有个小坑容易踩到把 Mapper XML 文件放在 src/main/java 下Maven 默认不会把 XML 文件打包到 classes 里需要在 pom 里加一段配置让 Maven 把 xml 也当作资源打包。更推荐的方式是放在 src/main/resources/mapper 下避免了这个问题。5.3 中文乱码问题的全套处理方案中文乱码问题前端页面显示“”或者后端口日志里乱码很多项目都会被这个坑绊一下。要分三层检查第一层数据库层面。建库时指定了 utf8mb4建表时也要指定字符集。如果库已经建好了可以用命令行修改ALTER DATABASE aerobics_score CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;第二层连接层面。jdbc 连接串要带 characterEncodingutf8 参数否则 Java 和 MySQL 之间的连接编码不对。注意这里写 utf8 即可因为连接层面 utf8 一般就够用了但在 MySQL 里存储却是 utf8mb4 更保险。第三层SpringBoot 层面。有时候前端传过来的 JSON 是 UTF-8但 Spring 框架层解析时用错编码。可以显式配置server.servlet.encoding.enabledtrue和server.servlet.encoding.forcetrue强制使用 UTF-8。这三层都对齐了中文乱码基本绝迹。5.4 前后端联调常见 401/CORS 报错集锦联调阶段还有两个高频报错我直接按续写下。401 Unauthorized前端所有请求都带了 token但后端拦截器校验时发现解析不出来大概率是拦截器放行路径配置错了把登录接口之外的所有接口都拦截了但请求头里又没带上 token。解决办法是把登录接口、静态资源路径加到 permitAll 里。CORS 跨域报错浏览器 Console 里报 Access-Control-Allow-Origin。这个问题如果你已经用 devServer 代理就不会遇到但有些人直接写后端 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); } }allowedOriginPatterns 在 SpringBoot 2.4 之后要这样写老版本的 allowedOrigins(*) 在带凭证时会被浏览器拒绝也是一个隐藏坑。5.5 性能优化与数据初始化经验别觉得这种小项目不需要优化有几处还是值得做的。第一是列表查询接口要分页运动员上百人时不分页前端渲染会卡。用 MyBatis 的 PageHelper 插件三行代码就能完成分页。第二是创建索引。registration 表的 event_id 字段、score 表的 registration_id 和 judge_id 字段都建议加索引。数据量上来之前感觉不到真有几万条评分记录时全表扫描的耗时差异就出来了。项目部署之后我建议写一个初始化 SQL 脚本把管理员账号、演示赛事、模拟运动员和裁判数据都插入进去。这个不麻烦但对整个项目上手体验帮助很大。别再让老师或者评审自己去找账号去建数据了一进来就能看到完整的赛事和评分信息这种细节会给人“项目完整度很高”的直观印象。6. 常见问题速查与避坑总结6.1 高频问题对照表我把实操中最容易踩中的坑整理成一张速查表方便你直接对照排查问题现象可能原因排查思路启动报错 Unable to connect to databaseMySQL 服务未启动、连接串参数错误先用命令行 / 客户端工具直连测试再检配置文件中文乱码建库字符集不是 utf8mb4 / 连接串缺编码参数按第 5.3 节三层方案逐个排查接口返回 401token 缺失或过期检查登录后是否存了 token、拦截器放行路径接口返回 403当前角色没有访问该接口的权限检查拦截器或注解里的角色判断逻辑BindingExceptionMapper.xml 和接口没正确关联检查 namespace、id、mapper-locations 配置成绩算出来是 0.00前端传的是字符串、后端没做类型转换检查参数类型和 JSON 序列化字段名精度丢失用 double 做除法替换成 BigDecimal指定保留位数这应该是实战里见到的几乎全部异常类型了最后排障时要有先后逻辑别一个地方卡半小时。6.2 让我后悔过的几个设计决策先说第一个最初把 score 表主键设计成自增 ID没有加 registration_id judge_id event_id 唯一索引。结果测试时一个裁判不小心对同一个选手点两次提交生成了两条评分记录最终汇总出来的分数完全不对。后来把这个唯一索引加回去问题立刻解决。在表设计阶段就把唯一性约束想清楚数据可靠性才有保证。第二个把“总分”同时冗余存在 score 表里但没有意识到这会导致数据不一致风险。后来我调整了方案总分由后端根据三个维度分实时计算存储时只存三个维度分。score 表保留 total_score 字段只是为了查询展示方便但所有写入都统一由后端计算后再落库前端不接受 total_score 参数。第三个前端页面一开始没有加表单校验导致负数和超过满分上限的分数都能录进去。后来在前端加了三段校验非空、范围 0-10、最多两位小数。后端同样校验双重保险。6.3 代码结构组织与注释习惯代码结构这块讲真你也别太纠结什么“最佳实践”但包的划分一定要清晰。我落地时用的是这样的结构com.example.aerobics ├── controller # 接口层只做参数接收和结果返回 ├── service # 业务逻辑层事务控制在这里 ├── mapper # MyBatis 接口 ├── entity # 数据库实体类 ├── dto # 前端交互的数据对象避免直接暴露实体 ├── common # 统一返回结果、异常处理、常量 └── config # 拦截器、CORS、WebMvc 配置这里面一个容易被忽视但很重要的点是Controller 层不要堆业务代码。我见过很多项目把评分计算逻辑直接写在 Controller 里看起来“一步到位”结果后面要加日志、要加事务、要加权限校验全都得改这一个方法维护成本极高。把评分计算放在 Service 层Controller 只做参数接收和调用 Service这是一个粗糙但有效分层纪律。注释怎么写别写那种“下面调用XXX方法”的废话注释而是要写清业务规则。比如计算最终得分的方法上面一定要注释“去掉一个最高分和一个最低分后取平均保留两位小数”。这些业务规则别人看代码不一定一下就能懂你写清楚一句比以后面对面解释十句都管用。7. 从课设到作品一些可以尝试的扩展方向我前面说的这些已经能帮一个项目完整交付并顺利结题了。但如果你还有余力下面几个扩展方向值得试试它们对提升技术视野和项目档次很有帮助。方向一接入 Redis 缓存热点数据。例如赛事列表、已发布的成绩单这类读多写少的数据查询时先看缓存命中就直接返回。用 Spring Cache 注解就能实现代码改动量很小但你在简历上能写“引入了 Redis 缓存降低了数据库压力”。方向二引入 WebSocket 实时推送。成绩发布后裁判端和运动员端自动刷新不用手动轮询。实现也不难Spring 里 STOMP 协议支持还是很成熟的。方向三做 Excel 导入导出。赛事报名一般都有大量运动员名单一个一个录入太费时。用 EasyExcel 做个批量导入导出选手信息、报名名单、最终成绩单都能一键生成。这个在真实使用场景里呼声最高。方向四增加系统监控能力。集成 Spring Boot Actuator 和简单的定时任务统计每个项目的平均分、最高分、裁判打分偏差度等数据比赛结束时自动生成一份赛事分析报告。这个方向会让你从“写管理系统的人”变成“理解赛事运营的人”。注意一点扩展功能时不要贪多能做精一个就行。评委或者面试官看到你一个功能想得比别人深比看到十个平平无奇的功能更打动人。8. 写在最后的实操建议做这种评分系统最容易出错的地方往往不是框架配置而是对业务本身的把握不够。你去网上搜同类的健美操评分系统源码最需要检查的点一是评分规则是否真的实现了“去掉最高最低取平均”这类逻辑还是说只是个摆设二是角色权限是否清晰裁判能不能越权三是成绩汇总是不是事务性的中途失败会不会半截话。如果你本身不是特别熟悉健美操比赛的流程我建议你花半小时看一场完整比赛录像留意裁判打分流程、选手出场顺序、成绩公布方式。这些东西都会直接转化为你系统的功能点和答辩素材。懂业务的技术人写出来的代码和只会套模板的差别一眼就能看出来。我在实际开发里面最大的体会是不要一开始就急着写代码。早上半天时间把表结构设计好把评分流程画清楚后面写代码基本顺风顺水。相反如果一上来就先把页面做出来再反推表和接口后面重构的痛苦会翻倍。这个项目本身难度适中但做完整并不容易。它需要的知识点都是现在 Java 岗位日常开发中的高频部分无论你是为了毕业设计过关还是想在简历上多一个能打的项目它都能帮你支撑起比较扎实的一段经历。把上面这些细节吃透你在答辩或者面试时能讲的深度会比大部分同学好一截。