☰
乡村养老管理系统开发实战:SpringBoot+Vue+MySQL全流程
2026/10/14 6:35:23 网站建设 项目流程

做“乡村养老服务管理系统”这种项目的人,我见得太多了。要么是毕业设计选了这个题,要么是帮本地乡镇做一个信息化小系统,技术栈几乎绕不开SpringBoot、Vue和MySQL这三件套。这个组合看起来常规,但真把养老业务做明白并不容易,从需求梳理到数据库设计,从权限控制到部署上线,中间会踩到不少坑。这篇就把我反复折腾这类项目的经验完整梳理一遍,适合正在做毕设、准备接手类似外包、或者想把乡村养老信息化落地的人参考。

1. 项目定位:乡村养老服务管理系统到底解决什么问题

1.1 乡村养老场景的特殊性

很多人拿到这个题目就直接开写代码,跳过了最该想清楚的一步:乡村养老和城市养老的信息化需求完全不是一回事。城市里社区养老系统往往强调线上预约、实时定位、智能设备接入,老人和护理员都习惯用手机操作。但乡村养老对应的使用人群完全不同,老人分散在多个自然村,很多高龄老人不会用智能手机,真正的系统使用者其实是村两委工作人员、乡镇民政助理、养老服务中心的护工,甚至还有在外地打工、定期打电话回来问情况的子女亲属。

乡村场景下信息化的核心矛盾是“底数不清、过程不明、统计全靠手工”。老人家住在哪个村、身体状况如何、有没有子女在本地、是否享受高龄补贴、上次体检是什么时候、护工上门服务了没有,这些信息都散落在纸质台账和不同的Excel表里。一到要做季度报表、申请补贴、迎接检查的时候,相关人员就得翻档案、打电话、重新录入。系统真正要解决的,是把这些散落的信息统一管理起来,让日常服务流程走系统,让统计报表自动生成,让管理层能看清全乡镇养老服务的实际运转情况。

所以这个系统的价值不在技术多花哨,而在能不能把“档案-健康-服务-补贴-统计”这条主线跑通。你后面所有的表结构设计、权限设计、页面布局,都应该围绕这个主线来,而不是为了展示技术硬塞一些炫酷功能。

1.2 需求能落地的功能边界

我在帮人梳理这类项目时,习惯先把功能边界切成五个模块,这五个模块基本就是乡村养老系统的标准答案。

第一是基础档案管理。老人基本信息、身份证号、住址、紧急联系人、自理能力评估(自理/半自理/全护理)、医保类型、家庭情况等。这是整个系统的数据底座,必须做得细致。

第二是健康管理。体检记录、血压血糖等日常测量数据、既往病史、用药情况,重点是要能按老人查看历史趋势,方便判断健康状况变化。

第三是服务工单管理。这也是乡村养老系统的核心业务流。护工或村干部接到服务需求后创建工单,按老人安排上门服务,完成后填写服务记录和评价,形成服务闭环。工单状态至少要包含待接单、服务中、已完成、已取消,最好再加一个待验收。

第四是补贴与费用管理。高龄补贴、护理补贴、服务费用减免等记录,做到每笔补贴有来源、有审批、有发放记录。这块做好了,系统在上报和迎检时特别好用。

第五是系统管理。用户管理、角色权限、菜单管理,以及登录日志等。这个模块看起来普通,但权限设计直接决定系统能不能在真实环境用起来,后面我会单独展开讲。

至于公告通知、数据看板、报表导出这些,可以作为辅助模块加上,但不要抢主线业务的戏。我见过有人把大屏可视化做得特别炫,结果档案录入、工单流转这些基本功能一塌糊涂,这种项目上线后很快会被弃用。

2. 技术选型解析:SpringBoot+Vue+MySQL的组合逻辑

2.1 为什么不用更重的架构

这套系统的定位是中小型业务系统,用户量级也就是一个乡镇几百人,并发量很低,数据量最多十万级。在这个前提下,SpringBoot+Vue+MySQL是性价比最高的组合,而不是唯一的技术选择,但绝对是最稳妥的。

