SpringBoot+Vue全栈实战:社区智慧养老监护管理平台开发

发布时间:2026/9/29 17:58:37
SpringBoot+Vue全栈实战:社区智慧养老监护管理平台开发 这两年接手的项目里社区智慧养老算是比较接地气的那一类。表面看是做一个管理系统实际上要打通的是一条“老人-设备-社区-家属”的完整链路既要管档案、管设备还要管实时告警和工单处理。真正做起来对Java后端、MySQL建模、Vue前端都有实打实的要求。我这次实现的“基于SpringBootVue的社区智慧养老监护管理平台”用的是JavaMySQLMyBatis这套组合前端走Vue配合Element UI后端SpringBoot搭单体骨架最终产出了一个从数据库到接口、再到页面联调均可直接跑起来的完整源码。这篇文章我打算按自己当时的开发顺序来写先讲为什么这么选型再拆核心模块和表结构设计然后落到SpringBootMyBatis的具体实现细节到前端Vue的关键页面和联调最后是部署和踩坑实录。项目虽然不大但覆盖了权限、告警、工单、数据可视化这些常见场景对想练手SpringBootVue全栈的开发者来说是个很好的完整样本直接照着改就能复用到其他管理类项目里。1. 项目定位与技术栈选择1.1 这个平台到底解决什么问题社区养老和机构养老有一个很明显的区别老人的居住地分散社区网格员或养老专员不可能24小时陪着每个人。于是监护管理平台的核心价值就是把“人盯人”变成“系统盯数据”。从实际场景来看平台至少要接住这样几件事老人基础档案的管理包括姓名、年龄、家属联系方式、既往病史、紧急联系人等智能硬件手环、血压计、睡眠监测垫、门磁等上报的健康指标和活动数据指标异常时自动产生告警并派发工单给对应网格员处理家属和管理员能够随时查看老人的健康趋势、告警记录和处理进度社区管理者用可视化图表掌握每天的告警量、已办结率和重点老人分布。说白了这套系统真正的主角不是“增删改查”而是“异常状态下的响应闭环”。如果没有告警和工单流转它就只是一个高级Excel有了异常检测和闭环处理它才称得上“监护平台”。1.2 为什么选SpringBootVueMyBatis这套组合这个选型在标题里已经写死了但我在刚立项时其实也认真纠结过。先说后端SpringBoot是当前单体应用里开发效率最稳的选择不用自己拼SSH那一堆XML配置Maven拉依赖就能起服务。配合自带的starterRedis、定时任务、参数校验这些常用能力都是开箱即用。MySQL负责数据落地横向对比过PostgreSQL但是考虑到这套系统要交给社区运维MySQL依然是团队最熟、社区资料最多的那个出问题随便一搜就有解。MyBatis则是国内Java项目里使用率极高的ORM框架半自动的模式适合对SQL有掌控欲的团队——复杂报表查询、多表关联、统计聚合写在XML里比JPA的自动SQL更直白也好优化。前端选Vue当时考虑的是社区管理端的页面交互量不大但数据看板、列表筛选、弹窗表单这类需求很典型Vue的响应式模型在中小型后台里够用且轻量。配合Element UI的表格、表单和图表组件开发速度很快。这套组合还有一个隐形的优势项目结构容易统一后端Controller- Service-Mapper三层前端Vue RouterAxiosVuex换人接手成本极低。对技术团队不固定的社区项目来说这是非常重要的工程权衡。1.3 整体架构与请求链路我给这套平台定了前后端分离的简单分层浏览器 - Nginx可选/开发模式前端Dev Server - SpringBoot Controller - Service - MyBatis Mapper - MySQL开发环境下Vue跑在8080端口SpringBoot跑在8081端口。前端通过Axios发起请求统一走/api前缀。我在后端加了一个CORS配置类放行8080来源所以本地联调时不需要额外配代理但生产环境建议用Nginx把/api反向代理到后端端口再把前端静态资源挂在同域下这样就不存在跨域问题了。单体的好处是部署简单。我打了一个SpringBoot的Fat Jar前端用npm run build构建静态资源直接把dist目录扔给Nginx就行。系统的监控大屏、家属端和管理端都在一套代码里通过角色权限控制入口暂时不需要拆微服务——社区项目的数据量远没到必须拆分的规模拆了反而增加运维负担。2. 核心功能模块设计与业务闭环2.1 老人档案与设备绑定每一个老人信息录入后系统会生成一个独立的监护档案。除了姓名、身份证、住址、家属电话这些常规字段我额外增加了两个重要内容健康标签和设备编号。健康标签是为了告警分析服务的。比如一个老人被标记为“高血压高危”那么他上报的收缩压超过140我们就需要提高预警等级而普通老人可能放宽到160。这个看似很小的设计影响的是整个告警规则的灵活性。设备绑定则是把硬件数据的归属关系落到表里一条手环的上报记录必须能够关联到某个老人否则数据就是孤岛。所以在设计老人表时我没有把设备信息做成独立外键而是用了device_id做一对一绑定并在设备表中冗余了elderly_id。这样查询“某老人当前佩戴设备”和“某设备当前使用人”都非常快避免了两张表双向维护的麻烦。2.2 健康数据采集与异常告警硬件上报的数据格式五花八门有的走MQTT有的走厂家HTTP接口。我这版系统做一个统一的HealthDataController作为接收端点设备端调POST接口把JSON数据送进来。核心字段是elderly_id、type、value、timestamp和source_device。在Service层做三件事校验老人是否存在、判断数据是否在正常区间、写入健康记录表。异常判断这里我没有做成硬编码而是设计了一个alert_rule表默认内置心率、血压、血氧、体温四类规则每类规则有上下限和优先级。管理员可以在后台调整阈值。比如:规则心率 上限 100 下限 60 等级 WARN 规则血氧 上限 100 下限 90 等级 CRITICAL当新数据进入时我按规则表循环匹配一次。如果触发告警生成一条alert_record并同步推送给对应的网格员。推送方式在本地环境先用WebSocket通知前端真正生产环境可以换短信或微信模板消息。这里最值得说的不是告警生成而是“防重复”。一个老人血氧持续低于90理论上每一分钟上报都会触发告警那系统就会被刷屏。我加了告警合并的逻辑同一位老人的同一类指标如果5分钟内已经存在“未处理”状态的告警就不重复生成只在原告警上更新last_occur_time。这个细节在做社区场景时非常必要否则网格员会被无效信息干扰到直接忽略系统。2.3 工单流转与家属端/管理端场景告警产生后必须有响应闭环否则就是狼来了。我设计了标准的工单流待处理 - 处理中 - 已办结 - 已关闭。网格员在待办列表里看到告警详情可以一键“接单”进入处理中状态然后填写处理记录。比如“已联系家属家属判断老人是轻微不适持续观察”。处理记录这条数据很重要我单独建了work_order_record表因为后续做数据统计、责任追溯时全凭这些记录。家属端相对简单只展示与自己绑定老人的健康趋势、告警列表和待办反馈。管理员端则能看到全部工单的流转情况以及基于时间的统计图表。这样设计既服务了日常监护也满足了管理者对平台使用效果的整体评估。3. 数据库设计与核心表结构3.1 核心表清单与字段说明数据库是这套系统的地基我在建表时重点考虑了三个原则字段能复用就不拆分、状态值统一用字典表、时间字段一律TIMESTAMP。下面列出我最终确定的几张核心表长者表elderly字段名类型说明idBIGINT主键自增nameVARCHAR(64)姓名genderTINYINT1男 2女birth_dateDATE出生日期phoneVARCHAR(32)家属电话health_tagsVARCHAR(255)健康标签逗号分隔device_idVARCHAR(64)绑定设备编号addressVARCHAR(255)详细住址statusTINYINT1正常 2重点关注 3已去世健康记录表health_record字段名类型说明idBIGINT主键elderly_idBIGINT长者IDtypeVARCHAR(16)指标类型heart_rate/bp_high/bo/trevalueDECIMAL(8,2)指标值unitVARCHAR(16)单位received_atTIMESTAMP数据上报时间告警记录表alert_record字段名类型说明idBIGINT主键elderly_idBIGINT长者IDrule_idBIGINT触发规则IDalert_levelVARCHAR(16)WARN/CRITICALcontentVARCHAR(255)告警内容statusTINYINT0未处理 1处理中 2已处理first_occur_timeTIMESTAMP首次触发时间last_occur_timeTIMESTAMP最近触发时间工单表work_order字段名类型说明idBIGINT主键alert_idBIGINT关联告警IDhandler_idBIGINT处理人IDhandler_nameVARCHAR(64)处理人姓名快照statusTINYINT1待处理 2处理中 3已办结 4已关闭create_timeTIMESTAMP创建时间finish_timeTIMESTAMP办结时间用户表sys_user和角色表sys_role就是标准的RBAC设计这里不赘述。需要注意的是一定要加上deleted逻辑删除标记用户误删除老人档案时不能直接物理删除否则历史健康数据分析会断链。3.2 状态流转与数据一致性的几个设计细节项目中容易被人忽略但又很关键的设计是“快照字段”的使用。工单里我冗余了handler_name告警里冗余了老人的实时基本信息和elderly_name。这么做的原因是如果用户被删除、老人被修改历史工单依然能展示当时的信息。报表统计时也不需要频繁JOIN性能更好。另外一个值得说的点是时间字段用了received_at而不是create_time。因为设备可能由于网络延迟滞后上报如果用数据库写入时间可能导致分析的时序错乱。我在代码里明确区分了“上报时间”和“系统接收时间”所有趋势图都以上报时间为准这样数据才真实。最后是索引设计。健康数据查询频次较高而且基本都是按照elderly_id received_at范围查询所以建了复合索引idx_elderly_time (elderly_id, received_at)。告警表按status elderly_id建立普通索引。实测下来在一个模拟了两万条健康记录的数据库里按老人查近一个月数据耗时在几十毫秒以内完全够用。4. 后端实操SpringBootMyBatis核心实现4.1 项目初始化与统一返回结构建项目我用的Spring Initializr选Java 8、Spring Boot 2.7.x。依赖选Spring Web、MyBatis、MySQL Driver、Lombok、Validation。没有引入额外的代码生成器Mapper接口和XML都是手写的这样更容易控制SQL细节。统一返回结构是前后端联调的地基。我定义了一个ResultT类包含code、message、data三个字段。约定code200表示成功其它为业务错误码。所有Controller返回这个结构前端Axios拦截器统一解包出现401跳登录页出现500弹错误提示。这个结构早期就定好能省掉后面大量无用沟通。4.2 告警规则判定与定时任务的实现细节告警判定的核心方法长这样public void evaluate(HealthData data) { ListAlertRule rules alertRuleMapper.selectByType(data.getType()); for (AlertRule rule : rules) { boolean hit false; if (gt.equals(rule.getOperator())) { hit data.getValue().compareTo(rule.getThresholdValue()) 0; } else if (lt.equals(rule.getOperator())) { hit data.getValue().compareTo(rule.getThresholdValue()) 0; } if (hit) { processAlert(rule, data); break; } } }这里有一个容易被忽视的问题数据库的DECIMAL字段映射到Java的BigDecimal比较时必须用compareTo不能用equals因为equals还会比较精度和标度比如140.00和140.0它认为是不等的。定时任务我用了Spring自带的Scheduled每天凌晨跑一次汇总任务把前一天每个老人的最大/最小/平均心率、血压汇总到health_daily_summary表。这样前端展示“近30天每日趋势”时只需要查30条汇总数据而不是上百万条明细性能差很多。4.3 MyBatis映射踩坑与TypeHandler使用场景MyBatis真正用起来会碰到一些坑特别是Java类型和数据库类型的映射。最典型的一个Map接收查询结果时如果字段是DECIMALMyBatis默认返回BigDecimal但如果你在JSP或前端模版里没注意就可能在页面上显示成科学计数法而用Map时数字类型的转换偶尔会出现精度丢失。所以我给统计查询都建立了对应的POJO而不是图省事直接用Map。另一个经典场景是TypeHandler。我的health_tags字段在数据库里是逗号分隔的字符串但在Java对象里我希望它是一个ListString。跟搜索热词里聊到的“MyBatis中TypeHandler的工作流程图”一样我实现了自定义TypeHandler在入库时把List拼接为逗号分隔串出库时再拆成List。核心思路就是继承BaseTypeHandlerListString然后复写setNonNullParameter和getNullableResult。还有日期类型建议统一用TIMESTAMP并配jdbcTypeTIMESTAMP否则一些MySQL版本下插入时会报日期无法识别。4.4 安全细节全局过滤器处理XSS涉及老人健康数据和个人隐私我对输入做了两层防护。第一层是全局XSS过滤用一个Filter拦截所有POST/PUT请求对请求体里的HTML标签进行转义。实现思路是把JSON字符串读出来用Jsoup.clean处理掉危险标签再重新包装进HttpServletRequestWrapper。第二层是SQL防注入因为MyBatis里全部用的是#{}预编译这块天然安全。热词里还提到“SpringBoot项目全局过滤器处理上传pdf文件时xss攻击”我遇到过类似问题上传PDF时文件内容是二进制如果统一走字符转义会把文件搞坏。所以过滤器里要判断请求头Content-Type只有application/json或application/x-www-form-urlencoded才做XSS清洗文件上传直接放行。5. 前端实操VueElement UI关键功能实现5.1 项目初始化与路由设计前端我用Vue 2配Element UI因为这套项目要尽量减少学习成本管理后台用Vue 2生态成熟稳定。脚手架用Vue CLI装好Router、Vuex、Axios。路由设计上我用了嵌套路由的经典后台布局/login / - Layout /dashboard - 监护仪表盘 /elderly - 老人台账 /elderly/detail/:id - 老人详情 /alert - 告警中心 /work-order - 工单列表 /stats - 统计分析 /settings - 规则阈值配置在router.beforeEach里加了全局导航守卫没拿到token就强制跳转登录页拿到token后再请求一次/api/user/info把角色存入Vuex用于控制菜单显示。5.2 核心页面拆解监护大屏与老人详情监护大屏必须做到“一眼能看到问题”。我用了Grid布局左侧展示告警滚动列表右侧用ECharts画今日各类型指标的异常分布饼图中间四块卡片放置重点关注老人数、今日告警数、待处理工单数、本周办结率。老人详情页是整套系统交互最复杂的页面。顶部是基本信息卡片中间是ECharts的三条折线图心率、血压、血氧下面是一个时间线组件把所有与该老人相关的告警和处理记录按时间倒序排列。这里有一个前端细节当从告警中心点“处理”按钮页面带着alert_id跳转详情页可以直接展示这条告警的时间线上下文方便网格员快速了解情况。5.3 与后端联调中的几个常见问题联调阶段经常翻车的地方我印象比较深的有三个。第一个是跨域。开发环境后端在8081前端在8080如果后端没配CORSAxios请求会报CORS错误。我在后端写了一个WebMvcConfigurer通过addCorsMappings放行8080。有几次报错是预检请求OPTIONS没有通过检查发现是因为自定义Filter拦截了OPTIONS请求导致响应体被吞掉后来在Filter里对OPTIONS直接放行。第二个是日期格式。SpringBoot默认返回的TIMESTAMP是一个数组格式的长串Vue端根本没法直接展示。我在application.yml里配置spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8才把时间统一成字符串。第三个是404问题。Vue Router用的是history模式生产环境如果Nginx不配置try_files直接刷新子路由页面会404。需要加location / { try_files $uri $uri/ /index.html; }这样才能保证所有路由都落到index.html上交给前端路由渲染。6. 踩坑实录与调试技巧6.1 MySQL连接配置与SSL问题如果是从官网现装MySQL 8.x连接时最容易遇到两个问题Public Key Retrieval is not allowed和SSL connection error。第一个要用allowPublicKeyRetrievaltrue第二个建议直接用useSSLfalse。完整JDBC连接串我给一下jdbc:mysql://localhost:3306/elderly_care?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue顺便提一句MySQL 8.0之后的默认认证插件是caching_sha2_password如果用的是老版本驱动5.x会报Authentication plugin错误。所以尽量选mysql-connector-java 8.0.x的新驱动。本地调试时我用Navicat比较多连接时也要记得选择MySQL 8版本否则同样的认证插件会卡住。6.2 MyBatis缓存与XML映射排查有次我发现修改了SQL语句却不生效排查后确认是二级缓存导致的。MyBatis默认一级缓存是SqlSession级别的我项目里开启了二级缓存Mapper查询结果会被缓存。如果直接改数据库数据比如用Navicat改了表二级缓存不会感知自然还是老结果。解决方式有两种第一开发阶段在Mapper XML里加cache-ref或关闭二级缓存第二用CacheNamespace(flushInterval...)设置合理刷新时间。生产环境如果像我这样数据变化频繁且不需要强一致的统计建议直接用flushCachetrue或干脆不开缓存省心很多。还有一次XML里报Invalid bound statement结果是Mapper接口和XML的namespace没有严格对应。MyBatis的要求是namespace必须等于接口全限定名statement id等于方法名。这个错误看不出什么逻辑问题但就是运行不到。请务必检查这个对应关系。7. 部署与二次开发建议7.1 本地部署四步走第一步准备好MySQL并导入数据库脚本。我提供的源码包里附带了sql/init.sql除了建库建表还会初始化管理员账号和几条演示数据。执行完以后用Navicat连一下确认表结构出现。第二步修改后端配置。在application.yml里把数据库用户名密码改成自己的如果端口被占用也可以改。然后执行mvn spring-boot:run或者mvn package打成jar再运行。第三步前端安装依赖。项目目录下执行npm install注意Vue 2项目安装时node版本尽量保持16以下否则可能会出现node-sass编译报错。这里建议直接用npm config set registry https://registry.npmmirror.com切到国内镜像源装依赖会快很多。第四步启动前端开发服务器npm run serve浏览器访问8080端口用管理员账号登录即可。此时前后端已经在联调状态。部署到服务器时按照前面提到的Nginx配置来。7.2 后续还可以往哪些方向扩展这套系统的核心骨架已经完整实际业务里可以继续加的东西还不少对接真实硬件目前上报接口是开放的只需要按协议适配设备厂家的SDK或MQTT网关即可引入消息推送把WebSocket换成微信服务号模板消息家属端体验会更友好增加语音告警大字版UI加上TTS播报对独居老人的实际帮助很大数据库读写分离当数据量增长后健康明细表可以做分区或者定时归档到历史表。我个人在实际开发中的一个感受是这个项目表面上是“管理平台”但真正的难点并不在于写多少页面而在于业务链路能不能跑通。告警能不能合并、工单状态流是否严谨、时间使用上报时间还是接收时间这些细节决定了系统在社区里能不能真正被用起来。不要急着加功能先把闭环走顺畅比什么都强。最后再分享一个小技巧写报表SQL的时候尽量先用Navicat把SQL跑通再反思一遍索引是否生效最后再粘贴进Mapper XML能省下不少来回调试的时间。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询