毕设选到 springboot 管理系统类题目的同学,估计占了计算机毕业设计的大半。这个“springboot 咸阳市隔离人员管理系统”,名字看起来像地区定制项目,但剥掉外壳,就是典型的“人员 + 场所 + 流程 + 报表”一体化闭环系统。我完整带过几届学生做类似题目,从环境准备、数据库设计、核心模块编码一直跟到答辩演示,中间踩过的坑非常多。今天把整套实现思路和实操细节复盘出来,给你做毕设的时候直接当参考,看这篇就够用了。
这类系统在毕业设计里热度高是有原因的:业务规则容易讲清楚,模块边界明确,又能覆盖 SpringBoot、MyBatis Plus、Redis、JWT、Vue 前后端分离等主流技术,工作量好控制,也方便在答辩时把亮点讲透。标题里的“咸阳市”只是业务范围上的限定,代码层面和普通隔离点管理平台没有本质区别,换一个地区名、甚至换一套业务对象,骨架都能复用。
1. 项目需求拆解:隔离人员管理系统到底在管什么
很多人看到“隔离人员管理”就以为只是增删改查,直接建一张表开始写 Controller。这样做到一半必定改需求,因为整个业务并不是“管一个人”那么简单,它要覆盖人员进入场所后的完整生命周期,任何一环缺失,系统都不成立。
1.1 先梳理核心业务链路,再谈功能模块
这个题目背后最核心的一条业务线是人员从登记进点、安排房间、日常健康监测到解除观察离点的全过程管理。以这套链路为骨架,用户的真实需求基本集中在以下几个环节:
- 进点时,工作人员需要快速登记人员基本信息,包括姓名、证件号、来源地、联系电话、进入日期等;
- 登记后要安排房间,这里牵扯到房间的状态维护,哪些房间空闲、哪些已经有人、哪些需要消毒后重新开放;
- 入住期间,每日要记录体温、症状表现、检查结果等健康信息,发现异常要能快速预警;
- 管理人员需要实时看到当前点内总人数、可用房间数、异常人员数等统计指标;
- 人员满足条件准备离点时,要走解除登记流程,同时保留历史分配记录方便追溯;
- 系统还需要有公告通知、系统用户管理等功能,方便不同角色协同使用。
按这个流程拆出的模块大致如下表:
| 功能模块 | 核心业务 | 对应角色 |
|---|---|---|
| 系统登录与权限 | JWT认证、用户角色控制 | 所有用户 |
| 用户管理 | 管理员、工作人员账号维护 | 系统管理员 |
| 人员信息管理 | 登记、查询、编辑、批量导入导出 | 工作人员 |
| 房间管理 | 房间可视化、状态维护、楼栋区域划分 | 工作人员 |
| 分配管理 | 入住分配、调房、解除分配 | 工作人员 |
| 健康记录管理 | 每日体温症状登记、异常标记 | 医护/工作人员 |
| 数据统计报表 | 人员状态统计、健康趋势、房间利用率 | 管理员/工作人员 |
| 公告通知 | 发布、置顶、查看 | 所有用户 |
1.2 为房间和设备做一次合理抽象
做人员管理时容易被忽略的一点是:业务逻辑不是围绕人单独转,人是依附在房间和区域上的。如果没有“房间”这个中间实体,所有人员只能存一个字符串房间号,到时候查“三号楼二层有多少人”“哪个房间目前空着”都得靠 Java 代码在内存里遍历,既慢又容易出错。
所以我建议在做数据库设计时,把区域、楼栋、房间做成独立维度,房间表里维护一个状态字段:空闲、占用、待消毒。用户界面可以按区域和楼栋去筛选,后端只需要做关联查询即可。这点做得好,整个系统在答辩时会让老师觉得你对业务有真正理解,而不只是在拼 CRUD。
1.3 为什么我建议用 SpringBoot 单体项目,不碰微服务
这是每年都会被学生问到的问题:能不能用 SpringCloud?能不能拆成多个服务?我的建议很直接:毕设周期内,除非你的题目本身就叫“微服务架构的XX平台”,否则不要主动去碰分布式。
原因有三方面。第一,这类管理系统的并发量和使用人数有限,单体应用配合 Redis 缓存已经能撑住演示和论文所需的一切性能指标;第二,微服务会带来服务注册、配置中心、网关、链路追踪、分布式事务等一系列额外复杂度,写出 Bug 后排查成本远高于单体;第三,答辩时间有限,用 SpringBoot 单体反而能让你把自动装配原理、事务控制、缓存策略这些点讲深。把单体的每个细节做扎实,比堆砌十几个只写了一个 hello 接口的微服务要有说服力得多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与工程初始化:前期不返工,后期才省心
技术选型这步是整个毕设的地基。地基打偏了,后面边写边改非常痛苦;选对了,照着文档和现成案例就能推进。
2.1 核心版本矩阵:SpringBoot 版本不是越新越好
很多同学喜欢一上来就下载最新的 SpringBoot 3.x,结果发现 JDK 版本不匹配、旧教程里的配置全部失效、本地环境怎么都跑不起来,最后折腾两天又退回老版本。SpringBoot 选型有一条很朴素的准则:毕业设计要追求稳定,而不是追求新特性。
我推荐使用 JDK 1.8 + Spring Boot 2.7.18 + Maven 3.6+ 的组合。为什么停在 2.7?因为 SpringBoot 2.7 是 2.x 时代的长期维护版本,对 JDK8 兼容最稳;SpringBoot 3 开始强制要求 JDK17 以上,很多实验室电脑、旧教学案例都还停留在 JDK8 环境,为了一个功能升级就把运行门槛抬高,并不划算。
MyBatis Plus 也建议使用 3.5.3 以上版本,新版本对分页插件、代码生成器的 API 更规整,遇到问题能搜到的新方案也更多。前端如果是 Vue2 熟练就选 Vue2 + Element UI,如果手上现成模板是 Vue3 + Element Plus,也可以直接沿用,毕设场景两者差别不大。
| 组件 | 推荐选型 | 选型理由 |
|---|---|---|
| JDK | 1.8 | 兼容性最好,学习资料最多 |
| SpringBoot | 2.7.18 | 2.x 维护版,稳定不折腾 |
| ORM | MyBatis Plus | 内置分页、代码生成器,省时间 |
| 数据库 | MySQL 5.7 / 8.0 | 免费、资料全、安装快 |
| 缓存 | Redis 5+ | 存 Token、缓存统计报表 |
| 认证 | JWT + 拦截器 | 轻量、面试常考、代码可控 |
| 前端 | Vue2 + Element UI | 后台管理模板多,上手快 |
| 接口文档 | Springfox / knife4j | 自动生成,方便自测与演示 |
创建一个标准 SpringBoot 项目时,我一般直接用 IDEA 内置的 Spring Initializr,或者在 start.spring.io 上生成后导入。生成时勾选 Web、MySQL Driver、Redis、Validation 这几个依赖,至于 MyBatis Plus、JWT、EasyExcel 这类第三方库,后面在 pom.xml 里手动加就行了,官网模板更新速度往往跟不上供应商版本。
2.2 包结构这样分层,写起来不拧巴
很多毕设代码最大的问题是所有类都堆在 controller 包下面,业务逻辑写在 controller 方法里。短期看是省事,等到要加权限拦截、复用某个查询逻辑时,才发现根本没法下手。
推荐按下面这种结构组织后端工程:
text复制com.example.isolation
├── common // 通用类:返回结果R、异常处理、常量
├── config // 配置类:MyBatis Plus分页、Cors、WebMvc
├── controller // 接口层:接收参数、返回结果
├── service // 业务层:核心业务逻辑
│ └── impl
├── mapper // 数据访问层
├── entity // 数据库实体
├── dto // 接收前端参数的封装对象
├── vo // 返回给前端页面的封装对象
└── utils // 工具类:JWT、日期处理等
entity 层直接映射数据库字段,dto 用来接收前端提交的数据,vo 用来聚合多表查询结果返回视图层。比如新增人员时,前端传的 PersonAddDTO 和数据库表结构并不完全一致,可能需要校验身份证格式、接收来源地编码;返回给前端展示时,可能还要带房间号、区域名称甚至最近健康记录,这些通过 VO 组装最合适。
Common 包里的统一返回体 R 是所有接口的数据外壳。我习惯封装成 code、msg、data 三段结构,code 为 200 表示成功,非 200 表示失败。再配一个全局异常处理器,把业务异常、参数校验异常、未知异常分别捕获,避免把堆栈信息直接暴露给前端页面。
2.3 把 SpringBoot 自动装配原理顺手搞懂,答辩就稳了
讲到 SpringBoot,老师基本必问“自动装配是怎么实现的”。这个问题不用背八股,核心就是三个注解的组合理解。
@SpringBootApplication 实质上由 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 三个注解组成。其中 @EnableAutoConfiguration 会通过 AutoConfigurationImportSelector 这个类,去读取依赖 jar 包中 META-INF 下的自动配置文件,把里面声明的配置类按条件加载进 Spring 容器;@ComponentScan 则负责扫描启动类所在包及其子包下带有 @Component、@Service、@Controller、@Repository 这些注解的类。
比如 SpringBoot 整合 Redis,只要我们在 pom.xml 里引入了 spring-boot-starter-data-redis,启动时 RedisAutoConfiguration 就会被自动加载;它通过 @ConditionalOnClass 判断类路径下是否存在 RedisTemplate 相关类,满足条件就自动创建连接工厂和模板对象。如果类路径上没有这个 starter,自动配置就不会生效,整个过程对开发者透明。把这条链路理解清楚,后面调任何“自动配置不生效”的 Bug 都更容易。
3. 数据库设计:系统稳不稳,看表拆得细不细
数据库设计是这类管理系统最容易决定成败的地方。表太少,业务状态都靠 Java 代码硬编码维护,边写边补字段;表太多且外键冗余,又会让关联查询复杂化。下面这套表结构我实际用在多个类似项目上,改动很小就能跑通完整业务。
3.1 先建一个轻量 RBAC 用户权限模型
系统至少需要系统管理员和普通工作人员两类角色,管理员维护人员账号,工作人员处理日常业务。很多教程会推荐直接用 Shiro 或 Spring Security 做权限,但对这个毕设来说,一套简单的“用户-角色-菜单”关系就够了。
用户表 sys_user:id、username、password(BCrypt 加密)、real_name、role_id、status、create_time。角色表 sys_role 可以做得很轻,只有 id、role_code、role_name 三个字段。功能权限方面,如果不想做复杂的动态路由控制,只需要在用户登录时把角色标识写进 Token,前端根据角色去控制页面按钮显隐即可。
不要把菜单权限表做得太夸张,否则工作量全耗在权限管理模块自身,而业务模块还没开始写。毕设的核心是“隔离人员管理”,不是“写一个通用权限框架”。
3.2 业务主表:人员、房间、分配记录、健康记录
下面这几张表是整个系统的核心,字段足够满足需求又不会过度设计。
人员信息表 isolate_person:
sql复制CREATE TABLE isolate_person (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
person_no VARCHAR(32) NOT NULL COMMENT '编号',
name VARCHAR(64) NOT NULL COMMENT '姓名',
id_card VARCHAR(18) NOT NULL COMMENT '证件号',
gender TINYINT COMMENT '性别 0女 1男',
phone VARCHAR(20),
source_address VARCHAR(255) COMMENT '来源地址',
enter_date DATE COMMENT '进入日期',
leave_date DATE COMMENT '离开日期',
status TINYINT DEFAULT 0 COMMENT '0待分配 1在点 2已解除 3异常转出',
room_id BIGINT COMMENT '当前房间id',
create_time DATETIME,
update_time DATETIME
);
房间表 isolate_room 要区分区域和房间状态:
sql复制CREATE TABLE isolate_room (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
building_name VARCHAR(64) COMMENT '楼栋',
floor_no INT COMMENT '楼层',
room_no VARCHAR(32) COMMENT '房间号',
capacity INT DEFAULT 2 COMMENT '最多容纳人数',
status TINYINT DEFAULT 0 COMMENT '0空闲 1占用 2待消毒',
create_time DATETIME
);
分配记录表 allocation_record 用来记录每次入住、调房、解除的历史,方便追溯:
sql复制CREATE TABLE allocation_record (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
person_id BIGINT NOT NULL,
room_id BIGINT NOT NULL,
allocate_time DATETIME,
release_time DATETIME,
remark VARCHAR(500)
);
健康记录表 health_record 用来记录每天的体温和症状:
sql复制CREATE TABLE health_record (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
person_id BIGINT NOT NULL,
record_date DATE NOT NULL,
temperature DECIMAL(4,1),
symptom VARCHAR(500) COMMENT '症状描述',
is_abnormal TINYINT DEFAULT 0 COMMENT '0正常 1异常',
create_time DATETIME,
UNIQUE KEY uk_person_date (person_id, record_date)
);
另外再搭配公告表 notice_info、操作日志表 operation_log,整个系统的数据基础就差不多了。核心思路是把“分配记录”和“人员当前状态”分开,人员表只存当前所在房间,历史流转存在分配记录表里。这样无论什么时候点进某个人的详情页,都能看到他曾经住过哪个房间、何时入住、何时解除。
3.3 状态流转和防止并发分配的设计
这系统业务上最容易出 bug 的是一个房间同时在住两个人的问题。要避免这种状况,不能只靠 Java 代码里先查再改,因为两个请求同时读到“房间空闲”,就可能同时分配出去。
可靠的做法是在房间表增加乐观锁或状态条件更新。执行分配时用类似这样的 SQL:
sql复制UPDATE isolate_room
SET status = 1
WHERE id = #{roomId} AND status = 0
update 返回的受影响行数为 1,说明抢锁成功,可以继续插入入住记录;如果返回 0,说明房间已经被其他请求占用,直接向前端返回“房间已被分配”。把并发控制下沉到数据库更新语句,比在 service 层加 synchronized 可靠得多。
人员状态同样要做约束:人员在待分配状态下才能分配房间;已解除状态下不能再次提交健康记录。这些校验写成独立方法,在 service 入层统一检查,不要在每个 controller 里复制粘贴。
4. 后端核心模块实现:把每一块写明白,讲清楚
4.1 登录认证采用 JWT + 拦截器,足够又能讲透
登录模块是所有后台系统绕不开的部分。毕设场景里我不推荐一上来整合完整的 Spring Security + OAuth2,那样光是过滤链配置就能耗掉大半周。更实用的方案是 JWT 生成 Token,配合一个拦截器做身份校验,再在需要角色限制的接口上用注解或简单判断控制权限。
用户登录成功后,后端根据用户 id、用户名、角色创建一个 Token 返回给前端,同时把 Token 存入 Redis 并设置过期时间。后续请求在请求头里带上 token,拦截器解析 Token、判断 Redis 中是否存在、再放行到对应接口。
JWT 工具类核心方法如下:
java复制public class JwtUtils {
private static final String SECRET = "your-secret-key-change-me";
public static String createToken(Long userId, String username, String role) {
return Jwts.builder()
.setSubject(username)
.claim("userId", userId)
.claim("role", role)
.setIssuedAt(new Date())
// Token 有效期 24 小时
.setExpiration(new Date(System.currentTimeMillis() + 86400000))
.signWith(SignatureAlgorithm.HS256, SECRET)
.compact();
}
public static Claims parseToken(String token) {
return Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
}
}
拦截器里要做三件事:检查请求头是否带 token、解析 token 是否合法、将用户信息放入 ThreadLocal 供后续业务使用。对于登录接口、Swagger 文档地址、静态资源路径要直接放行,否则前端还没进入登录页就被 401 拦住了。
这里特别提醒一个坑:集成 Swagger 以后,如果不放行 /swagger-resources/**、/v2/api-docs、/webjars/** 这几个路径,接口文档页面能打开但看不到任何接口信息,新手很容易误以为项目没配置成功。处理方式是在拦截器注册时把这些路径加进白名单。
4.2 人员登记与批量导入:Excel 导入导出提升“工作量感知”
如果说纯手工新增人员是及格水平,那“一键批量导入”绝对能让整个项目的完成度上一个台阶。实际上这类系统在真实使用中不可能让工作人员几百人一个个手敲录入,大部分时候都是拿 Excel 表格批量导入。所以这个功能不是花架子,而是贴合真实业务需求的一个点。
导入使用 EasyExcel 实现非常方便。先定义一个 PersonImportDTO,字段上加 EasyExcel 的 @ExcelProperty 注解指定列名,再写一个监听器继承 AnalysisEventListener,在 invoke 方法里逐行校验数据并封装成实体。全部读取完成后,用批量插入方法一次性写入数据库。
导入前要做两类校验:一类是基础必填项校验,证件号不能为空;另一类是重复性校验,同一证件号在人员表中如果已存在且状态还未解除,就不能再次导入,要给出明确的错误行号和数据。不要等库里出现大量重复数据才意识到没做校验。
导出的思路则是把人员列表查询条件传给 service,查询结果映射成导出 VO,然后用 EasyExcel 的 write 方法输出到 HttpServletResponse 输出流。设置好响应头 Content-Disposition 后,前端直接访问这个接口就能下载文件。
4.3 房间分配与事务:三步操作缺一不可
房间分配这个动作必须保证原子性。service 方法上加 @Transactional,内部执行三步:查到空闲房间对应行并尝试条件更新占用;往分配记录表插入一条入住记录;更新人员表当前房间 id 和状态为在点。任何一步失败,前面已更新的数据都要回滚。
伪代码思路如下:
java复制@Transactional(rollbackFor = Exception.class)
public void assignRoom(AssignDTO dto) {
// 1. 校验人员和房间状态
Person person = personMapper.selectById(dto.getPersonId());
if (person == null || person.getStatus() != 0) {
throw new BusinessException("当前人员不可分配");
}
// 2. 条件更新抢占房间
int updated = roomMapper.updateStatusById(dto.getRoomId(), 0, 1);
if (updated == 0) {
throw new BusinessException("房间已被占用,请刷新后重试");
}
// 3. 插入分配记录、更新人员状态
allocationRecordMapper.insert(...);
person.setRoomId(dto.getRoomId());
person.setStatus(1);
personMapper.updateById(person);
}
这里有几个隐藏细节。第一,条件更新使用的是“原状态=0”作为条件,在 MyBatis Plus 中要写自定义 SQL,不能依赖 updateById 的乐观锁字段,因为房间表通常没有 version 字段,直接按条件更新更直观。第二,不同房间有不同容纳人数,分配前需要查一下 room.capacity 和当前已住人数,避免超员。第三,如果业务支持一人分配多天和自动释放,需要加一个定时任务去扫描到期记录,但毕设手工释放也足够,可以作为扩展点提一句。
4.4 健康记录与统计报表:少一点“假大空”,多一点可视化
健康记录的提交页要控制当天只能提交一次,这里数据库层的兜底手段就是 health_record 表唯一的联合索引 person_id + record_date。后端提交时也要先查一次,提示“今日已提交,可修改不可重复新建”。
统计报表板块是很多毕设做得水的地方,最常见的问题是在前端写死几个图表数字,老师随便点一下数据根本对不上。正确的做法是后端提供统计接口,数据完全从数据库聚合而来,比如:
- 当前人员状态分布:按 status 分组 count;
- 每日新增人数趋势:按 enter_date 分组统计;
- 房间利用率:统计 room.status = 1 的数量占总房间数比例;
- 健康异常记录数:按日期查询 is_abnormal = 1 的数量。
这些统计直接用 MyBatis 写 group by 查询就能出结果。如果数据量变大、查询变慢,可以先用 Redis 缓存结果,每天第一次请求查库后写入缓存,后续请求直接读缓存,这部分优化在论文里能当性能亮点来写。
5. 前端页面与前后端联调:把后台界面做到“演示能打”
5.1 Vue 工程搭建与请求封装
前端我习惯用现成的 Vue 后台管理模板,例如 vue-element-admin 或者经过精简的若依前端。直接用模板可以省去路由、导航栏、登录页这些基础工作,把精力花在业务页面上。
工程内部的核心封装是 axios 请求拦截器和响应拦截器。请求拦截器从 localStorage 中取 token 并加到 Authorization 请求头;响应拦截器判断 code,code 为 200 直接返回 data,401 则清除本地登录状态并跳回登录页,其他错误码通过 Element UI 的 Message 组件弹出后端返回的错误信息。
开发环境下跨域问题的处理方式是使用 Vite 或 Webpack 的 proxy 代理。以 Vite 为例,在 vite.config.js 里配置:
js复制server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
前端所有请求写 /api/login 这种相对路径,代理把请求转发到后端 8080 端口,就不需要后端额外配置 CORS 了。如果后端也要支持非代理方式访问,再单独配一个 CorsFilter 放行指定域名即可。
5.2 核心页面的设计与交互细节
隔离人员管理页面建议使用表格形式展示,顶部筛选条件包含姓名、身份证号、状态、入住日期区间。表格列除了基础字段,还要展示当前房间号,并用 tag 标签显示人员状态:待分配显示黄色、在点显示蓝色、已解除显示灰色。
新增和编辑操作不要跳转单独页面,直接在表格上弹 dialog 表单,用户体验更连贯。房间分配可以做成一个独立弹窗:左边展示可用房间表格,按楼栋-楼层-房间号三级展示,点击选中后再点确认分配。如果房间数多,加一个搜索框和状态筛选。
首页统计面板用 ECharts 做 2 到 3 个图表即可。比如折线图展示近 14 天进入隔离点的人数变化,饼图展示当前人员状态分布,卡片展示今日新增人数、在点人数、可用房间、异常人数。图表数据统一从后端统计接口取,不要在页面里写死。
5.3 联调过程中最容易卡住的三个细节
第一个是前端传参格式对不上后端实体。比如日期字段,前端拿到的是 “2025-04-20T12:00:00” 这种 ISO 字符串,后端 LocalDateTime 直接接收会报格式错误。处理方法是前端提交前做格式化,或者后端在 dto 字段上加 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 注解。
第二个是跨域请求带了自定义 Header,导致后端预检请求失败。使用代理后这个问题通常消失,若用独立域名部署,后端 CorsFilter 里要允许 Authorization 请求头。
第三个是删除操作没有确认提示,误点就把数据删了。所有危险操作前端都要用 Popconfirm 做二次确认,后端删除也要判断人员状态,比如在点状态的人不允许删除,只能操作解除。
6. 打包部署与答辩演示准备:别让演示环境拖后腿
6.1 Maven 多环境打包配置
项目写完后要能在演示电脑上一键跑起来,不能依赖某个开发者的 IDEA 配置。推荐拆分 application.yml、application-dev.yml、application-prod.yml 三份配置,开发环境连本地 MySQL,生产环境连服务器数据库。
如果用 IDEA 右侧 Maven 面板执行 package 打包,要先跳过测试,否则测试类里如果初始化了 Spring 容器,而数据库没启动就会打包失败。命令可以写成:
bash复制mvn clean package -DskipTests
打包完成后,target 目录下会生成一个可执行 jar 包,用一条命令就能启动:
bash复制java -jar isolation-system.jar --spring.profiles.active=prod
启动参数里指定 profile,可以灵活切换环境,不需要重新打包。
6.2 Docker 部署步骤(本地和服务器通用)
想在答辩演示时避免环境问题,最省心的办法是使用 Docker 部署。先创建一个比较简单的 Dockerfile:
dockerfile复制FROM openjdk:8-jre-alpine
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=prod"]
然后把后端 jar 包、MySQL、Redis 用 docker-compose 编排起来:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root1234
MYSQL_DATABASE: isolation_db
ports:
- "3306:3306"
volumes:
- ./mysql-data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
app:
build: .
depends_on:
- mysql
- redis
ports:
- "8080:8080"
数据库初始化脚本通过 volume 挂载或手工导入都行。用 docker-compose 的好处是演示时只需要执行 docker-compose up -d,所有服务自动拉起,不用在答辩现场手忙脚乱地配环境。如果你用的是自己电脑上的 Docker Desktop,也要注意给容器分配足够内存,否则 MySQL 启动到一半会被 OOM 杀掉,看起来很像是配置写错了。
6.3 演示数据要“有故事、有画面”
演示系统和测试系统最大的区别是有没有一套逻辑完整的数据。不要只在库里塞几百条“张三”“李四”的随机数据,而是准备一组能讲出业务闭环的演示数据:
- 有 3 到 5 个人是正在点状态,分布在不同的楼栋房间;
- 有 1 到 2 个人刚提交过今日健康记录,页面能看到记录;
- 有 1 个人今天的体温偏高,健康记录被标记为异常,首页统计卡片能体现出来;
- 近 7 天新增人数按日期有波动,折线图能画出曲线;
- 房间状态包含空闲、占用、待消毒三种,方便演示房间分配时的状态变化。
所有数据的创建时间要相对近一些,否则首页趋势图只显示一个孤零零的点。
7. 常见问题与答辩避坑指南(实操阶段真实经验)
7.1 这些 SpringBoot 运行错误,我几乎每次都会遇到
项目明明代码没问题,启动却报循环依赖:SpringBoot 2.6 以后默认禁止循环依赖,两个 service 互相注入直接启动失败。很多初学者踩到这个问题不知道怎么解决。最简单的处理是重构业务,把互相调用的部分抽到第三个 service 中;如果只是初始化顺序问题,可以在其中一个注入点上加 @Lazy 注解延后加载,但治标不治本,答辩时不建议强调这个解法。
数据库连接报时区错误是另一个高频问题。MySQL 8.x 的驱动要求指定 serverTimezone,否则启动或首次查询时抛异常。jdbc 连接串加上 serverTimezone=Asia/Shanghai 或改成 useSSL=false&serverTimezone=UTC 就能解决。如果还出现中文乱码,把连接串再加 characterEncoding=utf8。
Redis 连接不上,先确认服务器上 Redis 是否启动、配置文件是否设置了 protected-mode yes 导致外部访问被拦。本地开发可以直接关掉保护模式或设置 bind 0.0.0.0,生产环境则要设置密码并限制访问来源。
7.2 技术答辩高频问答整理
把下面的问题准备到位,基本可以应对老师的大部分追问:
| 常见问题 | 建议回答思路 |
|---|---|
| SpringBoot 自动装配原理 | @EnableAutoConfiguration 读取自动配置文件,按条件装配 Bean |
| 为什么用 MyBatis Plus | 内置单表 CRUD 和分页插件,减少样板代码,复杂 SQL 仍可手写 |
| Token 过期如何处理 | 前端响应拦截器捕获 401,跳转登录页;后端 Redis 存储 Token 可主动失效 |
| 为什么数据库加唯一索引 | 从数据库层面防重复数据,避免并发请求造成脏数据 |
| 房间分配如何防止超分 | 条件更新 update room set status=1 where id=? and status=0,按更新行数判断 |
| 系统响应慢如何优化 | 列表查询加索引、用 Redis 缓存统计结果、SQL 避免深分页 |
| 如果人数增加到几千人怎么处理 | 读写分离、分库分表、引入消息队列削峰,但注意不要过度展开 |
回答时尽量落到自己项目的具体代码上。比如讲到防超分,直接说“我在 roomMapper 里写了一条 update 语句,用 status=0 作为条件更新”,比背一堆概念更有真实性。
7.3 工作量不够时,往这几个方向扩展最合理
如果时间充裕,希望把项目做得更有区分度,可以从三个方向扩展:一是给隔离人员增加扫码自助登记的小程序端或 H5 端,通过二维码填报个人信息,减少工作人员手动录入压力;二是引入 Flowable 7 工作流引擎,把异常上报、解除审批等流程做成真正可跟踪的审批流,设计器可在线绘制流程;三是给整个系统配置一套完善的可视化监控大屏,把多维度统计投到大屏展示。这三个方向都不需要改动现有核心表结构,往现有接口上叠加新功能即可。
不过我要提醒一句:扩展前先把核心链路测试完整,不要为了追求新增功能导致基础流程都不稳定。答辩老师只要点开页面看到数据对不上、功能 500,再多的扩展亮点都会被扣分。
在做这套系统时我最深的体会是:不要把它当成纯粹“写代码练手”的题目,而是要当成一次完整软件交付的小型演练。先画业务流程图,再设计数据库,然后才轮到 controller 和页面。把“人员登记—房间分配—健康记录—异常统计—解除离点”这条主链路跑通以后,其他的公告、用户、日志模块都只是补充工作量。你如果正卡在这个项目上,建议按这个顺序一步步来,做完之后对 SpringBoot 整套开发流程会有一个特别通透的感觉。
