ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot+Vue疾病防控综合管理平台设计思路与实战解析

SpringBoot+Vue疾病防控综合管理平台设计思路与实战解析 SpringBoot Vue 的疾病防控综合系统管理平台这几年在毕业设计和课程设计里出场率非常高。它本质上是一个围绕公共卫生业务做的前后端分离管理系统技术底座就是 Java、SpringBoot、Vue 和 MySQL。整套系统解决的不是什么高深算法而是把防控工作中常见的对象——人员、疾病、接种、健康申报、物资——统一管理起来做成可查询、可统计、可预警的后台。如果你正在找一套能跑通、能答辩、能学到真实项目结构的源码这篇文章就把它的设计思路、核心实现、运行方式和经典坑位全部拆开讲一遍。适合的人群我大概分三类准备做毕设的学生需要一个真实可演示的业务系统正在做课设或实训、想快速搭建一套前后端分离项目的同学以及想完整过一遍 SpringBoot Vue 开发流程把技术栈串起来的自学者。不管你是哪种这套系统的难度都处在“跳一跳够得着”的区间里——太简单没有答辩内容太难又会卡在环境上浪费时间。下面我按从整体架构到具体实现、再到部署答辩的顺序慢慢聊。1. 项目整体架构与技术选型1.1 为什么选 SpringBoot Vue 这套组合很多人问过我毕设题目是不是不该选前后端分离怕自己给自己挖坑。我的看法恰好相反前后端分离才是当下企业项目的常见形态SpringBoot 负责后端接口Vue 负责页面渲染两边通过 JSON 交互。你把这个结构装进简历和项目描述里面试官第一印象就是“这人接触过真实项目”比一个单体的 JSP 管理系统的说服力强得多。更关键的是这套组合的生态太完整了。后端遇到问题搜索 SpringBoot 基本都有现成答案前端遇到问题搜索 Vue 也有一堆案例组件库、脚手架、部署方案都成熟得不能再成熟。对开发经验不多的学生来说选一个“资料多、坑少、轮子全”的组合比选一个新奇但冷门的技术重要得多。后端按 Controller、Service、Mapper 分层写下来哪怕是第一次做项目代码也能保持整洁搭配 MyBatis-Plus 后单表 CRUD 几乎不用手写 SQL开发效率明显提升。前端 Vue 的学习曲线比想象中平滑组件化开发和响应式数据绑定很容易上手Element 这类组件库再把表格、表单、弹窗、分页全部兜住你只需要专注业务逻辑。1.2 版本选型与模块划分思路版本选型是个容易忽略但非常要命的点。早期毕设源码大量使用 SpringBoot 2.x Vue 2 Element-UI这套老组合 JDK 1.8 就能跑资料丰富稳定可靠Vue 3 Element Plus Vite 是当前新项目的主流但搭配 SpringBoot 3.x 通常需要 JDK 17。如果你拿到的源码是老版本别急着“升级”优先保证代码能平稳跑起来技术选型的现代化可以放在后面再考虑。我建议的稳定组合是SpringBoot 2.7.x MyBatis-Plus 3.5.x JJWT 0.9.x Vue 2.7.x Element-UI 2.15.x ECharts 5.x MySQL 8.0。这套方案我在 Windows 和 Linux 上都实测过依赖下载、编译、打包都很顺畅。功能模块是这套系统真正的核心看点一般至少包含系统管理、健康申报、病例管理、疫苗接种管理、防控物资管理、统计报表和公告通知。系统管理下面又拆分用户、角色、菜单三项用来支撑权限控制健康申报负责每日体温和症状上报病例管理和疫苗接种管理是业务主线数据量最大物资管理要处理出入库和库存预警统计报表把所有数据变成图表也是答辩时最容易展示成果的模块。2. 数据库设计与核心表结构2.1 建库规范与表设计思路数据库是整个系统的地基地基不稳后面全是坑。我用 MySQL 8.0建库统一使用 utf8mb4 字符集排序规则用 utf8mb4_general_ci这样中文字段和特殊符号都能正常存放避免乱码问题。所有表的主键都用自增 bigint统一命名为 id字段全部使用下划线风格比如 user_name、create_time。为了避免误删数据我建议在有业务关联的表上都加 delete_flag 逻辑删除字段用 0 表示未删除、1 表示已删除。MySQL 版本如果低于 5.7datetime 类型默认值的写法会因为版本差异报错建议在老版本里直接写 CURRENT_TIMESTAMP或者升级到 8.0 再统一处理。再说为什么一定要保留逻辑删除。疾病防控系统的数据是有连续性的一条病例记录会关联后续的接种记录、健康申报、隔离观察记录。如果直接把病例物理删除所有关联数据都会悬空后续统计也全乱套。用了逻辑删除之后用户只是界面里看不到这条数据数据本身仍然存在做趋势分析也不会丢历史。2.2 核心数据表详细拆解下面这张表把系统涉及的核心表整理成了清单方便你对照源码理解表名说明关键字段sys_user系统用户表id, username, password, nickname, role_id, avatar, phone, status, delete_flagsys_role角色表id, role_name, role_key, descriptiondisease_info疾病信息表id, disease_name, disease_type, pathogen, incubation_period, transmission_route, prevention_measure, statuscase_record病例记录表id, disease_id, patient_name, id_card, gender, age, address, onset_date, diagnosis_date, report_date, doctor, hospital, isolation_flag, current_status, descriptionvaccination_record疫苗接种表id, patient_id, patient_name, vaccine_name, dose_no, vaccination_date, vaccination_site, manufacturer, doctor, remarkhealth_report健康申报表id, user_id, report_date, temperature, cough_flag, fatigue_flag, other_symptom, location, statusmaterial_info防控物资表id, material_name, material_type, unit, stock, warn_value, specificationmaterial_record物资出入库表id, material_id, type, quantity, operator, operation_time, remarkisolation_record隔离观察表id, user_id, patient_name, start_date, end_date, address, contact_phone, daily_temp, statusannouncement公告通知表id, title, content, publisher_id, publish_time, status这里重点说病例记录表。疾病防控系统和普通 CRUD 系统最大的区别在于“追踪”所以 case_record 里一定要有 onset_date发病日期、diagnosis_date确诊日期、report_date上报日期三个时间字段。后面做趋势统计、计算报告及时率全都靠它们。id_card 字段建议加唯一索引防止同一个人被重复登记这个约束在真实场景里非常关键。2.3 表关系与常用统计 SQL表之间尽量不建物理外键只保留逻辑关联。比如 case_record 通过 disease_id 关联 disease_infohealth_report 通过 user_id 关联 sys_user。不建物理外键的好处是方便数据清理和批量导入也避免外键带来的性能损耗开发时少了很多约束麻烦。但这不代表可以乱删程序代码里仍然要严格控制关联关系防止出现孤儿数据。统计报表需要几条高频 SQL。统计每月病例数的 SQL 长这样SELECT DATE_FORMAT(report_date, %Y-%m) AS month, COUNT(*) AS total FROM case_record WHERE delete_flag 0 GROUP BY DATE_FORMAT(report_date, %Y-%m) ORDER BY month;统计物资库存预警的 SQLSELECT material_name, stock, warn_value FROM material_info WHERE delete_flag 0 AND stock warn_value;这两条 SQL 就是后端统计模块的数据来源。写统计 SQL 的时候一定记得把 delete_flag 0 放在 WHERE 条件里否则逻辑删除的数据会混进统计结果图表数据对不上答辩被老师一问就很尴尬。我在这个细节上吃过亏当时图表显示的病例数量怎么都对不上查了半天才发现是清理数据的同学把记录标记成了删除状态。3. 后端核心模块实现3.1 项目分层与统一返回封装后端项目我习惯按“控制器到服务到数据访问”拆包典型结构如下com.example.disease ├── config // 配置类如跨域、拦截器注册 ├── controller // 接收请求、返回结果 ├── service // 业务逻辑 ├── mapper // 数据访问 ├── entity // 数据库实体 ├── dto // 请求参数封装 ├── vo // 返回视图对象 └── common // 通用工具、统一结果Controller 只做参数接收和结果返回业务全部下沉到 ServiceMapper 只负责数据读写。这样拆的核心好处是后期加功能时不会牵一发动全身。比如我想在健康申报模块里加一个自动预警就只需要改 Service 层的方法Controller 完全不用动。代码结构清晰答辩时讲项目也能分模块讲得有条理。为了统一前后端交互规范必须封装统一返回结构。我封装了一个 Result字段为 code、msg、data。成功返回 code200业务异常返回 code500未登录返回 code401。前端 axios 拦截器统一判断 code 然后弹出对应提示接口逻辑一下干净了很多。Data public class ResultT { private Integer code; private String msg; private T data; public static T ResultT ok(T data) { ResultT r new Result(); r.setCode(200); r.setMsg(操作成功); r.setData(data); return r; } public static T ResultT error(Integer code, String msg) { ResultT r new Result(); r.setCode(code); r.setMsg(msg); return r; } }3.2 登录认证与权限控制设计权限控制我推荐 Spring Security JWT 的组合。用户登录时校验用户名密码成功之后签发一个 JWT前端把 token 保存在 localStorage每次请求在请求头里携带 Authorization。后端拦截器解析 token从 Redis 里取用户信息再判断当前接口是否有访问权限。Redis 里没存用户信息时再查数据库这样可以减少数据库压力又不会因为缓存更新不及时导致权限判断出错。如果不熟悉 Spring Security 的复杂配置也可以退一步写一个简单的 JWT 拦截器把所有需要登录的接口拦截下来解析 token把用户信息塞进 ThreadLocal。但既然题目叫“综合系统管理平台”答辩时提到 Spring Security 比只写“我用了一个拦截器”要专业得多。密码必须用 BCrypt 加密存储千万不能明文保存。我见过太多学生源码把密码直接放在数据库里答辩老师让打开数据库一看就穿帮了这是一个非常掉价的低级问题。JWT 的过期时间我一般设置为 2 小时过期后要求重新登录避免 token 被长时间滥用。实际项目里还可以做“单设备登录”同一账号登录后新 token 覆盖旧 token旧 token 直接失效。实现方式就是在 Redis 里存当前有效 token每次请求比对一下即可代码量不大但能讲出的故事很多。3.3 核心业务接口实现示例以健康申报模块为例业务流程是用户进入申报页系统自动带出当前登录人信息填写体温、症状、当前城市后提交后端保存数据如果体温大于 37.3℃ 或者勾选了咳嗽、乏力这些症状系统自动把这条记录标记为异常并在首页生成预警提示。这个流程可以完整展示“提交到校验到反馈”的后端闭环。Controller 层代码大致如下RestController RequestMapping(/api/healthReport) public class HealthReportController { Autowired private HealthReportService healthReportService; PostMapping(/submit) public Result? submit(RequestBody HealthReportDTO dto) { healthReportService.submitReport(dto); return Result.ok(null); } GetMapping(/page) public Result? page(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String status) { return Result.ok(healthReportService.getPage(pageNum, pageSize, status)); } }Service 里需要处理的事情就多了先判断该用户当天是否已经申报如果已申报则提示“今日已提交不能重复申报”然后组装实体用 MyBatis-Plus 的 insert 入库最后判断异常状态异步生成一条预警记录。这里“一天只能申报一次”的业务约束我建议在数据库层面用唯一索引 user_id report_date 来兜底否则高并发场景下可能出现重复数据。虽然毕设不一定会被并发打到但这样做体现了对数据完整性的重视。4. 前端 Vue 页面实现4.1 工程搭建与依赖安装前端工程可以选 Vue CLI 或者 Vite 初始化。如果你下载的是成熟的毕设源码里面多半已经带好 package.json直接执行 npm install 装依赖就行。但单靠命令行执行 install经常遇到网络超时或者某些依赖反复下载失败的问题我建议先把 npm 镜像切换到国内镜像速度会快很多能省下大量查报错的时间。必要依赖包括vue-router 负责路由axios 负责请求element-ui 负责组件echarts 负责图表。安装时注意版本和 Vue 版本要匹配Vue 2 配 Element-UIVue 3 则需要 Element Plus。装反了会出现组件全部不渲染、页面白屏的诡异现象。一个干净的前端目录大致如下src/ ├── api/ // 接口请求封装 ├── assets/ // 静态资源 ├── components/ // 公共组件 ├── router/ // 路由配置 ├── store/ // 状态管理 ├── views/ // 页面 ├── App.vue └── main.js4.2 路由配置与权限守卫路由配置分两块静态路由和动态路由。静态路由包含登录页、404 页动态路由是登录后根据用户角色从后端拉取菜单再通过 router.addRoutes 动态添加这样不同角色登录后看到的菜单不一样配合后端接口鉴权形成双保险。角色为管理员时能看到系统管理和全部业务菜单普通用户登录后只看到健康申报和公告这比所有用户看到同一套界面要合理得多。路由守卫的作用是防止未登录用户直接输入地址跳进系统。我把检查逻辑写在 router.beforeEach 里没有 token 就跳登录页有 token 但没角色信息就去拉取用户信息。这个守卫写得不好会出现循环跳转所以跳转时要判断目标路由是否就是登录页否则你会发现控制台疯狂报 “NavigationDuplicated” 或路由守卫死循环日志刷得根本停不下来。4.3 axios 封装与接口对接axios 封装我固定放在 src/api/request.js。统一配置 baseURL拦截器里给每个请求加上 token响应拦截器里统一处理错误码。如果后端返回 401清空本地登录态并跳转登录页如果返回 500用 Element-UI 的 Message 组件弹出后端 msg。这样前端页面里只需要关心业务数据不用每个接口都写一遍错误处理。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] token } return config }) request.interceptors.response.use(response { const res response.data if (res.code ! 200) { Message.error(res.msg || 请求出错) if (res.code 401) { localStorage.clear() router.push(/login) } return Promise.reject(res) } return res.data }, error { Message.error(网络异常请检查后端服务) return Promise.reject(error) }) export default request4.4 列表、表单、图表实现要点列表页的一般套路是页面加载时请求第一页数据表格显示分页组件关键字查询时重置页码到 1。表格的列字段要和后端返回的字段名保持一致时间字段先格式化再显示性别字段用 formatter 转成中文。Element-UI 的 el-table 配合 el-pagination几分钟就能完成一个标准列表。需要特别注意的是表格加载时会有一瞬间的空白最好绑定 loading 状态否则体验很差。表单页要小心回显和校验。编辑场景下打开弹窗时用数据回显到表单保存时要区分新增还是更新通常通过 id 是否为空来判断。校验规则用 el-form 的 rules必填项给 required数字字段用数字类型校验日期字段限制范围的逻辑写在 change 事件里。我见过很多同学习惯性把新增和编辑写成两个接口其实一个接口加一个 id 判断就能搞定代码量减半。图表用 ECharts。柱状图展示每月新增病例饼图展示疾病类型分布折线图展示健康申报异常率趋势。这里有一个经典坑图表容器高度为 0 导致图表不渲染解决方案是在容器上强制设置 height: 400px并且 init 的时机放在 DOM 渲染完成后必要时配合 setTimeout 延迟初始化。图表数据加载前先显示 loading数据返回后 setOption 再隐藏 loading展示效果会专业很多。5. 环境准备与本地运行5.1 版本兼容对照与安装建议运行环境是很多同学第一个卡住的地方版本不匹配导致的各种诡异报错能浪费一整天。我整理一份对照表照着搭基本不会翻车软件推荐版本说明JDK1.8对应 SpringBoot 2.x或 17对应 SpringBoot 3.x用老源码别碰新 JDK高版本 JDK 编译老代码经常报 Lombok 兼容问题Maven3.6建议配置国内镜像仓库否则下载依赖等到怀疑人生Node.js14/16/18 LTSVite 项目需要 Node 14老 Vue CLI 项目用 Node 14 最稳MySQL5.7 或 8.0注意驱动配置和 serverTimezoneIDEIntelliJ IDEA社区版也能完成所有操作准备工作完成后的第一步不是写代码而是先建库。建库脚本一般在源码的 sql 文件夹里用 Navicat 或命令行执行均可。直接跑可视化工具比命令行省事跑之前确认字符集建库语句带 DEFAULT CHARSETutf8mb4数据导入后中文才不会乱码。5.2 后端启动流程后端启动的核心是 application.yml以下是一份典型配置改成你自己的数据库账号密码就能用server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/disease_prevention?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: 123456 servlet: multipart: max-file-size: 10MB mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleteFlag logic-delete-value: 1 logic-not-delete-value: 0启动时有两提醒第一端口 8080 被占用时要么结束占用进程要么改 server.port第二MySQL 8.0 的驱动必须是 com.mysql.cj.jdbc.Driver老驱动在新版本下会直接报 ClassNotFoundException。启动成功后控制台看到 Tomcat started on port(s): 8080后端就算活了可以先用 Postman 调一个接口测试。5.3 前端启动流程前端启动前先安装依赖到前端项目根目录执行npm install npm run serveVite 项目则执行 npm run dev。启动后浏览器访问 http://localhost:8081登录页就能看到。前后端分离开发时前端通过代理解决跨域在 vue.config.js 里配置 devServer.proxy把 /api 开头的请求转发到 8080。这一步不配浏览器请求就会因为跨域被拦截页面列表永远出不来数据。如果你用的是 Vite则在 vite.config.js 里配置 server.proxy规则略有差异但思路一致。5.4 打包部署到服务器部署到服务器时先用 maven package 把后端打成 jar然后执行java -jar disease-prevention.jar前端执行 npm run build会生成 dist 目录。这里有两种部署方式一是把 dist 里的资源复制到 Nginx 的 html 目录再配置 Nginx 反向代理 /api 请求到后端二是把 dist 文件复制到 SpringBoot 的 resources/static 目录重新打包成单体应用一个 jar 直接跑前后端。我推荐 Nginx 方式静态资源和接口请求分离后期维护方便扩展也更灵活。单体打包时注意要把前端打包后的 index.html 放到 static 目录同时确保 SpringBoot 没有开启严格的静态资源映射否则刷新页面会出现 404。Nginx 方式则要在配置里加 try_files把前端路由的所有访问都重写到 index.html否则用户在首页点进二级页面后一刷新就是 404。6. 常见问题与排查技巧6.1 后端启动报错速查后端最常见的报错是数据库连不上。报错信息里只要出现 Communications link failure第一反应检查 MySQL 服务有没有启动第二检查 IP、端口、账号密码第三检查驱动和 url。用 druid 连接池时还需要检查连接池配置是否超过了 MySQL 的默认连接数。我建议把 mybatis-plus 的 log-impl 打开这样每个 SQL 都打印在控制台排查问题一目了然。Maven 依赖下载不下来是另一个高频问题。换国内镜像后如果仍然报错就清理本地仓库缓存文件再重新 import。遇到 Lombok 编译报错先检查 IDEA 是否安装了 Lombok 插件并开启 Annotation Processing。还有一类隐蔽问题JDK 版本过高导致 maven 插件解析失败这种错误信息通常很抽象把 JDK 降到 1.8 或 17 的对应版本后问题自然消失。6.2 前端运行报错速查前端最常见的表现是页面能打开但表格数据为空、接口一直报错。先从浏览器 Network 面板看请求状态如果请求被 CORS 拦截说明跨域没配好如果请求 404说明前端代理配置不对或者后端接口路径有差异比如前端的 baseURL 是 /api后端接口却写成了 /api/healthReport前端请求 /api/api/healthReport 时路径就多了一段这种情况仔细对比就能发现。Element UI 组件不渲染、页面白屏多半是依赖版本或引入方式问题。Vue 2 项目用了 Vue 3 的 Element Plus 会导致组件全部消失需要检查 package.json 里版本号。还有一种情况是组件注册了但忘记在模板中使用页面自然一片空白。这种低级错误很常见排查时从最小页面开始逐步缩小范围比盯着整屏代码瞎找有效得多。6.3 部署后的经典坑部署后最容易遇到的是刷新 404。这个问题的本质是 Nginx 没有处理前端路由。Vue 用 hash 路由时 URL 里带 #不会触发这个问题但 history 模式下服务器必须把所有路径都重写到 index.html配置如下location / { try_files $uri $uri/ /index.html; }后端配置了拦截器但前端不知道偶尔会出现已登录但请求仍被拦截的情况。排查时先看请求头里有没有 token 字段再看拦截器读取的字段名是否一致比如前端传的是 Authorization后端读的是 token两边对不上必然 401。Token 过期也会产生类似表现所以后端拦截器返回 401 时最好附上具体原因前端根据原因提示“登录过期”还是“未登录”用户体验差别很大。7. 毕设答辩与功能扩展建议7.1 讲清楚项目的三个核心亮点答辩时老师不会逐行看代码更关心你有没有真正理解业务系统。我建议抓住三点去讲。第一是权限设计为什么要做多角色一张 user 表加 role_id 字段如何撑起数据权限如果把某个菜单加给用户需要改几张表这些细节讲清楚能体现思考深度。第二是流程闭环以健康申报为例从用户提交、后端校验、异常标记到预警展示完整链路有多长异常分支怎么处理这是综合型项目最有价值的部分。第三是工程化细节统一返回、全局异常、逻辑删除、SQL 统计每一条都证明你具备基本工程意识而不是只会复制粘贴。7.2 二次开发与扩展方向如果想让项目更有竞争力我强烈建议在原有体系上做几个小的增量优化。最省力的方向是引入 Redis登录 token 存储、缓存统计数据、记录用户在线状态代码改动量不大但能讲出很多干货。其次是 EasyExcel防控数据批量导出在真实场景很常见给报表模块加一个导出 Excel 的功能答辩现场演示很加分。再做深一点可以加定时任务每天凌晨自动汇总前一天的数据生成日报表这就是把真实业务场景落地的表现。所有扩展都建议在保障原功能可运行的前提下进行不要贪多。每加一个功能都要能说清它解决什么痛点、实现方式是什么、有没有副作用。比如 Redis 加缓存要能说清缓存更新策略否则老师追问“数据不一致怎么办”就容易卡壳。还有一点必须提醒密码明文存放这类低级安全问题一定要处理掉。密码用 BCrypt 加密登录时用 matches 校验只是几行代码的事但对系统专业度观感的提升非常明显。做完这个系统最直接的收获是它逼着我真正打通了几个以前只是“看过”的技术点JWT 认证在请求到后端之后是怎样一步步被验证的MyBatis-Plus 的逻辑删除是怎么在 SQL 层生效的Vue 路由守卫为什么会循环跳转Nginx 为什么会刷新 404。这些都是在教程里看一百遍不如自己踩一遍的坑。如果你拿到的源码能跑起来先把每一层代码打开看一遍然后改一个小需求再跑通一次比如给健康申报加一个“所属区域”字段。哪怕只是加一个字段也会迫使你从前端表单、后端接收、数据库字段、列表展示完整走一遍。做完这一步这套源码才算真正变成你自己的东西答辩时心里才有底。最后再说一个小技巧拿到任何毕设源码后第一件事不是启动项目而是先建库、再手动造几套完整的测试数据。空数据库的演示效果非常差页面图表全空白看起来像系统没做完。把病例、接种、申报、物资各造十几条有规律的数据时间跨度拉开一点图表和统计立刻就有说服力。这个动作花不了半小时但对最终演示观感和答辩印象的影响值得你再三重视。
返回列表