基于SSM的智慧养老平台设计:从角色权限到业务闭环
2026/8/31 18:03:42 网站建设 项目流程

简介:本资源是一套完整的基于SSM框架的智慧养老平台毕业设计实现方案,面向计算机专业本科生、Java Web初学者及课程设计/期末大作业实践者,聚焦老龄化社会背景下的养老服务信息化需求。压缩包共1048个文件,涵盖128个Java后端核心类、75个JSP页面、242个JS交互脚本、125个CSS样式文件及2个SQL建库脚本(含db.sql),前端采用Bootstrap+Font Awesome+UEditor等成熟组件,兼顾适老化界面与系统可维护性;整体包体仅10.55MB,轻量易部署。已有56人学习下载,资源包含可直接运行的完整源码、配套论文与说明文档、数据库初始化脚本及README部署指南,结构清晰分层明确——从Spring容器配置、SpringMVC控制器路由到MyBatis动态SQL映射均有完整体现,特别适合理解企业级Java Web项目分层架构与真实业务模块(如健康档案管理、在线预约、家属远程监护)的落地整合。 说实话,我最初接到“基于SSM的智慧养老平台设计”这个项目时,第一反应是“这不就是一个带增删改查的管理系统嘛”。但真正从需求梳理到把源码和文档打包交付,我才意识到这套系统的价值核心不在代码本身,而在“业务分层”和“角色权限”的设计上。养老平台和普通后台管理系统最大的区别是:它既要管人(老人、家属、护工、管理员),又要管数据(健康档案、服务订单、异常预警),还要管流程(服务预约、派单、回访),而且每一类角色的操作边界差异非常大。

这篇文章我就把整套平台的拆分思路、SSM技术选型理由、数据库设计、源码跑通步骤、部署坑点以及配套文档的组织方法,一次性讲清楚。适合正在做毕业设计、SSM课程设计,或者想快速搭建一个中小型养老服务信息管理平台的开发者参考。

1. 养老服务数字化,这个平台到底在解决什么问题

1.1 从一份手写档案说起:业务痛点和需求边界

我接触过一些小型养老机构,它们日常管理老人信息的方式相当原始:一份纸质档案袋,装着身份证复印件、体检报告、家属联系方式、缴费记录。查一个老人的健康记录需要翻半天,护工交接班靠口头传达,家属问情况只能打电话。这种模式下,最要命的还不是效率低,而是“信息孤岛”——老人的健康变化、服务记录、紧急联系人信息散落在不同人手里,出了问题根本追溯不到责任链条。

这个智慧养老平台要解决的,就是把这套线下流程搬到线上,让“老人-家属-护工-管理员”四个角色在同一个系统里协同。注意,这里的“智慧”不是指人工智能,而是指数据驱动的服务闭环,比如健康指标异常能自动触发预警、服务订单状态能实时流转、家属可以远程查看老人的基本情况。需求边界一旦清晰,系统的功能范围就不会失控。

1.2 三类使用角色,决定了系统的权限骨架

做SSM项目最容易犯的错是一上来就画表、写代码,结果做到一半发现权限混乱。我做这个项目时第一步是梳理角色,最终确定三个核心角色,每个角色对应一套独立的功能菜单:

  • 管理员:用户管理、员工管理、服务项目管理、订单全流程管理、数据统计看板、公告发布。管理员是整个系统的中枢,拥有所有数据的查看和修改权限。
  • 护工/工作人员:录入老人健康数据、维护每日照护记录、接收服务派单、更新订单执行状态、查看负责老人的档案和预警信息。
  • 家属/老人端:查看老人基础档案、健康趋势、服务订单进度,发起新的服务预约,接收预警通知。家属端不需要登录后台,单独做一套简易界面。

这三个角色的权限边界必须通过拦截器或Shiro来控制,不能只靠前端隐藏按钮。因为SSM项目是服务端渲染页面,权限校验如果只做前端拦截,直接拼接URL就能跳过认证,这在实际交付评审时会被一票否决。

1.3 范围控制:先做哪几块,才能让项目真正落地

