简介:基于安卓的养老院管理系统是一套覆盖后端、前端和移动端的完整项目源码,以Java语言结合SSM框架、Vue前端及MySQL数据库实现,面向Java Web与移动端开发学习者,也适合需要快速搭建养老院管理后台的开发者。系统包含老人档案、床位分配、护理记录等典型业务模块,采用分层架构与组件化开发,能帮助理解权限控制、数据交互和移动端接口等常见实现方式。资源包内含1500余个文件,压缩后约24MB,主体由Java后端代码、Vue页面组件、JavaScript交互脚本、SQL初始化脚本及大量界面图片构成,目录规划清楚,便于按模块查找。目前已有83人学习浏览,适合用于课程设计、毕业设计或企业原型参考,拿到后结合数据库脚本即可完成本地部署,并继续扩展管理功能。
1. 养老院管理系统源码拆解:Java + SSM + Vue + Android 怎么组成一套可运行的系统
第一次拿到这套养老院管理系统源码时,我最先做的是翻目录里那几个 .bak 备份文件和 3 个 bat 脚本。它并不是课程设计里那种单页 Demo,而是一套前后端分离的管理后台加一个 Android 移动端:SSM 负责业务接口,Vue 负责 Web 管理界面,MySQL 存老人档案、床位、护理记录和家属留言,Android 端解决移动访问。适合正在做毕设、接手别人代码做二次开发、或者想找一套完整 SSM+Vue 实践项目的开发者。这篇我会直接讲这套源码怎么跑起来、改哪里、哪些地方容易翻车。
2. 工程目录和 Vue 前端:从 .bak 备份文件还原一套可用的后台界面
2.1 先认清目录:后端、前端、Android 和 SQL 脚本各在哪
拿到源码别急着双击 bat。先把根目录完整过一遍。常见的 SSM+Vue 项目工程布局是:
- 后端 Java 代码在
src/main/java下面,Controller、Service、Mapper 三层齐全,配置文件在src/main/resources。 - 前端 Vue 代码可能直接放在根目录的
vue或web目录,也可能和静态文件混在一起。这个项目里能看到main.css.bak、IndexMain.vue.bak这些备份,说明前端管理后台是基于 Vue 组件化的页面结构,大概率用了 vue-element-admin 那套布局。 - Android 端是一个独立工程,一般放在
android或mobile目录,包名类似com.xxx.nursing。 - 数据库初始化脚本通常放在
sql目录,里面有建库建表的.sql文件。
第一步打开后端的pom.xml看依赖,确认 Spring 版本、MyBatis 版本、MySQL 驱动版本是否匹配。常见问题是pom.xml里引入了spring-boot-starter-parent,同时又把spring-context、spring-webmvc单独加了一份,版本冲突在启动时会报各种奇怪的 Bean 创建异常。拿到源码先跑一次mvn clean compile,能过再继续。
2.2 处理 .bak 文件:先对比再覆盖,别急着删
项目里出现的main.css.bak、update-password.vue.bak、IndexMain.vue.bak、IndexAsideStatic.vue.bak、BreadCrumbs.vue.bak、IndexHeader.vue.bak这几个文件,说明上一个开发者改动了这些文件但没完全验证,留下了旧版本备份。处理方式很简单:
# 进入备份文件所在目录 cd src/main/resources/static/css # 对比当前文件与备份文件的差异,看改了什么 diff main.css main.css.bak | head -50 # 如果确认当前文件改坏了,用备份覆盖回来 cp main.css.bak main.cssdiff命令在 Linux 和 macOS 自带,Windows 下可以用 Git Bash 或者 Beyond Compare 打开对比。对比时重点看update-password.vue.bak和当前update-password.vue之间的 axios 请求地址、参数名、路由跳转差异,很多改动只是为了修一个弹窗样式,但顺手把接口地址改成了测试环境,这种最坑。
我的习惯是先把所有.bak文件集中移到一个_backup_20250101目录,等系统跑起来、核心页面都点过一遍,确认某个备份文件确实没用了再删。直接删备份等于扔掉了后悔药。
2.3 Vue 页面改造:登录地址、菜单路由、接口前缀
Vue 端如果沿用了 vue-element-admin 的封装结构,src/utils/request.js里会统一配置 axios 实例,baseURL默认可能是/dev-api,本地开发时靠vue.config.js的 devServer.proxy 转发到后端。这部分要改成你自己的后端地址:
// vue.config.js module.exports = { devServer: { port: 8081, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } };port是前端开发服务器端口,改成 8081 是为了避开后端 8080;target是后端 SSM 项目的实际地址;changeOrigin必须为true,否则后端拿到的 Host 头不对,个别接口会异常。改完后重新npm run dev,登录页面输入管理员账号,打开浏览器开发者工具 Network 面板,看登录请求是否发到localhost:8080。如果返回 404,基本是代理路径和后端 Controller 的 RequestMapping 前缀对不上。
菜单配置在src/router/index.js,新增一个功能页面需要同时配置component路径和meta.title,只改侧边栏菜单显示不注册路由,点进去就是白屏。IndexAsideStatic.vue和BreadCrumbs.vue这两个文件,一个是侧边栏、一个是面包屑导航,里面如果有硬编码的图片路径或跳转链接,记得改成相对路径或者走服务端返回的地址。IndexHeader.vue通常是顶部导航栏,里面可能包含退出登录、修改密码等入口,修改密码组件对应update-password.vue。
3. SSM 后端和 MySQL:业务分层、核心表设计、登录拦截
3.1 Spring、SpringMVC、MyBatis 在这个项目里的分工
这个项目用的是 SSM 三件套,但实际工程里又引入了 SpringBoot 做整合入口,准确说是 SpringBoot 管装配、SSM 管业务。Spring 管理 Service 层的 Bean 和事务,SpringMVC 负责 Controller 的路由分发和参数封装,MyBatis 负责 Mapper 层 SQL 和实体映射。
很多人纠结为什么不用 Spring Data JPA 或者直接全用 SpringBoot。这个项目选 MyBatis 的好处是 SQL 可控性强,养老系统里老人列表、床位统计、护理记录查询这类报表型 SQL,写起来更直观。你看看src/main/resources/application.yml:
spring: datasource: url: jdbc:mysql://localhost:3306/nursing_home?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 20MB mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.xxx.entity configuration: map-underscore-to-camel-case: true server: port: 8080serverTimezone=Asia/Shanghai是 MySQL5.7 必须带的,不配上数据库连接会报时间差错误;map-underscore-to-camel-case开启后,数据库字段bed_no能自动映射到实体属性bedNo,省去大量resultMap配置。mapper-locations指定 XML 文件位置,对应src/main/resources/mapper下的*.xml。
3.2 核心表设计:老人档案、床位、护理记录、家属账号
养老院管理系统最基础的几张表是:老人表、床位表、护理记录表、员工表、家属账号表。老人和床位是一对一关系,护理记录和老人是多对一关系,家属账号可以关联到老人。
下面是老人表和护理记录表的简化建表 SQL:
CREATE TABLE `elderly` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL, `gender` TINYINT NOT NULL COMMENT '0女 1男', `age` INT DEFAULT NULL, `bed_no` VARCHAR(20) DEFAULT NULL, `status` TINYINT DEFAULT 1 COMMENT '1在住 0离院', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `nursing_record` ( `id` INT NOT NULL AUTO_INCREMENT, `elderly_id` INT NOT NULL, `content` VARCHAR(500) NOT NULL, `nurse_name` VARCHAR(50) DEFAULT NULL, `record_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_elderly_id` (`elderly_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;设计表的时候有几个点要注意。第一,外键不要物理建,用逻辑关联,也就是只在业务代码里通过elderly_id去关联,这样删数据更灵活,尤其适合这类会频繁导入导出数据的系统。第二,性别、状态这类固定枚举值用TINYINT存数字,别直接存字符串。第三,record_time用DATETIME而不用TIMESTAMP,MySQL 5.7 里TIMESTAMP有 2038 年上限,DATETIME 没这个问题。
3.3 登录鉴权:Controller 到 Interceptor 的完整链路
登录接口的思路很直接:前端把用户名密码 POST 到后端,Controller 接收后调 Service 查数据库,比对密码,成功后把用户信息放进 Session,前端每次请求带上 Session 或者 token。这个项目没有引入 Spring Security,用的是轻量方式,但原理是一样的。
Controller 层典型写法:
@RestController @RequestMapping("/api") public class LoginController { @Autowired private UserService userService; @PostMapping("/login") public Result login(@RequestBody LoginDTO dto, HttpSession session) { User user = userService.login(dto.getUsername(), dto.getPassword()); if (user != null) { session.setAttribute("loginUser", user); return Result.success(user); } return Result.error("用户名或密码错误"); } }@RequestBody把前端传的 JSON 转成 LoginDTO,Service 层查数据库,成功就写入 Session。关键在后面的登录拦截器:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/api/login", "/static/**", "/error"); } }addPathPatterns("/**")表示拦截所有请求,excludePathPatterns("/api/login", "/static/**")把登录接口和静态资源放行。如果不加excludePathPatterns,前端访问静态 CSS、JS 都会被拦截到登录页,出现那种“页面突然变成纯文字”的问题。实际生产上这里还会加一个/upload/**的放行,否则图片访问也会被拦。
4. Android 端和接口对接:移动端访问养老系统的实现
4.1 Android 端的技术选型:为什么不能直连 MySQL
Android 端是这个项目比较有辨识度的部分。很多初学者拿到这种源码,第一反应是“Android 能不能直连 MySQL 数据库”,答案是不建议。原因有三个:一是把数据库账号密码写在手机上,反编译 APK 就全泄露了;二是 MySQL 的连接数有限,几十个手机同时连会把数据库拖垮;三是手机网络环境变化大,直连数据库没法做统一鉴权和日志记录。
标准做法是 Android 发 HTTP 请求到后端 API,由后端操作数据库。Android 端常见的结构是:Activity/Fragment负责界面,OkHttp负责网络请求,Gson或Fastjson负责 JSON 解析。如果源码里没有用 Retrofit,也不用觉得奇怪,很多课程设计用 OkHttp 手写请求,虽然代码重复但更好理解。
4.2 接口对接示例:登录、床位列表、护理记录上传
以登录为例,Android 端请求后端/api/login接口的 OkHttp 代码:
private void login(final String username, final String password) { new Thread(new Runnable() { @Override public void run() { try { OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .build(); JSONObject body = new JSONObject(); body.put("username", username); body.put("password", password); RequestBody requestBody = RequestBody.create( MediaType.parse("application/json;charset=utf-8"), body.toString()); Request request = new Request.Builder() .url("http://192.168.1.100:8080/api/login") .post(requestBody) .build(); Response response = client.newCall(request).execute(); String result = response.body().string(); // 在这里解析返回的JSON,拿到用户信息和token } catch (Exception e) { e.printStackTrace(); } } }).start(); }注意三处。第一,new Thread必须要有,Android 4.0 以后网络请求不允许放在主线程,否则直接抛 NetworkOnMainThreadException。第二,connectTimeout和readTimeout建议都设成 10 秒,养老院场景经常是弱网环境,超时太短会导致登录频繁失败。第三,.url()里的地址如果是局域网 IP,要保证手机和电脑在同一 WiFi 下。
4.3 API 地址配置:内网调试和外网部署的切换
Android 端的后端地址一般写死在代码里,拿到的源码大概率是http://localhost:8080或者某个模拟器地址。模拟器与真机的差异很大:Android 模拟器访问电脑后端要用http://10.0.2.2:8080,真机要用电脑的局域网 IP,比如http://192.168.1.100:8080。
这里有一个高频坑:Android 9.0 以上默认禁止明文 HTTP 流量,如果接口地址是http://而不是https://,请求会被直接拦截,报错信息类似CLEARTEXT communication to xxx not permitted。解决方法是暂时开启明文流量:
<application android:usesCleartextTraffic="true" android:label="养老院管理系统"> </application>android:usesCleartextTraffic="true"是开发阶段的通用做法,上架前如果接口还是 HTTP,建议在后端加 HTTPS 证书再改回false。否则随便一个 WiFi 环境下抓包就能看到登录密码,这种安全问题在养老系统里是不能接受的。
5. 部署启动避坑排查:从 IDEA 导入到 MySQL 5.7 的五个常见问题
5.1 问题一:1-install.bat、2-run.bat 双击后一闪而过
现象:双击1-install.bat或2-run.bat,黑色命令窗口闪一下就不见了,没有任何提示,后端也没启动。
原因:脚本里的命令执行失败,但因为没有pause语句,窗口直接关闭,错误信息全被吞掉。还有一个常见原因是 bat 脚本里用了相对路径,当前工作目录不对导致找不到mvn或java命令。
解决:不要直接双击,先打开 cmd,把 bat 文件拖进窗口按回车执行,错误信息会留在窗口里。再检查脚本内容,把mvn、java命令的路径写成绝对路径。另外确认系统环境变量里有 JDK 1.8 和 Maven,命令行输入mvn -version能正常输出才算过了这一关。
5.2 问题二:后端启动报 Communications link failure
现象:IDEA 里启动 SpringBoot 应用,控制台报Communications link failure或者Access denied for user 'root'@'localhost',应用启动失败。
原因:连不上 MySQL。具体分三种:数据库服务没启动、application.yml里账号或密码不对、MySQL 驱动版本与数据库版本不匹配。
解决:先用 Navicat 或者 MySQL 命令行确认数据库能连上,再检查application.yml里的username和password。MySQL 5.7 的数据库连接串里必须加上useSSL=false&serverTimezone=Asia/Shanghai,这两个参数缺一个都可能在启动时被卡住。驱动依赖如果是mysql-connector-java8.x,它要求数据库端allowPublicKeyRetrieval=true,否则还会报Public Key Retrieval is not allowed,连接串里一并加上即可。
提示:参数修改后记得重新编译再启动,SpringBoot 2.x 对
application.yml的读取是在启动时完成的,改完不重启等于白改。
5.3 问题三:npm install 超时卡住,或者前端端口被占用
现象:执行npm install时进度条长时间不动,几十分钟都没反应;另一种情况是npm run dev启动时提示端口已被占用。
原因:npm 默认源在境外,网络不稳定;端口被占用通常是有其他开发服务把 8080 或 8081 占了。
解决:npm install可以把 registry 切换到国内镜像源,常见做法是npm config set registry后重新 install,速度会明显提升。端口占用用系统命令查:
# Windows 下查看谁占用了 8080 端口 netstat -ano | findstr :8080 # 找到 PID 后强制结束进程 taskkill /PID 1234 /F如果杀掉了进程还是不行,直接在vue.config.js里把devServer.port改成 8082。记住改完端口后,前端配置的代理转发那条规则不用动,target指向的是后端地址,和前端端口无关。
5.4 问题四:Android 模拟器能通,真机连不上后端
现象:模拟器里访问后端一切正常,换成真机后请求超时,或者返回Connection refused。
原因:真机上不能用localhost或10.0.2.2。10.0.2.2是 Android 模拟器专用的宿主机地址,真机上自然不通;真机需要用电脑在局域网里的 IP,比如192.168.1.100。
解决:查电脑 IP 后,把 Android 端 API 地址改成http://192.168.1.100:8080,同时确保手机和电脑连的是同一个路由器。电脑防火墙如果是开启状态,记得放行 8080 端口的入站连接,否则真机请求会被系统防火墙拦掉。这个坑很多人查了半天代码发现根本没问题,就是防火墙的事情。
5.5 问题五:图片上传成功但页面不显示,返回 404
现象:管理端上传老人照片或证件图片,页面提示上传成功,但<img>标签不显示,浏览器访问图片地址返回 404。
原因:上传文件被写到了本地磁盘某个目录,比如D:/upload/,但项目的虚拟路径没有把/upload/**映射到这个目录,SpringMVC 找不到文件。
解决:在 Spring 配置类里添加静态资源映射:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/upload/**") .addResourceLocations("file:D:/upload/"); } }addResourceHandler("/upload/**")表示 URL 中以/upload/开头的请求会去服务器D:/upload/目录找文件。注意addResourceLocations最后必须带目录分隔符,写file:D:/upload不带上斜杠有时候会出现拼接路径错误。改完重启后端,再刷新页面看图片是否正常。
6. 二次开发验证:从管理端到移动端的一套自检方法
6.1 用 Postman 或 curl 快速验证接口
拿到源码后,先不急着改功能,把核心接口全部验证一遍。用 curl 测试登录接口:
curl -X POST http://localhost:8080/api/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"123456"}'如果返回 JSON 里有用户信息和成功状态码,说明后端基本可用。再测试老人列表、护理记录新增、床位分配三个核心接口,每个接口确认返回格式。把接口地址、请求方式、参数名整理成一张表,和 Android 端代码里的请求一一对照,确保字段名完全一致。最容易出错的是create_time这类字段,后端返回的是2025-03-01 14:30:00,Android 端解析时如果用了SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")就会炸。
6.2 手机端真机调试注意点
真机调试时,除了前面提到的 IP 和防火墙问题,还有两个细节很影响体验。第一,Android 应用要申请网络权限,AndroidManifest.xml里必须有<uses-permission android:name="android.permission.INTERNET"/>,很多源码里这个权限被误删。第二,建议先用浏览器访问http://电脑IP:8080/api/login,能通再启动 Android 应用,这样能快速定位问题在网络层还是应用层。
调试过程中把加密前的密码打印到 Logcat 里,确认特殊字符没有被转义。家属留言、护理记录这类文本字段,注意utf8mb4编码是否覆盖,否则存 emoji 表情会报Incorrect string value错误。从那以后我拿到这种多端项目,第一件事永远是一张接口清单,把后端每个接口和 Android 端、Vue 端的调用点逐个对应起来,全链路走一遍再碰业务代码。这个习惯帮我省了无数二次开发的排查时间,希望帮到你。
本文还有配套的精品资源,点击获取