接到养老公寓信息化这块内容的第一反应是:市面上确实太多“管理系统”了,但真正把“大健康”落进日常业务流的少之又少。这套基于SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0的大健康养老公寓管理系统源码,属于那种拿到手就能跑、业务闭环相对完整的项目。我花了一周时间把源码从数据库到前端页面完整过了一遍,这篇就按实际使用顺序,把技术选型、业务模块、部署过程和扩展思路一次讲清楚。
1. 养老公寓管什么:从纸质台账到信息化的业务全景
1.1 传统养老机构的信息化痛点
我接触过不少养老机构的实际运营场景,先说一个很真实的画面:办公室文件柜里一排排纸质档案,每位老人一个牛皮纸袋,里面塞着入住协议、体检报告、护理记录,有些纸张已经泛黄卷边。工作人员查一份两年前的体检数据,得先翻索引本,再逐袋找,运气好五分钟,运气差二十分钟。费用结算全靠Excel手工算,护理等级调了价,月底对账对到凌晨还经常发现错项。
这套系统的定位,不是简单的“信息登记软件”,而是把养老公寓的“人、房、健康、护理、费用”五条业务线全部拉通。老人从入院评估、健康档案建立、日常护理执行、费用账单生成到退住结算,每个环节都有对应的模块和数据流承接。管理员看的是全局报表,护工看的是今日待办,护士关注健康异常,财务盯账单,家属在授权范围内查看老人状态——这就是典型的角色分权协作场景。
1.2 “大健康”不是噱头:健康档案闭环怎么走通
很多系统号称“大健康”,实际只有一张体检表。这套源码的处理方式更接近业务闭环:老人入住时建立基础健康档案,之后每次体检、每日体征测量、慢病随访记录都持续追加;健康数据按时间维度形成曲线,异常指标可以触发提醒;护理计划根据健康评估结果动态调整,护理记录反过来又能反映健康变化。这个正反馈闭环,正是养老机构区别于酒店管理系统的地方。
我把健康相关模块在系统里对应的功能点列一下,方便后面阅读源码时对照:
- 老人基础档案:病史、过敏史、用药情况、既往手术记录
- 健康评估:入院评估量表、定期复评结果、护理等级动态调整依据
- 每日体征记录:血压、血糖、心率、体温等,支持批量录入
- 慢病管理:高血压、糖尿病等专病随访计划与执行记录
- 异常预警:体征指标超限时生成提醒任务,推送给责任护士和家属
1.3 系统覆盖的角色与核心业务流程
从权限设计上,系统内置了几类典型角色:超级管理员、机构运营人员、护士/护理员、医生(或健康顾问)、财务人员、家属。每类角色的菜单和操作权限不同,这在源码的菜单管理和角色管理模块中体现得很清晰。
核心业务流程可以用一条主线串起来:老人提交入住申请或直接到院评估,管理员录入档案并分配房间床位;护士根据健康评估结果设定护理等级,生成个性化护理计划;护工按计划执行日常护理并填写记录;医生定期查看健康数据曲线,调整用药或护理建议;财务按月生成费用账单,包含床位费、护理费、伙食费、医疗耗材等;最后老人退住时做费用结算和档案归档。这条链路从头到尾在系统里都能找到对应页面和接口,这也是我判断一个管理系统“是否完整”的核心标准。
2. SpringBoot2 + Vue3 + MyBatis-Plus + MySQL8.0:这套技术栈为什么是当前的最优解
2.1 MyBatis-Plus解决的核心痛点:从繁琐CRUD到关注业务
先说说后端ORM这块。如果早几年用原生MyBatis,写一个简单的分页查询,要手写XML、配置ResultMap、处理动态SQL,光一个老人列表页面的查询可能就要上百行配置。这套源码使用MyBatis-Plus,核心优势不只是少写代码,而是把CRUD变成了“约定式”操作。
看源码里的Mapper层,大部分接口直接继承BaseMapper<T>,单表增删改查零SQL。比如查询老人分页列表,用LambdaQueryWrapper构造条件,再配合Page对象,一句baseMapper.selectPage(page, wrapper)就完成了以往需要手动拼接SQL的活。遇到复杂统计再写自定义SQL,比如Dashboard看板里的入住率、护理等级分布、健康异常趋势这类跨表聚合查询,MyBatis-Plus也支持在Mapper接口上直接写注解SQL,不用为了一个统计函数单独维护XML文件。
字段填充也做得聪明。像create_time、update_time、create_by这类公共字段,通过@TableField(fill = FieldFill.INSERT)配合MetaObjectHandler统一自动填充,业务代码里根本不用关心创建时间是谁写入的,既保证数据规范又减少遗漏。
2.2 MySQL8.0的实际收益:字符集、窗口函数与JSON扩展
既然选了MySQL 8.0,就不能只当它是5.7的升级版,几个细节差距在养老这类长周期业务系统里特别有用。
第一是字符集默认utf8mb4。老人姓名里偶尔会出现生僻字或特殊符号,老版本utf8存不下来,直接变问号,这在医疗健康档案里是不可接受的。8.0建表默认utf8mb4,配合utf8mb4_unicode_ci排序规则,兼容性省心很多。
第二是窗口函数。统计连续多周的健康指标趋势时,ROW_NUMBER() OVER (PARTITION BY ...)这类窗口函数可以方便地实现“每个老人取最近一次体检记录”的需求,比传统GROUP BY + MAX(id)自连接写法更清晰、性能也更好。
第三是JSON字段。老年人健康档案中,过敏史、既往病史这类信息结构不固定,用关系表维护会非常繁琐。MySQL 8.0的JSON类型可以直接在字段里存结构化数据,查询时用JSON_EXTRACT或->>操作符取属性,灵活性高出不少。源码里这种用法不算多,但为二次开发留了很好的扩展空间。
2.3 Vue3组合式API对前端项目开发的真实影响
前端这块,Vue3相对Vue2最大的变化是组合式API。看这套源码的页面结构,每个功能页面不再是data、methods、mounted一堆选项堆在一起,而是按业务逻辑组织。以老人档案页面为例:查询表单、表格列配置、分页逻辑、新增编辑弹窗,全部抽成一个个setup函数内的独立逻辑块,相关代码集中在一起,维护时不用上下跳转。
Composition API对团队协作的另一个好处是复用。像“导出Excel”“上传图片”“获取字典”这类通用能力,可以封装成组合式函数放到src/composables目录,页面里直接useExport()调用,比mixin更清晰,也没有命名冲突问题。
配合Vite构建,开发服务器冷启动基本是秒级,热更新也是毫秒响应。相比Vue2时代Webpack动辄十几秒的启动等待,体验是跨代的。所以看到这套源码选择Vue3我完全不意外,2024年之后新起的前后端分离项目,再用Vue2反而不太合理了。
2.4 SpringBoot2还是SpringBoot3:为什么这个选择更务实
有人可能会问,SpringBoot3都发布了,为什么还在用SpringBoot2?我的判断是,SpringBoot3强制要求JDK17,而国内大量服务器和运维环境还停留在JDK8,很多银行接口、加密组件、老旧中间件的兼容性在JDK8上最稳。
养老公寓管理系统本质上属于企业级业务系统,追求的是稳定、易部署、好维护,不是技术尝鲜。SpringBoot2.7.x处于SpringBoot2的维护末期,安全补丁仍在更新,生态兼容性经过多年验证,配合JDK8+Maven这套组合,在任何云服务器上都能顺畅跑起来。源码选择SpringBoot2是务实的工程决策,不是技术落后。
3. 源码落地:目录结构、核心表设计与权限链路
3.1 后端分层架构:从Controller到Mapper的请求流转
整个后端模块结构非常标准,我建议拿到源码先看包名,框架就清楚了:
com.xxx.system ├── controller # 接收前端请求,参数校验,返回统一结果 ├── service # 业务逻辑层,接口+实现 ├── mapper # MyBatis-Plus Mapper接口 ├── entity # 数据库实体类 ├── dto # 数据传输对象,避免直接暴露实体 ├── vo # 视图对象,按前端需要裁剪字段 ├── config # 配置类,安全、跨域、MybatisPlus分页插件 ├── common # 统一返回结果、异常处理、常量 └── utils # 工具类,JWT、日期、加密等请求链路是标准的Controller → Service → Mapper。Controller层很薄,只做参数接收和结果封装;业务逻辑在Service层处理,事务注解也加在这里;Mapper层专注数据访问。这套分层在中小型项目里非常合适,每层职责单一,出了问题定位很快。
统一返回结果设计得也合理。前端每次请求拿到的都是一个固定结构:code、message、data。code=200表示成功,其他为各类业务错误码。全局异常处理器把参数校验异常、业务异常、未知异常统一转成这个结构,前端只需要在响应拦截器里判断code即可,不需要每个请求单独写try/catch。
3.2 数据库核心表:不只是建表,字段设计有讲究
我梳理了一遍SQL脚本,十几张核心业务表基本覆盖了前文提到的业务全景。重点挑几张说明设计思路:
- sys_user(用户表):不仅存登录账号密码,还冗余了关联老人ID、所属机构、角色标识,方便在业务查询中直接关联。密码字段存的是BCrypt加密后的哈希值,绝不允许明文。
- old_man(老人档案表):主表包含基础身份信息、入住状态、护理等级、所属房间床位、紧急联系人。特别留意
status字段,它驱动了整个生命周期的状态流转:待入住、在住、已退住。 - health_record(健康记录表):每一条体检或体征测量是独立记录,包含指标类型、测量值、异常标记、记录人、记录时间。通过
(old_man_id, record_time)组合索引可以快速拉出时间曲线。 - nursing_plan(护理计划表):关联老人和护士,包含护理等级、计划内容、起止日期。计划下挂多条护理执行记录,形成主从结构。
- charge_bill(费用账单表):每个月初根据房间费、护理费、餐费等生成,支持减免和优惠,字段包含应收、实收、优惠金额、账单状态、支付方式。
3.3 权限链路:从登录到接口鉴权的完整闭环
有人在前后端分离项目里经常忽略权限,导致任何会调接口的人都能直接拉取全部数据。这套源码的权限设计整体链路是闭环的,拆解下来分四步:
- 登录时后端验账号密码,通过后生成JWT Token,返回给前端,同时把用户信息、角色信息一并返回。
- 前端把Token存到localStorage或Pinia中,axios请求拦截器在每次请求头里自动带上
Authorization: Bearer <token>。 - 后端用拦截器统一解析Token,校验有效期和签名,解析出用户ID和角色信息。
- 后端在需要权限的接口上通过角色判断是否放行,比如
@RequiresPermissions("oldMan:add")这类注解,或者在Service层手动判断当前用户角色。
前端路由也做了配合:路由守卫检查是否已登录,未登录跳转登录页;动态路由根据用户角色过滤可见菜单,不同角色登录后看到的菜单项不一样。这套“前端路由控制+后端接口拦截”的双层校验,虽然没有Spring Security那么重,但在中小型管理系统里完全够用,而且代码容易读懂,二次开发门槛低。
4. 入住、健康与收费:三个重点模块的实现逻辑拆解
4.1 老人入住与床位分配:状态机思维很关键
老人入住这个模块,表面看是“新增一条老人记录”,实际涉及多个关联操作。我在源码里看到的处理顺序值得参考:
- 登记老人基础信息,生成档案ID。
- 选择楼层房间,系统实时显示房间的空闲床位数量和当前占用情况。
- 绑定床位后,床位状态自动从“空闲”变为“占用”,房间状态联动更新。
- 创建初始健康评估单,护理等级由评估结果自动建议,管理员确认后生效。
- 生成入住记录,入住房号和入住时间写入档案。
这里的核心是一个隐式的状态机:床位有“空闲/占用/维修”状态,房间根据床位状态聚合出“可住/已满/维修中”,老人有“待入住/在住/退住”状态。每次操作都触发状态流转,而不是简单改一个字段。很多初学者做这类功能只会单表修改,导致床位满了还能继续分配的情况。这套源码的状态联动逻辑写法和判断条件,值得作为模板学习。
4.2 健康档案模块:MyBatis-Plus查询技巧的实战
健康档案的数据结构特点是“追加式”的,随着时间推移,每个老人的健康数据量会持续增长。查询场景也有两类:一类是“最近一次体检结果”,另一类是“某指标的历史趋势曲线”。
源码里的处理方式很典型。查最近一次结果,用LambdaQueryWrapper按老人ID过滤,再按record_time倒序,最后last("limit 1")取出最新一条。查历史趋势,用条件构造器按时间范围过滤,再按时间正序排列,前端拿数组直接画折线图。
有一个细节值得注意:当老人数量增长到几百上千,体检记录可能到几万条时,全表扫描就撑不住了。源码在健康记录表上建了(old_man_id, record_time)的复合索引,查询时索引命中,性能不会成为瓶颈。二次开发时如果新增其他高频查询字段,记得同步走索引策略。
4.3 费用管理:账单生成和减免计算的实现思路
养老公寓的收费逻辑比普通民宿复杂得多:房间费按床位等级、护理费按护理等级、餐费按实际用餐次数,还有代购药品、医疗耗材等杂费。这套系统的设计是“收费项目字典+月度账单”。
每月生成账单时,系统先读取所有在住老人的费用配置,按项目汇总,生成账单草稿。处理人核对后确认,账单状态变为待支付。如果老人有减免政策(比如优抚对象、困难补助),系统提供优惠金额字段,实收=应收-优惠。支付完成后自动记录流水号,财务对账直接按账单状态和支付时间筛选即可。
我在这里看到了一个很好的细节:账单生成时记录了bill_month字段,用唯一索引(old_man_id, bill_month)防止同一老人同一月份重复生成账单。这个设计避免了不少月底对账时“多收一笔”的尴尬问题。
4.4 看板统计:聚合查询怎么写才不卡
Dashboard页面通常是一堆统计数字:总老人数、当前入住率、今日新增入住、本月费用应收、健康异常告警数等。源码里这些统计分开查询,每个查询独立走索引,同时为了减轻数据库压力,提供了缓存策略,刷新间隔大概是几分钟。
统计SQL的核心是聚合函数配合条件过滤。比如计算入住率,先统计全部可用床位总数,再统计已绑定老人的床位数量,两者相除保留两位小数。这类跨表统计在MySQL里执行计划还算简单,但如果数据量大,建议把统计结果落到一张“统计快照表”,每天定时任务刷新,前端读快照而不是实时聚合,性能会稳很多。这也是后续做数据大屏时可以优化的方向。
5. 本地运行全流程:从导入SQL到前后端联调的避坑记录
5.1 本地部署的前置环境清单
先把运行环境列出来,版本不匹配是新手最常见的问题:
| 软件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 1.8(8u202+) | SpringBoot2.7对JDK8支持最稳,不要用Java17 |
| Maven | 3.6.3+ | 建议配置阿里云镜像加速依赖下载 |
| MySQL | 8.0.x | 5.7部分语法和驱动配置不兼容,不建议混用 |
| Node.js | 16.x LTS | Vue3+Vite对Node16支持友好,Node20可能遇到依赖兼容问题 |
| 开发工具 | IDEA + Navicat | 后端用IDEA,数据库工具随意 |
5.2 后端启动步骤与配置修改
后端启动逻辑很简单,但有几个坑提前说一下。
步骤一:创建数据库。用Navicat新建数据库,建议起名springboot_vue之类的英文名,字符集选utf8mb4,排序规则utf8mb4_unicode_ci。然后执行项目目录下的sql/init.sql脚本,正常情况下会生成全部表结构和初始数据。
步骤二:修改配置文件。打开src/main/resources/application.yml,重点改三处:数据库地址(jdbc:mysql://localhost:3306/xxx)、用户名、密码。连接字符串末尾建议加上?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true,否则经常会遇到时区和公钥检索报错。
步骤三:启动项目。在IDEA中运行主启动类,控制台出现“Started ... in xxx seconds”即代表成功。默认端口是8080,如果被占用,在配置文件中改server.port。
常见报错和处理方式我整理成了一张表,部署遇到问题直接对照:
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
Access denied for user 'root'@'localhost' | 数据库密码错误或权限不足 | 核对密码,确认root允许本地登录 |
Unknown database 'xxx' | 数据库未创建或库名不对 | 检查配置文件的库名与SQL脚本创建的是否一致 |
Public Key Retrieval is not allowed | MySQL8.0认证方式变化 | 连接串加allowPublicKeyRetrieval=true |
The server time zone value 'xxx' is unrecognized | 时区未配置 | 连接串加serverTimezone=Asia/Shanghai |
Port 8080 was already in use | 端口被占用 | 改server.port,或关掉占用进程 |
Table 'xxx' doesn't exist | SQL脚本未完整执行 | 重新执行init.sql,注意执行顺序 |
5.3 前端启动流程与Vite代理配置
前端代码在vue目录(或frontend目录),打开终端执行:
npm install这一步最容易出问题的是Node版本过高导致node-sass编译失败。这套源码如果用的是sass(dart-sass)而不是node-sass,兼容性会好很多。安装完成后执行:
npm run dev启动后访问http://localhost:5173即可看到登录页。如果页面能打开但接口报404或超时,大概率是Vite代理配置问题。打开项目根目录vite.config.js,确认里面有类似这样的配置:
server: { host: '0.0.0.0', port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } }这段配置的作用是把前端请求的/api前缀自动转发到后端的8080端口,解决前后端联调时的跨域问题。如果没有代理,浏览器直接请求后端就会出现CORS错误,登录都进不去。
5.4 联调容易忽略的细节
前后端都启动后,有几个细节容易浪费新手很长时间。
第一,确认浏览器访问的地址是前端地址而不是后端地址。登录请求通过前端代理转发,页面访问localhost:5173,不是8080。
第二,后端返回的接口路径统一带/api前缀吗?需要核对后端的server.servlet.context-path配置和前端请求路径是否一致。如果后端设了context-path: /api,而前端请求已经带/api,就会出现双重前缀导致404。源码如果统一设计好了,不改配置就不会出问题。
第三,初始管理员账号密码通常在SQL初始化脚本里,比如admin/123456,首次登录后建议在用户管理中修改密码。找不到账号时,去sql/init.sql里搜sys_user表插入语句,直接看明文或加密后的初始值。
6. 二次开发怎么接:家属端、智能设备和报表的扩展思路
6.1 模块扩展:从管理端到家属端和移动端
这套源码以管理后台为核心,实际运营中家属端是刚需。家属关心的大健康数据主要就三块:老人今日状态、最近体检结果、护理计划执行情况。扩展思路也很清晰:后端已有的老接口大部分可以复用,比如按老人ID查健康记录、查护理计划。只需要为家属角色单独写几个聚合接口,把老人档案、最新体征、近7天健康趋势打包返回。
前端家属端可以做成小程序,也可以做H5。数据来源完全复用后端,不需要另外建表。访问控制在原有权限链路中增加一个“家属”角色,绑定老人ID即可。这类扩展本质上加的是“展示层”和“权限配置”,对核心业务表不需要大动。
6.2 与智能硬件对接:血压仪、睡眠监测、呼叫器
养老公寓里智能硬件越装越多:智能血压计、睡眠监测带、一键呼叫器,这些设备的核心价值是实时采集数据并自动入库。对接思路一般是:硬件设备通过网关把数据上报到平台的MQTT消息,后端写一个监听服务消费消息,解析后写入健康记录表。写入时复用现有health_record表结构,根据设备类型设置指标编码,前端趋势图不用重新开发。
数据异常预警也可以在这个环节打通:消费健康数据消息后,如果血压、心率、血糖指标超出阈值,自动生成一条告警记录,同时推送通知给责任护士和家属。这套源码中告警模块留了基本的字段设计,扩展对接时主要工作量集中在协议解析和消息入队,业务表几乎不用改。
6.3 在现有源码上做二次开发的三条建议
拿到源码不要急着改代码,先做三件事:
- 完整跑通一遍业务:用初始账号登录,走一遍老人入住到生成账单的完整流程,弄明白每个按钮背后的接口调用和数据变化。
- 画出核心表关系图:用Navicat逆向数据库生成ER图,理清
sys_user、old_man、health_record、nursing_plan、charge_bill之间的关系。 - 从一个小需求下手:比如给老人档案加一个“紧急联系人”的编辑弹窗,或者给健康记录加一个导出功能,用最小的改动熟悉项目代码风格。
二次开发时改动最大的通常是两组内容:新增业务表的CRUD代码、给已有模块加字段。前者因为MyBatis-Plus的代码生成器存在,效率很高;后者需要注意数据库增量脚本的维护,别直接把旧表删了重建,线上数据经不起折腾。
这套源码的整体结构属于“务实型”,没有花哨设计,但每一层都踩在常规工程的正确位置上。我实际运行和修改的过程中,感受最深的是它的模块边界清楚:想改健康管理,只需要盯住health_record相关的Controller、Service、Mapper三层和对应前端页面,不影响其他模块。对于需要快速交付毕业设计、课程项目,或者在真实养老机构里做信息化的团队来说,这个结构带来的维护成本优势很实在。