SpringBoot+Vue构建社区智慧养老监护平台:设计与实现全解析 简介本资源是一套面向计算机专业本科生的智慧养老领域实战项目适用于毕业设计、课程设计及SpringBootVue全栈开发能力提升。项目聚焦社区级老人监护场景通过前后端分离架构实现老人信息管理、监护人联动、紧急报警等核心功能帮助学习者深入理解企业级Web应用开发流程与智慧养老信息化落地逻辑。压缩包共474个文件含141个Java后端业务与接口代码、64个Vue组件页面、161个SVG图标资源辅以SQL建表脚本、YML配置、BAT一键部署脚本及演示视频等整体25.13MB结构清晰便于模块化学习。已有188人下载学习配套提供详细部署说明、功能演示视频及源码级介绍文档覆盖从环境搭建、数据库初始化、前后端联调到核心功能验证的完整实践路径是掌握现代Web开发技术栈与行业应用结合的优质教学案例。 社区智慧养老监护管理平台这类项目我这两年其实陆陆续续接触过好几个——有毕业设计也有真实接单的小项目。SpringBoot Vue 的组合在养老领域非常典型因为这类系统既要覆盖管理端的复杂业务又要兼顾终端设备的接入前后端分离是性价比最高的选择。但真正动手做的时候你会发现养老场景和普通管理系统差别很大设备数据、告警联动、视频流、工单闭环、家属端授权任何一个环节都藏着坑。这篇文章我把完整的设计思路、技术选型依据、核心模块拆解、部署流程和踩坑记录都整理出来希望能帮到正在做类似项目的朋友。1. 社区的养老服务到底卡在哪个环节1.1 信息断层是最大的问题社区养老服务中心不是没有服务而是服务过程不可见、结果不可追踪。一个护理员一天可能要上门拜访十几位老人今天去了没去、血压测了没测、家属问起来有没有交代全靠纸质记录和口头汇报。管理端想统计服务质量只能月底翻台账、找聊天记录根本形成不了数据闭环。我在设计这个平台之前先花了两周时间调研真实场景走访了几个社区服务中心。最常见的痛点有三个老人健康数据散落在不同设备里血压计、血糖仪、智能手环各自为政没有统一汇聚入口紧急呼叫发生后值班人员只能通过电话了解情况缺乏老人实时位置和健康状态的辅助判断家属想了解老人动态只能打电话问护工缺乏一个透明的、可自主查看的渠道。所以这个平台的核心价值不是做一个花哨的管理后台而是把感知层—服务层—管理端—家属端这条链路打通。1.2 平台整体定位整个系统拆成三个端管理后台Web社区运营人员使用负责老人档案管理、护工排班、工单派发、设备数据查看、告警处理护工工作台Web 移动适配接收任务、上报服务结果、记录老人健康数据家属端H5/小程序查看老人基础健康数据、接收告警通知、在线缴费或预约服务。后台统一用 SpringBoot 做服务端前端用 Vue3 做主应用本质上是一个后端服务支撑多个前端入口的架构。这样数据模型只需要维护一套权限体系也能统一控制后续接小程序、App 只需要加一个前端壳子后端接口不用重复开发。1.3 业务边界要控制住养老平台的业务域非常宽如果一开始就把医疗、康复、家政、餐饮全部纳入系统项目规模会失控。我做的时候先把业务边界刻意收窄到四条主线老人档案与健康管理基础信息、健康档案、设备绑定、健康趋势服务工单闭环计划生成 → 派单 → 执行 → 结果回写 → 评分告警联动处置SOS/设备异常 → 生成告警 → 通知值班 → 处置记录家属触达通道数据查看、告警接收、服务预约。这四条主线覆盖了社区养老最核心的日常运作又不会让系统变成一个什么都想干、什么都干不好的大杂烩。后来做演示和答辩的时候这四条主线正好也能串成一个完整的业务故事。2. 技术选型的逻辑为什么是 SpringBoot Vue而不是别的2.1 后端选 SpringBoot 的理性考量很多人选 SpringBoot 是因为大家都在用但实际做养老项目有几个真实需求决定了 SpringBoot 比 Node.js、Go 更合适生态成熟人才好找这个项目不是写完就完了后期要有人维护。SpringBoot 在国内 Java 生态里资料最全遇到问题搜得到答案Spring 家族天然适配Spring Security 做权限、Spring Data JPA / MyBatis 做持久层、Spring Task 做定时任务、Spring Validation 做参数校验一套组合拳下来不需要引入太多第三方框架Java 17 SpringBoot 3.x 的稳定性实际开发中我用的 SpringBoot 2.7.x不是因为 3.x 不好而是 2.7 的生态兼容性最好——很多第三方 starter 对 SpringBoot 3 的 Jakarta 迁移还不太友好。做项目求稳不为等新特性搭上排坑时间。2.2 前端选 Vue3 的具体原因养老平台的管理端交互不算特别复杂但是页面数量多、状态管理需求高。Vue3 相比 Vue2 有几个点对这个项目帮助很大Composition API 让业务逻辑复用变简单工单列表、告警列表、健康趋势这些页面逻辑高度相似用 composable 函数可以把加载数据 分页 筛选的逻辑抽出来不用在各个组件里复制粘贴TypeScript 支持更好老人档案、工单、设备这些数据模型字段多有类型约束能少掉很多低级 bugElement Plus 组件库表格、表单、穿梭框、时间线这些组件拿来即用一个管理后台 80% 的界面都能用 Element Plus 拼出来。另一个选择是 React但就这个项目而言 Vue 的学习曲线更平缓团队协作时沟通成本低而且 Element Plus 的组件风格非常契合这种信息密集型管理后台的界面需求。2.3 数据库与中间件怎么选组件选型选择理由关系型数据库MySQL 8.0业务以事务性数据为主老人、工单、告警都是强关系模型MySQL 最稳妥缓存Redis 7.x登录 Token 缓存、验证码存储、热数据读取实时通信WebSocketSpring 原生支持告警推送、工单状态变更提醒比轮询实时性高且省资源文件存储本地存储 Nginx 静态映射演示阶段不需要上 OSS本地存储加 Nginx 映射最省事视频流HLS 切片 Nginx 代理监护摄像头输出 m3u8 流通过 Nginx 代理播放这套组合的特点就是不折腾。每个组件都是经过大量项目验证的成熟方案对于社区养老这种需要稳定运行而非追新尝鲜的场景够用且可控。3. 核心功能模块拆解每个模块到底设计到什么程度3.1 数据看板让管理层一眼看懂运营状态平台首页不是放一张静态欢迎图而是一个运营看板。我用 ECharts 做了几个核心可视化组件老人统计卡片总人数、健康状况分布、年龄段分布工单完成率趋势近 7 天计划工单 vs 完成工单的折线图告警类型分布SOS 告警、设备离线、健康异常的比例饼图实时滚动列表最近 10 条待处理告警带跳转链接。看板数据不是每次请求都实时查库那样压力太大。我设计了一个DashboardService用 Spring 的Scheduled每 5 分钟把聚合结果缓存到 Redis前端页面打开时优先读缓存。这样保证首页秒开数据库压力也小。3.2 老人档案模型设计是整张表的关键老人档案是整个平台的数据基座很多功能都要 join 这张基础表。老人表我拆成三张elderly_info基础档案、联系人、地址、紧急联系人elderly_health_profile既往病史、过敏史、用药记录elderly_device_binding设备绑定关系一个老人可以绑多个设备。为什么要拆因为基础档案是低频变更数据健康档案是高频更新数据如果放一张表字段过多、更新锁竞争严重。拆开后各自的读写频率都能独立优化。前端档案页面用 ElTabs 组织这三个子模块切换 Tab 请求对应接口不一次性加载所有数据页面响应明显更快。3.3 工单闭环从派单到回写的状态机工单是这个平台业务闭环的主动脉设计重点是状态机。我用一个枚举OrderStatusEnum定义了完整流转PENDING → ASSIGNED → IN_PROGRESS → COMPLETED → EVALUATED ↘ CANCELED关键业务规则有两条已完成工单不能直接改状态必须走回访确认流程防止护工误操作超时未开始的工单定时任务每 10 分钟扫描一次自动通知值班人员介入。这里有个设计细节工单状态变更不做硬删除所有历史记录写进order_status_log表方便管理层追溯。前端展示用 ElTimeline 组件把状态流转以时间线形式呈现家属和护理员都能看得明白。3.4 告警联动从设备到处置的自动流转告警来源分三类老人主动按 SOS、设备离线、健康指标越界。每类告警的处置流程都不同但都汇入同一个alert_center告警来源 → 生成告警记录 → 匹配值班人员 → WebSocket 实时推送 → 手机短信可选 → 处置结果回填 → 关闭或升级WebSocket 推送是我用 Spring 的TextWebSocketHandler实现的。老人按下 SOS 之后值班大屏必须在一秒内弹出告警卡片这个实时性只有 WebSocket 能做到。前端收到告警后用 ElNotification 弹出全局通知同时播放提示音这个可以配置开关不然半夜告警能把值班室所有人吓醒。3.5 家属端小程序的轻量入口家属端我做得比较轻量核心只做三件事查看绑定的老人健康数据最近 7 天趋势图接收告警通知通过 WebSocket 与服务端保持长连接App 退到后台后降级为短信通知在线预约探访或服务。家属端和后台共用同一套接口只是通过不同的角色权限控制可见范围。家属账号本身没有独立注册入口只能由管理后台创建后生成邀请码绑定。4. 开发中卡得我比较久的几个技术点4.1 m3u8 视频流在 Vue 播放器的落地养老平台里会有视频监护需求摄像头输出的是 HLS 协议也就是 m3u8 索引文件加 ts 切片。前端播放方案我对比了一下放弃了很多播放器兜底方案最后选了hls.js 自定义播放器组件。原因很简单video.js和vue-video-player确实封装度高但版本兼容问题比较多——它依赖的 videojs-contrib-hls 已经停止维护对 HLS 的解析还是旧逻辑。核心代码如下import Hls from hls.js const playM3u8 (videoElement, url) { if (Hls.isSupported()) { const hls new Hls({ maxBufferLength: 30, maxMaxBufferLength: 60, enableWorker: true }) hls.loadSource(url) hls.attachMedia(videoElement) hls.on(Hls.Events.MANIFEST_PARSED, () { videoElement.play() }) return hls } else if (videoElement.canPlayType(application/vnd.apple.mpegurl)) { videoElement.src url return null } }实际部署时 m3u8 流不是直接暴露给浏览器的前端只请求后端接口拿播放地址播放地址指向 Nginx 代理的流媒体服务。跨域问题由 Nginx 统一处理前端代码只关心播放本身。4.2 健康数据实时推送WebSocket 的心跳与重连WebSocket 单独推一次数据不难难的是连接稳定。养老平台的告警推送要求长时间在线如果连接断了自己不知道告警就会漏掉。我在前端封装了一个useWebSocketcomposable核心逻辑包含三个机制心跳检测每 30 秒客户端发送一个 ping服务端 10 秒内未响应则主动断开重连断线重连断开后按 1s、3s、5s 的退避策略重连最多重试 5 次消息确认服务端推送的消息带messageId客户端收到后回执 ACK服务端超过 30 秒未收到 ACK 会转短信通道。const ws ref(null) let heartbeatTimer null let retryCount 0 function connect() { ws.value new WebSocket(wsUrl) ws.value.onopen () { heartbeatTimer setInterval(sendPing, 30000) retryCount 0 } ws.value.onclose () { clearInterval(heartbeatTimer) if (retryCount 5) { const delay [1000, 3000, 5000][retryCount] || 5000 setTimeout(connect, delay) retryCount } } }Spring 端我用的WebSocketHandler加ConcurrentWebSocketSessionDecorator给每个 session 设置发送超时和缓冲上限防止某个慢客户端把整个推送通道阻塞住。4.3 接口权限RBAC 模型下最容易踩的坑Spring Security JWT 做 RBAC 是标准方案但养老平台的角色权限有个特殊点同一用户可能同时拥有多个角色。比如社区负责人既需要管理权限又是值班组成员要做告警处置。如果权限设计成一人一角色运营的时候就要频繁切换账号非常痛苦。我的做法是用户表关联多个角色角色关联多个权限点菜单权限 接口权限 操作权限。JWT 中只放userId和roleIds权限判断放在后端拦截器里实时查询避免修改权限后需要重新登录的问题。接口权限用自定义注解实现Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface RequirePermission { String value(); }在拦截器里解析注解判断当前用户的权限点列表是否包含value()不包含就抛 403。这个方案的好处是权限点和接口一一对应新增接口时只需要加一行注解不用去配置中心维护一大堆规则。4.4 地图轨迹在 Vue 里的处理工单执行经常涉及护理员上门需要记录执行轨迹。地图选型我考虑过高德和百度最后选了高德原因是它在 H5 端的兼容性好Key 申请简单且 JavaScript API 的文档更新及时。轨迹绘制用的是高德的Polylineconst polyline new AMap.Polyline({ path: pathData, strokeColor: #3366FF, strokeWeight: 4, strokeStyle: solid }) map.add(polyline) map.setFitView([polyline])这个功能本身不难坑在于轨迹点保存的频率。如果每 3 秒存一个点一位老人的日常活动轨迹一天就是 28800 个点数据库压力不小。我的方案是前端每 30 秒上报一次聚合点如果两个点距离小于 3 米就自动合并只有转向或位移超过阈值才单独记录。这样既能还原轨迹又不会把数据库打爆。5. 部署与上线从开发机到 Linux 服务器的完整路径5.1 后端打包SpringBoot 后端打成可执行 jar 包这是最省事的部署方式。我在application-prod.yml里配置了生产环境的数据库地址和 Redis 连接打包时指定 prod 环境mvn clean package -DskipTests -Pprod打出来的 jar 大概 80MB 左右包含了所有依赖用nohup启动nohup java -Xms512m -Xmx1024m -jar /opt/eldercare/eldercare-server.jar \ --spring.profiles.activeprod \ /opt/eldercare/logs/eldercare.log 21 5.2 前端构建与 Nginx 配置Vue 前端构建产物是dist目录直接放到 Nginx 的静态目录下npm run build sudo cp -r dist/* /var/www/eldercare/Nginx 配置有几个关键点WebSocket 长连接需要配置Upgrade头/api前缀的请求反向代理到后端服务/media前缀的请求代理到流媒体服务前端路由用 history 模式时需要配置try_files否则刷新页面会 404。server { listen 80; server_name eldercare.example.com; root /var/www/eldercare; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /ws/ { proxy_pass http://127.0.0.1:8080/ws/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_read_timeout 3600s; } location /media/ { proxy_pass http://127.0.0.1:8888/media/; } }5.3 数据库初始化与数据迁移生产环境的 MySQL 我用的是 8.0初始化和开发时一致即可。但有个细节必须提醒千万不要直接在生产库手动建表。项目里我用了 Flyway 管理数据库版本src/main/resources/db/migration下放了 V1__init.sql、V2__add_device_table.sql 等脚本打包后启动时会自动执行这样开发、测试、生产环境的结构永远是一致的。老人基础数据导入可以写一个 Excel 导入工具用 EasyExcel 读表格按模板校验后批量插入。这个功能对演示特别加分因为演示时需要展示大量数据靠手工录入根本不现实。5.4 服务器部署的完整步骤部署步骤我整理成一个 shell 脚本每次发版只改版本号就行# deploy.sh #!/bin/bash APP_NAMEeldercare-server JAR_PATH/opt/eldercare/$APP_NAME.jar LOG_PATH/opt/eldercare/logs/$APP_NAME.log # stop old process pid$(ps -ef | grep $APP_NAME | grep -v grep | awk {print $2}) if [ -n $pid ]; then kill -9 $pid fi # start new process nohup java -Xms512m -Xmx1024m -jar $JAR_PATH --spring.profiles.activeprod $LOG_PATH 21 # check status sleep 10 if ps -p $! /dev/null; then echo Application started successfully, pid: $! else echo Application failed to start, check log: $LOG_PATH fi脚本很简单但生产环境足够用。如果后续访问量变大可以改成 systemd 服务但对社区养老这个量级nohup 加定时重启已经能保证稳定。6. 避坑手册这些问题是演示时最容易翻车的6.1 端口占用与防火墙这是 90% 演示翻车的原因。后台启动成功前端页面打不开排查半天发现是 Nginx 的 80 端口被其他服务占了。建议部署完先测一波# 检查端口监听状态 netstat -tlnp | grep -E 80|8080|6379|3306 # 测试后端接口 curl http://127.0.0.1:8080/api/health # 测试前端页面 curl -I http://127.0.0.1/6.2 跨域问题前后端分离项目本地开发时跨域是高频问题。我自己踩过一个坑前端用 Vite 配置了代理指向 8080后端也加了 CORS 配置结果两个机制叠加导致请求发了两次一次预检、一次真实请求预检响应被代理拦了总是失败。后来统一原则开发环境用 Vite 代理生产环境用 Nginx 代理后端可以不配 CORS 或只允许特定域名。两边只留一个通道问题就少了一半。6.3 数据库连接池耗尽演示时操作快了偶尔报Connection is not available, request timed out after 30000ms这是连接池满了。普通社区规模撑不到这个量但写批量导入功能的时候很容易触发——Excel 导入 1000 条数据如果用循环单条插入每条占一个连接且不释放连接池很快就满了。解决方案是导入函数强制用批量插入并且用Transactional包住整个方法保证所有插入在一个事务里完成Transactional public void batchImport(ListElderlyInfoDTO list) { for (int i 0; i list.size(); i 100) { ListElderlyInfoDTO batch list.subList(i, Math.min(i 100, list.size())); elderlyInfoMapper.batchInsert(batch); } }6.4 前端构建后的缓存问题Vue 构建后文件名带 hash按理说不会缓存旧文件但如果服务器返回的index.html有强缓存头用户打开页面还是旧版。生产环境 Nginx 配置给index.html加Cache-Control: no-cache给带 hash 的静态资源加超长缓存location /index.html { add_header Cache-Control no-cache, no-store, must-revalidate; } location /assets/ { expires 30d; add_header Cache-Control public, immutable; }这个配置能避免每次发版后用户需要强制刷新才能看到新页面的尴尬。6.5 演示视频要录什么最后多提一句交付物。项目包里有演示视频但很多人不知道演示视频该录什么。我的经验是录完整的业务闭环而不是功能词典从管理员登录 → 创建老人档案 → 绑定设备 → 模拟一条健康异常数据 → 告警弹出 → 生成工单 → 派给护工 → 护工处理 → 处理结果回写 → 家属端看到数据更新。这样一条线走下来评委或客户能在 5 分钟内理解系统的完整价值比把所有页面截图念一遍有效得多。最后再分享一点个人体会这类平台做下来我的感受是技术难点其实不复杂真正复杂的是业务逻辑里那些如果...结果...的分支处理老人换了设备怎么办、SOS 按错了怎么办、护工请假了工单谁来接手。这些边界问题前期想得越细后期越省事。整个项目从设计到部署我大概花了六周其中需求理解和数据模型设计占了差不多两周写代码反而快。如果你也在做类似的项目建议先把核心业务表设计好、把状态机画清楚再动手写接口后面返工的几率会大大降低。另外养老行业的数据安全和隐私保护非常重要演示的时候涉及老人姓名、住址、健康信息最好用脱敏或模拟数据。这不是形式主义而是真实项目交付时必须具备的合规意识。系统上线之后我也会建议运营方定期导出操作日志方便审计追溯。本文还有配套的精品资源点击获取