☰
微信小程序+SSM社区养老服务系统:毕业设计实战与避坑指南
2026/10/8 4:31:30 网站建设 项目流程

简介:这份资源是面向高校计算机相关专业学生与初级开发者的毕业设计完整方案,主题为基于微信小程序的社区养老服务系统,采用SSM后端架构,适合作为毕设项目、课程设计或工程实训的参考模板。压缩包共1709个文件,约88.43MB,涵盖Java后端源码、微信小程序端的wxml与wxss页面文件、Vue前端组件、JavaScript脚本、JSON配置以及SQL建表脚本等,另附论文、答辩PPT、开题报告与任务书,形成从选题到答辩的闭环材料。资源中Java文件对应SSM业务逻辑,小程序端文件负责用户交互界面,SQL脚本用于数据库初始化,整体目录按前后端与文档分模块组织,便于按需查阅与二次开发。目前已有63人学习下载,读者可据此快速理解社区养老服务系统的功能划分与实现思路,并在此基础上修改复刻,扩展出预约、健康档案等模块。

1. 从一份“zip 交付物”说起:社区养老服务系统到底在做什么

如果你正在搜“微信小程序 社区养老 SSM 毕业设计”,大概率不是想听概念,而是想知道这套东西能不能跑起来、论文能不能写、答辩能不能过。我先把结论放前面:基于微信小程序 + SSM 的社区养老服务系统,本质是一个“双端 + 一后台”的信息管理系统——老人或家属用小程序下单、查服务、看健康记录;社区工作人员用后台管理老人档案、服务工单、护工排班;SSM(Spring + SpringMVC + MyBatis)负责把这两端的数据串起来。它解决的不是“养老”这个宏大命题,而是社区场景下信息不透明、工单靠纸质、家属不放心这三个具体痛点。适合谁?适合计算机、软件工程、物联网方向的毕业生,尤其是选题被卡、想要一个“业务清晰、技术栈主流、工作量够写论文”的同学。这套东西的边界也很清楚:它不涉及医疗诊断,不做硬件采集,核心就是 CRUD 加权限加状态流转,别把它想复杂,也别把它想太简单。

2. 技术选型与架构拆解:为什么是 SSM 而不是 SpringBoot

2.1 小程序端 + SSM 后端的分工边界

先明确一件事:微信小程序不是“网页套壳”,它有自己的运行环境和 API 体系。小程序端负责展示和交互,SSM 后端负责业务逻辑和数据持久化,两者通过 HTTPS 接口通信。常见做法是后端暴露 RESTful 风格的 JSON 接口,小程序用wx.request调用。这里有个新手容易翻车的点:小程序不允许直接连数据库,也不允许把数据库账号密码写在前端,所有数据操作必须走后端接口。所以你的 SSM 后端至少要提供这几类接口:用户登录与身份绑定、老人档案增删改查、服务项目列表、工单创建与状态更新、健康记录录入与查询。

为什么很多毕业设计选 SSM 而不是 SpringBoot?说实话,SpringBoot 更省事,但 SSM 的“配置量大”反而成了论文素材——你可以在论文里写 Spring 事务管理、MyBatis 映射文件、SpringMVC 拦截器,这些在答辩时都是可讲的点。而且很多学校的指导老师对 SSM 更熟悉,出了问题能帮你定位。如果你时间紧,用 SpringBoot 也不是不行,但论文里要写清楚“为什么选它”,别只写“因为流行”。

2.2 数据库表设计:先画 ER 图再动手

表设计是这套系统的地基。我一般会先画 ER 图,再落成 SQL。核心表大概有这些:

表名作用关键字段
elder老人档案id, name, age, phone, address, community_id
service_item服务项目id, name, price, duration, category
order服务工单id, elder_id, item_id, worker_id, status, create_time
worker护工/服务人员id, name, phone, skill, status
health_record健康记录id, elder_id, blood_pressure, heart_rate, record_time
user系统用户id, openid, role, phone

注意order是 MySQL 关键字,建表时要用反引号包起来,或者改名叫service_order。这个坑我见过不止一个同学踩,跑 SQL 时报语法错误,查半天才发现是表名问题。

2.3 小程序登录与手机号获取的完整链路