SpringBoot的价值在于快速集成和生态成熟。你要做登录认证,有Spring Security和JWT的成熟方案;要做数据库操作,有MyBatis-Plus帮忙省掉大部分SQL;要做文件上传,有现成的静态资源映射方式。更重要的是,这个技术栈的参考资料数量巨大,随便遇到一个问题都能搜到解决方案,对于毕设或者小团队外包来说,这是巨大的隐性成本优势。

MySQL作为关系型数据库,处理这种多表关联的业务场景非常顺手。老人档案、服务工单、健康记录之间天然有外键关系,用关系型数据库设计起来清晰,查询也方便。有人会建议引入Redis做缓存、用MongoDB存健康数据,但在这个量级下纯属给自己找麻烦。我见过一个项目引入了四五个中间件,结果部署时服务器内存不够,还得换机器,这种过度设计在实战中非常不可取。

2.2 工程结构和接口设计

工程结构我建议直接采用前后端分离,后端一个SpringBoot工程,前端一个Vue工程。后端按标准分层:controller、service、mapper、entity、common,前端按页面和组件拆分,配合Vue Router和Vuex/Pinia做路由与状态管理。

接口设计遵循RESTful风格,但不用死守规范。比如查询老人列表用GET请求,创建工单用POST,更新状态用PUT,逻辑上没有歧义就行。路径上建议统一以/api开头,方便前端代理和后端做统一拦截。比如/api/elder/page、/api/order/create、/api/user/login。

前后端联调时,最容易出问题的是跨域和接口路径不一致。开发环境下前端用Vite或webpack的代理把/api转发到后端端口,生产环境用Nginx做反向代理,后面部署部分我会给完整的配置示例。这块只要一开始约定清楚,后面能省掉大量联调时间。

2.3 环境版本配置清单

版本选择看起来是个小事,但实际坑不少。我建议用这个组合,这些版本都是经过大量项目验证的,互相兼容性没什么问题。

组件推荐版本说明
JDK1.8或11上生产建议JDK11,语义更清晰
Maven3.6以上不要用3.8以下的老版本
SpringBoot2.7.x不要急着上3.x,和旧依赖兼容麻烦
MyBatis-Plus3.5.x分页、条件构造器很省事
Vue2.7或3.4如果熟悉Element Plus建议Vue3
Node.js16.x或18.x安装依赖时不容易报错
MySQL5.7或8.0推荐8.0,注意字符集utf8mb4

顺便提醒一句,SpringBoot 3.x 要求JDK17起步,如果你按JDK8的习惯查资料,很多写法已经变了,容易卡住。我这个建议比较保守:项目不是用来追新的,是用来稳定交付的。

3. 数据库设计:先把表结构想清楚

3.1 按业务域拆分表

数据库设计是这个项目里最不该赶时间的部分。表结构一旦定了,后面改起来就是连锁反应,字段要改、接口要改、前端页面要改,改一处牵一发动全身。

我习惯于按业务域拆表,而不是一个大表解决所有问题。核心是老人信息和用户信息分开,因为老人是服务对象,用户是系统操作人员,两者不是一回事。亲属作为老人档案的联系人字段存进elder_info里就可以,没必要单独建亲属表,除非要做亲属登录查看功能。

主表规划大致是这样的:

表名用途关键关联
sys_user系统用户(管理员、护工等)关联角色表
sys_role角色定义管理员、护工、村干部
elderly_info老人档案主表关联健康记录、工单
health_record体检和日常健康数据关联老人ID
service_order服务工单表关联老人ID、处理人ID
service_type服务类型字典助餐、助洁、陪诊等
subsidy_record补贴发放记录关联老人ID
notice_info公告通知管理员发布
operation_log操作日志记录关键操作

表不在多,够用就行。我见过有人连“老人床位表”都建出来了,实际业务里根本不用,纯浪费开发时间。

3.2 核心表字段拆解

