资讯动态

SpringBoot+Vue高校疫情防控管理系统设计与业务闭环拆解

发布时间:2026/9/26 20:54:12 来源:尧图企业网站定制
每年一到毕业设计季后台就会收到大量同类的需求给我一个能用的管理系统、最好前后端分离、技术栈时髦一点、能答辩能演示。而“SpringBootVue高校疫情防控web系统管理平台”这类项目几乎是这几年被问得最频繁的选题之一。原因很简单——它场景真实、需求明确、技术覆盖全面从基础的增删改查、权限控制到相对复杂的审批流、数据可视化、Excel导入导出全都涉及。无论你是拿它应付课程设计还是想在毕设里融入一点真实业务逻辑这套东西练完前后端的底子基本就扎实了。这篇文章我不会给你贴大段源码而是带你把它当成一个真实交付的项目来拆。我会从需求设计、数据库建模、后端接口落地、前端页面实现到最后部署避坑一条线讲清楚。哪怕你现在手里只有一份不知道从哪儿下载的源码照着这篇的思路过一遍也能在答辩时讲明白每一个模块为什么这么设计每一段核心代码解决了什么问题。1. 项目核心需求与整体设计思路1.1 高校健康管理场景到底要解决什么问题很多同学拿到这类题目第一反应是“不就是做个带登录的CRUD吗”。如果你抱着这个思路去做做完也就停留在“会写增删改查”的层面答辩时导师一问业务流程就卡壳。真实的高校健康管理场景核心要解决三类问题。第一类是每日信息收集全校几万师生每天都要上报自己的体温、健康状况、是否接触过风险人群、当前所在地。靠人工统计根本不可能系统得让学生自助提交并且要防止漏报——所以需要“按人按天”约束同一个人同一天只能提交一次后台能实时看到“谁还没报”。第二类是出入与离校审批学生有事要出校或者从外地返校不能直接走人得先提交申请辅导员或学院管理员审批门岗再根据审批结果放行。这中间就牵扯到一个状态机待审核、通过、驳回。第三类是异常数据追踪一旦有人上报体温异常系统要能自动标红、通知对应管理员、形成处理记录而不是让异常数据淹没在大表格里。搞清楚这三个问题你再去设计表结构、接口、页面思路会清晰很多。这也是为什么我一直建议拿到项目先别急着写代码先画一遍业务流程图把“谁在什么场景下操作什么数据”列出来。你甚至可以用纸笔画画完再去建表效率反而更高。1.2 为什么选SpringBoot Vue前后端分离技术选型这件事在毕设里往往不是“谁最好”的问题而是“谁最稳妥且能讲出道理”。SpringBoot Vue MySQL这套组合属于当下最主流、资料最多、遇到问题最容易搜到解决方案的一条路。从后端讲SpringBoot的好处是“开箱即用”。你不用像早期SSH框架那样写一堆XML配置一个启动类就能把Web容器、数据库连接、事务管理全部带起来。配合MyBatis-Plus单表的增删改查几乎不用手写SQL这对开发周期紧的课设、毕设来说性价比极高。而且SpringBoot自带的starter机制让你后面想加Redis缓存、加定时任务、加消息通知都只需要引依赖加载配置文件扩展性强。从用户体验讲Vue带来的前后端分离架构让前端页面和后端接口可以完全独立开发、独立部署。学生端、教师端、管理端可以做成不同的页面路由配合Element UI组件库表格、表单、弹窗、时间选择器都现成做出来的界面比传统JSP模板好看一个量级。答辩时演示流畅的页面交互本身就是加分项。从面试或答辩的角度讲前后端分离架构本身就自带话题点——跨域怎么处理、Token怎么携带、路由守卫怎么拦截、Nginx怎么反向代理——这些是面试官和答辩老师都爱追问的细节也是这套项目能让你说满十分钟的技术点。1.3 系统角色划分与功能矩阵高校健康管理平台从用户角色上大致能拆成四层系统管理员、校级管理员学生处/校医院、学院管理员辅导员、普通师生学生与教职工。每一类角色看到的界面和能做的操作完全不同。普通用户端解决的是“自我上报 提交申请 查看通知”这是高频低权限操作。辅导员端解决的是“查看所带班级的上报情况、审批学生的出入申请、标记异常人员”这是中频中权限操作。校级端解决的是“查看全校上报率、各学院数据对比、异常事件总览、公告发布”这是低频高权限操作。系统管理员则负责账号分配、角色管理、基础数据维护比如学院、班级、专业这些字典表。我在实际开发时没有一上来就写五张角色表而是用一张用户表加一个role字段搞定。简单场景下完全够用权限控制通过后端拦截器校验角色编码前端再根据角色动态渲染菜单。后面如果时间充裕再升级成Spring Security RBAC也不冲突。这个设计思路在答辩时也很好讲先用轻量方案满足需求再说明升级路径体现你考虑过架构演进。2. 数据库设计核心表结构与关键字段规划2.1 从业务闭环反推数据表我建表有个习惯就是先把业务闭环画出来再一张表一张表去对应。健康管理平台的闭环大概是用户登录 → 提交每日上报 → 产生异常则进入异常处理 → 需要出行则提交申请 → 辅导员审批 → 门岗扫码/登记确认 → 数据汇总展示。落到数据库上最少需要这几张核心表sys_user用户表存账号、密码、姓名、学号/工号、角色、学院、班级、手机号、状态。health_report每日健康上报表存用户ID、上报日期、体温、健康状况、是否接触风险人群、当前所在地、备注。leave_apply出入/请假申请表存申请人、申请类型出校/返校/请假、起止时间、目的地、事由、审批状态、审批人、审批意见。access_record出入登记表存用户ID、进出方向、体温复测、登记时间、登记门岗。abnormal_case异常事件表存异常类型、关联用户、异常描述、处理状态、处理人、处理结果。notice_info通知公告表存标题、内容、发布人、接收范围标识、发布时间。我自己做的时候还加了一张sys_dict字典表专门存学院、班级、角色这些枚举数据。好处是你的页面下拉框不用写死后端管理端维护字典前端直接通过接口拉取。这一张表能省掉后续大量改代码的工作。2.2 关键字段设计背后的注意事项先说health_report表。这里最重要的约束就是“一人一天只能上报一条”。我用的方案是加一个report_date字段日期格式统一为yyyy-MM-dd再和user_id一起建联合唯一索引(uk_user_date)。代码层面同时做一次查询校验双保险。不然学生连续点两次提交库里就会出现两条同一天记录后台统计上报率直接翻车。体温字段我建议直接存DECIMAL(4,2)比如36.50。不要用FLOAT浮点比较和展示都会出现奇怪的问题。判断是否异常在代码里做超过37.3就自动打标数据库里只存原始值这样数据可追溯。审批状态字段用TINYINT0待审核、1通过、2驳回比存字符串更省空间、查询更快。这个设计所有人一看就懂。特别注意一个细节审批表里一定要存approver_id和approve_time缺了这个字段答辩老师会质疑“这个审批到底是谁、在什么时候批的”这是审计留下的硬要求。用户表里的密码字段千万别明文存。我用的是BCrypt加密Spring Security里自带BCryptPasswordEncoder单独引一个spring-security-crypto依赖就能用。注意BCrypt每次加密同一个密码得到的哈希串都不同所以校验要用matches()方法不要拿两个哈希直接“”比较。2.3 状态流转与数据一致性这套系统里最核心的状态流转是leave_apply的审批状态。我从一开始就定了规则只能从0待审核流转到1通过或2驳回驳回的申请允许学生修改后重新提交但重新提交时不能直接改原记录而是生成一条新记录状态回到待审核。这样所有历史申请都有迹可循。异常处理模块类似abnormal_case的状态是0待处理 → 1已联系 → 2已解除。这里我特意加了一个handle_result字段存“电话已联系学生反馈是普通感冒校医院复测正常”这类辅助信息。因为导报表的时候上级要看的不是你处理了几个异常而是每个异常到底“怎么处理的”这个字段就是支撑这个问题的关键。数据一致性方面页面上展示的“今日上报率”我没有每次请求都去count表而是维护了一张daily_summary汇总表每天凌晨通过定时任务统计后写入。统计接口直接读汇总表速度飞快。虽然毕设数据量不大看似没必要做汇总表但这张表的价值在于向老师展示你懂“读写分离思想”和“空间换时间”的取舍这就是细节分。3. 后端核心实现认证、上报、审批与统计3.1 基于JWT的用户认证与权限拦截后端接口写得漂亮与否第一眼看的就是登录和权限控制。我选的方案是JWT 拦截器既比传统Session更适合前后端分离又不像Spring Security那样配置繁琐容易把自己绕晕。简单说下JWT的流程用户登录成功后后端用用户ID和角色生成一个TokenToken里带签名返回给前端前端每次请求都把这个Token放到请求头Authorization里后端写一个拦截器在请求进入Controller之前先解析Token解析成功就把当前用户信息放到ThreadLocal里后续业务代码随时可取。在SpringBoot里实现拦截器核心是继承HandlerInterceptorAdapter或直接实现HandlerInterceptor。preHandle方法里先放行登录接口再对其他接口做Token校验。放行名单我建议用配置项维护别写死在代码里类似excludeUrls: /api/auth/login, /api/auth/captcha这样后面想加白名单只改配置即可。同时要注意设置响应头的跨域允许Access-Control-Allow-Headers里必须包含Authorization否则前端带了Token也会被浏览器拦截。这里有个很多人踩过的坑JWT的密钥千万别用弱密码最好在application.yml里单独配置并至少32位。校验Token过期时间时我是通过parser().parseClaimsJws(token).getBody().getExpiration()拿到过期时间再用new Date()比较。千万别只依赖JWT自带的过期校验有些场景你会需要“Token还有多久过期”这个信息来决定要不要提前刷新。3.2 每日健康上报接口与防重复设计健康上报是整个系统请求频率最高的接口设计和实现必须稳。前端是一个表单页后端对应一个POST /api/report/commit接口接收体温、健康状况、是否接触风险人群、所在地、备注等字段。后端拿到请求后第一步不是直接入库而是先查今天有没有上报记录。用lambdaQuery().eq(UserReport::getUserId, userId).eq(UserReport::getReportDate, today).count()大于0就直接抛业务异常提示“今日已上报不能重复提交”。然后再组装实体类入库。这套组合拳之前讲过联合唯一索引兜底查询校验提示友好两者配合利用数据库约束。批量导入这个功能我强烈建议做。辅导员手里经常有一张Excel名单几十个学生某天的体温记录需要一个一个录吗不需要。后端提供一个POST /api/report/import接口前端用Element UI的上传组件把Excel发过来后端用Apache POI解析逐行校验数据最后批量插入。这里要注意事务控制我直接在导入方法上标注了Transactional(rollbackFor Exception.class)解析过程中有一条数据不合格整批回滚不然会出现“导入一半成功一半失败”的脏数据。异常自动识别是健康上报模块的亮点功能。我在提交接口里写了一个判断体温大于37.3或者健康状况标记为异常或者接触风险人群标记为是三者任一命中就在同一事务里往abnormal_case表插一条待处理记录状态为0待处理。这个联动逻辑在答辩时就是最好的演示素材——你提交一个异常数据后台异常列表立刻多了一条记录。3.3 审批流接口状态机思维在代码里的落地请假/出入申请的审批接口看起来就是一个update操作把状态字段改一下。但真正写的时候我有一条铁律修改状态必须带前置状态条件不能无条件更新。比如辅导员审批接口POST /api/leave/approve接收申请ID、审批结果、审批意见。后端的SQL应该是UPDATE leave_apply SET status #{newStatus}, approver_id #{approverId}, approve_time NOW(), approve_remark #{remark} WHERE id #{id} AND status 0。注意这个AND status 0就是前置条件保证只有待审核的记录能被审批。如果更新行数为0说明这条申请已经被处理过直接提示“申请状态已变更请勿重复审批”。这个细节的价值在于它展示了你对并发处理和状态一致性的理解。学生端看到的按钮是根据状态渲染的待审核显示“审核中”、通过显示“审批通过”、驳回显示“审批驳回”并展示审批意见。这种前后端配合让整个审批流程在演示时非常直观。同时我加了一个简单的通知机制申请通过后往notice_info表插入一条站内信标题是“出入申请审批结果通知”接收人就是申请学生。学生登录首页就能看到“我的通知”红点点击后查看详情。这个功能虽然简单但它打通了审批和通知两个模块让系统不再是孤立的表格堆砌。3.4 数据统计与汇总接口的设计统计模块是校级管理端的核心。首页大屏要展示今日应报人数、今日已报人数、今日上报率、异常事件数、近7天上报趋势、各学院上报率排行。如果用SQL现查每个指标都要扫描大表尤其“今日上报率”涉及用户表和上报表的关联接口响应会越来越慢。我的做法是建一张daily_summary每日汇总表字段包括统计日期、学院ID、应报人数、已报人数、异常人数、上报率。用一个SpringBoot定时任务Scheduled(cron 0 5 0 * * ?)每天凌晨0点5分统计前一天的数据写入汇总表。统计口径上要特别注意“应报人数”怎么算——正常是在校状态学生都要报有请假记录且审批通过的不计入应报人数。这个口径我写了很长的注释在代码里因为统计类代码最容易改着改着自己都搞不清口径。各学院上报率排行的实现就是按学院分组查询当天汇总表再按上报率倒序排列。前端用ECharts的柱状图和折线图展示数据接口返回的格式直接对应图表需要的data数组联调起来基本一次通过。这里建议后端接口返回结构统一为{code, message, data}data里再具体包含series、categories、total等字段和前端图表库的结构对齐而不是返回一堆嵌套对象让前端自己挖。4. 前端Vue实现从搭建工程到页面落地4.1 工程初始化与目录结构规划前端我用的是Vue 2 Element UI Vuex ECharts这套组合虽然不是最新版但资料最全、坑最少拿来做毕设和课设最稳。如果你电脑上有Node环境一句npm install -g vue/cli装好脚手架然后vue create health-web就能生成项目骨架。工程目录我建议按模块分而不是按文件类型分。我的习惯是src/api按模块封装接口请求方法比如auth.js、report.js、leave.js、dashboard.js。src/router路由配置并在这里挂载全局前置守卫。src/storeVuex的modules目录存用户信息、Token、动态菜单数据。src/views页面组件按角色分文件夹student、teacher、admin各管各的页面。src/utils统一的axios实例封装、时间格式化工具、文件导出工具。这种按模块划分的方式唯一的好处就是“找人方便”。写代码时你不用在一个几百行的文件里上下翻新增功能也知道往哪个文件夹放。很多开源项目都有类似约定养成这个习惯对你以后进团队开发非常有帮助。4.2 axios封装、登录态管理与路由守卫axios封装是所有前端模块的地基。我所有的请求都走一个统一的实例baseURL设为/api开发环境通过vue.config.js里的devServer.proxy代理到后端8080端口生产环境由Nginx配置反向代理。请求拦截器里从localStorage取出Token加上请求头Authorization响应拦截器里统一处理业务码code为401时跳转登录页并清掉本地Tokencode为500时弹出错误提示不用每个页面都写try catch。登录态管理的细节在于用户登录成功后后端返回{token, userInfo}前端把token存到localStorage把用户信息存到Vuex。为什么用户信息不存localStorage因为Vuex是响应式的页面刷新后数据虽然丢失但可以通过路由守卫里再调一次GET /api/auth/info拉回来。这样保证用户刷新页面后导航栏上的用户名和头像能正确恢复而不是要重新登录一遍。路由守卫是自己必须手写的一个功能因为这是前后端分离项目安全性的第一道门。在router/index.js里设置beforeEach判断目标路由是否需要登录需要就检查本地Token再来检查角色信息根据当前用户的角色动态判断是否有权访问该路由。这里我用了一个简单方案路由的meta字段上标记roles: [admin, teacher]守卫里判断用户角色是否在roles数组里。不在就跳转到403页面而不是直接跳登录页这样管理端一个人登录后不小心访问学生端的地址也会被拒之门外。4.3 Element UI表单与表格的关键写法健康上报页面是学生端用得最多的页面它本身不复杂就是一个表单加一个提交按钮。但表单的校验体验决定了学生愿不愿意用。Element UI的el-form组件支持rules校验规则我在体温输入框上加了自定义校验必须是两位小数的数字范围在35到42之间。这个校验规则在前置端拦截了几乎所有的非法输入避免垃圾数据进入后端。表格页面比如异常列表、上报记录列表我统一采用el-table el-pagination el-dialog的组合。el-table绑定data数组列配置用el-table-column的prop指定字段即可分页组件绑定pageNum和pageSize切换时触发handleQuery()重新请求接口。后端接口统一用PageHelper风格或者MyBatis-Plus分页插件返回{records, total}结构前端拿到后设置表格数据和总条数这一套配合非常固定写过两个页面之后就完全机械式操作。表格里有些列需要特殊渲染我建议用scopedSlots插槽来写组件逻辑。比如审批状态列用标签展示比纯文字更好看待审核用黄色标签、通过用绿色、驳回用红色。具体写法就是在列里加一个template slot-scopescope里面再判断scope.row.status动态渲染el-tag的type。这种细节能让表格一眼望去层次分明演示的时候尤其加分。4.4 数据可视化和大屏页面的实现管理端首页的看板页面是整系统视觉上最有冲击力的一页。我用ECharts完成四块内容上报率环形图、近7天趋势折线图、各学院上报率柱状图、异常类型饼图。ECharts的用法很简单npm install echarts后在组件里import * as echarts from echarts然后准备好dom容器mounted时初始化图表拿到接口数据后setOption。这里有几个需要注意的细节。第一图表容器必须设置明确的宽高stylewidth: 100%; height: 400px不然图表渲染不出来或者显示空白。第二图表要在mounted钩子里初始化不能在created里因为created时DOM还未挂载。第三组件销毁前要调用chart.dispose()释放实例不然切换路由时会出现内存泄漏警告。因为首页有多个图表我把ECharts的初始化封装成了一个mixin公共的chartInit和chartResize逻辑放进去每个图表组件调用mixin自动完成注册和销毁。这套代码结构让我后面新增图表的速度提高了不少也方便统一处理窗口自适应缩放的问题。5. 部署、常见问题与避坑实录5.1 从开发环境到生产部署的完整过程项目开发完最终要交付的是能跑在生产环境的东西。我总结了一套最简单的部署流程而且这套流程在毕设演示时也够用。第一步后端打包。在pom.xml所在的目录执行mvn clean package -DskipTests生成一个可执行的JAR包通常叫health-admin.jar。然后上传到服务器用java -jar health-admin.jar --spring.profiles.activeprod启动指定生产环境配置。生产环境数据库连接、JWT密钥、文件上传路径都在application-prod.yml里单独配置和开发环境隔离这是一个合格项目的底线。第二步前端打包。在health-web目录执行npm run build生成dist文件夹。这个文件夹里就是纯静态文件——HTML、CSS、JS。然后把dist里的所有文件上传到服务器Nginx的/usr/share/nginx/html目录下。第三步配置Nginx反向代理。前端页面上所有/api开头的请求要通过Nginx转发到后端服务的8080端口。核心配置就两行location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }注意proxy_pass末尾的/有没有效果完全不同。我在实际配置里没有加斜杠而是让后端接口本身以/api开头这样请求路径直接透传省掉路径重写那一步的调试烦恼。生产环境还要记得配HTTPS吗对于毕设项目默认HTTP足够了但如果后续想上线展示花几块钱买个域名然后申请免费证书配置HTTPSNginx里加监听443的server块也不是多复杂的事。5.2 常见问题速查表写代码过程中我踩过不少坑这里整理成速查表基本覆盖了这类项目90%的报错点。问题现象根本原因解决方案前端请求后端报CORS跨域错误后端未允许跨域或未包含Authorization头配置CorsFilterallowedHeaders里加AuthorizationallowedOriginPatterns用*登录成功后刷新页面就退出登录用户信息存在Vuex里刷新丢失路由守卫里调/api/auth/info重新拉取用户信息数据库时间比本地时间早8小时JDBC连接串未指定时区jdbc:mysql://localhost:3306/health?serverTimezoneAsia/Shanghai上传Excel文件报文件大小超限SpringBoot默认限制1MB上传配置spring.servlet.multipart.max-file-size50MB前端表格显示的长ID精度丢失后端Long型主键超过JS安全整数范围主键字段加JsonSerialize(using ToStringSerializer.class)转为字符串返回分页查询失效返回所有数据MyBatis-Plus分页插件未注册配置MybatisPlusInterceptor并添加PaginationInnerInterceptor定时任务到了时间没执行启动类未加EnableScheduling启动类加EnableScheduling注解这中间最隐蔽的是Long类型精度问题。学生学号是数字字符串我建表时用了BIGINT后端实体对应Long结果JSON序列化后前端拿到的学号末尾几位变成0查了好几个小时才意识到是JS精度问题。这个坑几乎每个做这个项目的人都会遇到一次建议直接记住解决方案——实体类主键及学号字段统一用String或者序列化转字符串。5.3 答辩时的知识点准备与讲解技巧项目跑通只是第一步答辩时导师问的问题才是真正的考验。我根据自己的经验把这类项目最高频的问题和回答思路整理一遍。“为什么用JWT而不用Session”回答要点前后端分离架构下后端服务可能部署在多个节点Session存在单台服务器内存里无法共享JWT是无状态认证Token里自带用户信息签名服务端只负责解析校验适合分布式场景。同时注意说明JWT的缺点比如无法主动失效所以要设置合理的过期时间并用Redis做黑名单这样显得你全面。“MySQL索引为什么用B树”回答要点B树非叶子节点不存数据单节点能存储更多索引项树更矮更宽减少磁盘IO次数叶子节点用链表串联天然支持范围查询和排序。这个知识点是数据库面试的常客在这一类管理系统中体现为对user_id report_date联合索引的设计。“MyBatis-Plus和MyBatis有什么区别”回答要点MyBatis-Plus是MyBatis的增强工具内置通用Mapper单表CRUD不用手写SQL但也有局限性——复杂多表联查和动态SQL仍需手写XML核心价值是提高单表操作开发效率让我能把精力放在业务逻辑上。“Vue路由守卫的作用是什么”回答要点前端路由守卫是前端资源访问控制的一种手段配合后端接口校验形成双重防护。我这里的beforeEach守卫在每次路由跳转前判断Token和角色保证未登录用户只能访问登录页非对应角色不能进入特定管理页面。5.4 拿到源码后如何改造成自己的项目现在网上这类项目的源码非常多但直接交源码当作业的风险很大。我对拿源码改项目的同学有几点实用建议。第一一定要先在自己电脑上把项目跑起来。官网下载JDK、Maven、MySQL把这些依赖装好。遇到环境配置问题不要慌几乎所有人第一次都会在Maven依赖下载或Node版本兼容上卡住。跑通之后你才有底气说“这个项目你亲手调试过”。第二替换数据库初始化脚本里的默认账号密码。几乎所有开源项目的初始化SQL里都有admin/123456这类弱口令这是安全审查看得最紧的一点。你把默认密码改掉再在代码里搜索硬编码的密码、密钥并移动到配置文件里这一项在课设答辩中就能额外加分。第三增加一个原创模块。哪怕只是加一个“公告附件上传下载”或者把某个列表增加导出PDF功能都要比原封不动交源码好。原创模块能让你在“项目创新点”这一页有话说这也是最容易体现你确实理解系统的地方。别贪多加一个功能即可把新模块的代码吃透能够独立讲解比加十个半懂不懂的功能有用得多。第四记得把项目里的个人信息、学校信息、Logo全部替换掉。这个是常识但每年都有学生忘记答辩时被老师一眼看出是下载的。最后说一个个人经验做课设或毕设最重要的不是把代码敲得多炫而是“讲得出、说得通”。你去看那些拿到高分的人往往不是代码写得多牛而是能把自己的设计决策、业务理解讲得头头是道。把这份系统当成一个真实产品去研究——它解决什么问题、每个模块为什么存在、数据从哪里来到哪里去——哪怕代码有瑕疵态度和思路也能让老师觉得这是你自己做出来的东西。提前祝你这个项目能顺利通过答辩。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