很多教程项目喜欢堆功能,什么聊天室、支付、GPS定位都往上加。但我建议首次做智慧养老平台时,把范围压到五个核心模块,做完再扩展:

  1. 登录认证与权限管理(SpringMVC拦截器 + 会话控制)
  2. 老人档案管理(基础信息 + 家属信息 + 住养状态)
  3. 健康数据管理(体温、血压、心率、血糖等指标的录入和趋势查看)
  4. 服务预约与工单管理(家属发起预约,管理员派单,护工执行并回写状态)
  5. 预警提醒(健康数据超出阈值时生成预警记录,管理员和家属可见)

这五个模块能覆盖一个完整的业务闭环,而且在答辩或项目汇报时有明确的“业务故事线”:老人信息从哪来,健康数据怎么流转,异常怎么发现,服务怎么响应。反过来,如果一上来就做十几张表、几十个接口,最后大概率是每个模块都半成品。

2. SSM不是老掉牙:这套框架选型的真实逻辑

2.1 Spring、SpringMVC、MyBatis各管哪一段

很多初学者对SSM有误解,觉得这就是三个东西拼在一起,甚至有人认为它是过时技术。但实际上SSM的每一层边界非常清晰,非常适合用来理解Java Web开发的整体骨架。

  • Spring:核心是IoC容器和AOP事务。在养老平台里,用户Service、老人档案Service、订单Service这些对象的创建和依赖注入全部交给Spring管理,事务边界也由Spring的声明式事务控制。比如“创建订单 + 扣减服务名额 + 生成操作日志”这三个操作必须在一个事务里完成,只要有一个失败就整体回滚,这正是Spring事务的典型场景。
  • SpringMVC:负责Web层的请求分发。前端传来的/elder/list/order/assign这类URL,由DispatcherServlet分发给对应的Controller,再通过ModelAndView或JSON响应给前端。在养老平台中,家属端的健康数据查询走Ajax + JSON,后端返回JSON格式数据由前端渲染;后台管理页面则是Controller返回JSP视图。SpringMVC可以同时处理这两种模式,灵活度很高。
  • MyBatis:负责持久层SQL映射。我自己更喜欢手写SQL而非JPA自动生成,因为健康统计、订单状态流转这类查询涉及多表关联和条件拼接,手写SQL的可控性最好。MyBatis的优势在于SQL和Java代码分离,修改SQL不需要重新编译Java,排查问题时直接把XML里的SQL复制到数据库客户端里执行即可验证。

2.2 为什么不用SpringBoot:对比之后的选择

有人会问,现在新项目都用SpringBoot,为什么这个平台还用SSM?我的答案分两层。

第一层是项目可行性。这个选题定位是“SSM框架的智慧养老平台”,核心目的是把SSM三条技术线分别讲清楚。SpringBoot把大量配置自动化了,一个spring-boot-starter-web就搞定依赖,但对学习框架原理来说反而容易“知其然不知其所以然”。用SSM,你得手动配置web.xmlspring-mvc.xmlapplicationContext.xml,这些配置本身就是最好的学习材料。

第二层是实际部署环境。很多高校服务器或小型机构的现有环境还是JDK 8 + Tomcat 8 + MySQL 5.7,SSM项目直接打war包丢到Tomcat的webapps目录就能跑,不需要额外搞Docker或SpringBoot内置容器。如果你后续想迁移到SpringBoot,SSM项目的业务代码(Service层、Mapper层)基本可以无缝复用,只是把配置层替换掉而已。所以做SSM不是走回头路,而是给底层打基础。

2.3 项目目录结构的组织方式

我的项目结构是标准的Maven webapp结构,分包按“controller / service / mapper / pojo / common”组织。很多初学者喜欢按照“按层分包”但controller里写业务逻辑,或者把service实现类和接口混在一起,这会导致后续维护非常痛苦。

推荐的分包方式:

com.smartelder ├── common // 通用工具类、统一返回结果、异常处理 ├── controller // 只负责接收参数、调用service、返回视图或JSON ├── service // 业务接口 + impl实现类 ├── mapper // MyBatis的Mapper接口 ├── pojo // 实体类(数据库表映射),可按模块建子包 └── interceptor // 登录拦截器、权限拦截器