elder_info这张表是整个系统的心脏,字段设计要兼顾信息完整和录入方便。除了id、name、gender、birth_date、id_card这些基础字段,我建议重点加上这几个字段:care_level代表自理能力等级,用字符串存可读性更好;health_status作为健康摘要字段;family_contact和family_phone存紧急联系人;source_type记录数据来源,是导入的还是手动录入的。另外要放一个village字段,乡村场景下统计各个村的老人分布非常常用。

service_order表是业务流程的核心,字段上要覆盖一条工单的完整生命周期。order_no生成一个业务编号,比如日期加随机数,方便线下对账。service_type_id关联服务类型;elder_id关联老人;assignee_id记录接单人也就是护工;appointment_time和actual_start_time、actual_end_time分别记录约定时间和实际执行时间,这样能分析服务准时率。status字段我建议用字符串枚举,比如PENDING、PROCESSING、COMPLETED、CANCELLED,代码里用常量类统一管理,可读性远好过数字。

health_record表相对简单,就是elder_id、check_date、blood_pressure、blood_sugar、temperature、weight、heart_rate以及check_result和remark。注意血压血糖这些字段建议用字符串存,因为实际录入的是“130/85”这种格式,用int类型会非常别扭。

3.3 索引、状态值和金额字段的细节

字段类型选择有几个容易踩坑的地方。金额字段一定要用decimal(10,2),不要用double,否则累加和展示时会出很多诡异的小数。时间字段用datetime就行,不要为了省空间用timestamp,因为在跨时区场景下timestamp会有各种不必要的麻烦。所有表最好都带上create_time、update_time、deleted这三个通用字段,deleted是软删除标记,用逻辑删除代替物理删除,就算误操作也能把数据找回来。

索引方面,elder_info表的id_card建议建唯一索引,因为身份证号不能重复;service_order表的elder_id、status这种高频查询字段一定要建普通索引,否则数据量到了几万条之后分页查询会明显变慢。业务编号order_no也要建唯一索引。另外外键我建议只在逻辑上关联,不建物理外键约束。这个可能和学校教的不太一样,但实际项目里物理外键在删除数据、批量导入时会非常麻烦,逻辑关联配合索引就够了。

4. 核心功能模块实现:从登录到统计报表

4.1 登录认证与权限拦截

登录模块虽然老生常谈,但却是整个系统里安全要求最高的地方。我这里推荐用JWT配合拦截器的方案,比用Session要适合前后端分离。步骤很清晰:用户提交用户名密码,后端校验通过后生成Token返回给前端,前端存到localStorage里,每次请求在请求头里带上Authorization: Bearer token,后端拦截器统一解析Token并放行。

密码加密必须用BCrypt,不要自己写MD5加盐逻辑。Spring Security里自带BCryptPasswordEncoder,单独引入security的crypto包就行,不用启用整个Spring Security的过滤器链,否则配置复杂度会陡增。下面这个代码是生成Token和解析用户信息的最简骨架,你可以参考:

