尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SpringBoot+Vue+MyBatis+MySQL疾控系统源码解析与部署

SpringBoot+Vue+MyBatis+MySQL疾控系统源码解析与部署 1. 项目定位与整体架构思路1.1 一套疾控系统到底要解决什么问题做企业级疾病防控管理系统的朋友大概率是接到了这样的需求整个单位、园区或者区域范围里员工/居民的健康数据散落在Excel里消杀记录写在纸质台账上异常情况靠微信群喊上级检查时临时凑报表。这套系统的核心价值就是把“人、事、物、数”四条线全部收拢到一个平台里人人员的健康档案、体温监测、异常症状记录、疫苗接种情况事疫情上报、流调追踪、消杀任务、隔离管理、通知公告物防护物资的入库、出库、库存预警数各类统计报表、趋势分析、可视化大屏我拿到这套SpringBootVueMyBatisMySQL的完整源码时第一反应是去看它的模块边界是否清晰。很多“完整版”源码其实只是CRUD堆砌但这一套在业务流程上是能闭环的——从“发现异常”到“上报审批”、“任务派发”、“消杀执行”、“结果复查”每个环节都有对应的表和状态流转。这一点对于参考学习或者二次开发都非常重要因为只有流程闭环你才能在里面真正跑通一个业务场景而不是对着空壳子看代码。1.2 前后端分离技术栈为什么这么选这套系统采用的是经典的前后端分离方案后端SpringBoot前端Vue持久层MyBatis数据库MySQL。很多新人会问现在都2025年了为什么不直接上Spring Cloud微服务为什么不配个Redis为什么不搞个XXL-Job我的看法是企业级不等于大规模分布式。对于一个单体就能扛住几千人同时访问的疾控管理系统来说用微服务纯属给自己找麻烦。具体到每个组件的选型理由组件选型理由实际工作中的体会SpringBoot简化配置内置Tomcat快速启动版本别追太高2.7.x这个区间最稳Vue组件化开发配合Element UI能快速搭建后台界面2.x和3.x都行源码用的哪个版本就按哪个来MyBatisSQL可控性强复杂关联查询好调优比JPA直观排查SQL问题方便MySQL成熟稳定运维成本低生产环境建议8.05.7也完全能跑这套组合最大的优势用一句行话概括就是“没有惊喜也没有惊吓”。每个环节都有海量的文档和踩坑案例遇到诡异问题基本都能搜到答案。我之前经手过用JPA写的项目查询逻辑一复杂生成的SQL惨不忍睹还得靠Query手写绕了一圈还不如直接用MyBatis。1.3 系统整体架构规划整个系统可以拆成三层来看前端层Vue脚手架项目路由由Vue Router管理状态用Vuex/PiniaUI框架用Element系列组件表格、表单、弹窗、树形控件都是现成的图表用ECharts。构建产物是纯静态文件打包后丢到Nginx或SpringBoot的static目录里都行。后端层标准的Controller-Service-Mapper三层架构。Controller层只做参数接收和结果封装Service层处理业务逻辑和事务Mapper层通过MyBatis操作数据库。安全认证这块用的是JWT无状态令牌前端每次请求头里带Authorization即可不需要Session天然适合前后端分离。数据层MySQL负责持久化核心业务表包括用户表、角色权限表、健康档案表、异常上报表、消杀任务表、物资表、通知公告表等。表与表之间通过外键逻辑关联实际开发中一般不建物理外键靠应用层维护配合MyBatis的动态SQL处理复杂查询。2. 后端核心模块设计与实现细节2.1 基于RBAC的权限管理体系疾控系统涉及的人员角色非常多系统管理员、疾控专员、部门负责人、普通员工、消杀人员……如果没有一套靠谱的权限模型后面加功能的时候会痛不欲生。这套系统用的是经典的RBAC基于角色的访问控制模型五张表用户表、角色表、菜单表、用户角色关联表、角色菜单关联表。我重点看了它的权限拦截实现登录后后端根据用户ID查出角色再根据角色查出菜单权限码集合生成JWT时把这些权限码塞进Claims里。前端拿到Token后通过this.$store.dispatch(getInfo)拉取用户信息和权限码列表路由守卫里做动态路由注册菜单根据权限码过滤渲染。这套逻辑是比较成熟的做法具体到代码里的实现要点有三个密码存储不能明文源码里用的是BCrypt加密这个别改。BCrypt会自动加盐同一个密码每次加密结果都不同安全性远超MD5。Token要设置过期时间一般2小时。别忘了刷新机制否则用户用着用着突然被踢出去体验极差。接口层面也要校验权限不能只依赖前端藏按钮。后端的做法是写一个PreAuthorize(hasAuthority(disease:report:add))之类的注解或者在拦截器里统一校验。注意我见过不少“完整版”源码前端菜单做了权限控制后端接口裸奔任何登录用户都能调管理接口。排查源码时重点看一眼后端有没有做接口级鉴权没有的话一定得补上否则等于把门锁装在了画上。2.2 疫情上报与预警的流程设计疾病防控系统区别于普通OA的最大特点就是有“事件驱动”的业务逻辑。这套源码里疫情上报模块不是一个简单的增删改查而是一条带状态机的审批流程。我梳理了一下它的核心状态流转待上报 → 待审核 → 已确认/已驳回 → 处理中 → 已处置 → 已归档每个状态变更都记录在日志表里谁在什么时间把状态从A改成了B一目了然。这个设计思路值得学习——不是所有业务都值得上工作流引擎Activiti/Flowable对于状态清晰、流转固定的场景用状态字段加日志表反而更轻量、更好维护。预警这块是亮点系统里有一个定时扫描任务用SpringBoot自带的Scheduled注解每隔一段时间扫描异常上报表中“待处理且超过N小时未响应”的数据自动给对应的负责人发通知。还有一个阈值预警如果某个区域当日发热报告人数超过设定阈值自动触发黄色预警推送短信或站内信。这套逻辑不复杂但是因为它把“被动录入”变成了“主动发现”整个系统的使用价值就上来了。实现定时任务时有几个细节容易踩坑Scheduled默认是单线程串行执行多个任务会互相阻塞。要配一个ThreadPoolTaskScheduler或者把spring.task.scheduling.pool.size调大。定时任务里一定要做幂等控制防止重复执行导致重复通知。源码里用的办法是加一个task_status字段执行前先UPDATE抢占状态执行完再改结束状态。扫描SQL要注意索引WHERE status pending AND create_time NOW() - INTERVAL 2 HOUR这种查询在status和create_time上建联合索引否则表数据量一大就慢。2.3 消杀任务调度与跟踪消杀管理是这个系统里业务流程最完整的模块。从任务创建指定区域、指定负责人、指定消杀方式、任务派发短信/站内信通知、执行反馈上传消杀记录和照片、到结果验收检查合格/不合格整条链路都有对应功能和页面。我在源码里特别注意了它的照片上传部分用的本地文件存储上传路径可配置保存后在数据库记录文件URL。这种方式在中小型系统里完全够用但有几个坑必须提醒本地存储路径千万别写在项目根目录下否则每次重新部署文件就丢了。要配置成绝对路径比如/data/upload/。上传文件的访问要单独做映射。SpringBoot里可以通过addResourceHandlers方法把/upload/**映射到本地磁盘路径。如果将来要部署在多台服务器上本地存储会出问题那时候再考虑改造FastDFS或MinIO。前期没必要过度设计。任务调度这里还涉及一个多角色协作的场景疾控专员创建任务 → 分配给消杀小组 → 消杀人员手机端或者PC端接收任务 → 执行后回传结果 → 疾控专员审核。这套源码的前端页面里任务列表针对不同角色有不同视图用的全是同一套接口靠后端根据当前登录用户的角色动态返回不同数据。这个设计比较巧妙避免了给每个角色单独写一套接口。2.4 数据统计与可视化接口设计管理类系统做到最后领导最关注的就是数据大屏和统计报表。这套系统的统计模块用的是ECharts做可视化后端提供聚合查询接口。我看了它的SQL写法几个关键点做得比较规范日报/周报/月报通过MySQL的DATE_FORMAT函数按时间分组配合COUNT、SUM聚合。趋势图按日期序列返回每天的累计确诊/疑似/治愈人数前端用折线图展示。区域分布按部门/楼栋/区域分组统计前端用柱状图或地图展示。排名各部门异常情况排名、各区域消杀完成率排名用ORDER BY加LIMIT实现。这里有个性能问题值得单独说如果统计接口每次都是实时查全表数据量一上来就废了。解决办法有两个方向——一是定时把统计结果算好存到冗余表里查询只查结果表二是用MySQL的物化视图思路手动维护一个汇总表。这套源码用的是实时查询在小规模场景下没问题但如果要做大屏实时展示建议提前考虑汇总表的方案。另外大屏数据接口要做好缓存控制。ECharts大屏通常是轮询刷新比如30秒一次如果每次都打数据库压力不小。可以在Service层加一层ConcurrentHashMap做短时缓存或者直接上Redis。源码里没有Redis我建议在二次开发时补上成本很低但收益明显。3. 数据库设计表结构、事务与性能优化3.1 核心表结构拆解拿到源码第一步先看sql目录下的初始化脚本。这套数据库脚本是完整的建库、建表、初始化数据一步到位。我挑几张核心表说一下设计思路用户表sys_user主键、用户名、密码BCrypt密文、姓名、手机号、部门ID、状态、创建时间。有个细节做得不错用户表里存了dept_id通过部门ID可以快速做数据隔离比如“我只查得到本部门的人员健康数据”这个字段在后续做数据权限时非常关键。健康档案表health_record人员ID、体温、症状描述、接触史、检测结果、记录时间。这张表是典型的高频写入表每天每个员工可能有多条记录。设计上的要点是给person_id和record_date建联合索引因为最常见的查询就是“某个人某段时间的体温趋势”。异常上报表disease_report上报人、异常类型、涉及人员、描述、状态、审核人、审核意见、时间。状态字段用tinyint类型存0待审核、1已确认、2已驳回、3处理中、4已处置配合status索引。消杀任务表disinfect_task任务编号、区域ID、消杀方式、负责人、执行时间、完成状态、检查结果。注意任务编号不要用自增ID要用类似XT20250612001的业务编号方便线下沟通时引用。物资台账表material_stock物资名称、规格、库存量、安全库存阈值、入库时间、最后更新时间。库存操作必须有事务控制否则并发下会超卖。初始化数据这块要给个好评源码带了完整的菜单、角色、管理员账号数据导入数据库后直接能用admin登录不用自己挨个建菜单建权限省了大量前期调试时间。3.2 MyBatis层的最佳实践MyBatis在这套系统里的用法非常规范我按照“XML配置 接口绑定”的方式去审视了一遍有几个点值得大家在自研时参考别名与驼峰映射application.yml里全局开启了map-underscore-to-camel-case: true数据库字段的user_name自动映射到Java属性的userName省去了一堆resultMap。这个配置强烈建议保留别因为看着不习惯就关掉。动态SQL在员工健康档案的列表查询中用了where标签配合多个if条件实现多条件组合查询。这是MyBatis最精髓的用法比在Java代码里手动拼SQL字符串优雅一万倍。批量操作批量插入用的是foreach标签注意MySQL的JDBC连接串要加allowMultiQueriestrue或者使用rewriteBatchedStatementstrue参数否则批量插入性能还是上不去。结果映射多表关联查询时MyBatis提供了association和collection标签。源码里用户和角色、任务和区域就是用的这种写法一个嵌套查询搞定不用写多条SQL再手工装配。缓存MyBatis自带一级缓存SqlSession级别和二级缓存Mapper级别。这套系统默认没开二级缓存我的建议是查询频率高、数据变化少的配置表比如区域表、物资类型表可以开二级缓存但注意缓存失效策略要设好业务表千万别开会出现脏读。3.3 MySQL配置与索引优化要点数据库是整个系统的底座配置不好后面业务跑起来全是坑。结合这套源码我建议按以下配置来优化字符集建库时用utf8mb4不是utf8。utf8在MySQL里最多存3字节像“”这种生僻字或某些特殊符号会存不进去导致报错。utf8mb4是完整版兼容性最好。连接参数JDBC连接串里一定要加serverTimezoneAsia/Shanghai否则默认时区跟中国差8小时所有时间字段都会错位。如果你用的MySQL是8.x还要加useSSLfalse不然启动时会有SSL警告极端情况下直接连接失败。排序规则推荐utf8mb4_general_ci不区分大小写或utf8mb4_unicode_ci。中文排序需求不强一般用前者就够。核心索引这个要说细一点。排查了源码里所有Mapper的SQL之后我把高频查询整理了一遍health_record(person_id, record_date)联合索引支撑“查某人某段时间的记录”disease_report(status, create_time)联合索引支撑“查待处理/按时间排序”disinfect_task(assignee_id, status)联合索引支撑“查某人名下未完成任务”sys_user(username)唯一索引登录查询用这里要特别纠正一个新手常见错误索引不是越多越好。每个索引都会降低写入性能、占用磁盘空间。拿disease_report表来说你建了(status, create_time)联合索引单独查status的时候也能命中这个索引最左前缀原则所以没必要再单独建一个status索引。事务控制物资出库、任务状态变更这类涉及金额/状态的操作Service层一定要加Transactional注解。这套源码在物资管理模块做了事务控制但任务状态流转有些地方没加。建议二次开发时全面检查一遍凡是“先查后改”“先扣库存再记日志”的全部包上事务。4. 从源码到上线完整实操记录4.1 环境准备与后端启动拿到源码后我最建议的顺序是先跑起来再看代码。一个能运行的系统比一份代码更能让你快速建立起整体认知。环境准备这块我用的是下面的组合实测兼容性非常好JDK 1.8如果你用的SpringBoot是2.x就别上JDK17会有兼容问题Maven 3.6MySQL 5.7或8.0Node.js 14Vue项目构建用IDEA 或 Eclipse后端开发IDE第一步创建数据库。执行源码里提供的sql/init.sql脚本mysql -uroot -p source /path/to/sql/init.sql;脚本执行完成后检查一下是不是所有表都建出来了。我遇到过很多次的情况是脚本中间某条SQL报错后面的表全没建系统启动时Mapper映射找不到表各种报错。稳妥的做法是执行完后用SHOW TABLES;确认一遍表数量。第二步修改数据库连接配置。打开application.yml或application-dev.yml把数据库地址、账号、密码改成自己的spring: datasource: url: jdbc:mysql://localhost:3306/disease_control?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver第三步启动后端。在项目根目录执行mvn clean package -DskipTests cd target java -jar disease-system.jar看到Started Application in x.xxx seconds就说明启动成功了。默认端口一般是8080如果被占用在application.yml里改server.port即可。提示如果你在IDEA里直接运行主类需要先确认项目的resources目录被标记为资源目录否则application.yml加载不到启动会直接报端口绑定失败或数据源初始化失败。4.2 Vue前端构建与联调前端部分我用的Node版本是16.x。如果你Node版本太高比如18以上可能在npm install阶段就报错。前端构建流程如下cd frontend npm install npm run dev开发环境默认走的是代理把接口请求转发到后端的8080端口。这个代理配置在vue.config.js里核心代码大概是这样devServer: { port: 9527, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }如果你后端端口改了这里也要同步改否则前端页面能打开但接口全是404。前端跑起来后用源码里提供的初始账号密码登录通常是admin/admin123之类具体看数据库初始化脚本或README。登录后第一件事把各功能模块都点一遍对照数据库表看看数据是怎么流转的。我强烈建议在这个过程中对着一张纸画“数据流向图”——点击一个按钮前端调哪个接口后端查哪张表返回什么数据页面怎么渲染。把这个闭环跑通了你对这套系统的理解就比只看代码深刻得多。4.3 打包部署与生产环境配置开发环境跑通之后还要考虑真正部署上线的问题。前端打包npm run build打包完成后dist目录就是纯静态文件。部署方式有两种我说说各自的适用场景方式一Nginx部署推荐。把dist目录整个拷到服务器的/usr/share/nginx/html下配置Nginx反向代理把/api请求转发到后端server { listen 80; server_name your-domain.com; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }try_files $uri $uri/ /index.html;这行是Vue前端部署的重中之重。没有这行刷新页面时Vue Router会404因为实际上服务器上并没有/xxx这个路径的真实文件。方式二打成Jar包内置静态资源。把dist目录拷到后端项目的src/main/resources/static下重新打包。这种方式适合小规模快速部署但前端每次更新都要重新打包后端耦合度高我一般不用在生产环境。后端生产环境启动建议用nohup或systemd托管nohup java -jar disease-system.jar \ --spring.profiles.activeprod \ --server.port8080 \ logs/app.log 21 生产环境记得把spring.profiles.active切到生产配置用独立的生产数据库不要用开发库。5. 部署与使用中常见问题排查实录5.1 环境类问题速查现象原因解决办法后端启动报Access denied for user数据库账号密码不对或权限不足用root账号登录MySQLGRANT ALL PRIVILEGES ON disease_control.* TO userlocalhost;前端npm install报错Node版本过高或过低切换Node到16.x或者删除node_modules和package-lock.json后重新安装启动报Port 8080 was already in use端口被占用换端口或netstat -anoFailed to configure a DataSource项目找不到数据源配置检查application.yml里的spring.datasource配置还有SpringBootApplication的exclude参数MySQL连接报Public Key Retrieval is not allowedMySQL 8.0的新特性导致JDBC连接串加allowPublicKeyRetrievaltrue前端页面能打开但接口报CORS错误跨域问题开发环境配代理生产环境用Nginx反向代理后端加CrossOrigin或全局CORS配置5.2 框架配置类问题SpringBoot版本问题这套源码用的SpringBoot是2.x版本如果你本机装了3.x很多配置会不兼容。最典型的是javax.servlet变成了jakarta.servlet如果源码里有import javax.servlet.http.HttpServletRequest这类代码在SpringBoot 3.x下编译直接报错。解决方案是别改代码把SpringBoot降回2.7.x。如果你非要用新版本那要做完整的包名迁移工作量不亚于重写一遍。MyBatis XML配置文件报错最常见的是XML文件没有放在resources/mapper目录下或者application.yml里的mybatis.mapper-locations路径配错了启动时Mapper接口报“Invalid bound statement (not found)”。排查思路确认XML文件在target/classes目录下存在有时候Maven没把它打进去确认mapper-locations: classpath:mapper/*.xml路径和你实际放的位置一致确认XML里namespace的值和Mapper接口的全限定名完全一致MyBatis缓存导致数据不更新前面说了二级缓存如果配置不当会出现脏读。实际表现是数据库里的数据已经改了但接口返回的还是旧值。排查方法把application.yml里MyBatis缓存相关配置临时关掉重启测试。如果恢复正常就是缓存问题。5.3 前后端联调类问题这类问题我在部署这套系统时踩得最深专门拿出来说说。问题一登录接口返回401但账号密码没错。可能原因有三个一是用户被禁用了检查sys_user表的status字段二是JWT过期时间配置不对如果application.yml里jwt.expiration设置的太短登录成功但马上过期三是后端时间跟服务器时间不一致JWT生成和校验用的是本机时间如果前后端在不同机器上时间偏差会导致Token校验失败。问题二前端能登录但菜单空白。这通常是权限码匹配问题。前端动态路由注册依赖后端返回的菜单/权限数据如果数据库里的菜单数据不完整或者sys_role_menu关联表没配好前端就渲染不出菜单。解决思路把当前的menu表数据跟初始化脚本的原始数据对比确认没有丢数据。问题三Vue打包后刷新404。这个上文提到过就是Nginx没配try_files。还有一个隐蔽的点如果Vue Router用的是history模式服务器必须配好如果你的部署环境不方便配Nginx可以用hash模式代码改动很小URL会带个#但不会404。问题四上传图片无法访问。本地存储模式下后端服务重启、路径配置错误都会导致这个问题。确认配置好的上传目录在服务器上是真实存在的且有读写权限。Nginx部署时要加一个location /upload/的映射指向磁盘上的实际目录。6. 项目扩展方向与个人实操心得6.1 可以做的扩展方向源码能跑通只是第一步真正落地到企业环境里我建议按以下优先级做扩展第一优先级安全性补强。给所有接口加上日志记录AOP切面即可实现敏感操作删除、审批、物资出库做操作留痕。密码策略加强比如要求复杂度、定期强制更换。生产环境启用HTTPS这些改动成本低但合规性检查的时候都是硬指标。第二优先级对接能力。企业级系统往往不是孤立存在的需要对接钉钉/企微的组织架构同步对接短信服务商做预警通知对接上级监管平台做数据上报。这套源码预留了SmsService接口但没有具体实现二开时按需接入即可。第三优先级性能优化。如果用户量超过一万人实时统计接口会扛不住。建议引入Redis做缓存引入消息队列RabbitMQ或RocketMQ做异步处理把定时扫描任务从单机改成分布式调度XXL-Job。再往后才是考虑微服务拆分把健康档案、任务调度、统计分析拆成独立服务。第四优先级移动端。现在的疾控管理场景里消杀人员大概率不在电脑前。用一个H5页面或者小程序端做任务接收、现场照片上传、位置打卡这个需求在落地时几乎是刚需。后端接口是通用的前端复用现有API就行工作量主要在移动端页面开发。6.2 实操中的一点体会最后分享几个我在这套系统部署和二次开发过程中的真实感受希望能帮到正在折腾的朋友。第一数据库初始化脚本别乱改。我一开始觉得初始菜单太乱手动删掉了一批结果前端菜单和权限全乱了排查了大半天。正确的做法是先跑原始脚本把系统完整跑通了再按照业务需求用后台界面去调整菜单而不是直接改数据库。第二多看日志比猜原因高效得多。后端启动和运行过程中日志会记录关键信息。用logging.level.com.exampledebug打开调试日志MyBatis会打印执行的SQL和参数排查数据问题的时候简直不要太爽。改完记得关掉不然生产环境的日志文件会膨胀得很快。第三备份意识要刻在骨子里。对源码做任何改动之前先把原版完整备份一份。我就吃过亏改完代码发现跑不通想回退结果原文件已经被覆盖了只能重新解压源码从头再来。用Git管理代码每一个功能点开一个分支验证通过再合并这是基本功。第四这套源码的最大学习价值在于“完整”。它不是那种只有几个演示页面的半成品而是从用户认证、权限管理、业务流转到数据统计全都通着的完整系统。对一个想入门企业级开发的人来说把每一张表、每一个接口、每一段动态SQL吃透比看十本框架教程都有用。对一个要拿项目落地的团队来说在完整可运行的基础上做二次开发比从零开始搭建省掉的时间足够用来打磨真正有差异化的业务功能。这套系统我目前还在持续维护随着实际业务场景的变化新需求和优化点会不断冒出来。如果你们也正在做类似的企业级管理系统或者准备在这套源码上做二次开发希望这篇东西能让你少踩几个坑。
返回列表