前后端分离养老院管理系统:SpringBoot+Vue架构设计与部署实战

📅 发布时间:2026/10/13 7:19:25
前后端分离养老院管理系统:SpringBoot+Vue架构设计与部署实战
“前后端分离养老院管理系统”这个标题乍一看像是某个课程设计或者毕业设计项目但如果你真的把整套源码跑起来、把部署流程走一遍会发现它其实是一个很完整的业务系统样板——涉及角色权限、床位管理、护理记录、费用核算、健康档案这些真实业务模块。我前阵子刚好帮一个做智慧养老服务的团队审过一套同类系统发现这类项目踩坑的点其实非常集中前端接口对接混乱、MyBatis关联查询写不好、跨域配置漏掉、部署时数据库编码出问题。这篇就把我从这套养老院管理系统中拆解出来的核心设计、代码实现和部署细节整理出来适合正在做管理系统类项目的开发者参考也适合想快速搭一套可用后台的前端或全栈同学。1. 项目整体设计与架构拆解1.1 这套系统解决了什么问题养老院管理系统的业务场景和普通的增删改查系统不太一样。它涉及的实体多、状态变化频繁、权限层级分明。举个具体的例子一个老人从入院到退住要经历入住登记、体检建档、床位分配、护理等级评估、费用记账、家属探访预约、健康状况跟踪这些环节。每个环节都涉及不同的角色——前台接待、护士、护工、财务、院长、家属——如果不用系统管理全靠表格和微信群信息基本是碎的。这套后端前端完全分离的架构核心就是把这些业务流程从线下搬到线上并且做到权限可控、数据可查、流程可追溯。后端只负责提供接口和数据逻辑前端只负责页面展示和交互两者通过JSON格式的接口通信。这样带来的直接好处是前端可以单独替换比如以后想换移动端接口不用动后端可以单独扩展比如接入智慧硬件设备开发和联调也能并行推进。1.2 为什么选SpringBoot Vue这套组合选型这个问题很多人在项目开始前纠结很久。这套系统用SpringBoot Vue MyBatis MySQL其实是目前中小型管理系统最成熟的组合之一理由很直接SpringBoot省去大量XML配置内嵌Tomcat打成一个jar就能跑。对养老院这类业务逻辑偏重、并发量不高的系统来说性能完全够用。Vue响应式数据和组件化开发的体验比传统的JSP、Thymeleaf好了不止一个档次。页面状态管理比如老人列表的筛选条件、床位图的选中状态用Vue的data和computed处理非常顺手。MyBatis复杂查询写SQL更灵活尤其是多表关联查询老人床位护理等级可以手动控制SQL不会像JPA那样自动生成一堆低效的联表语句。MySQL开源、稳定、运维成本低配合Navicat或MySQL Workbench管理数据非常方便。这套技术栈对开发者最友好的地方是生态成熟遇到问题网上资料多招人也好招。对团队来说上手成本低后期维护的压力也比较小。1.3 前后端分离的核心协作约定前后端分离项目最关键的不是技术本身而是接口约定。这套系统里前后端通信有几个约定非常值得一提统一响应结构后端所有接口返回固定JSON格式包含状态码、消息、数据三部分。前端拿到响应后先判断状态码再决定是正常渲染数据还是弹出错误提示。Token鉴权登录成功后后端签发Token前端存在本地存储里之后每个请求都在请求头里带上。后端通过拦截器验证Token没带或过期就直接返回401。接口路径规范统一以/api开头模块名用复数名词比如/api/elders、/api/beds。这样前端封装请求模块的时候可以完全对应后端Controller的名字不会找不到接口。这套约定看起来简单但实际项目里很多团队就是因为没定好规范前端写一个路径、后端定义另一个路径联调时来回改费时又容易出错。2. 核心功能模块与数据库设计2.1 业务模块的划分思路养老院管理系统的业务模块我拆解下来核心是六个老人档案、床位管理、护理记录、费用管理、员工管理、系统设置。其中老人档案是主数据床位和护理记录都围绕老人生成费用模块则从护理记录和入住天数自动计算。每个模块的页面结构都遵循同一个模式列表页带搜索、分页 新增/编辑弹窗 详情页。这种模式的好处是前端代码复用率高后端接口设计也可以统一成列表查询、根据ID查详情、新增、更新、删除这几类标准接口。系统里还配了登录页、首页仪表盘、个人信息页和密码修改形成一套完整可用的后台管理体系。2.2 数据库表的关联关系设计数据库设计是这个系统里含金量比较高的部分。核心表我列一下sys_user系统用户表存储登录账号、密码加密存储、角色ID、是否启用。人员类型包括管理员、护士、护工、财务等。elder_info老人档案表姓名、性别、身份证号、家属联系方式、入住日期、健康状态、紧急联系人。这张表关联了床位ID和护理等级ID。bed_info床位表楼栋、楼层、房间号、床位号、床位状态空闲/占用/维修。养老院管理里床位状态非常关键决定新老人能不能入住。nursing_level护理等级表等级名称、护理内容说明、每日护理费用。等级不同费用标准也不一样。nursing_record护理记录表每天由护工录入记录老人当日护理情况比如体温、血压、饮食、用药、特殊护理操作。fee_record费用记录表每月或定期生成包含床位费、护理费、餐饮费、医疗费支持实收金额和欠费状态。visit_record探访记录表家属探访登记记录来访人、与被探访老人关系、来访时间、离开时间。表与表之间关系很清晰老人表关联床位表、护理等级表、家属表护理记录表关联老人表和护工ID费用表关联老人表。这样设计的好处是数据不冗余、查询链路短比如查询某个老人的详情时通过老人表的外键就能直接关联出床位号、护理等级和所有护理记录。2.3 角色权限的设计要点权限设计上这套系统用的是比较经典的RBAC模式基于角色的访问控制。角色分成超级管理员、护工、护士、财务、家属只读几类。后端在做接口设计时不光是写CRUD每个接口都限制了角色超级管理员全部权限包括员工账号管理、床位信息维护、系统参数配置。护工只能查看自己负责的老人列表录入护理记录修改个人密码。护士可以查看全部老人健康档案维护护理等级审核护理记录。财务只能访问费用相关接口生成收费单标记实收/未收。这个设计思路在代码层面就是通过SpringBoot的拦截器或注解实现的。实际开发中拦截器里面判断用户角色再决定是否放行请求比在每个Controller里写if判断要干净得多。3. 后端SpringBoot核心技术实现3.1 项目目录结构与启动流程后端项目结构按功能分包看起来很简单但对新手来说很友好一眼就能找到入口src/main/java/com/example/eldercare ├── controller # 接口层接收前端请求 ├── service # 业务逻辑层处理具体业务 ├── mapper # MyBatis数据访问接口 ├── entity # 数据库实体类 ├── config # 配置类跨域、拦截器等 ├── common # 通用类统一返回结果、Token工具等 └── EldercareApplication.java # 启动类启动流程也很好理解启动类运行后SpringBoot自动扫描所有配置加载数据库连接然后启动内嵌Tomcat。前端请求到达ControllerController调用Service处理业务逻辑Service调用Mapper和数据库交互结果一层层返回最后包装成统一JSON结构响应给前端。3.2 统一响应结构与全局异常处理这点值得单独拿出来讲因为统一的返回结构能直接决定前端联调的效率。系统里定义了一个通用Result类格式是这样的{ code: 200, // 状态码200成功400业务错误401未登录500系统异常 message: 操作成功, data: { } // 具体业务数据可以是对象或列表 }所有Controller的返回值都封装成这个Result对象。前端拿到响应后只需要检查code字段不需要在response里找半天数据。配套的还有全局异常处理用RestControllerAdvice捕获所有异常统一转换成Result格式返回。这一招很实用因为没做全局异常处理的话后端一报错前端拿到的就是一堆看不懂的堆栈信息开发体验很差。做了全局异常捕获后即使代码里有bug前端也只会收到系统异常请稍后再试不会直接暴露接口内部结构。3.3 MyBatis映射与动态SQL的实战技巧MyBatis在这套系统里的应用最有学习价值的其实是动态SQL。养老院的老人列表页一般都有筛选条件按姓名模糊查询、按护理等级筛选、按入住时间段筛选——但用户不见得每次都会填所有条件。如果为每种情况写一套SQL代码会非常臃肿。MyBatis的if标签就是为这个场景设计的。比如查询老人列表的SQL大致长这样select idfindElderList resultTypecom.example.eldercare.entity.ElderInfo SELECT * FROM elder_info where if testname ! null and name ! AND name LIKE CONCAT(%, #{name}, %) /if if testnursingLevelId ! null AND nursing_level_id #{nursingLevelId} /if if teststatus ! null AND status #{status} /if /where ORDER BY create_time DESC /select这样用户填了姓名就按姓名查选了护理等级就按等级查什么都不填就返回全部。这套写法的好处很明显一个方法处理多种查询组合SQL逻辑一目了然而且能有效防止SQL注入因为所有参数都是通过预编译的#{}传入的。3.4 Token登录鉴权与密码加密登录模块是整个系统安全性的第一道门处理不好后面全是漏洞。这套系统的实现思路值得参考用户输入账号密码后后端先查询用户是否存在然后用BCrypt算法校验密码不是MD5或者明文比对BCrypt每次加密结果不同而且自带盐值安全性高很多。校验通过后用JWT生成TokenToken里面存了用户ID、用户名、角色这些信息设置7天有效期。后续所有请求都在请求头Authorization带上Token后端通过拦截器统一解析Token拿到用户信息后放入请求上下文。如果Token校验失败或过期拦截器直接返回401前端收到401就跳转登录页。这套机制的实战价值在于后端不需要在数据库里存Session服务重启用户也不用重新登录扩展成多实例部署时天然支持水平扩展不会因为Session不同步导致登录失效。4. 前端Vue页面与交互实现4.1 前端项目结构与路由配置前端项目同样按功能拆分结构很标准src/ ├── api/ # 接口请求模块每个模块对应后端一类接口 ├── assets/ # 静态资源 ├── components/ # 公共组件分页、弹窗、上传等 ├── router/ # Vue Router路由配置 ├── store/ # Vuex状态管理用户信息、Token等 ├── views/ # 页面组件登录、首页、老人管理等 └── App.vue路由配置里用到了路由守卫——这是保护页面安全的关键。前端路由守卫的作用是判断用户是否已登录有没有Token没登录就强制跳转到登录页。页面权限也通过路由元信息控制管理员能访问的路由普通护士访问时会直接跳转到无权限提示页。4.2 Axios请求封装与拦截器前端请求封装这块系统里做得比较完善直接可以抄作业的思路是这样的创建axios实例设置基础URL为/api配置超时时间然后添加请求拦截器和响应拦截器。请求拦截器负责在每次请求的header里带上Token响应拦截器负责统一处理响应数据// 请求拦截器 service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config }) // 响应拦截器 service.interceptors.response.use( response { const res response.data if (res.code ! 200) { // 统一处理业务错误 Message.error(res.message) return Promise.reject(new Error(res.message)) } return res.data }, error { // 处理HTTP错误比如401跳登录页 if (error.response.status 401) { router.push(/login) } Message.error(请求失败请检查网络) return Promise.reject(error) } )封装的好处是每个页面组件在调用接口时只需要关注业务数据不需要每次写鉴权逻辑、错误处理逻辑代码量直接砍掉一半以上。4.3 核心页面的交互设计系统里几个核心页面的交互设计也相当典型值得抄作业床位管理页面用可视化卡片展示床位状态绿色表示空闲、红色表示占用、灰色表示维修。点击空床位弹出老人入住表单点击已占用床位弹出老人信息和退住操作。这个交互比传统表格直观太多养老院的前台工作人员几乎不需要培训就能上手。护理记录录入页护工选择自己负责的老人然后录入当天各项护理数据。页面用表单组件按区域分组提交后自动刷新当日记录列表还能看到今天的录入进度已录入多少人、未录入多少人。费用管理页财务人员选择老人、选择计费周期系统根据床位费和护理费单价自动计算出总费用支持手动追加项目然后生成费用单据。这里前端用到了计算属性单价和数量改变时总价会实时重新计算体验很流畅。首页仪表盘展示今日入住人数、空床数量、今日护理记录数、本月收入等统计卡片。后端提供聚合统计接口前端用图表组件比如ECharts展示趋势图院长打开系统第一眼就能看到全局状态。5. 完整部署流程与关键配置5.1 本地开发环境准备先把开发环境说清楚这套系统的部署其实是分两部分的本地跑起来调试以及生产环境部署。本地环境你需要准备的工具是JDK 1.8或以上版本建议直接用JDK 1.8兼容性最稳Maven 3.6后端依赖管理Node.js 14前端构建MySQL 5.7或8.0数据库Navicat或MySQL Workbench可选数据库可视化工具IDEA后端开发和VS Code前端开发安装这些工具本身不难但版本匹配问题经常把人卡住。我个人建议用MySQL 8.0搭配JDK 1.8的组合兼容性测试过很多次基本没踩过坑。MySQL 5.7也完全可以只是连接驱动的配置稍有区别后面会提到。5.2 数据库初始化步骤数据库这块最容易出错的是字符集。养老院系统里老人姓名、地址这些字段都是中文如果字符集没设置成utf8mb4入库就会出现乱码。建议建库时直接执行CREATE DATABASE elder_care DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;然后使用项目中提供的SQL脚本文件导入表结构和初始数据。脚本里通常会包含管理员账号的初始密码经过BCrypt加密导入后直接用管理员账号登录系统第一步建议把初始密码改掉。如果导入后发现表里的中文都是问号基本就是字符集问题排查方向连接串有没有加characterEncodingutf8参数、表字符集是不是utf8mb4、数据库客户端默认字符集是否正确。5.3 后端打包与配置调整后端配置文件application.yml里有几个关键项需要根据自己环境调整server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/elder_care?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver这里有个高频坑MySQL 8.0的驱动是com.mysql.cj.jdbc.DriverMySQL 5.7的是com.mysql.jdbc.Driver。用错驱动启动时会直接报数据库连接失败。另外如果数据库服务器设置了时区连接串里的serverTimezone一定要配置不然会报时区错误。配置改好后在项目根目录执行mvn clean package -DskipTests打包完成后target目录下会生成一个eldercare-0.0.1-SNAPSHOT.jar这就是后端可执行文件。启动命令很简单java -jar eldercare-0.0.1-SNAPSHOT.jar看到日志里出现Started EldercareApplication就说明后端启动成功了浏览器访问http://localhost:8080/api/xxx即可测试接口。5.4 前端构建与Nginx部署前端部署的第一步是修改API请求地址。开发环境前端通过代理解决跨域问题生产环境则需要把请求地址指向后端服务器。通常前端项目vue.config.js里会配置代理生产构建前改.env.production文件VUE_APP_BASE_URLhttp://你的服务器IP:8080然后执行npm install npm run build构建完成后会在项目目录生成dist文件夹把dist里面的内容部署到Nginx的html目录下。Nginx还需要配置反向代理把/api开头的请求转发到后端服务同时解决前端路由history模式的刷新404问题server { listen 80; server_name your_domain.com; root /usr/share/nginx/html; 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那行是history模式下必须的配置不加的话刷新页面会报404。前端部署这一套搞明白后以后部署任何Vue项目的后台系统都可以复用这套Nginx配置。5.5 生产环境部署注意事项如果是要部署到云服务器有几个细节千万别漏数据库远程访问授权默认情况下MySQL只允许本机连接需要给后端服务器的IP授权才能访问或者后端和数据库在同一台服务器上就不用额外配置。防火墙端口后端8080端口和前端80端口需要在安全组里放行。很多人服务都启动了浏览器访问不了最后发现是安全组没开端口。日志文件配置生产环境建议在启动命令里加上日志输出路径方便排查问题java -jar eldercare-0.0.1-SNAPSHOT.jar /var/log/eldercare.log 21 进程守护用nohup上面命令已包含或者注册成systemd服务防止误关终端后服务就停了。如果服务器内存够也可以装个宝塔面板之类的工具做可视化进程管理能省不少事。6. 常见问题排查与开发经验总结6.1 高频问题速查表开发部署这套系统的过程中下面这些问题出现频率最高问题现象可能原因排查思路前端接口全部403Token没带或已过期检查请求拦截器是否从本地存储读取Token数据库连接失败驱动类写错或MySQL服务没启动检查jar包依赖版本和连接串配置中文数据乱码数据库字符集不是utf8mb4修改数据库/表字符集前端页面刷新404Vue Router history模式未配置Nginx加try_files配置跨域请求被拦截前端端口和后端端口不一致配置跨域过滤器或用Nginx代理接口数据返回null实体类字段名和数据库字段名不对应检查MyBatis的resultMap映射登录后接口401Token过期时间太短调整JWT有效期配置内存溢出默认堆内存太小启动命令加-Xmx512m参数6.2 跨域与接口联调踩坑记录前后端分离项目里跨域问题几乎必踩。开发环境下前端跑在http://localhost:9528Vue默认端口后端跑在http://localhost:8080两个端口不一样浏览器就会发起跨域请求。后端的解决方式是配置一个CORS过滤器Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); config.addAllowedOrigin(http://localhost:9528); config.addAllowedMethod(*); config.addAllowedHeader(*); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }这里有个细节很容易坑到人setAllowCredentials(true)配置了允许携带凭证后前端请求就必须使用相对路径的axios封装方式不能用随便找的接口测试工具直接测否则会因为Origin不一致被拦截。联调阶段最稳妥的方式还是用Nginx代理这样前端请求是同源的不涉及跨域问题。6.3 代码层面的优化建议整个系统跑通之后如果还想继续优化我基于实际经验给几个提升方向数据量大了之后老人列表和费用记录这种高频查询的表一定要加索引特别是在外键字段和创建时间字段上。加索引对查询性能的提升是肉眼可见的不加的话数据到几万条就会明显变慢。图片上传功能老人档案里的证件照、体检报告扫描件建议存到独立的对象存储服务里数据库只存URL地址不要把图片转成Base64存数据库否则数据库体积膨胀很快查询性能也会受影响。操作日志系统上线后建议加上关键操作的日志记录。养老院是涉及人身安全和收费的行业出纠纷时有没有日志就是两回事。用AOP切面统一记录操作人和操作时间侵入性很小。数据备份MySQL数据库每天做一次自动备份保留最近7天。养老院的数据是持续产生的丢了就真的找不回来。写个cron脚本定时跑mysqldump成本很低但价值极高。6.4 二次开发的可扩展方向这套系统最让我觉得有价值的地方在于它的扩展性。跑通源码之后后面可以加的东西非常多健康监测对接现在很多养老院会配智能手环、体征监测设备后端加一个设备数据接收接口老人的心率、血压就能实时入库并在前端大屏展示。移动端适配护工大部分时间在老人房间和公共区域活动不太可能在电脑前录护理记录。做一个微信小程序或企业微信端让护工用手机拍照、语音录入护理记录使用率会大幅提升。家属端开放给家属开一个只读端口能在手机上看到老人的每日护理记录、探访预约、费用账单能显著提升养老院的服务满意度和信任感。数据分析报表基于现有的费用、入住率、护理记录数据生成月度经营报表、护理质量分析这些对养老院管理层做决策非常有用。做了这么多年管理系统相关的项目我的体会是技术栈其实只是工具真正花时间的是理解业务逻辑和把细节做得像样子。这套养老院系统在业务理解和代码规范性上找到了一个很不错的平衡点从架构设计到部署文档都很完整。尤其是权限设计、统一响应结构、MyBatis动态SQL这块换个场景比如医院管理系统、物业管理系统、教务系统照样能用同一套思路。如果你正在做一个前后端分离的管理系统最值得借鉴的其实是它的结构规范和接口约定这部分才是真正省事的东西。