很多大四或者大二大三的朋友第一次接触 Spring Boot 课程设计,面对“运动会平台”这种题目,第一反应往往是:这不就是一个运动员信息增删改查?其实真做起来,运动会平台涉及的角色、流程和数据关系比想象中多一些,从登录认证到报名、成绩录入、排名统计,每一环都能深挖。这篇就围绕一个完整的 Spring Boot 运动会平台项目,把从开发环境搭建到数据库设计,再到核心功能实现和最终部署的全过程拆开讲清楚,看完之后你不仅能复现这个项目,还能理解为什么每个环节要这么设计,写论文、做答辩的时候也有素材可用。
1. 这个运动会平台到底是什么,解决什么问题
先把这个项目定位清楚。这是一个基于 Spring Boot 的传统 Web 管理系统,服务于一所高校的校运动会业务,核心使用方是运动会组织者(管理员)和参赛的运动员(学生),有时候还牵涉到裁判录入成绩。
在没有系统的情况下,校运会怎么运转?报名靠班长统计纸质表,项目安排靠黑板板书,成绩记录用纸质表格,最后排名全靠人工汇总。几十个项目、几百个运动员、几千条成绩记录堆在一起,光是核对名次就能折腾一晚上。运动会平台要解决的正是这些问题:让运动员在线查看比赛项目并报名,让管理员维护运动员信息、项目安排、发布公告,让裁判(或管理员代录)录入成绩后系统自动排序,最终还能按总分汇总团体排名。
从技术栈上看,这个项目选 Spring Boot 是非常典型也极其合理的选择。Spring Boot 在 Java 课程设计中的统治力不需要多解释:自动配置省掉大量 XML 配置,内嵌 Tomcat 让启动只需要一个 main 方法,生态丰富,找资料容易,写论文也有东西可写。而且网上开源案例多,遇到问题搜一下基本都有答案,对不熟悉 Java Web 的同学来说是最稳的路线。
这个平台适合谁来参考?第一类是准备做运动会管理系统的同学,你可以直接把架构和数据表设计拿过去用;第二类是已经在做但功能思路还不清晰的同学,后面讲的功能模块拆解和数据库关系可以帮你理清脉络;第三类是想从课程设计里学到点真东西、不只是抄代码的同学,后面写的原理和避坑经验就是为你准备的。
项目整体模块可以拆成六个部分:登录注册、运动员管理、比赛项目管理、比赛报名、成绩录入与排名、公告管理。外加一个首页统计面板,展示运动员总数、项目总数、报名人次等数据,服务于校领导查看和运动会调度。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 开发环境搭建:从零到能跑起来持续打基础
环境这块是很多新手的第一道坎,装个 JDK、配个 Maven、建个数据库,看着简单,实际操作里处处是坑。我把整个环境准备过程捋一遍,顺便解释每个环境为什么不能跳过。
2.1 JDK、Maven 和 IDE 怎么选
JDK 我强烈建议使用 1.8(也就是 Java 8),不要一上来就装 JDK 17 或 21。原因很现实:Spring Boot 2.x 系列对 Java 8 支持最完美、稳定,学校机房和大部分教程也以 JDK 8 为准,等以后工作了再升级也不迟。JDK 安装完成后,在命令行输入 java -version 能正常输出版本号就说明配好了,这一步很多人漏了配置 JAVA_HOME 环境变量,导致后面 Maven 无法识别。
Maven 是项目构建和依赖管理工具,Spring Boot 项目通过它下载 jar 包,所以必须安装。我建议下载 Maven 3.6.x 或 3.8.x,太新的版本偶尔会和旧项目的插件冲突。设置方面,在 conf/settings.xml 里改两个东西:第一个是本地仓库路径,默认在 C 盘用户目录下,建议改到 D 盘或其它盘,避免 C 盘越装越臃肿;第二个是添加阿里云镜像仓库,国内访问 Maven 中央仓库经常慢到怀疑人生,配了镜像之后依赖下载速度能提升十倍。
IDE 这块没有悬念,用 IntelliJ IDEA。社区版完全够用,不需要付费版。如果你学校强制用 Eclipse,也能做,但体验和插件生态差一截,课程设计阶段没必要为难自己。
提示:Windows 上配置 Maven 后,记得在 IDEA 的 Settings 里手动指定 Maven 路径和 settings.xml 位置,因为 IDEA 默认使用自带 Maven,你改的镜像配置不会被读取。
2.2 项目骨架和核心依赖配置
在 IDEA 里新建 Spring Boot 项目有两种方式,一种是通过 Spring Initializr 在线生成,另一种是直接建 Maven 项目然后手动写 pom.xml。课程设计阶段我建议用第一种,省事。如果在线生成失败(网络原因),再退回手动创建:新建一个 Maven 项目,然后在 pom.xml 中声明 Spring Boot 父依赖。
一个标准的运动会平台 pom.xml 核心依赖应该是这样:
xml复制<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
为什么要 Spring Boot 版本锁定在 2.7.18?这是 2.x 系列的最后一个维护版本,稳定、资料全,配合 MyBatis-Plus 也不会出现版本的诡异冲突。Spring Boot 3.x 虽然新,但要求 JDK 17,很多课程设计项目的教材和服务器环境跟不上,不推荐冒险。
我选 MyBatis-Plus 而不是原生 MyBatis,是因为它对单表增删改查的支持极其友好,内置 BaseMapper 直接给你提供了几十个 CRUD 方法,不用手写一堆 SQL。而运动会系统里大量操作就是基础的单表数据维护,正好匹配。如果你用的还是 SSM 项目那套手写 SQL 的方法,也能做,只是写代码的效率差别比较大。
前端方面用 Thymeleaf 模板引擎,Spring Boot 对它的整合是开箱即用,直接在 src/main/resources/templates 下面放 HTML 文件就能访问,不用单独配视图解析器。页面布局就老老实实用 Bootstrap 4 + 手写 CSS,不要碰太复杂的前端框架,课程设计重点在后端逻辑,前端保持干净清晰即可。
2.3 核心配置文件 application.yml 写法
网上很多教程还在用 application.properties,我推荐用 YAML 格式,层次清楚、不易写错。运动会项目最常见的配置如下:
yaml复制server:
port: 8080
servlet:
context-path: /
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/sports_meeting?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
thymeleaf:
cache: false
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
global-config:
db-config:
id-type: auto
map-underscore-to-camel-case: true 这个配置值得单独说:数据库字段是下划线风格(比如 stu_no),Java 实体类属性是驼峰风格(比如 stuNo),开启这个配置后 MyBatis-Plus 自动完成映射,不用写繁琐的 resultMap。URL 里那个 serverTimezone=Asia/Shanghai 必写,否则连接 MySQL 8 时会出现时间时区相关报错。
password 改成你自己 MySQL 的密码,sports_meeting 是数据库名,要和后面建库的脚本保持一致,不一致就会出现 Unknown database 的启动报错。
3. 数据库设计:运动会的排兵布阵
运动会平台最大的价值不在代码,而在数据。设计好表结构,项目就成功了一半。很多人做系统喜欢所有字段塞一张表,这是最典型的坏习惯,后面改起来想哭。
3.1 核心表结构拆解
运动会系统我设计了几张核心表分别对应不同的业务角色:用户表、运动员表、项目表、报名表、成绩表、公告表。一张一张说。
用户表(sys_user) 管登录认证。字段包括 id、username、password、role、status、create_time。角色分三种:admin 管理员、referee 裁判、student 学生。密码不能用明文,至少要用 MD5 加盐或者 BCrypt 加密存。课程设计阶段 MD5 加个固定盐就可以,但答辩时如果你能说出 BCrypt 更安全,会是一个加分点。
运动员表(athlete) 存运动员基本信息和所属单位。字段有 id、stu_no 学号、name 姓名、gender 性别、college 学院、phone 联系电话、user_id 外键关联 sys_user。gender 建议用 tinyint 存 0 和 1,而不是直接存字符串“男”“女”,这样查询统计更方便。college 字段后续可以按学院分组统计团体总分,非常有价值。
项目表(sport_item) 存比赛项目。字段有 id、item_name 项目名称、item_type 项目类型(径赛/田赛/趣味项目)、match_time 比赛时间、location 比赛场地、limit_num 每个单位限报人数、status 报名状态。item_type 是很有用的一层分类,后面首页统计和成绩分组都要靠它。
报名表(sign_up) 是运动员和项目之间的中间表。字段有 id、athlete_id、item_id、sign_time、status。为什么要单独一张表?因为一个运动员可以报多个项目,一个项目有多个运动员,这是典型的多对多关系,中间表负责解耦。有了这张表,查“某个项目有多少人报名”就是一条 count 语句的事。
成绩表(game_score) 存比赛结果。字段有 id、item_id、athlete_id、score_value 成绩值、score_rank 名次、total_score 获得积分、create_time。根据运动会计分规则,第一名记 9 分、第二名 7 分、第三名 6 分这种,可以直接在录入成绩时算出 total_score。score_rank 和 total_score 在成绩录入后由系统自动生成,避免人工算错。
公告表(notice) 简单一些:id、title、content、publisher、create_time。用于运动会赛程通知、获奖公示。
3.2 表关系的核心设计思路
这几张表的关系画出来一目了然,重要的是理解为什么这么设计:
- 用户表和运动员表是一对一关系。为什么分开?因为用户表管登录认证,运动员表管业务信息,职责不同。以后系统扩展裁判管理、领队管理,各角色信息放在各自业务表里,不会污染用户表。
- 运动员表和项目表多对多,通过报名表连接。这条关系是整个系统的命脉,所有业务查询都要穿过它。
- 成绩表同时关联项目表和运动员表。因为一条成绩记录必须能回答两个问题:比的是什么项目,谁跑的。
- 首页统计比如“某学院总积分”,就是
game_score关联athlete表,按college分组求和total_score。
设计数据库时,我一直推荐一个习惯:在 MySQL 客户端里先用 SQL 创建库和表,跑通了再在代码里用实体类映射,不要在代码里用 MyBatis-Plus 自动建表。自动建表虽然方便,但表结构不受控、字段注释不全,后面写论文和答辩讲表结构时很尴尬,手写 SQL 能保证每个字段都有清清楚楚的注释,论文里的数据字典章节直接照搬就行。
下面给一个项目表创建脚本示例,其余表结构可以按同样思路扩展:
sql复制CREATE TABLE sport_item (
id int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
item_name varchar(50) NOT NULL COMMENT '项目名称',
item_type varchar(20) NOT NULL COMMENT '项目类型:径赛/田赛/趣味',
match_time datetime DEFAULT NULL COMMENT '比赛时间',
location varchar(100) DEFAULT NULL COMMENT '比赛场地',
limit_num int DEFAULT 0 COMMENT '每单位限报人数',
status tinyint DEFAULT 1 COMMENT '报名状态:1开启 0关闭',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='比赛项目表';
ENGINE=InnoDB 和 CHARSET=utf8mb4 是两条硬性规范。InnoDB 支持事务和外键,MyISAM 不支持;utf8mb4 能完整支持中文和表情符号,老旧的 utf8 在存特殊字符时可能有坑。
3.3 给课程设计的一个建表建议
如果你做的是课程设计,建议严格做成“服务层 + 控制层 + 持久层”三层结构,也就是 Controller、Service、Mapper 三件套。注意:出了一个名次字段自动计算的难点,就是报名表的唯一性校验。同一个运动员重复报名同一个项目,在表中会出现两条记录,这是必须避免的。最简单的处理方式是在 sign_up 表给 athlete_id 和 item_id 建联合唯一索引,从数据库层面杜绝重复报名:
sql复制ALTER TABLE sign_up ADD UNIQUE KEY uk_athlete_item (athlete_id, item_id);
再配合代码层先查后插,双保险。我在实际项目中遇到过好几次这类问题:只做了代码判断,两秒内提交两次请求就会绕过去,数据库层的唯一索引是最后的防线。
4. 核心功能模块实现与实操细节
环境搭好了、表建好了,接下来就是实现功能。运动会系统的功能看起来多,实际上每个模块都是增删改查的变体,关键看你有没有把通用方法吃透。
4.1 登录和权限控制
登录是系统的入口,没有登录就不能进入任何业务页面。Spring Boot 里做登录认证有两种常见方案:一是用 Spring Security,安全性和架构更好;二是用拦截器 + Session,简单直接好理解。
课程设计阶段我推荐拦截器方案,理由很现实:Spring Security 的学习曲线陡峭,配置不当会出现资源放行问题,或者方法权限注解不生效之类的坑,折腾半天和它斗智斗勇。用拦截器加 Session,几十行代码就搞定了。
登录流程大致是这样:用户提交用户名密码,Service 层查库校验,密码验证通过之后把用户对象放进 Session,然后跳转到系统首页。同时写一个 LoginInterceptor 实现 HandlerInterceptor 接口,在 preHandle 里判断有没有登录 Session,没有就直接重定向到登录页。注册到配置类时把静态资源和登录接口放行掉,这样静态的 CSS、JS 文件才能正常加载。
登录之后还有一个细节:不同角色看到的菜单不同。管理员看到“运动员管理、项目管理、成绩管理”全套菜单,裁判只看到成绩录入模块,学生看到报名模块和自己的成绩。这个可以用 Thymeleaf 的 sec 标签,或者更简单地在模板里根据 Session 角色判断显示哪些菜单项。别小看这个细节,答辩时提到“基于角色的菜单控制”能加分不少。
4.2 运动员管理和项目管理的通用套路
运动员管理是标准的单表 CRUD,用 MyBatis-Plus 写起来非常快。Service 接口继承 IService<Athlete>,实现类继承 ServiceImpl<AthleteMapper, Athlete>,然后 Controller 里注入 Service,调用 .list()、.page()、.save()、.updateById()、.removeById() 就完成了大部分功能。
这里我想重点讲讲分页查询。很多同学做列表页喜欢一次查出所有数据,浏览器端再分页,这个方案数据量小的时候无所谓,但数据量一大就卡。正确做法是后端分页,MyBatis-Plus 提供了 PaginationInnerInterceptor,配置一下就能用:
java复制// 配置 MybatisPlusInterceptor
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
然后 Service 层直接这样查:
java复制Page<Athlete> page = athleteService.page(new Page<>(current, size), queryWrapper);
Page 对象返回的 records、total、current、size 直接给前端用,再也不用手算分页偏移量了。课堂上学 SSM 时手动 limit 分页那种痛苦,用 MyBatis-Plus 之后彻底告别。
项目管理的实现思路和运动员管理几乎一样,只是多了一个“报名状态”字段的控制:报名阶段开启时,学生才能报名;报名截止后,状态置 0,前端按钮置灰。这个状态字段用 tinyint 存,读取时通过下拉框选择再更新,操作逻辑非常清晰。
4.3 比赛报名与成绩录入这两个关键流程
报名模块是整个系统中最能体现业务逻辑的部分。学生登录后进入“可报名项目”列表,系统要过滤出两类:一类是报名状态开启的,另一类是该学生未报名的。报名操作执行前,还要检查性别限制和限报人数,比如“男子 100 米每单位限报 2 人”,用户必须是男性且该单位报名人数未满。
这部分逻辑写起来不难,但容易遗漏,强烈建议把所有校验逻辑抽成一个独立方法,比如叫 checkSignUpCondition(athleteId, itemId),返回校验结果信息。这样做的好处一是有条理,二是写论文的时候可以重点展开讲“业务校验流程设计”。
成绩录入模块设计要注意一点:录入的表单里,项目是固定的,运动员需要从已报名名单中选择而不是从全体运动员中选择。也就是说裁判录成绩只能在“该项目已报名”的运动员范围内录,不能随便录一个没报名的人。这个在实际操作中很容易踩坑,很多人图省事直接拿全体运动员下拉框做,然后就出现了“没参赛的人有成绩”的尴尬数据。
成绩录入后要触发排序和积分计算。我的建议是写一个 rankScore(itemId) 方法,当某个项目的所有成绩录入完成后手动触发或者新增成绩时自动触发:查询该项目所有成绩按值排序,依次给 score_rank 赋 1、2、3……,再根据对应名次更新 total_score。
注意:成绩值单位要格式统一,比如 100 米用“秒”并精确到小数点后两位,跳远用“米”。这里我踩过一个坑:不同录入者有的填“11.2”有的填“11.21”,排序时 11.2 会被当作 11.20 还是 11.2?在 Java 的
BigDecimal里比较没问题,但存数据库用 decimal(5,2) 才能保证精度一致,这个细节应该在表设计时就考虑清楚。
4.4 公告管理和首页统计
公告管理没什么高深的,就是公告表的 CRUD,在前端按时间倒序展示。需要注意的是内容可能带格式,直接展示时注意 XSS 转义问题,不能把用户输入的内容原样渲染成 HTML,否则存在安全问题。Thymeleaf 默认会对文本内容转义,在没有引入额外富文本组件的情况下问题不大。
首页统计很有意思。它要把整个系统的价值直观地呈现出来:总报名人数、各项目报名人数、各学院获得的总积分排名。这些统计全部是 SQL 分组聚合操作,例如:
java复制// 查询各学院总积分排名
List<Map<String, Object>> collegeRankList = gameScoreMapper.selectCollegeScoreRank();
对应的 XML 映射文件里写一句 left join 加 group by 就能查出来。很多课程设计到这一块就缩水了,只放一个静态欢迎页。我的建议是把这个统计页认真做出来,它既直观体现系统效果,又是论文图表素材的重要来源,答辩时打开首页一个个数字讲,比空口白话有说服力得多。
5. 调试部署实战:让系统真正跑起来
很多人写到代码能跑就算了,其实调试部署是课程设计应该重点展示的加分能力。这个环节也是实际中最容易反复出问题的地方,我按我自己的部署顺序把这部分讲透。
5.1 本地启动常见报错及处理
环境准备好以后,点击启动类的 main 方法,项目开始启动,控制台刷日志,整个过程看着挺顺利,但总有几类高频问题等着你。
端口被占用。 如果控制台报 Port 8080 was already in use,说明 8080 被别的进程占了。常见来源是之前启动过没关掉的 Java 进程,或者本地跑着其它服务。最简单的处理是改端口:在 application.yml 里把 server.port 改成 8081 或 8090,重启就行。想保留 8080 的话,可以用命令行查进程并杀掉:
bash复制netstat -ano | findstr 8080
taskkill /pid 进程号 /f
Windows 下这两个命令够用,macOS 或 Linux 用 lsof -i:8080 查。
数据库连接失败。 控制台出现 Cannot create PoolableConnectionFactory 或者 Access denied for user,第一反应就是检查三件事:数据库名是否存在、用户名密码是否正确、MySQL 服务有没有启动。这三个问题占了数据库连接失败的九成。我见过太多同学改了 application.yml 的库名,但实际 MySQL 里没建对应的库,启动时当然连不上。先执行 use sports_meeting; 看能不能切库,是最直接的验证方法。
表不存在报错。 如果项目能启动但请求某个接口时报 Table 'sports_meeting.sys_user' doesn't exist,那基本可以断定没有导入 SQL 脚本。在课程设计项目里,数据库脚本文件通常放在项目根目录,名字类似 sports_meeting.sql,找到后在 MySQL 客户端或 IDEA 自带的 Database 面板直接执行即可,注意先选中目标数据库再执行。
白标错误页 Whitelabel Error Page。 Spring Boot 遇到 404 或其它未处理异常时,默认显示白底黑字的提示页。出现这个页不是你系统坏了,而是路径没匹配上控制器。排查思路:看控制台完整异常信息,确认访问路径和 Controller 里的 @RequestMapping 是否对应,有没有多一层上下文路径前缀。比如控制器里写了 /api/xxx,你访问的时候忘了加 /api,自然就是 404。
Bean 依赖注入失败。 启动时如果报 Field xxxService in xxxController required a bean of type 'xxxService' that could not be found,就四件事逐项检查:Service 接口对应的实现类有没有加 @Service 注解;实现类有没有用 @Autowired 正确注入 Mapper;Mapper 接口有没有加 @Mapper 注解或者被 @MapperScan 扫描到;ServiceImpl 有没有继承 ServiceImpl<XxxMapper, Xxx> 导致泛型写错。这个报错解决一次之后基本就全会了,本质是 Spring 容器里没有对应对象。
5.2 打包部署:从 IDEA 到可执行 jar
本地跑通之后,最终交付时最好打成 jar 包让它在任意环境直接运行。Spring Boot 的打包基于 Maven,完成打包前需要确认 pom 里没漏了 <build> 插件配置:
xml复制<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
这个插件是 Spring Boot 项目能打出可执行 jar 的关键,它会自动把内嵌 Tomcat 和所有依赖一并打包进去。打好的 jar 是一个“胖包”,里面有一切运行环境,可以潇洒地在命令行执行:
bash复制mvn clean package
java -jar target/sports-meeting-0.0.1-SNAPSHOT.jar
如果打包过程很慢,通常是 Maven 在下载插件依赖,配置了阿里云镜像后基本不会卡太久。jar 包启动成功后,访问 http://localhost:8080 就能看到系统首页。
部署到服务器时有一个额外注意点:项目配置文件里数据库地址不能还是 localhost,要改成服务器的内网地址或者公网地址,账号密码也要对得上。如果你没有独立服务器,用一台闲置电脑充当本地服务器也能演示,不少同学的课程设计答辩就是这么跑的。
5.3 部署前必做的三件检查
交付部署之前,强烈建议做一轮自检,这些都是实际评分和演示时的关键场景:
一是初始化数据检查。默认管理员账号密码要在文档里写清楚,让评委或者老师拿到系统之后直接用管理员登录就能看到全功能界面,而不是进去一张空表,还得自己手动注册。
二是中文乱码检查。前后端编码不统一时,可能数据库存的中文乱码。解决思路就是保证四层编码一致:数据库 utf8mb4、JDBC URL 配置 characterEncoding=utf8、页面 Content-Type 的 meta 标签声明 utf-8、代码文件保存编码 utf-8。逐一排查基本能解决。
三是跨模块链路检查。走一遍完整流程:管理员建项目、开启报名,学生注册登录报名,裁判录成绩,系统自动排排名,首页统计更新。整个链路只要有一个环节报错,都要尽快修好,因为答辩现场最怕的就是演示到一半页面崩了,尴尬不说还会影响心态。
6. 常见问题与排查技巧实录
这部分我从项目的实操出发,把运动会平台中最常见的问题堆成一张速查表,你遇到类似情况可以按表索骥。
| 症状 | 原因 | 处理方式 |
|---|---|---|
| 启动即报端口被占用 | 8080 被其它进程占用 | 换端口或 taskkill 结束占用进程 |
| 连接数据库公钥检索失败 | MySQL 8 与连接驱动兼容性问题 | 在 JDBC URL 加 allowPublicKeyRetrieval=true |
| 时间字段显示乱码或差 8 小时 | 时区不一致 | URL 配置 serverTimezone=Asia/Shanghai |
| 保存中文变成问号 | 库表字符集非 utf8mb4 | 建表时明确 CHARSET=utf8mb4 |
| 列表页样式全乱 | 静态资源被拦截或路径不对 | 放行静态资源并检查 thymeleaf 路径 |
| 无法录入成绩,报外键错 | 运动员未报名该比赛项目 | 先完成报名流程再录入成绩 |
| 登录成功后刷新就退出 | Session 失效或 cookie 未正常工作 | 检查 Session 配置及拦截器放行逻辑 |
除了表里这些,我再分享三个容易踩、但资料上很少写明白的细节。
第一个是 MyBatis-Plus 的字段自动填充。创建时间和更新时间这类通用字段,如果每个 Service 都手动 setCreateTime(new Date()),代码会非常啰嗦。可以用 MetaObjectHandler 实现自动填充,然后在实体类的 createTime 字段上加上 @TableField(fill = FieldFill.INSERT)。答辩时提到“通用字段自动填充”是很好的架构意识体现。
第二个是 SQL 日志打印。开发阶段强烈建议打开 MyBatis-Plus 的 SQL 日志输出,在 application.yml 里加一行日志级别配置:
yaml复制logging:
level:
com.example.sportsmeeting.mapper: debug
这样控制台会把执行的每一条 SQL 都打印出来,排查数据查不到、关联查错这类问题时无比高效。到了部署阶段再关掉,避免日志膨胀。
第三个是 ftp 下载或图片上传相关,运动会的文化展示和风采展示板块如果加了照片上传功能,务必限制文件类型和大小,并做文件存储路径的独立配置。不然收到一个超大文件或者恶意脚本,轻则系统卡死,重则直接被打穿。课程设计阶段如果确实没有这类需求,不加这个功能反而省心,不要为了凑模块把安全问题带进来。
关于“带论文文档”这部分,我以过来人的身份说一句:论文不是代码的说明书,而是设计思路的表达。运动会平台这个题目写论文,核心章节可以这样组织:绪论讲背景和意义;需求分析画用例图、定角色和功能清单;系统设计给架构图、功能模块图和数据字典;系统实现把核心功能的页面截图和关键代码放上去;测试部分写功能测试用例表和部分性能分析。一万字不难写,数据字典、测试用例这些表格填满之后,核心内容基本就到六千字以上,再加上前言、总结和参考文献,达标是水到渠成的事。
我个人在这个项目上踩过最深的坑,是早期把所有通用方法都堆在 Controller 里,一个方法几百行,后面加需求简直没法维护。后来老老实实按照 Controller 薄、Service 层厚的标准重新组织,每个功能对应 Service 的一个方法,代码结构立刻清爽了,后面加功能、写测试都顺畅很多。如果你做这个项目时也感觉到代码乱,第一反应别是硬着头皮往下写,先停下来理一理分层,收益会大得多。
最后分享一个小技巧:把所有配置里能抽的都抽到常量类或配置项里,比如默认页码大小、系统名称、计分规则里各名次对应的分数值。计分规则如果写死在代码里,以后运动会赛制改成第八名也有积分,你就要翻代码找半天。“名次转积分”这映射用一张 Map 常量存起来,改的时候只动一处,这不仅是代码整洁度问题,是实际维护里能省时间的细节。等你们真正接手一个老项目改需求时,就会明白这类细节有多香了。
