基于SpringBoot+Vue+MyBatis+MySQL的疫情防控系统开发
发布时间:2026/10/2 4:03:11来源:尧图网络
作为一个常年泡在前后端项目里的开发者看到“SpringBoot Vue MyBatis MySQL”这套组合基本就能想到这是一个典型的企业级业务系统骨架。如果再把“疫情防控管理”这个业务场景套进去其实本质上就是一套带权限、带信息录入、带审核流程、带数据统计的通用管理系统——这类项目在面试、毕业设计、企业内部系统里出现频率极高因为它的业务复杂度适中正好能覆盖前后端分离开发中的大多数核心知识点。这篇博文就围绕这个项目从最底层的数据表设计说起逐步拆解后端 SpringBoot 怎么分层、MyBatis 的 Mapper 怎么写得高效不踩坑再到前端 Vue 的路由和权限控制怎么设计最后把部署流程完整过一遍包括那台服务器上的 Tomcat 怎么处理前端打包产物、MySQL 初始化脚本怎么跑。整个过程不整虚的全部是照着实际开发流程走的适合正在做类似系统或者准备拿这个项目练手的人参考。1. 项目整体设计思路与功能模块拆解1.1 前后端分离架构到底解决了什么问题以前做 Java Web 项目很多人习惯用 JSP 或者 Thymeleaf页面和服务端代码混在一起。改一个页面样式要重启服务前端同学没法独立开发后端也不敢轻易动页面模板两边互相牵制效率非常低。前后端分离的核心思路是把“页面渲染”和“业务数据处理”彻底拆开。前端只负责展示和交互通过 HTTP 接口从后端拿 JSON 数据后端只负责业务逻辑、权限校验和数据持久化不再关心页面长什么样。两边通过接口文档或者在线调试工具比如 Swagger完成协作。落到这个疫情防控管理系统上分离的好处更明显。管理端的页面逻辑比较复杂有数据表格、图表统计、多条件筛选、表单校验这些用 Vue 来做非常顺手。而后端要处理多角色登录验证、健康数据上报、审批流程等事务用 SpringBoot 来管再合适不过。两边开发可以并行推进部署的时候也能分开优化接口压力大了就多挂几个后端实例前端静态资源直接扔到 Nginx 或者 Tomcat 里。1.2 技术栈选型的底层逻辑SpringBoot 在这个项目里承担的作用是快速搭建后端服务。它的自动配置机制省掉了大量 XML 配置内嵌的 Tomcat 让应用可以打成 Jar 包直接运行配合 Maven 做依赖管理干净利落。Vue 这个框架在这个场景里属于“打遍天下无敌手”的选择。它的响应式数据绑定让表格和表单这类高频交互页面做得非常流畅组件化开发方式也让页面结构清晰复用性高。配合 Vue Router 做前端路由跳转、Vuex或者新一点的 Pinia做全局状态管理比如存登录用户的角色信息整套前端生态非常成熟。MyBatis 在这类管理系统中几乎是标配。它比 JPA 更接近原生 SQL开发者可以精确控制每一条查询语句。对于要多表联查、条件拼接、动态筛选的管理系统来说MyBatis 的灵活性优势很明显。MySQL 作为底层存储也不用多解释。单机部署成本低、性能稳定、运维资料多应付这种量级的管理系统绰绰有余。如果以后数据量涨上去了配合 MyBatis 改分库分表或者读写分离也有很好的扩展路径。1.3 系统功能模块怎么拆站在使用者角度这个系统大致需要覆盖这么几类操作登录认证不同角色管理员、普通用户走同一套登录入口登录成功后返回 Token前端保存起来后续请求都带上。人员信息登记姓名、身份证号、手机号、住址、健康状况、行程信息等基础数据的增删改查。健康打卡与上报用户定期提交体温、健康码状态、行程轨迹等信息系统记录每次填报的详细数据。出入管理门岗或管理员登记进出记录绑定人员信息和出入时间、事由、体温检测结果。审核管理对上报的异常数据或者特殊出入申请进行审批审批通过或驳回都要有记录。数据统计按日期、区域、健康状况等维度统计人数并形成图表给管理决策做支撑。这些模块表面上是业务需求实际上对应的是后端一系列 CRUD 接口、联表查询、状态流转逻辑以及前端一系列页面、路由和权限控制是整个系统开发的核心骨架。2. 数据库设计表结构、字段规划与初始化要点2.1 核心数据表及其关联关系数据库设计是这类系统的地基表建得不好后面写 SQL 会很难受。我把这个项目拆成五张核心业务表再加一张用户表来支撑登录权限sys_user用户表登录账号、密码、姓名、角色、状态person_info人员信息表身份证、手机号、住址、单位、紧急联系人health_report健康上报表用户ID、体温、症状描述、行程码状态、上报日期access_record出入记录表人员ID、进出方向、体温、出入时间、事由、审核状态audit_log审核日志表审核人、被审核记录类型、记录ID、审核结果、备注这五张表之间的关系比较直接sys_user 和 person_info 是一对一一个人对应一个登录账号person_info 和 health_report 是一对多一个人每天可以多次上报person_info 和 access_record 是一对多一个人有多条进出记录audit_log 则是一个泛化表通过 record_type 字段区分审核的是上报记录还是出入记录。这个设计的思路是“通用和专用结合”。核心业务表健康上报、出入记录单独建表因为它们的字段和业务约束完全不同而审核记录统一放一张表通过类型字段区分这样不需要为每种业务单独建一张审核表。2.2 字段规划与数据类型选择以 health_report 表为例核心字段设计如下idbigint 主键自增。user_idbigint关联 sys_user 表 id索引必加因为查询“某个人某段时间的上报记录”是最高频操作。temperaturedecimal(4,1)存体温保留一位小数即可比如 36.5。symptom_flagtinyint0 表示无症状1 表示有症状这个字段用数值型而不是字符串后续统计更方便。trip_code_statusvarchar(20)存行程码状态用字符串是因为状态种类可能后期调整直接存“normal”“warning”之类的枚举值更直观。report_datedate上报日期注意这里用的 date 而不是 datetime因为业务上每天每人只上报一次date 类型在查询“某天所有上报记录”时效率更高。create_timedatetime记录创建时间用数据库默认值 CURRENT_TIMESTAMP 即可。这看起来是很基础的字段设计但实际很多新手会在这里犯错。比如 temperature 用 float 类型结果算出 36.600000001或者上报日期用 datetime索引和分组统计的效率都受影响。这类细节我建议在设计阶段就定下来比后期改表省太多事。2.3 初始化脚本的编写技巧拿到源码后首先要跑的是 SQL 脚本。我要给一个提醒别直接双击把整个脚本扔进 Navicat 执行一定要先检查两件事。第一是数据库字符集。建库语句应当显式声明 utf8mb4CREATE DATABASE IF NOT EXISTS health_manage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 不然一旦数据里出现生僻字或者特殊符号比如用户填了 emoji 表情入库直接报错或者变成乱码。第二是初始化数据。数据表结构全部执行完之后要检查是否有初始管理员账号的 INSERT 语句。很多项目在开发环境调试时没问题换到新环境一执行就发现没有管理员账号页面登录都登不了最后只能手插数据库。源码里如果没有自己加一条 INSERT INTO sys_user 语句即可密码记得写入 BCrypt 加密后的值。有个看源码时的实用小技巧把 SQL 脚本从头读一遍关注每个 CREATE TABLE 语句里是否跟着索引创建语句KEY idx_xxx 或单独的 CREATE INDEX。如果查询字段没有索引数据量几百条的时候没感觉上万条之后联表查询和条件筛选就会明显变慢。3. 后端 SpringBoot 核心实现与开发要点3.1 项目分层结构与 Maven 依赖管理拿到后端源码后第一件事就是看包结构。合理的分层通常是这种形式com.health.system ├── controller接口层只做参数接收和结果返回 ├── service业务逻辑层处理具体业务规则 ├── mapper数据访问层定义 MyBatis 接口方法 ├── entity实体类对应数据库表结构 ├── dto数据传输对象用于接收前端传来的参数 ├── vo视图对象用于给前端返回定制化数据 ├── config配置类如跨域配置、拦截器配置 ├── common通用类如统一返回结果、异常处理 └── utils工具类如 JWT 工具、日期工具这个分层要严格依赖Controller 不能直接调 Mapper必须走 Service。看着多绕一层但业务复杂以后你才知道这一层的价值同一份逻辑可以被多个接口复用事务边界也能划清楚。Maven 的 pom.xml 是另一个关键点。SpringBoot 2.7.x 的依赖管理用 spring-boot-starter-parent 做父工程再加上 web、mybatis-spring-boot-starter、mysql-connector-java、lombok、jjwt 这些常见依赖。需要注意的是 JDK 版本如果比较高比如 JDK 17SpringBoot 版本最好选 2.6 以上否则会有不兼容的问题。3.2 统一返回结果与全局异常处理前后端分离项目中后端返回的数据格式一定要统一否则前端处理起来很痛苦。我通常定义这样一个通用返回类public class ResultT { private Integer code; // 状态码200成功400业务错误401未登录500系统错误 private String message; // 提示信息 private T data; // 业务数据 public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(Integer code, String message) { ResultT result new Result(); result.setCode(code); result.setMessage(message); return result; } }为什么不能用裸的 JSON 字符串返回原因在于前端 Axios 拦截器需要根据状态码判断全局如何处理。比如登录过期时返回 401前端拦截器统一跳转登录页比每个页面单独监听错误省太多事。全局异常处理使用 RestControllerAdvice 注解把所有业务异常和系统异常统一拦截转换成 Result 格式返回给前端。如果没有这一层一个空指针异常直接抛给前端前端拿到的是一堆堆栈信息既不安全也不友好。3.3 MyBatis 的 Mapper 写法与动态 SQL 实战MyBatis 在这个系统里的核心使用场景是动态条件查询。比如健康上报记录前端查询时需要按用户姓名、上报日期、体温范围、症状状态做组合筛选如果为每种组合都写一条 SQL会写死人。正确的做法是用动态 SQLselect idselectReportList resultTypecom.health.system.vo.HealthReportVO SELECT hr.id, u.real_name, u.phone, hr.temperature, hr.symptom_flag, hr.trip_code_status, hr.report_date FROM health_report hr LEFT JOIN sys_user u ON hr.user_id u.id where if testrealName ! null and realName ! AND u.real_name LIKE CONCAT(%, #{realName}, %) /if if teststartDate ! null AND hr.report_date gt; #{startDate} /if if testendDate ! null AND hr.report_date lt; #{endDate} /if if testsymptomFlag ! null AND hr.symptom_flag #{symptomFlag} /if /where ORDER BY hr.report_date DESC, hr.create_time DESC /select这里有几个细节值得强调。LIKE 查询要注意不能直接写 % #{realName} %要用 CONCAT 函数拼接这样能避免 SQL 注入风险。日期范围查询用 和 而不是 BETWEEN因为 BETWEEN 在边界值上的处理容易让人困惑。ORDER BY 用两个字段做排序主排序report_date相同时用次排序create_time区分先后保证列表顺序稳定。另一个高频操作是批量插入。健康上报场景可能涉及批量导入人员信息MyBatis 的批量插入用 foreach 标签insert idbatchInsert INSERT INTO person_info (name, id_card, phone, address, unit, create_time) VALUES foreach collectionlist itemitem separator, (#{item.name}, #{item.idCard}, #{item.phone}, #{item.address}, #{item.unit}, NOW()) /foreach /insert批量插入时一次性插入条数不要太大建议每批 200-500 条太多的话 MySQL 的 SQL 长度上限和事务日志都会可能出问题。3.4 登录认证与 JWT 权限控制这个系统的权限模型相对简单管理员和普通用户两类角色。我推荐用 JWT 做登录认证而不是传统的 Session因为前后端分离项目里Session 的跨域和跨服务问题比较烦人JWT 天然无状态后端不用存登录状态。JWT 的核心思路是用户登录成功后后端生成一个签名后的 Token 串返回给前端。Token 里包含了用户ID、角色、过期时间等信息。前端把 Token 存在 localStorage 里每次请求时在请求头加上 Authorization: Bearer 。后端拦截器解析 Token验证签名和有效期从 Token 里取出用户信息放入请求上下文。生成 Token 的核心代码大致这样String token Jwts.builder() .setSubject(String.valueOf(user.getId())) .claim(role, user.getRole()) .setExpiration(new Date(System.currentTimeMillis() 1000 * 60 * 60 * 24)) // 24小时有效 .signWith(SignatureAlgorithm.HS256, secretKey) .compact();这里的 secretKey 一定不要硬编码在代码里要放到 application.yml 的配置文件中用 ConfigurationProperties 或者 Value 读取。很多人为了省事把密钥写在源码里结果代码一泄露所有 Token 都能被伪造这是很严重的安全隐患。拦截器解析 Token 时要注意过期时间的异常处理。JWT 在过期后调用 parseClaimsJws 会抛异常需要捕获并返回 401 状态码而不是直接让请求进入业务逻辑。4. 前端 Vue 核心实现与开发要点4.1 前端工程结构与目录组织Vue 项目拿到手后先看 src 目录的组织方式合理的结构通常是src ├── api按模块划分的接口请求文件 │ ├── user.js │ ├── report.js │ └── access.js ├── assets静态资源 ├── components公共组件 ├── layout主布局组件包括侧边栏和顶栏 ├── router路由配置含动态路由逻辑 ├── store全局状态管理 ├── utils封装工具比如 request.js 中的 Axios 实例 └── views页面视图 ├── login ├── dashboard ├── report ├── person └── accessapi 目录单独拆分模块这个细节很关键。不是把每个请求都写在页面组件里而是统一放在 api 文件里导出函数。这样页面只关心调用函数获取数据接口地址或者参数变化只需要改 api 文件一处即可维护成本大大降低。4.2 Axios 封装与请求拦截器设计Axios 封装这一步可以说是前端项目的“基础设施”。所有 HTTP 请求都经过同一个 Axios 实例那么在拦截器里就能统一处理 Token 注入和错误提示。import axios from axios import { ElMessage } from element-plus import router from /router const request axios.create({ baseURL: /api, timeout: 10000 }) // 请求拦截器注入 Token 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) { localStorage.removeItem(token) router.push(/login) return Promise.reject(new Error(登录已过期)) } else { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } }, error { ElMessage.error(error.message || 网络异常) return Promise.reject(error) } ) export default requestbaseURL 设置为 /api配合开发环境的代理proxy配置这样在本地开发时不会有跨域问题。生产环境部署时 Nginx 再把 /api 路径反向代理到后端服务地址。实际开发中接口地址我会用相对路径比如 /api/report/list然后后端 Controller 的 RequestMapping 写成 /api/report。这样前端和后端的接口前缀保持一致代理规则或 Nginx 配置时只需要处理 /api 这一个前缀逻辑很清爽。4.3 动态路由与权限控制实现权限控制在管理系统里算是个绕不开的难点。这个项目里比较实用的做法是登录成功后根据用户角色动态生成可访问的路由表而不是把全部路由都静态注册进去。具体的实现思路是这样的路由文件拆成两部分constantRoutes所有人都能访问的公共路由比如登录页、首页与 asyncRoutes需要权限的路由比如人员管理、审核管理在路由 meta 字段里标记需要的角色。登录成功后前端拿到用户角色信息遍历 asyncRoutes过滤出角色匹配的路由用 router.addRoute 动态添加。侧边栏菜单也基于过滤后的路由表生成。function filterAsyncRoutes(routes, role) { const res [] routes.forEach(route { const tmp { ...route } if (hasPermission(role, tmp)) { if (tmp.children) { tmp.children filterAsyncRoutes(tmp.children, role) } res.push(tmp) } }) return res } function hasPermission(role, route) { if (route.meta route.meta.roles) { return route.meta.roles.includes(role) } return true }这个方案比在路由守卫里一个个判断要优雅得多新增加一个需要权限的页面时只需要在路由表的 meta 里标上允许的角色其余逻辑全部自动生效。路由守卫beforeEach里还需要做另一件事检查是否有 Token。没有 Token 直接访问管理页面全部重定向到登录页。这就是为什么前端不能只在路由配置里检查权限因为路由是懒加载的在刷新页面时路由表会重置必须借助守卫做二次校验。4.4 管理页面的核心交互实现管理系统的页面交互通常由几个高频组件构成表格展示数据、表单弹窗新增编辑、筛选条件查询、分页切换。这套组合用 Element PlusVue 3 项目或者 Element UIVue 2 项目能快速搞定。一个列表页面的标准做法是页面挂载时调用获取列表接口渲染到 el-table 组件中。搜索表单采用“搜索按钮触发查询”而不是实时搜索避免每次输入都发一次请求浪费资源。新增和编辑共用一个表单弹窗组件通过一个 type 字段区分是增加还是修改。分页组件绑定页码和条数值变化时重新调接口。el-pagination v-model:current-pagequeryParams.pageNum v-model:page-sizequeryParams.pageSize :page-sizes[10, 20, 30, 50] layouttotal, sizes, prev, pager, next :totaltotal size-changegetList current-changegetList /分页参数 pageNum 和 pageSize 要作为查询参数传给后端后端通过 PageHelper 分页插件或者手写 LIMIT 来实现分页。这个项目如果引入了 PageHelper那在 Service 层调用 Mapper 前只需写 PageHelper.startPage(pageNum, pageSize)后面紧跟的查询会被自动拦截分页。5. 完整部署教程从本地开发到服务器上线5.1 本地开发环境搭建一开始搭建环境的时候我建议按这个顺序来先装 JDK 和 Maven再装 MySQL接着装 Node.js最后装开发工具 IDEA 和 VSCode。JDK 选择 1.8 还是 11看源码里的 pom.xml 怎么写的。这个项目如果是基于 SpringBoot 2.xJDK 1.8 是最稳的。Maven 安装后配置阿里云镜像国内拉依赖会快很多不然光下载依赖都能等半小时。MySQL 安装时要注意字符集和时区设置。Windows 上用 MySQL Installer 安装时务必将默认字符集选成 utf8mb4时区选成 (UTC08:00) 中国标准时间。启动后如果遇到 SSL 连接错误可以在连接 URL 上加 useSSLfalse 参数比如jdbc:mysql://localhost:3306/health_manage?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiserverTimezone 参数必须加否则新版 MySQL 驱动会报时区相关错误。5.2 后端打包与常见打包错误SpringBoot 后端打包用 Maven 命令即可mvn clean package -DskipTests执行完会在 target 目录生成一个 Jar 包。这里有个常见问题如果 pom.xml 里没有配置 spring-boot-maven-plugin打出来的 Jar 包是普通的可执行 Jar运行 java -jar 会报“没有主清单属性”异常。确保 pom 里有这一段build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build另一个打包时容易遇到的问题JDK 版本不匹配导致编译失败。Maven 默认编译级别可能和代码里用的语法不一致需要在 pom.xml 的 properties 里声明properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target /properties5.3 前端打包与产物部署前端打包前要检查一个关键配置vue.config.js 里的 publicPath。如果部署时前端文件被放在服务器某个子路径下publicPath 要改成对应的子路径如果直接用根路径访问保持 / 即可。module.exports { publicPath: /, devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这里的 proxy 配置是本地开发用的。执行的打包命令是npm install npm run build执行完会在 dist 目录生成静态文件包括 index.html 和一堆 JS/CSS 文件。注意 dist 目录里的 JS 文件名是带有哈希值的比如 app.8f3a2b.js这是为了让浏览器能正确缓存更新后的文件。这个目录整体上传到服务器即可。5.4 Tomcat 部署前后端分离项目的方式前后端分离项目部署到 Tomcat 有几种方案我推荐直接用 SpringBoot 自带内嵌 Tomcat 来部署后端 Jar 包前端静态文件用独立的 Nginx 来服务这是最标准、改动最小的方案。不过如果服务器上已经装了 Tomcat想直接把前端 dist 目录放进 Tomcat 的 webapps 下也是可行的。具体步骤如下把 dist 目录改名为 ROOT放到 Tomcat 的 webapps 目录下替换原本的 ROOT 目录。这样直接访问 Tomcat 根路径就能看到前端页面。在 Tomcat 的 server.xml 里将 Connector 的 port 改为 80需要 root 权限。让前端请求能通到后端需要在 Tomcat 里配置虚拟主机或反向代理最方便的是加一个 Servlet 容器级别的 filter 做路径转发或者干脆用 Nginx 做统一入口。这里给一个更简单的推荐路径服务器上安装 Nginx 作为唯一入口静态文件交给 Nginx接口请求反向代理到 SpringBoot 监听端口server { listen 80; server_name your-domain.com; # 前端静态资源 location / { root /opt/health-frontend/dist; 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 很关键它保证前端路由比如 /report/list在刷新时能找到 index.html否则刷新页面会 404。这是 SPA 应用部署中最常见的坑。5.5 服务器端 MySQL 初始化与配置服务器上 MySQL 初始化数据库我习惯用命令行方式mysql -u root -p health_manage.sql或者登录后 source 方式执行source /opt/health_manage.sql;执行完成后需要创建一个专门给应用使用的数据库账号而不是直接用 root。这个习惯很重要一是避免密码泄露后数据库完全暴露二是方便在出问题时单独回收权限。CREATE USER health_applocalhost IDENTIFIED BY YourStrongPassword; GRANT ALL PRIVILEGES ON health_manage.* TO health_applocalhost; FLUSH PRIVILEGES;后端 application.yml 里的数据库连接信息改成这个新账号然后重新打包部署。连接上数据库后先确认一下时间时区是否对齐否则健康上报按日期统计的数据会发生偏移。6. 常见问题与部署排错实录6.1 数据库连接相关的坑问题1MySQL 连接报 Public Key Retrieval is not allowed这是因为 MySQL 8 的默认认证插件是 caching_sha2_password在使用 SSL 连接时客户端需要先向服务器请求公钥。解决办法是在 JDBC URL 里加上 allowPublicKeyRetrievaltrue或者把数据库用户的认证插件改为 mysql_native_password。问题2中文乱码数据库、表、连接 URL 三处都要设置 utf8mb4。只建库时设置但连接 URL 没加 characterEncodingutf8照样会乱码。排查时先用 SQL 查看表定义SHOW CREATE TABLE health_report;确认 DEFAULT CHARSET 是 utf8mb4。问题3时区错误报错信息里出现 The server time zone value Öйú±ê׼ʱ¼ä 这种乱码提示是因为 MySQL 服务器时区问题。在连接 URL 上加 serverTimezoneAsia/Shanghai 即可。6.2 前端常见问题排查问题1页面能打开但列表数据不出来先打开浏览器控制台F12的 Network 面板看请求状态。如果是 404检查后端接口路径和前端 request 里的 URL 是否一致如果是 403检查 Token 是否过期或缺失如果是跨域错误CORS检查后端跨域配置或开发环境代理配置。问题2生产环境刷新页面404这个就是我之前提到的 SPA 路由问题。Nginx 里必须加 try_files 规则才能解决Tomcat 部署的话则要配置对应的 RewriteRule 将非静态资源请求重写回 index.html。问题3接口能通但白屏大概率是打包过程出错打开 dist/index.html看引用的 JS 路径是否正确。如果路径带上一级目录而 publicPath 配置没跟上就会出现这种问题修改 publicPath 后重新打包即可。6.3 部署运维问题记录问题1端口被占用后端 8080 端口被其他进程占用SpringBoot 启动直接失败。用 lsof -i:8080 或 netstat -tunlp | grep 8080 找到占用进程确认不是系统关键进程后 kill 掉。问题2Java 进程启动后过一段时间自动挂掉查看日志注意是 SpringBoot 的 logs 目录不是控制台最常见的原因是内存不足。服务器内存比较紧张时在启动命令中合理控制 JVM 参数java -Xms256m -Xmx512m -jar health-system.jar不要把 Xmx 设置太大给操作系统和其他服务留够内存空间。问题3配置了 HTTPS 但请求仍然走 HTTP这个出问题的原因一般是前端代码里把接口地址写成了 http://页面是 https 访问的浏览器会拦截“混合内容”。统一改成相对路径 /api 或者通过环境变量控制接口地址。我把这段时间实操踩坑的记录整理成一个速查表方便大家对照现象原因解决方案后端启动报数据库连接失败URL 参数配置错误检查驱动、地址、账号密码、参数登录接口返回 500密码加密方式不一致确认注册时用的加密算法和登录校验一致前端报跨域错误后端未配置跨域或代理未生效开发环境用 proxy生产环境用 Nginx列表查询非常慢联表查询字段未建索引在 WHERE 和 JOIN 字段上建索引页面刷新后回到登录页Token 失效或路由守卫误判检查 Token 过期时间和路由守卫逻辑中文内容变成问号字符集设置不一致库、表、连接 URL 全部改为 utf8mb46.4 我的几条实操心得第一遇到任何接口异常不要在页面上一遍遍刷新看效果直接看后端控制台日志。SpringBoot 的异常堆栈信息会准确告诉你是哪一行代码出的问题。养成看日志的习惯能省下 80% 的排查时间。第二前端打开 Network 面板看具体请求的 Request Headers 和 Response Body。前后端联调时两边说的“我这边没问题”大概率都是因为只看了自己那一侧。把请求和响应的完整报文都截图发给对方问题一次就能定位。第三编写接口时不要急于一下子写完所有功能。先把一个最小流程跑通建表、写 Mapper、调通接口、把数据渲染到页面上然后在这个基础上逐步加功能。整个链路通了以后剩下的事情都是重复劳动信心会足很多。7. 这套源码还能怎么延伸如果基础功能都跑通了想要在简历上或者实际项目中让这个系统更有亮点有几个扩展方向。第一个方向是数据可视化增强。在现有统计接口的基础上引入 ECharts 做更丰富的图表展示按区域、年龄段、时间维度做健康趋势分析。后端的统计 SQL 写法其实不复杂关键在于按维度做 GROUP BY并把结果封装成前端图表组件可用的结构。第二个方向是文件上传功能比如导入 Excel 批量登记人员信息。后端使用 Apache POI 解析 Excel 文件前端用 Element Plus 的上传组件上传后调用接口解析数据并批量入库。这个功能非常实用医院、学校这类客户一定用得上。第三个方向是引入缓存机制。健康上报的每日汇总数据变化不频繁完全可以使用 Redis 做缓存或者先用 MyBatis 的二级缓存顶一顶减少数据库压力。等系统访问量上来了再考虑引入消息队列做异步处理上报数据的统计汇总。第四个方向是系统监控与日志收集。在生产环境部署后配置 SpringBoot Admin 监控服务状态使用 AOP 统一记录操作日志这些都属于“生产级系统必备”的能力加上以后系统完整度能上升一个档次。个人建议是如果时间充裕优先做第二个方向Excel 批量导入因为它的业务价值最直接能体现你对实际应用场景的理解。技术上涉及文件解析、数据校验、批量插入、错误反馈几个环节也比较考验开发者的基本功。这个系统的技术栈虽然谈不上新潮但都是当前企业级项目里最常用的组合。把这套代码真正吃透对自己理解前后端交互流程、接口设计规范、权限控制逻辑都会有比较大的提升。如果卡在某个环节一直不顺利回头再看看我上面写的那些部署细节大概率能帮你把问题找出来。
网站建设高端定制企业官网