微信小程序的登录流程是必考内容,也是答辩老师最爱问的。完整链路是这样的:小程序调用wx.login()拿到临时code,把code发给后端;后端用code+appid+secret调用微信接口换openid和session_key;后端生成自定义登录态(比如 token)返回给小程序;小程序后续请求带上 token。如果要获取手机号,需要用户点击授权按钮,小程序拿到encryptedData和iv,传给后端解密。

// 小程序端:登录并获取手机号 wx.login({ success(res) { if (res.code) { wx.request({ url: 'https://your-domain.com/api/login', method: 'POST', data: { code: res.code }, success(loginRes) { // 拿到 token 存起来 wx.setStorageSync('token', loginRes.data.token); } }); } } }); // 获取手机号(需要 button open-type="getPhoneNumber") getPhoneNumber(e) { if (e.detail.errMsg === 'getPhoneNumber:ok') { wx.request({ url: 'https://your-domain.com/api/decryptPhone', method: 'POST', data: { encryptedData: e.detail.encryptedData, iv: e.detail.iv, token: wx.getStorageSync('token') }, success(res) { console.log('手机号:', res.data.phone); } }); } }

后端解密用 AES-128-CBC,密钥是session_key,偏移量是iv。这里有个血泪经验:session_key有时效性,如果用户长时间不操作,解密会失败,需要重新走登录流程。另外,appid和secret不要硬编码在代码里,放到配置文件,答辩时老师看到会加分。

3. 从零跑通后端:SSM 环境搭建与核心接口实现

3.1 环境版本与依赖配置

我一般用这套组合:JDK 1.8、Maven 3.6、MySQL 5.7、Tomcat 8.5。别用 JDK 17 配老版本 Spring,容易出兼容问题。pom.xml里核心依赖包括:spring-webmvc、spring-jdbc、mybatis、mybatis-spring、mysql-connector-java、druid(连接池)、fastjson(JSON 处理)。版本号建议用 Spring 5.3.x + MyBatis 3.5.x,稳定且资料多。

<!-- pom.xml 核心依赖片段 --> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.30</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.13</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.1.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.20</version> </dependency> </dependencies>

3.2 Spring + MyBatis 配置文件怎么写

SSM 的配置分三块:applicationContext.xml(Spring 容器)、spring-mvc.xml(MVC 配置)、mybatis-config.xml(MyBatis 设置)。我一般把数据源、事务管理、MyBatis 的SqlSessionFactory放在applicationContext.xml,把 Controller 扫描、视图解析器放在spring-mvc.xml。

<!-- applicationContext.xml 关键片段 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/elder_care?useUnicode=true&amp;characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="your_password"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.eldercare.mapper"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>

参数说明:url里的useUnicode=true&characterEncoding=utf8必须加,否则中文会乱码;mapperLocations指向 MyBatis 映射文件目录;basePackage是 Mapper 接口所在包。如果启动时报No qualifying bean,先检查包扫描路径对不对。

3.3 工单状态流转接口的实现

工单是这套系统的核心业务。状态一般有:待接单、服务中、已完成、已取消。后端要提供创建工单、护工接单、完成工单、取消工单四个接口。用 MyBatis 的update实现状态变更,注意加乐观锁或状态判断,防止重复接单。

// OrderController.java 片段 @RestController @RequestMapping("/api/order") public class OrderController { @Autowired private OrderService orderService; @PostMapping("/create") public Result createOrder(@RequestBody Order order) { // 参数校验:elderId、itemId 不能为空 if (order.getElderId() == null || order.getItemId() == null) { return Result.error("参数缺失"); } order.setStatus("PENDING"); order.setCreateTime(new Date()); orderService.insert(order); return Result.success(order.getId()); } @PostMapping("/accept") public Result acceptOrder(@RequestParam Long orderId, @RequestParam Long workerId) { // 先查状态,只有 PENDING 才能接单 Order exist = orderService.selectById(orderId); if (exist == null || !"PENDING".equals(exist.getStatus())) { return Result.error("工单状态不允许接单"); } orderService.updateStatus(orderId, "SERVING", workerId); return Result.success(); } }