public class JwtUtil { private static final String SECRET = "your-secret-key-change-in-production"; private static final long EXPIRATION = 24 * 60 * 60 * 1000; // 24小时 public static String createToken(Long userId, String username, String role) { return Jwts.builder() .claim("userId", userId) .claim("username", username) .claim("role", role) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody(); } }

权限控制建议用注解加拦截器配合。自定义一个@RequireRole("ADMIN")注解,标注在Controller方法上,拦截器解析Token后检查角色是否匹配,不匹配直接返回403。这种方法轻量又直观,比引入完整的Spring Security配置更适合这种中小型项目。

权限粒度上,我建议至少区分三种角色:系统管理员可以操作用户和数据处理所有模块;护工只能看到自己接单的工单和自己服务的老人;村干部可以看本村的数据台账,但不能修改系统参数。这个设计既能保证管理便利,又避免基层人员误操作。

4.2 老人档案与健康管理

老人档案的核心操作是分页查询、新增、编辑、详情查看和导入导出。分页这块直接用MyBatis-Plus的Page对象,配合条件构造器写成动态条件查询。查询条件一般有姓名模糊搜索、村庄下拉筛选、自理能力筛选,这些条件用LambdaQueryWrapper拼起来非常干净,也没有SQL注入风险。

public Page<ElderInfoVO> pageElders(ElderQueryDTO dto) { Page<ElderInfo> page = new Page<>(dto.getPageNum(), dto.getPageSize()); LambdaQueryWrapper<ElderInfo> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.hasText(dto.getName()), ElderInfo::getName, dto.getName()) .eq(StringUtils.hasText(dto.getVillage()), ElderInfo::getVillage, dto.getVillage()) .eq(StringUtils.hasText(dto.getCareLevel()), ElderInfo::getCareLevel, dto.getCareLevel()) .orderByDesc(ElderInfo::getCreateTime); Page<ElderInfo> result = elderInfoService.page(page, wrapper); // 再补充分页VO数据 return convertToVO(result); }

健康管理的重点在趋势展示。录入血压血糖数据时,前端用ECharts折线图展示近半年的变化趋势,让管理人员能直观看到老人健康波动。后端接口返回一个时间段内的健康记录列表就够了,前端自行聚合数据。我建议在录入健康数据时增加简单的异常判断,比如血压超过160/100时标记为异常,列表里用颜色突出显示,这个小细节很能体现业务思考。

4.3 服务工单状态流转

工单模块最容易做成一堆增删改查,但真实业务里它是一条状态流:管理员或村干部接到老人需求后创建工单,系统根据服务类型和片区推荐护工,护工接单后上门服务,服务完成后填写记录,管理人员验收确认。这个过程中每个状态变更都要有时间记录,方便以后追责和绩效统计。

状态流转的代码建议写成状态机,用Map或者枚举管理合法流转路径,避免乱序操作。比如:待接单只能流向服务中和取消;服务中只能流向已完成;已完成可以向管理员发起验收;验收通过后工单关闭。非法流转直接抛出业务异常,返回提示信息给前端。这样比每个方法里写一堆if判断要清晰得多。

护工登录后首页要展示“待办工单数”“今日服务数”和最近几条待接单记录,这个看板逻辑简单但很实用。前端拿一个聚合接口的数据,后端写一条带group by的SQL就能解决。

4.4 统计报表与数据导出

报表统计是乡村养老系统里多半会被领导重点关注的功能。常见统计项包括:各村老人数量分布、自理能力占比、年龄结构、月度工单量、服务类型占比、补贴发放汇总。这些统计全部可以通过SQL的聚合函数实现,不用额外引入报表引擎。

导出Excel我用的是EasyExcel,相比POI写起来省非常多代码,内存占用也低。Excel导出在服务端要特别注意文件流关闭问题,导出完记得把临时文件删掉,否则服务器上会堆积大量无用文件。我建议导出的文件名带上日期,比如“20240801老人信息台账.xlsx”,线下整理台账时一眼就能看出是哪批数据。

5. 部署调试全流程:从IDEA到服务器

5.1 本地环境搭建与数据库初始化

拿到源码之后,第一步不是急着启动,而是先把环境和数据准备好。MySQL里新建一个数据库,名字建议用elder_care,字符集选utf8mb4,排序规则选utf8mb4_general_ci,否则后面中文查询排序和存储会出问题。然后把项目里自带的sql脚本导入,通常脚本会创建所有表结构和初始数据,包括一个默认的管理员账号。

启动后端前重点检查application.yml里的数据源配置。很多项目写死的数据库密码和你本地不一致,用户名密码、端口、数据库名都要核对一遍。我习惯把配置拆成application-dev.yml和application-prod.yml,本地用dev配置,部署时切换profiles,避免改来改去改出错。

5.2 前后端打包构建

本地跑通开发模式后,再做生产环境打包。后端点一下mvn clean package -DskipTests,打出来是一个可执行的jar包。注意如果报测试类里的错,加上-DskipTests一般就绕过去了。打出来的jar包如果比较大,可以先看下是不是把本地依赖重复带进去了,不影响运行就不用管。

前端打包的时候节点依赖版本很敏感。别人给的源码里package.json锁定的是某个Node版本下的依赖,你用太新的Node版本执行npm install,经常报ERESOLVE依赖树冲突。我的习惯是看下engine字段或者.nvmrc,没有就按Node16处理。安装依赖失败时先删掉node_modules和package-lock.json再重新安装,一般能解决。

5.3 服务器部署与Nginx反向代理

部署到服务器上的标准套路是:jar包用nohup java -jar跑起来,前端构建出的dist目录放到Nginx的html目录下,Nginx配置把/api路径反向代理到后端的8080端口。一个最小可用的Nginx配置大概是这样:

server { listen 80; server_name your-domain-or-ip; root /opt/elder-care/dist; index 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; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { try_files $uri $uri/ /index.html; } }

这里的try_files $uri $uri/ /index.html;非常关键。Vue Router如果用history模式,刷新页面时服务器会找不到路由路径,不加这句直接404。很多人部署完发现刷新页面白屏,就是少了这一行。

后端jar包部署时,我一般写一个systemd服务或shell脚本管理启停。比较省事的做法是在jar包目录下放一个start.sh和stop.sh,start脚本里加上nohup java -jar -Xms256m -Xmx512m xxx.jar > logs/app.log 2>&1 &,stop脚本用jps找到进程号再kill。对于这种小系统,512M内存完全够用,不用调很大。

6. 常见问题与排查速查表

6.1 高频报错对照表

真实部署调试过程中,遇到问题不要慌,大部分报错都是固定套路。我整理了一份高频问题对照表,基本能覆盖80%的情况:

现象可能原因解决办法
后端启动报端口被占用8080被其他进程占用`netstat -ano
数据库连接拒绝数据库没启动或端口不对确认MySQL服务运行,核对host、port
Access denied for user用户名密码错误检查密码,注意MySQL8的认证插件
SQLSyntaxErrorExceptionMySQL版本差异或SQL方言问题检查是否用了MySQL8新语法,如窗口函数
前端接口全部404后端没启动或代理没配先curl接口,再检查Nginx或Vite代理
登录后刷新页面白屏路由history模式没配try_filesNginx加fallback到index.html
中文数据变成问号数据库字符集不是utf8mb4修改库、表字符集为utf8mb4
上传文件失败上传目录没有写权限给目录授权chmod 755,或换到/tmp
Token失效但登录状态还在前端没做401统一处理在axios响应拦截器里跳转登录页

6.2 排查思路和工具

排查问题首先要学会看日志。后端日志在控制台或者日志文件里,报错信息永远比现象本身管用。看到空指针先看哪一行,看到连接超时先检查网络。前端问题就按F12打开开发者工具,Network面板里看请求状态码和响应内容,比瞎猜快十倍。

我自己的排查习惯是三步走:先确认服务是否在运行,再确认接口是否能通,最后才看页面逻辑。第一步用ps或任务管理器看进程,第二步用浏览器直接访问接口URL或者用接口调试工具请求一次,第三步再看代码。大部分问题在第二步就能定位出来,不用每次一头扎进代码里。

还有一个容易忽略的点:本地能跑,服务器上跑不起来,大概率是环境差异。服务器上MySQL版本是不是一样、Nginx有没有装、Java版本够不够,先把这些对齐了再启动项目。我见过最离谱的一个案例,服务器上根本没有安装MySQL服务,光导入了一个sql文件就一直在后端报连接超时。

7. 讲解思路、演示流程与文档交付思路

7.1 项目讲解的思路

如果你做这个项目是为了毕业答辩或者给甲方交付,讲解思路一定要从业务切入,而不是从技术切入。不要一上来就说“我用了SpringBoot和Vue”,而是要先说清楚乡村养老服务存在什么管理痛点,然后自然地引出你的系统是怎么解决的。

我建议的讲解主线是这样的:先用一个真实场景讲故事,比如村委王主任每月要统计80岁以上老人数量,原来要翻台账打半天电话,现在系统里一键导出。然后展开系统架构,说明前后端分离、三个核心模块。再选一个核心业务流程串起来讲,比如从老人建档、体检记录到生成服务工单、护工完成服务、管理人员查看统计报表。最后再讲技术亮点,比如JWT认证、工单状态机、Excel导出,这些是加分项,不是主线。

7.2 演示流程怎么设计

演示项目时最怕的就是现场翻车。我的经验是准备一条“标准演示路径”,每一步都不要临时去找数据。登录用默认管理员账号,进去先看数据看板,然后搜索一个测试老人,点击查看详情,展示健康趋势图,新建一个服务工单,切换护工账号接单,完成工单,再切回管理员查看统计报表和导出Excel。整个过程控制在五分钟左右,每个环节都连贯,不用现场输入一大串数据。

演示时还要准备好“容错预案”。比如网络突然断了,就切到本地的演示环境;比如某个页面没数据,就提前在数据库里准备几条测试数据。演示前把浏览器缓存清一下,所有接口都提前跑一遍,确保没有报错。我见过太多人在演示时打开页面一片空白,最后才发现后端没启动。

7.3 大文档怎么组织

旁边那份“大文档”一般是需求分析、概要设计、详细设计、数据库设计、测试报告、部署文档的合集。真实写的时候,不要按教科书那样堆概念,而是要让人能照着文档还原项目。比如数据库设计文档里,每张表除了字段说明还要画清楚表关系;部署文档里要写清楚环境版本和每个命令;测试文档里要列出实际测试过的用例和结果。

我觉得文档里最有价值的部分是“功能需求描述”。这一段要把每个模块的业务流程写清楚,比如工单状态的流转条件、不同角色的操作权限边界,这些内容不仅方便别人理解项目,也方便你自己在答辩时回答“这个功能为什么这么设计”这类问题。

8. 踩坑心得与扩展方向

8.1 你一定会踩的坑

做这类项目,我最大的心得是:写代码的时间只占三分之一,剩下时间全在联调、部署和改需求上。前端和前后端联调时,接口字段大小写不一致这类低级错误经常出现。解决方式是定义一个统一返回体,比如Result对象包含code、message、data,所有接口都返回这个结构,前端解析就固定了,不会出现一个接口返回map、一个返回list的情况。

安全意识要提前做。系统里存的是老人身份证、健康状况这类隐私数据,生产环境如果还在用明文密码登录、Token密钥写死在代码里,一旦泄露非常麻烦。至少做到密码BCrypt加密、密钥放到配置文件中用环境变量注入、上传文件做类型校验防止传可执行文件。这些改动量不大,但能让系统安全级别上一个台阶。

我特别想提醒的是,这种项目最容易犯的错是“把简单问题复杂化”。明明只用到了几个基础表,非要去搞分布式锁;明明百度查得到的问题,非要自己造轮子。乡村养老系统应该轻量、稳定、可维护,而不是堆技术名词。

8.2 后续可以这样扩展

如果做好了基础版想继续扩展,方向其实很清晰。第一是增加亲属端微信小程序,让在外务工的子女能查看老人的健康数据和护理记录,这个需求在乡村特别真实。第二是接入智能设备,比如电子血压计、手环的数据自动上传,减少人工录入。第三是增加地图功能,在地图上标注老人居住位置和护工上门路径,解决乡村地域分散的问题。第四是增加语音提醒,老人不会用手机,就用电话语音或短信方式提醒用药和体检。

我个人最推荐的是小程序端,因为乡村养老里亲属异地关注需求最强烈,而且小程序开发成本和系统对接成本相对可控。做这个扩展时,复用现有的后端接口,再补一个用户端小程序的模块就行,核心的档案和工单数据不需要改动。

最后再说一个小经验:这种系统交付以后,真正的考验是谁来维护。所以无论如何,数据库设计尽量简单清晰,代码里多做注释,文档里写清部署流程,甚至给村干部留下一段“如何恢复系统”的说明。这些事做起来不显眼,但能让整套系统的寿命长很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询