原则只有一条:controller不写SQL,service不写HttpServlet代码,mapper只做数据访问。这样拆完,后面写文档、画架构图、做单元测试都会轻松很多。

3. 从登录到健康预警:核心功能模块如何拆解

3.1 登录与角色权限,最先要写的功能

登录模块是整个平台的入口,也是最容易被低估的模块。我先做了用户表(sys_user),包含usernamepasswordrolestatus字段。密码存储没有用明文,而是用MD5加盐处理,也就是用户输入的密码 + 一个固定盐值,再做MD5摘要,存数据库的是摘要值而不是原始密码。

登录成功后,把用户ID和角色写入Session。然后写一个LoginInterceptor,在SpringMVC配置里注册拦截路径和排除路径,拦截器的逻辑非常朴素但实用:

public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user = request.getSession().getAttribute("loginUser"); if (user == null) { response.sendRedirect(request.getContextPath() + "/login"); return false; } return true; } }

排除路径包括/login/logout、静态资源(/static/**/css/**/js/**),以及家属端专门开放的API(/api/**)。角色权限的控制是通过一个RoleInterceptor,在preHandle里根据请求路径前缀判断角色,比如/admin/**只允许role=1访问,/worker/**只允许role=2访问。这是最原始的RBAC(基于角色的访问控制)实现,但对这个项目规模已经足够了。

3.2 老人档案管理,核心实体怎么设计

老人档案是整个平台的数据基石。我的elder_info表包含这些主要字段:

字段名类型说明
idint主键自增
namevarchar老人姓名
id_cardvarchar身份证号(唯一索引)
gendertinyint性别
birthdaydate出生日期
bed_novarchar床位号,用于机构管理
statustinyint住养状态:0-待入住,1-在住,2-已退住
family_namevarchar紧急联系人姓名
family_phonevarchar紧急联系人电话
create_timedatetime建档时间
update_timedatetime更新时间

注意我把家属联系方式直接冗余在了elder_info表里,而没有单独建一张家属表。原因是这个阶段一个老人对应一个主要紧急联系人,如果直接建关联表会让查询变得复杂,而且实际业务中“主要联系人”才是关键。如果你想做更完整的“一老多家属”场景,再拆elder_family表也不迟,但用冗余字段起步会让页面展示和表格查询都简单很多。

3.3 健康数据与预警:一条记录背后的状态机

健康数据模块是“智慧”二字的体现。我设计了一张health_record表,记录老人每天的体温、血压(收缩压/舒张压)、心率、血糖等指标。录入页面的表单不复杂,关键在于后端要有一个“阈值判断”的逻辑——比如当收缩压大于等于140或舒张压大于等于90时,系统自动生成一条预警记录插入warning_record表,并把该老人的预警状态置为未处理。

这里我用了一个简单的方式:在HealthRecordServiceImpl里写一个checkHealthData方法,每次插入健康记录后调用它,并根据预设阈值返回是否异常。异常时不仅插入预警表,还会把当前记录标记为红色背景展示,让护工在列表页一眼就能看到。这个逻辑用MyBatis的@Insert或XML SQL都比较容易实现,不涉及复杂计算,完全是业务规则代码。

3.4 服务预约与派单,业务闭环的关键

服务模块是整个平台的业务闭环。业务链路是:家属发起预约申请 → 管理员看到待审核订单 → 管理员分配护工 → 护工接单执行 → 护工完成并填写完成说明 → 家属(或管理员)确认,订单状态变为已完成。

订单状态流转我设计为整数状态码,避免直接存中文导致数据冗余和拼写不一致:

  • 0:待审核
  • 1:待派单(审核通过)
  • 2:待执行(已派单)
  • 3:执行中(护工开始服务)
  • 4:已完成
  • 5:已取消
  • 6:已拒绝

每笔订单通过order_no生成唯一编号方便追溯,同时还记录了操作人ID和时间戳。每当状态变更时,更新update_time,但保留create_time不变,这样写操作日志时能与原始申请时间对比,判断服务响应效率。

4. 数据库表设计:老人、家属、护工、服务怎么关联

4.1 基础用户表与三张扩展表

我上面讲到sys_user表存登录账号,这里补充角色字段的设计。我直接用role字段标识角色:0-管理员,1-护工,2-家属,3-老人账号(老人如果需要独立登录可以单独开通)。然后用profile_typeprofile_id两个字段来做多态关联,也就是说,某个登录账号可以关联到老人表、护工表或家属表。

这种设计的优势是:登录后根据角色去查询对应的扩展表信息,不需要为每种角色建一张login表;劣势是查询时如果只关联了主表而没有判断角色,容易查错。解决方式很简单,在Service层先根据role判断,再选择查询哪张扩展表。

三张扩展表分别是:

  • elder_info:老人信息表,如上面所述。
  • worker_info:护工/员工表,包含姓名、手机号、职位、负责区域、在职状态、入职时间。
  • family_info:家属表,包含姓名、手机号、与老人关系、关联的老人ID。这里和“冗余字段”方案的区别是,如果你做了家属独立登录账号,就必须要单独的family_info表。

4.2 健康记录、订单、关联表的数据关系

平台里最主要的关联关系是三张业务表:

  1. health_record表通过elder_id关联elder_info,一条健康记录唯一属于一个老人。
  2. service_order表记录订单,包含elder_idworker_id(被指派的护工)、family_id(发起预约的家属,可为空)、service_item_id(服务项,比如“日常照护”“康复理疗”“陪同就医”)。
  3. warning_record表通过elder_idhealth_record_id关联健康记录,保存预警类型和处理状态。

在写SQL时,我习惯将所有关联查询放到XML里统一管理。比如查询某个老人的“健康档案列表并显示是否预警”,就在HealthRecordMapper.xml里写:

<select id="selectHealthRecordsWithWarning" resultType="map"> SELECT h.*, CASE WHEN EXISTS ( SELECT 1 FROM warning_record w WHERE w.health_record_id = h.id ) THEN '有预警' ELSE '正常' END AS warning_status FROM health_record h WHERE h.elder_id = #{elderId} ORDER BY h.record_time DESC </select>

这里用EXISTS而不是LEFT JOIN,是为了避免一条健康记录关联多条预警时产生重复行,导致页面显示重复。这是一个很细的SQL优化点,但做数据统计时很管用。

4.3 索引、级联和时间字段的细节

数据表设计里,最容易踩坑的其实是索引和时间字段。我在实际设计时遵循几个简单规则:

  • 所有外键关联字段(elder_idworker_idfamily_id)加上普通索引,否则多表关联查询数据量上来后会全表扫描。
  • 状态字段(statusorder_status)加索引,因为列表页通常按状态筛选。
  • create_time字段默认值设为CURRENT_TIMESTAMPupdate_time设为ON UPDATE CURRENT_TIMESTAMP,这样Java代码里不需要手动维护时间字段,减少出错。
  • 主键统一用int自增,不用UUID作为主键,因为UUID在InnoDB里作为主键时,随机写入会导致页分裂严重,性能明显下降。如果要分布式唯一ID,应该用雪花算法,而不是数据库主键用UUID。

外键约束我用了,但只用了ON DELETE CASCADEhealth_recordelder_info之间;订单表的elder_id用的是ON DELETE RESTRICT,防止误删老人档案连带删掉历史订单。真实项目中,删除业务数据的操作一般建议逻辑删除(加is_deleted字段),而不是物理删除,这样数据可追溯。我当时为了演示方便用了物理删除,但文档里强调了生产环境应用逻辑删除。

5. 源码跑通实战:环境和部署中我踩的坑

5.1 环境版本搭配,别在第一步翻车

我一开始就被版本兼容性问题卡住了。JDK版本、Tomcat版本、Maven版本、Spring版本任何一个不匹配,都会导致莫名其妙的报错。我最终稳定使用的版本组合是:

组件版本
JDK1.8
Maven3.6.3
Tomcat8.5.x
MySQL5.7.x
Spring5.3.x
MyBatis3.5.x
mybatis-spring2.0.x

特别提醒一下,Spring 5.3的spring-webmvc依赖会自动引入Spring 6的类吗?不会,但如果你用Maven依赖传递时不指定版本,很可能拉取到5.2或5.0。所以在pom.xml里请在<properties>标签统一指定Spring版本号,避免jar包冲突。当时我本地因为缺了spring-aspects,AOP切面编译直接报ClassNotFound: org.aspectj.lang.annotation.Aspect,排查了很久。

5.2 配置文件里最容易被忽略的三个地方

SSM项目跑不起来的坑,大部分出在配置文件。我列三个最有代表性的:

第一,web.xml里的SpringMVC配置映射路径必须与前端资源路径匹配。如果DispatcherServleturl-pattern/,那么静态资源(CSS、JS、图片)需要单独放行。我用了<mvc:resources location="/static/" mapping="/static/**"/>来解决,否则页面上所有样式全部丢光,而且控制台不报错,很难察觉。

第二,spring-mvc.xml里的<context:component-scan>如果配置了过大的包路径,会把@Service@Repository全部扫进Web容器,导致事务配置失效。正确做法是Spring根容器扫描servicemapper,SpringMVC只扫描controller

<!-- applicationContext.xml 中 --> <context:component-scan base-package="com.smartelder"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- spring-mvc.xml 中 --> <context:component-scan base-package="com.smartelder.controller"/>

第三,jdbc.properties里配置数据库连接时,必须加useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai。如果不加serverTimezone,MySQL 5.7以上版本会报时区错误;不加characterEncoding,插入中文数据可能乱码;不加useSSL=false,启动时日志会有一大串SSL警告。

5.3 MyBatis编写和中文乱码的排查

MyBatis最常见的坑是下划线字段和Java驼峰属性不对应。MySQL里习惯用create_time,Java实体写createTime,如果MyBatis配置里没有开启驼峰映射,查询结果就是null。在mybatis-config.xml里加一行即可:

<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>

中文乱码则有两类:一是数据库乱码,建库时没指定字符集,或者JDBC连接没指定UTF-8;二是HTTP响应乱码,Controller返回字符串时未设置编码。前者在Spring的CharacterEncodingFilter里设置:

<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

后者在JSP页面顶部加<%@ page contentType="text/html;charset=UTF-8" language="java" %>,并在Tomcat的server.xml中调整URIEncoding="UTF-8",否则通过GET请求传中文参数也会乱码。

5.4 从war包到Tomcat的部署步骤

项目完成后,我打包方式用的是mvn clean package,生成smart-elder.war,然后直接丢到Tomcat的webapps目录下。启动Tomcat后,访问http://localhost:8080/smart-elder/login即可看到登录页。

这里有一个细节:如果Tomcat的webapps目录下已经存在同名项目,要先删除旧的war解压出的文件夹,否则新war解压时会报文件被占用。另外,如果项目使用了自定义的静态资源前缀,比如项目名是smart-elder,那么所有JSP里的绝对路径都应该通过${pageContext.request.contextPath}获取,不要写死相对路径,否则部署到不同环境会全部404。

部署完成后,还要修改数据库配置文件里的URL为实际数据库地址,并在MySQL中执行项目附带sql目录下的init.sqlsample_data.sql,初始化表结构和演示数据。我在这份源码压缩包里特意放了一个部署说明.txt,把这几步逐条写清楚,因为我知道如果不写,使用者大概率会卡在环境上。

6. 配套文档怎么组织,才能让对方真正复现

6.1 需求分析文档要怎么写得有说服力

项目压缩包里除了源码,文档也很关键。需求分析文档我建议不要写成“系统需要……”,而是按照“背景-用户-场景-功能”顺序推进。比如在描述健康预警功能时,先写养老院护理场景里护士每天测血压,纸质记录无法发现趋势异常,由此引出需要自动阈值判断和预警展示,然后再写功能明细和界面原型说明。这种写法的好处是,评审老师或验收方能快速理解系统是奔着解决什么痛点去的。

功能需求表要按模块组织,每项写清楚功能编号、功能名、描述、优先级、对应页面和接口。比如:

功能编号功能名描述优先级
F001登录验证用户输入用户名密码,校验通过后跳转对应角色首页
F002老人档案新增管理员录入老人信息和家属联系方式
F003健康数据入库护工每日录入老人健康指标,保存到health_record表
F004服务订单审核管理员对待审核订单进行通过或拒绝操作

6.2 数据库设计文档和接口说明的取舍

数据库设计文档要包含每张表的表结构清单,但不建议每个字段全抄一遍,重点写字段业务含义、是否为空、取值枚举、与其他表的关系。另外一定要附ER图。在文档里我画了一张简版的逻辑ER图(用文字和表格形式表达),把sys_userelder_infohealth_recordservice_orderwarning_record之间的关联画清楚。这个ER图是文档的“地图”,阅读者先看图再读表结构,理解速度会翻倍。

接口说明文档则是前后端对接的契约。我当时给家属端(通过Ajax调用)提供了/api/health/list/api/order/submit等接口,文档里统一记录请求URL、请求方式、入参字段表、出参JSON示例和错误码含义。后台管理页面虽然有JSP模板,但我还是分类整理了Controller层方法清单,说明每个URL对应的操作,这样后续任何一位开发接手都能快速定位代码。

6.3 我自己的文档目录模板

最后分享一下我最终打包里的文档结构,这也是我梳理了很多项目之后沉淀下来的模板:

智慧养老平台_设计文档/ ├── 0_项目说明.md // 一句话介绍项目,技术栈,运行环境 ├── 1_需求分析.md // 背景、角色、功能模块、用例说明 ├── 2_数据库设计.md // ER图(文字版)、表结构、字段说明、索引说明 ├── 3_接口设计.md // 接口清单、参数说明、返回示例 ├── 4_部署说明.md // 环境版本、初始化步骤、常见问题 └── 5_项目演示脚本.md // 演示时按什么路径点哪些功能

演示脚本可能很多同学忽略,但我建议一定要写。内容是“先用管理员账号登录,创建一位老人档案,添加健康数据,然后以家属身份登录发起服务预约,再回到管理员端派单,最后以护工身份执行完成”。按照这个脚本演示,业务闭环一目了然,评委或验收人就能在很短时间看完整套流程,印象分会明显不同。

7. 源码交付前的自检清单和扩展思路

在我把整个压缩包交付前,我列了一份自检清单,确保拿到项目的其他人能顺利跑起来。环境方面,确认JDK、Maven、MySQL、Tomcat版本记录在部署文档里。数据库方面,执行初始化SQL后能正常创建表结构和样例数据,样例账号至少在文档里写明。代码方面,全局搜索所有硬编码的数据库密码和绝对路径,替换为配置项和相对路径。

我还有一点个人习惯:所有Mapper XML里的SQL都先在MySQL客户端里实际跑一遍再贴进项目,特别是有动态<if>条件的,用三种不同参数组合分别测试。这样能提前发现where条件拼错、参数判空逻辑不对等隐藏问题,避免在部署现场爆出低级错误。

关于扩展思路,这个平台后续可以在几个方向做增强。一是增加数据可视化,用ECharts展示健康趋势和预警占比;二是引入WebSocket做实时预警推送,家属端在浏览器里即时收到告警;三是对接智能手环或血压计的硬件数据,通过MQTT上报到后端自动写入健康记录,这样才算真正达到“智慧养老”的硬件联动。这些方向任选一个深挖,都能把项目从课设级别提升到生产级应用。

如果你现在正准备动手做这样一个SSM项目,我的建议是不要急着写代码,先花两三天时间把角色、流程、表关系彻底想明白,尤其是订单状态机和预警规则的边界。这个前期投入非常值得——后面写功能时基本就是按照流程填充代码,很少会返工,交付文档也能一路顺畅写下来。

本文还有配套的精品资源,点击获取

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

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

立即咨询