逻辑说明:createOrder里先做参数校验,再设置初始状态和时间戳;acceptOrder里先查再改,避免并发下两个护工同时接同一单。参数说明:orderId和workerId用@RequestParam接收,前端传参时注意格式。如果要做更严谨的并发控制,可以在 SQL 的update里加and status = 'PENDING',根据影响行数判断是否成功。

4. 小程序端页面与接口联调:导航栏、单选框与请求封装

4.1 顶部导航栏高度与自定义导航

微信小程序的顶部导航栏高度不是固定的,它跟设备状态栏高度有关。如果你要做自定义导航栏,需要先获取状态栏高度和胶囊按钮位置。常见做法是用wx.getSystemInfoSync()拿到statusBarHeight,再结合wx.getMenuButtonBoundingClientRect()计算导航栏总高度。

// 计算自定义导航栏高度 const systemInfo = wx.getSystemInfoSync(); const menuButton = wx.getMenuButtonBoundingClientRect(); const navBarHeight = (menuButton.top - systemInfo.statusBarHeight) * 2 + menuButton.height; // 最终导航栏总高度 = statusBarHeight + navBarHeight

这个计算逻辑在大部分机型上没问题,但个别安卓机有偏差,建议留 2px 余量。如果你不想折腾,直接用默认导航栏,在app.json里配navigationBarTitleText就行,毕业设计够用了。

4.2 单选框与表单提交的坑

小程序的原生单选框是<radio-group>包<radio>,但样式比较丑,很多人会用自定义组件。这里有个坑:radio的value必须是字符串,如果你传数字,bindchange拿到的也是字符串,后端接收时要做类型转换。表单提交前一定要做非空校验,别指望后端兜底。

// 服务预约表单提交 Page({ data: { serviceItems: [], selectedItemId: '', elderName: '', elderPhone: '' }, onItemChange(e) { this.setData({ selectedItemId: e.detail.value }); }, submitOrder() { if (!this.data.selectedItemId) { wx.showToast({ title: '请选择服务项目', icon: 'none' }); return; } if (!this.data.elderName || !this.data.elderPhone) { wx.showToast({ title: '请填写老人信息', icon: 'none' }); return; } wx.request({ url: 'https://your-domain.com/api/order/create', method: 'POST', header: { 'token': wx.getStorageSync('token') }, data: { elderId: this.data.elderId, itemId: this.data.selectedItemId }, success(res) { if (res.data.code === 200) { wx.showToast({ title: '预约成功' }); } else { wx.showToast({ title: res.data.msg, icon: 'none' }); } } }); } });

4.3 请求封装与 token 统一处理

别在每个页面里写重复的wx.request,封装一个request.js,统一加 token、统一处理 401、统一弹错误提示。这样后期改接口地址或加签名,只改一个文件。

// utils/request.js const BASE_URL = 'https://your-domain.com'; function request(options) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + options.url, method: options.method || 'GET', data: options.data || {}, header: { 'Content-Type': 'application/json', 'token': wx.getStorageSync('token') || '' }, success(res) { if (res.statusCode === 200) { if (res.data.code === 401) { // token 过期,重新登录 wx.removeStorageSync('token'); wx.showToast({ title: '请重新登录', icon: 'none' }); reject(res.data); } else { resolve(res.data); } } else { reject(res); } }, fail(err) { wx.showToast({ title: '网络异常', icon: 'none' }); reject(err); } }); }); } module.exports = { request };

参数说明:BASE_URL换成你自己的域名,小程序正式环境必须用 HTTPS 且域名要在微信后台配置。token放在 header 里,后端用拦截器统一校验。如果后端返回 401,前端清 token 并提示重新登录。

5. 避坑与排查:答辩前最容易翻车的 5 个点

5.1 小程序请求报“不在以下 request 合法域名列表中”

现象:开发者工具里能跑,真机预览或上传体验版后接口全部失败,控制台提示域名不合法。原因:微信小程序正式环境要求所有请求域名必须在微信公众平台后台配置,且必须是 HTTPS。解决:登录微信公众平台,在“开发管理 → 开发设置 → 服务器域名”里添加你的后端域名。如果后端还没部署,开发阶段可以在开发者工具里勾选“不校验合法域名”,但答辩演示时最好用真机 + 已配置域名,否则老师一问就露馅。

