
大三那年选毕设题目我在一堆“图书管理系统”“学生选课系统”里翻来翻去最后盯上了这个方向SpringBootVue 疫情隔离管理系统平台。附带完整项目源码、SQL脚本和接口文档算是Java Web毕设里相当标准的一套配置。说实话这类系统做起来不复杂但涉及的模块足够多从人员登记、隔离点分配、每日健康上报到解除审核、数据统计一条链路走完后端、前端、数据库都能练到答辩时也有东西可讲。这篇就把我做完整个项目的思路和实操过程拆开讲一遍包括技术选型为什么这么定、SQL脚本怎么设计、前后端怎么对接、项目怎么跑起来以及最后答辩时那些容易翻车的问题。1. 疫情隔离管理系统到底要管什么业务拆解决定项目上限很多同学拿到这类题目第一反应是“先建表、再写个增删改查”。这个顺序其实是反的。业务没想清楚之前表结构和接口设计都是空转。我做这套系统时最先做的是把业务角色和流程一条条画出来再反推需要哪些数据、哪些接口。1.1 三个核心角色与六条业务主线隔离管理系统表面上是在管“人”实际上管的是人、地点、状态、记录四类对象的流转。系统中主要涉及三类角色管理员维护系统基础数据管理隔离点、房间、工作人员查看全局统计。工作人员接收隔离人员、分配房间、录入每日健康数据、登记核酸结果、上报物资需求。隔离人员提交个人信息、每日上报体温和症状、申请生活物资、查看隔离倒计时。围绕这三类角色业务主线可以梳理成六条隔离登记流程隔离人员信息录入 → 分配隔离点 → 分配房间 → 状态变为“隔离中”。健康监测流程每日体温填报 → 症状记录 → 异常标记 → 工作人员复核。核酸管理流程采样登记 → 结果录入 → 结果关联到隔离记录。解除隔离流程满足隔离天数且健康数据正常 → 工作人员提交解除申请 → 管理员审核 → 状态变为“已解除”。物资管理流程隔离人员提交需求 → 工作人员处理 → 物资发放记录。统计展示流程在管人数、累计人数、今日新增、房间使用率、健康异常趋势。这套拆解做完你会发现系统真正的难点不在单个表的增删改查而在状态流转。一个隔离人员从“待分配”到“隔离中”再到“已解除”中间涉及多个表的联动更新。数据库设计时如果没把状态字段和关联关系理清后面写接口会非常痛苦。1.2 功能清单从隔离登记到解除隔离的完整闭环根据上面的业务主线系统功能模块可以落到这么一份清单里功能模块子功能数据表拟定备注登录认证账号密码登录、验证码user支持管理员/工作人员/隔离人员三种角色隔离点管理隔离点增删改查、房间管理isolation_site, room房间需要区分“可用/占用/消毒中”隔离人员管理人员登记、分配房间、档案查询quarantined_person, quarantine_record核心表状态字段必带健康上报每日体温/症状填报、异常列表health_report关联隔离记录核酸管理采样登记、结果录入、批量导入nucleic_acid_test结果直接回写隔离状态物资管理需求提交、发放记录、库存统计material_demand, material_issue可做简单库存扣减解除审核到期列表、解除申请、管理员审核quarantine_record状态机核心数据统计在管/累计/新增、房间利用率、图表统计类查询ECharts展示这套功能做完系统已经是一个能自圆其说的完整闭环不是那种“看起来像半成品”的毕设。答辩时评委看到你有状态流转、有统计、有权限区分印象分会好不少。2. 技术选型与项目初始化SpringBootVue这套组合的来龙去脉标题里直接写明SpringBootVue说明这已经是当前Java Web毕设的主流配置。但选这套组合的时候我还是认真权衡过几个替代方案的这里把我的选择逻辑讲清楚。2.1 为什么是SpringBoot而不是SSH/SSM课程里教的SSMSpring SpringMVC MyBatis组合不是不能用但配置太散了。SSM要手动写一堆XML数据源、事务、AOP切面哪个配置不对都能卡你半天。SpringBoot的核心价值是约定优于配置一个application.yml把端口、数据库连接、日志级别都收拢进来内嵌Tomcat打完包直接java -jar就能跑。对于毕业设计这个场景SpringBoot的优势特别明显启动速度SSM启动慢调试一次要等半天SpringBoot几秒起来改完代码热重启也快。依赖管理starter机制一行依赖搞定一个模块不用自己找版本、排冲突。部署简单内嵌Tomcat本地和服务器环境一致性更好。我自己用SpringBoot 2.7.x搭配MyBatis-Plus做数据层操作。MyBatis-Plus主要图它的条件构造器和分页插件——这种管理类系统就是大量列表查询和条件筛选单表CRUD如果一个个手写XML工作量太大又容易出低级错误。2.2 Vue 2 Element UI还是Vue 3 Element Plus到2024、2025年新项目直接上Vue 3 Element Plus其实更合理。但毕设场景要分情况如果你熟悉Vue 2的写法且在网上找到的资料大多基于Vue 2那选Vue 2 Element UI问题不大生态成熟报错搜得到答案。如果你从零开始或者想顺便学点新技术直接Vue 3 Element Plus Vite性能更好组件库也在持续维护。我做这套系统时用的是Vue 3 Element Plus配合Vite。Vue 3的组合式API在写图表页、表单页的时候更清爽逻辑抽出来复用也方便。前端工程结构大致这么安排src/ ├── api/ // 接口请求封装 ├── assets/ // 静态资源 ├── components/ // 公共组件 ├── router/ // 路由配置 ├── store/ // Pinia状态管理 ├── views/ // 页面组件 ├── utils/ // 工具函数 ├── App.vue └── main.js2.3 项目初始化的具体步骤后端工程我用IDEA Maven初始化步骤并不复杂新建Spring Initializr项目选择Java 8或Java 11看本机环境别选太高版本导致一堆依赖不兼容依赖勾选Spring Web、MySQL Driver、MyBatis-Plus这个在官网手写坐标、Lombok、Validation。关键配置写在application.yml里server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/epidemic_quarantine?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto前端项目我用的Vite创建npm create vitelatest isolation-admin -- --template vue cd isolation-admin npm install npm install vue-router pinia axios element-plus element-plus/icons-vue echarts npm run dev踩过的坑说两个一个是Vite默认端口5173后端接口8080前后端联调一定记得配代理否则跨域问题会折腾你一个下午另一个是Element Plus的图标是按需引入的如果在模板里直接用了el-iconPlus //el-icon却不做注册页面会白屏报错。我用的是全量引入毕设项目不用太纠结打包体积。3. SQL脚本的设计隔离业务的数据模型怎么建模这套项目附带的SQL脚本是整个系统能不能跑起来的地基。很多同学喜欢先写实体类再SQL我反着来——SQL先定稿实体类跟着表结构生成。因为表结构定了字段含义才明确实体类只是表的映射。我建表时遵循一套规则每张表必须有主键id采用自增时间字段用datetime由后端统一生成避免数据库默认时区问题状态字段用tinyint或varchar都行但必须加注释说明每个值代表什么不然过俩月自己都看不懂。3.1 核心表的字段设计与关联关系这套系统的核心表我拆成6张下面列出关键字段isolation_site隔离点表CREATE TABLE isolation_site ( id BIGINT PRIMARY KEY AUTO_INCREMENT, site_name VARCHAR(100) NOT NULL COMMENT 隔离点名称, address VARCHAR(255) COMMENT 详细地址, manager VARCHAR(50) COMMENT 负责人, phone VARCHAR(20) COMMENT 联系电话, total_rooms INT DEFAULT 0 COMMENT 总房间数, used_rooms INT DEFAULT 0 COMMENT 已用房间数, status TINYINT DEFAULT 1 COMMENT 状态:1营业 0停用, create_time DATETIME, update_time DATETIME );room房间表CREATE TABLE room ( id BIGINT PRIMARY KEY AUTO_INCREMENT, site_id BIGINT NOT NULL COMMENT 所属隔离点ID, room_no VARCHAR(20) NOT NULL COMMENT 房间号, room_type VARCHAR(20) DEFAULT 单人 COMMENT 房间类型, status TINYINT DEFAULT 0 COMMENT 0空闲 1占用 2消毒中, current_person_id BIGINT DEFAULT NULL COMMENT 当前入住隔离人员ID, create_time DATETIME );quarantined_person隔离人员表CREATE TABLE quarantined_person ( id BIGINT PRIMARY KEY AUTO_INCREMENT, person_name VARCHAR(50) NOT NULL, id_card VARCHAR(18) NOT NULL COMMENT 身份证号, phone VARCHAR(20), gender TINYINT, source_area VARCHAR(100) COMMENT 来源地, quarantine_start DATE COMMENT 隔离开始日期, quarantine_days INT DEFAULT 14 COMMENT 隔离天数, quarantine_end DATE COMMENT 预计解除日期, site_id BIGINT COMMENT 隔离点ID, room_id BIGINT COMMENT 房间ID, status TINYINT DEFAULT 0 COMMENT 0待分配 1隔离中 2已解除 3异常, create_time DATETIME );quarantine_record隔离记录表这张表是用来记录每次隔离期间的健康跟踪、工作人员操作留痕的。health_report健康上报表CREATE TABLE health_report ( id BIGINT PRIMARY KEY AUTO_INCREMENT, person_id BIGINT NOT NULL, record_date DATE NOT NULL COMMENT 上报日期, temperature DECIMAL(3,1) COMMENT 体温, is_cough TINYINT DEFAULT 0 COMMENT 是否咳嗽:0否 1是, is_fatigue TINYINT DEFAULT 0 COMMENT 是否乏力, is_other TINYINT DEFAULT 0 COMMENT 其他异常, remark VARCHAR(255), create_time DATETIME );nucleic_acid_test核酸检测表采样时间、结果、检测机构加一个result_status标记阴性阳性。material_demand / material_issue物资需求与发放表需求关联人员ID发放记录关联工作人员ID。表间关系一句话概括隔离人员关联隔离点和房间健康报告和核酸记录都挂在人员ID下隔离记录贯穿整个隔离周期物资和通知围绕人员产生。SQL脚本里加上外键约束会显得更规范但实际项目中我通常只做逻辑关联、不加物理外键因为大批量插入数据和删除数据时物理外键会带来额外校验开销对毕设这种规模反而不明显。答辩时如果评委问为什么没加外键可以用这个解释。3.2 隔离状态流转数据库里怎么表达“正在隔离/已隔离/待解除”这是整个系统设计中最有价值的部分。隔离管理本质上是一条状态机待分配(0) → 隔离中(1) → 已解除(2) ↓ ↑ 隔离中(1) → 异常(3) → 复核通过 → 已解除(2)数据库层面状态用quarantined_person的status字段表示。每次状态变更不只是改一个字段而是要联动更新分配房间person.status 1room.status 1room.current_person_id更新。解除隔离person.status 2room.status 0room.current_person_id置空site.used_rooms减1。异常上报health_report出现异常体温或症状person.status 3工作人员处理完后可选择恢复隔离中。这些联动不能靠前端多请求几个接口硬拼而是每个状态变更都对应后端一个事务方法。SpringBoot里用Transactional注解多个UPDATE操作在同一个事务里执行任何一个失败都回滚不会出现人隔离了但房间没占用的脏数据。3.3 统计报表类SQL的写法统计模块是答辩时的加分项也是SQL脚本里最能体现水平的部分。几个常用统计的写法在管人数SELECT COUNT(*) FROM quarantined_person WHERE status IN (0, 1, 3);近7天新增隔离人员趋势SELECT DATE(create_time) AS date, COUNT(*) AS cnt FROM quarantined_person WHERE create_time DATE_SUB(CURDATE(), INTERVAL 7 DAY) GROUP BY DATE(create_time) ORDER BY date;房间使用率SELECT s.site_name, s.total_rooms, s.used_rooms, CONCAT(ROUND(s.used_rooms * 100.0 / s.total_rooms, 1), %) AS usage_rate FROM isolation_site s;这些SQL直接给到前端做图表数据返回不用在Java里做二次处理。统计接口通常需要聚合多张表如果觉得SQL写起来长可以用多个简单查询再用Java分组优先保证逻辑清晰不要为了炫技写一堆子查询嵌套后面你自己都维护不动。4. SpringBoot后端实现接口开发与关键业务逻辑后端是这套系统的“大脑”接口文档能不能撑起来全靠后端这块写得规不规范。我实际开发时顺序是先搭工程骨架、设计统一返回结构、实现登录鉴权再去逐模块填充业务接口。4.1 工程结构包划分与统一返回后端工程我按这样的包结构划分com.epidemic.isolation ├── controller // 接口层 ├── service // 业务逻辑 ├── mapper // 数据访问 ├── entity // 实体类 ├── dto // 请求/响应封装 ├── config // 配置CORS、拦截器、等 ├── utils // 工具类JWT、等 └── common // 统一返回、异常处理所有接口返回统一使用ResultT包装public class ResultT { private Integer code; private String msg; private T data; // 构造方法、getter/setter 略 }成功返回code200业务失败返回code500或自定义业务码未登录返回code401。前端拿到返回值后统一拦截出现401就跳转登录页。这套规范看起来简单但在前后端联调时能省掉大量“这个接口到底返回啥”的沟通成本。异常处理上用RestControllerAdvice做全局兜底业务异常、参数校验异常、系统异常分别处理保证任何情况下前端拿到的都是统一格式不会让Tomcat默认的错误页糊到接口响应里。4.2 健康上报与状态自动计算的逻辑健康上报接口是重点。核心逻辑不是简单insert一条记录那么简单而是要在插入健康数据后自动判断该人员的隔离状态是否要变更。判断规则我写在Service层一个单独的方法里当天体温记录是否大于37.3℃是否勾选了咳嗽、乏力或其他症状连续异常的天数是否达到阈值比如连续2天异常则状态置为“异常”。Transactional public ResultVoid reportHealth(HealthReportDTO dto) { HealthReport report new HealthReport(); BeanUtils.copyProperties(dto, report); report.setReportDate(LocalDate.now()); healthReportMapper.insert(report); // 查询该人员最近几天的健康数据 ListHealthReport recent healthReportMapper.selectRecentByPersonId( dto.getPersonId(), LocalDate.now().minusDays(2), LocalDate.now()); long abnormalCount recent.stream() .filter(r - r.getTemperature().compareTo(new BigDecimal(37.3)) 0 || r.getIsCough() 1 || r.getIsFatigue() 1) .count(); if (abnormalCount 2) { quarantinedPersonMapper.updateStatus(dto.getPersonId(), 3); } return Result.success(); }这段逻辑里有个容易被忽略的点temperature字段用DECIMAL(3,1)存比较时一定要用BigDecimal的compareTo而不是直接或者equals。直接equals会连精度一起比较37.3和37.30会判定不相等这类Bug查起来相当隐蔽。4.3 JWT鉴权与角色权限控制后台管理类系统一定要有鉴权不然登录功能就没有意义。我用的方案是JWT 拦截器。登录成功后生成token把用户id、角色塞进token的claims里String token Jwts.builder() .setSubject(user.getUsername()) .claim(userId, user.getId()) .claim(role, user.getRole()) .setExpiration(new Date(System.currentTimeMillis() 24 * 60 * 60 * 1000)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact();拦截器统一校验token并解析出当前用户信息放入ThreadLocalpublic class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token request.getHeader(Authorization); if (token null || !token.startsWith(Bearer )) { throw new BusinessException(401, 未登录); } // 解析token校验角色权限 // 通过则放行不通过则抛异常 } }角色权限控制用自定义RequireRole注解加Spring AOP实现。管理员专属接口比如审核解除申请加上该注解非管理员角色调用直接拒绝。这种设计比在每个接口里手写if (user.getRole() ! 1)要干净得多。4.4 定时任务与到期提醒隔离到期提醒这类功能如果全靠用户自己去看列表体验很差。我用SpringBoot自带的Scheduled做了个定时任务每天凌晨扫描隔离人员表Scheduled(cron 0 0 6 * * ?) public void checkQuarantineExpiry() { ListQuarantinedPerson persons quarantinedPersonMapper.selectByStatus(1); for (QuarantinedPerson p : persons) { if (LocalDate.now().compareTo(p.getQuarantineEnd()) 0) { // 生成待解除提醒记录或者自动将状态标记为待解除 } } }注意Scheduled默认是单线程执行的如果以后加了多个定时任务一定要在配置里设置线程池大小否则两个任务会互相阻塞。这个细节面试或答辩时提出来能说明你是真的跑过生产环境不是只在写demo。5. Vue前端页面架构、路由与接口对接前端部分我用Vue 3 Element Plus重构了三版才定下来。最初想直接把所有页面堆在views里后来发现管理后台有几个模块的页面结构高度相似——比如“人员管理”和“房间管理”都是表格搜索框新增弹窗操作按钮。如果每个页面单独写代码重复量太大。最后还是抽了公共组件效果立竿见影。5.1 前端工程搭建Router、Axios与代理配置前端初始化时我踩过的最大的坑就是跨域。本地开发时Vite跑在5173后端跑在8080浏览器直接请求后端接口会被CORS拦截。解决办法不是在后端加CrossOrigin而是用Vite的代理// vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) } } } })这样前端请求/api/user/login实际会被转发到http://localhost:8080/user/login。后端的CORS配置就不需要了生产环境把前端静态文件丢进SpringBoot的static目录后同源部署更没有问题。Axios封装方面我在utils/request.js里做了一层拦截器import axios from axios import { ElMessage } from element-plus 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) { return res.data } else if (res.code 401) { router.push(/login) return Promise.reject(new Error(未登录)) } else { ElMessage.error(res.msg || 请求失败) return Promise.reject(new Error(res.msg)) } }, error { ElMessage.error(网络异常) return Promise.reject(error) } )抽好这层拦截器之后业务代码里调用接口就清爽很多不需要每个页面都做response.status判断。5.2 核心页面数据看板与专项管理页首页数据看板用的是ECharts。我的路由配置里首页是/dashboard组件里放了三个统计卡片在管人数、累计隔离、今日新增加两个图表7天新增趋势折线图、房间使用率饼图。ECharts在Vue 3里的用法是先在onMounted里初始化实例在数据请求完成后通过setOption更新。一个容易忽略的坑容器div必须有明确的高度否则ECharts初始化和resize时图表是空的。我给图表容器统一设置了height: 300px并且在window.resize事件里调用了chart.resize()。隔离人员管理页是整个系统最核心的页面。表格展示人员列表支持姓名/身份证/状态/隔离点等条件组合筛选。状态列做了Tag展示待分配灰色、隔离中蓝色、已解除绿色、异常橙色。操作列根据状态动态渲染待分配可“分配房间”隔离中可“查看健康记录”“手动解除”异常可“复核处理”。这套页面做完基本上一眼能看出系统功能全不全。我建议写这类代码时保持一个习惯每个表格查询都支持分页前端列表页不一次性把所有数据拉回来。刚开始我偷懒人员表100条以内还好等到几千条数据页面明显卡顿。后来统一改成了pageNumpageSize的参数传递MyBatis-Plus分页插件后端处理体验就顺了。5.3 权限控制动态路由与按钮级校验前端的权限控制不能只靠后端的接口拦截页面上不该让普通用户看到的菜单、不该让工作人员点击的按钮都要在前端屏蔽掉。我采用了动态路由方案登录成功后后端根据角色返回菜单权限列表前端用router.addRoute动态注册可见的路由。同时封装了一个v-permission指令做按钮级校验// directives/permission.js export const permission { mounted(el, binding) { const required binding.value const role localStorage.getItem(role) const allowed required.split(,).includes(role) if (!allowed) { el.parentNode?.removeChild(el) } } }比如管理员专属的“审核解除”按钮加上v-permission1非管理员进来这个按钮直接不渲染。这种东西不是面子工程是真实权限系统该有的样子答辩时也可以顺带提一句“我们对前后端做了双重权限控制”。6. 接口文档、SQL脚本与完整源码怎么用起来拿到这套项目源码最怕的不是不知道功能有哪些而是不知道怎么把它跑起来。这里把从解压到运行的完整流程和应该怎么阅读项目的思路写出来。6.1 接口文档的阅读顺序与联调思路接口文档一般由两部分构成文档说明和接口明细。拿到文档先不要急着看接口先看文档说明里的通用约定包括接口基础路径比如/api请求头要求是否需要携带Authorization统一返回结构{code, msg, data}code为200表示成功分页参数命名pageNum/pageSize还是page/limit这些约定确定后再按模块看接口。我的习惯是先从“登录接口”开始看因为它能拿到token而后续所有接口联调都需要token。登录接口通了再按“用户管理→隔离点管理→隔离人员→健康上报→解除审核→统计”的顺序逐个过。联调时有个实用建议用Postman或Apifox把接口按模块建好文件夹把同一个请求的不同参数情况都保存下来特别是边界情况查不到数据、参数缺失、状态不合法。开发完前端再回头看这些东西能帮你快速定位是前端参数传错还是后端逻辑写错。6.2 SQL脚本导入与初始账号配置SQL脚本拿到手先看里面的表结构再执行导入。执行前确认几件事MySQL版本脚本是用5.7还是8.0写的8.0的utf8mb4_0900_ai_ci不兼容5.7。我建议统一用5.7的utf8mb4_general_ci兼容性最好。字符集执行前用set names utf8mb4;防止中文乱码。初始账号脚本里通常包含初始化管理员账号登录进去第一件事就是改初始密码避免演示时被人顺走账号。导入命令通常是mysql -uroot -p --default-character-setutf8mb4 epidemic_quarantine sql/epidemic_quarantine.sql如果在Navicat里导入记得选择“运行SQL文件”而不是直接把SQL内容复制到查询窗口执行前者对大文件更稳定后者容易因为中途一个分号报错导致后续内容中断。6.3 本地运行全流程后端、前端与打包部署后端启动步骤# 1. 创建并导入数据库 mysql -uroot -p CREATE DATABASE epidemic_quarantine DEFAULT CHARACTER SET utf8mb4; exit mysql -uroot -p epidemic_quarantine sql/epidemic_quarantine.sql # 2. 修改application.yml里的数据库账号密码 # 3. IDEA里直接运行启动类或者命令行构建 mvn clean package -DskipTests java -jar target/isolation-system.jar前端启动步骤cd isolation-admin npm install npm run dev浏览器打开http://localhost:5173用初始账号登录系统就起来了。生产环境部署或者答辩现场演示如果不想同时开两个进程把前端打包后放进后端工程是常见做法。具体操作npm run build生成dist目录后把里面的index.html和assets文件夹整个复制到后端项目的src/main/resources/static目录下重新打包后端mvn clean package -DskipTests java -jar target/isolation-system.jar然后浏览器直接访问http://localhost:8080打包进SpringBoot的前端页面和后端API同源CORS问题天然不存在。这是热词里“vue打包放进springboot中”对应的核心操作也是毕设演示最稳的一种方式。注意复制dist内容时不要覆盖原来static目录下可能有用的文件先备份再动手。7. 毕设答辩避坑与二次开发扩展方向代码写完、系统能跑只是完成了毕设的一半。另外一半是答辩。这里把评委最常问问题的应答思路和自己的扩展建议总结一下。7.1 评委最爱问的几个问题“你这个系统和其他人的有什么区别”不要笼统说“功能全”要有具体记忆点。我当时的回答思路是系统里实现了隔离人员的全生命周期闭环管理从登记、分配房间、健康上报、核酸结果、解除审核到统计状态流转不是简单改个字段而是通过事务联动房间、隔离点、健康记录多张表保证数据一致性此外还有定时任务自动扫描到期人员减轻人工操作负担。“数据库为什么这么设计状态字段为什么用数字不用字符串”数字比字符串省空间、查询更快配合注释脚本不会丢失可读性用tinyint而不新建关联表是因为状态集合固定且简单不需要额外一张表的开销。“并发问题怎么考虑”比如同一个房间同时被两个人分配。我当时的回答是分配房间的SQL语句里加上条件WHERE id ? AND status 0用数据库行锁保证并发下只有一个请求能抢到空闲房间而不是先查再改的两步操作。boolean updated roomMapper.occupyRoom(roomId, personId) 0; if (!updated) { throw new BusinessException(500, 房间已被占用); }这种方案我在代码里确实写了也不是为了答辩临时编的。“为什么用JWT而不用Session”JWT是无状态认证后端不需要保存会话信息分布式部署时容易扩展token里自带用户信息和过期时间接口校验不需要查库。缺点是要自己处理注销失效问题但毕设场景无所谓。“测试数据怎么来的”SQL脚本里我预置了部分模拟数据提前编好的姓名、日期、来源地导入即可演示。演示场景前先在本地走一遍流程确保每一步都有数据展示效果不要让评委看到空表。7.2 低成本提分扩展点如果时间和精力有余以下几个扩展点性价比很高增加通知公告模块管理员发公告隔离人员登录后能看到最新规定功能简单却是很多同类系统缺失的。增加消息提醒用WebSocket实现后端主动推送隔离到期、核酸结果通知前端右上角弹出提醒。这个做实了答辩时技术亮点就多了。增加Excel导出用EasyExcel把隔离人员列表导出成表格管理人员很需要这功能实现不复杂但很能从实操层面加印象分。增加数据权限普通工作人员只能看到自己负责的隔离点数据管理员看到全部这是比简单角色鉴权更深一层的控制逻辑。我自己在这个项目里实际加了消息推送和Excel导出两个功能代码量不大但答辩展示页面时演示“点击导出表格”和“收到一条提醒”比单纯破解功能截图要有力得多。整个项目做完的体会是毕业设计选题能不能出彩不在于功能多花哨而在于有没有把一个主业务流程做完整状态流转和权限控制这两件事做好系统基本就立住了。题目里的技术栈SpringBoot、Vue、SQL脚本每一个都在项目里真刀真枪跑了一遍比我预想中更扎实。