5.2 MyBatis 映射文件不生效,报 Invalid bound statement

现象:启动不报错,但调用 Mapper 方法时抛Invalid bound statement (not found)。原因:mapperLocations路径写错,或者 Mapper 接口和 XML 的namespace不一致,或者 XML 没被打包到target/classes。解决:先检查applicationContext.xml里mapperLocations是否指向classpath:mapper/*.xml;再检查 XML 的namespace是否等于 Mapper 接口全限定名;最后看target/classes/mapper下有没有 XML 文件,没有就在pom.xml的<build>里加<resources>配置。

5.3 中文乱码:从数据库到小程序的完整链路

现象:数据库里存的中文正常,但小程序显示乱码,或者后端返回的 JSON 里中文变成问号。原因:可能是数据库连接没加characterEncoding=utf8,也可能是 Tomcat 的server.xml没配URIEncoding,还可能是@ResponseBody返回时没设produces。解决:数据库连接串加useUnicode=true&characterEncoding=utf8;Tomcat 的 Connector 加URIEncoding="UTF-8";Controller 方法上加@RequestMapping(value = "/xxx", produces = "application/json;charset=utf-8")。三个地方都查一遍,别只改一个。

5.4 工单状态并发问题:两个护工同时接单

现象:两个护工同时点“接单”,都提示成功,但数据库里只有一个worker_id被写入,另一个被覆盖。原因:先查后改不是原子操作,并发下两个线程都查到PENDING,然后都执行 update。解决:在 SQL 的 update 里加状态条件,update service_order set status='SERVING', worker_id=#{workerId} where id=#{orderId} and status='PENDING',然后根据返回的影响行数判断是否接单成功。如果返回 0,说明被别人抢先了,提示“手慢了”。

5.5 答辩演示时小程序加载慢或白屏

现象:答辩现场网络不好,小程序首页一直转圈或白屏。原因:首页请求太多、图片太大、或者没做 loading 状态。解决:首页接口做聚合,减少请求数;图片压缩到 100KB 以内;加wx.showLoading和wx.hideLoading;关键数据做本地缓存,比如服务项目列表可以缓存 5 分钟。另外,提前在答辩教室测一遍网络,别等到上台才发现连不上。

6. 论文与答辩的加分技巧:把“能跑”变成“能讲”

6.1 论文里必须写清楚的三个技术点

很多同学的论文像说明书,只写“我用了 SSM”,不写“为什么用、怎么用、遇到什么问题”。我建议重点写这三个:第一,微信小程序登录态与 SSM 会话管理的结合,讲清楚openid和session_key的作用;第二,MyBatis 动态 SQL 在工单查询中的应用,比如根据状态、时间范围、护工姓名组合查询;第三,事务管理在工单状态流转中的使用,用@Transactional保证接单和更新护工状态的一致性。这三个点写透了,论文的技术深度就够了。

6.2 答辩演示的脚本设计

答辩演示别现场随便点,提前写好脚本:先展示小程序登录和手机号授权,再展示老人档案录入,然后展示服务预约和工单状态变化,最后切到后台管理展示数据统计。每一步控制在 30 秒内,总共 3 分钟。演示前把测试数据准备好,别用空数据演示,老师看不到效果。如果现场网络不稳,提前录屏备份,但别一上来就放录屏,先试真机,不行再切录屏。

6.3 这套系统的扩展方向

如果你想让毕业设计更有亮点,可以在现有基础上加两个扩展:一是用 ECharts 在小程序里展示健康数据趋势图,比如血压、心率周变化;二是加一个简单的消息推送,工单状态变更时通过微信订阅消息通知家属。这两个扩展工作量不大,但答辩时很加分。订阅消息需要申请模板 ID,提前在微信公众平台配好。

6.4 我踩过的一个真实教训

最后说个我自己的教训。当年做类似系统时,我把appid和secret硬编码在 Java 文件里,提交代码时忘了删,结果被老师当场问“你这个密钥放这里安全吗”。后来我养成习惯:所有敏感配置放config.properties,.gitignore里排除掉,代码里用@Value注入。这个习惯后来在工作中救了我好几次。希望帮到你。

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

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

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

立即咨询