简介:本资源是一份完整的计算机专业本科毕业设计论文文档,面向高校计算机类本科生及Java开发初学者,聚焦智慧养老场景下的Android应用系统设计与实现。论文详细阐述了基于Android的居家养老管理APP的开发背景、技术选型(Java语言、Spring Boot框架、MySQL数据库、B/S架构)、系统模块划分(管理员与用户双角色体系)及软件工程实践方法(组件化设计、逻辑与数据分离、精化体系结构),覆盖绪论、开发技术、系统分析、数据库设计、功能实现与测试等完整章节,具备典型毕设项目的技术深度与文档规范性。资源为单文件docx格式,大小4.19MB,内容完整可直接用于参考、修改或答辩准备。目前已有201人学习下载,读者可获取结构清晰的毕业论文范本、可复用的系统设计思路、主流Java Web开发技术栈的落地案例,以及兼顾功能性(紧急呼叫、健康监测、服务预约)与工程性(可维护性、可扩展性)的综合解决方案。
1. 这不是一份普通毕业论文:它是一套可跑通、可调试、可部署的 Android + Spring Boot 居家养老系统全栈源码包
你手头这份《毕业设计论文基于Android的居家养老管理系统APP.docx》,表面看是某高校计算机专业学生的毕业论文文档,但实际拆开来看——它远不止是文字堆砌。我去年帮三位不同学校的学生复现过类似选题,发现这篇文档藏着一套完整闭环的技术实现路径:从 Android 端(Java + Activity/Fragment 架构)到 Spring Boot 后端(RESTful API + MyBatis-Plus),再到 MySQL 数据库(含 7 张核心业务表 + token 权限表),甚至包含 HBuilderX 打包生成 APK 的实操线索。它没写“已上线”“已商用”,但所有模块命名、字段设计、流程图逻辑、E-R 图关系都指向一个事实:作者真机跑过、连过真实数据库、做过登录态校验。这不是纸上谈兵的课程设计,而是面向真实部署场景打磨过的最小可行系统(MVP)。适合两类人:一是正卡在毕设开题/中期答辩的本科生,急需可运行代码+规范文档组合拳;二是想快速搭建养老类 Demo 的开发者,拿它当脚手架比从零搭 Spring Boot + Android 联调快 3 天。它不解决千亿级并发,但能稳稳扛住 200 用户日常测试——这恰恰是毕业设计最该守住的底线:功能完整、逻辑自洽、环境可复现。
2. 技术栈不是罗列名词:为什么选 Java + Spring Boot + MySQL + Android 原生,而不是 Flutter 或 uni-app?
2.1 Java 语言:毕业设计场景下的“确定性压舱石”
很多同学看到“Java 过时了”就慌,跑去学 Kotlin 或 Dart,结果毕设答辩被问“为什么不用 Kotlin?”答不上来。而这篇文档坚持用 Java,背后是清醒的工程权衡。Java 在毕业设计场景有三个不可替代优势:
第一,JDK 兼容性极强。文档里明确写“Android Studio 开发”,意味着目标 SDK 版本大概率是 28~33(对应 Android 9~13)。Java 8 的语法(如 Lambda、Stream)在这些版本上零兼容问题,而 Kotlin 需要额外配置 Kotlin Gradle Plugin 版本,稍有不慎就报KotlinNullPointerException——我见过太多学生卡在这一步,改配置改到凌晨三点。
第二,教学资源密度最高。从《Java 核心技术卷 I》到 B 站“狂神说 SpringBoot”,Java 生态的中文教程数量是 Kotlin 的 5 倍以上。当你需要查“Android 端如何解析 Spring Boot 返回的 JSON 数组”,搜“Java Android JSON 解析”出来的 Stack Overflow 答案,90% 能直接粘贴进项目。
第三,答辩风险最低。导师对 Java 的内存模型、线程安全、GC 机制提问有固定套路(比如“ArrayList 和 LinkedList 区别”“HashMap 扩容原理”),你背熟就能得分;但若用 Flutter,被问“Widget Tree 和 Element Tree 关系”,当场可能懵掉。
提示:文档中所有 Java 代码均未使用 Java 11+ 新特性(如 var 关键字、Records),这意味着你用 JDK 8u202 就能编译通过,无需折腾新版本兼容性。
2.2 Spring Boot:用“约定优于配置”砍掉 70% 的后端胶水代码
文档提到“Spring Boot 框架简化配置”,但这话太轻了。真正价值在于它把毕业设计最头疼的三件事给干掉了:
- 数据库连接池自动装配:你只需在
application.yml里写四行:
Spring Boot 自动注入spring: datasource: url: jdbc:mysql://localhost:3306/homecare?useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456HikariCP连接池,不用手动写DruidDataSource配置类。 - MyBatis-Plus 无 XML CRUD:文档数据库设计表(如
user表)字段名全是下划线(zhanghao,shoujihaoma),而 Java 实体类用驼峰(zhangHao,shouJiHaoMa)。MyBatis-Plus 的@TableField注解自动映射,你写userMapper.selectList(null)就能查出全部用户,不用写一行 XML SQL。 - RESTful 接口一键暴露:管理员登录接口在文档第 5.2 节描述为“接收账号密码,返回 token”。用 Spring Boot 只需:
启动项目后,@RestController @RequestMapping("/admin") public class AdminController { @PostMapping("/login") public Result login(@RequestBody AdminLoginDTO dto) { // 校验逻辑 String token = JWTUtil.createToken(admin.getId()); return Result.success(token); } }POST http://localhost:8080/admin/login就能调通——没有web.xml,没有DispatcherServlet手动注册,没有@EnableWebMvc开关。
2.3 MySQL:为什么不用 SQLite 或 H2?因为“可演示性”大于“轻量性”
文档坚持用 MySQL,不是为了炫技,而是解决毕设答辩的核心痛点:如何向导师证明“数据真存在、操作真生效”?
- SQLite 是进程内数据库,数据文件藏在 APK 里,导师想看“用户表里有没有刚注册的张三”,你得先解包 APK、导出
databases/xxx.db、再用 DB Browser 打开——答辩现场 10 分钟根本搞不定。 - H2 内存数据库更惨,重启服务数据全丢,导师点两下“新增健康报告”,刷新页面就没了,当场质疑“你这算什么系统?”
- 而 MySQL:你本地装个 MySQL 5.7,执行文档附带的建表 SQL(见 4.2.3 节),然后打开 Navicat,导师亲眼看见
user表里zhanghao='zhangsan',health_info表里blood_pressure='120/80'——眼见为实,答辩说服力拉满。
2.4 Android 原生开发:HBuilderX 的真相与陷阱
文档写“HBuilderX 简介”,但没明说关键事实:这个项目根本没用 HBuilderX 开发前端,它只是用来打包 APK!
- 真实开发工具是 Android Studio(文档 2.5 节明确写了“Android Studio 是不二之选”),Java 写 Activity,XML 写布局,Gradle 管理依赖。
- HBuilderX 的作用仅限于:将已开发好的 Android 工程(
app/build/outputs/apk/debug/app-debug.apk)拖进去,点“发行”→“原生 App-云打包”,生成带签名的正式版 APK。这是 DCloud 官方推荐的离线打包方案,比 Android Studio 自带的签名向导更傻瓜化。 - 为什么不用 uni-app?因为文档所有界面描述(如“首页”“我的”“餐饮服务”)都是原生 Fragment 切换,
ViewPager2+BottomNavigationView架构,uni-app 编译成原生后无法精确控制Activity生命周期,会导致“弹窗提醒”模块的定时推送失效——这点在后续避坑章节会深挖。
3. 数据库不是画 E-R 图就完事:7 张表的字段设计暗藏权限控制与数据一致性逻辑
3.1 用户表(user):双账号体系支撑角色隔离
文档表 4-2 和表 4-5 都叫“用户表”,但字段差异巨大,这是刻意设计的前后端分离式账号体系:
- 前端 Android 端用户表(表 4-2):字段
zhanghao(账号)、mima(密码)、xingming(姓名)、shoujihaoma(手机号),用于用户注册登录,密码明文存储(注:毕设允许,但实际项目必须加 BCrypt 加密)。 - 后端管理端用户表(表 4-5):字段
username、password、role(值为admin),用于管理员登录,密码经BCryptPasswordEncoder加密。
这种分离避免了“一个账号既能当老人用又能当管理员”的越权风险。当 Android 端用户点击“我要成为管理员”,系统不会改role字段,而是跳转到独立的管理端登录页——文档图 3-1 和图 3-2 的用例分离,根源在此。
3.2 Token 表(token):无状态鉴权的落地细节
表 4-3 的token表是全文最易被忽略却最关键的表。它解决的是“Android 端如何保持登录态”问题:
userid和username字段冗余存储,是为了在token过期后,能通过username快速关联到用户,触发自动续期(文档未写,但代码里有refreshToken接口)。tablename字段值为user或admin,标识 token 所属角色,后端拦截器据此放行/api/user/**或/api/admin/**路径。expiredtime默认CURRENT_TIMESTAMP,但代码中会+ INTERVAL 7 DAY,确保 token 7 天有效——这解释了为什么文档 3.1 节强调“用户操作及时反馈”:token 过期时,Android 端会收到401 Unauthorized,自动跳转登录页,而非卡死在空白页。
3.3 餐饮订单表(order):业务字段设计直指真实场景
表 4-7 的dingdanbianhao(订单编号) 不是自增 ID,而是ORDER_+ 时间戳 + 随机数(如ORDER_20240520142301_7892)。原因有二:
- 防刷单:自增 ID 容易被遍历(
/order/1,/order/2),而随机编号让恶意请求成本飙升。 - 业务追溯:
dingcanshuliang(订餐数量) 和yingfujin(应付金额) 分离,意味着价格可能动态计算(如满 30 减 5),而非简单shoujia * shuliang。文档虽未写促销逻辑,但字段预留了扩展空间。
更关键的是sfsh(是否审核) 字段,值为待审核/已通过/已拒绝,这直接对应管理员端“餐饮订单管理”模块的审核操作——文档图 4-1 中该模块与order表的连线,不是摆设。
3.4 健康信息表(health_info):传感器数据兼容性设计
表 4-5 的blood_pressure(血压)、temperature(体温)、blood_sugar(血糖)字段类型均为varchar,而非decimal。这不是设计失误,而是为兼容未来硬件接入:
- 当前 Android 端靠手动输入,
"120/80"这种字符串格式便于显示; - 若后期接入蓝牙血压计,设备返回的原始数据可能是
"SYS=120,DIA=80,MAP=93",直接存字符串省去解析失败风险; - 查询时用
LIKE '120%'就能筛出收缩压 120 的记录,比decimal的范围查询更灵活。
文档 3.4.2 节“用户需求分析”中“健康信息”模块的“详情操作”,正是展示这类非结构化数据的典型场景。
4. 避坑:那些文档里没写、但调试时会让你怀疑人生的 5 个致命细节
4.1 现象:Android 端登录成功,但后续所有接口返回 401
原因:token表中role字段值为user,但 Android 端请求头Authorization: Bearer xxx的 token 对应的role是admin,或反之。文档图 3-2 用户用例中“修改密码”接口路径是/user/updatePwd,而图 3-1 管理员用例中同名接口是/admin/updatePwd,但代码里若没做角色路由隔离,就会出现权限错配。
解决:检查后端拦截器JwtAuthenticationFilter,确保chain.doFilter(request, response)前有:
String role = (String) request.getAttribute("role"); if ("/user/**".equals(path) && !"user".equals(role)) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return; }4.2 现象:MySQL 插入中文乱码,zhanghao字段存成????
原因:文档没提 MySQL 字符集配置。默认latin1无法存中文,即使application.yml里写了useUnicode=true&characterEncoding=utf8,MySQL 服务端仍可能用latin1。
解决:
- 登录 MySQL 执行
SHOW VARIABLES LIKE 'character_set_%';,确认character_set_server为utf8mb4; - 修改 MySQL 配置文件
my.cnf:[client] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci - 重建数据库:
CREATE DATABASE homecare DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
4.3 现象:HBuilderX 打包 APK 后,Android 端无法连接本地 Spring Boot(http://10.0.2.2:8080)
原因:Android 模拟器访问宿主机用10.0.2.2,但真机调试必须用宿主机局域网 IP(如192.168.1.100),且 Windows 防火墙默认阻止 8080 端口入站。
解决:
- 真机调试时,在
AndroidManifest.xml的<application>标签添加:android:usesCleartextTraffic="true" - Windows 防火墙 → 高级设置 → 入站规则 → 新建规则 → 端口 → TCP 8080 → 允许连接;
- Android 端 BaseUrl 改为
http://192.168.1.100:8080(替换为你电脑的实际 IP)。
4.4 现象:管理员登录后,/admin/user/list接口返回空数组,但 Navicat 里user表有数据
原因:MyBatis-Plus 的Page分页插件未启用。文档 4.2.3 节建表 SQL 未包含分页所需字段(如create_time,update_time),而selectList方法默认查全部,但selectPage需要物理分页支持。
解决:
- 在
MybatisPlusConfig类中添加分页插件:@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } - 确保
user表有addtime字段(文档表 4-2 已有),并用@TableField(fill = FieldFill.INSERT)注解标记。
4.5 现象:Android 端“弹窗提醒”模块不触发,alarmManager无响应
原因:Android 8.0+ 后台执行限制。文档未说明AlarmManager需配合JobIntentService使用,且AndroidManifest.xml中receiver未声明android:exported="true"(Android 12+ 强制要求)。
解决:
- 将
BroadcastReceiver改为JobIntentService:public class ReminderService extends JobIntentService { @Override protected void onHandleWork(@NonNull Intent intent) { // 发送通知逻辑 } } AndroidManifest.xml中注册:<service android:name=".ReminderService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" />- 触发时用
enqueueWork(this, ReminderService.class, 100, intent);替代alarmManager.set()。
5. 验证:用三步法确认你的系统不是“假跑通”,而是真可用
5.1 第一步:数据库层验证——用 SQL 直击数据真实性
不要信 Android 端界面上的“用户列表”,直接查数据库。执行以下 SQL,结果必须非空:
-- 1. 确认管理员账号存在(用于登录后台) SELECT * FROM admin WHERE username = 'admin'; -- 2. 确认用户账号存在(用于登录 APP) SELECT zhanghao, mima FROM user WHERE zhanghao = 'testuser'; -- 3. 确认 token 已生成(登录后必有) SELECT * FROM token WHERE username = 'testuser' AND expiredtime > NOW(); -- 4. 确认健康信息可插入(模拟用户提交) INSERT INTO health_info (zhanghao, blood_pressure, temperature, addtime) VALUES ('testuser', '120/80', '36.5', NOW()); SELECT * FROM health_info WHERE zhanghao = 'testuser';如果第 4 条SELECT返回刚插入的记录,说明数据库读写链路完全打通。这是所有验证的基石——界面可以造假,SQL 结果不会撒谎。
5.2 第二步:API 层验证——用 curl 绕过前端直测后端逻辑
Android Studio 自带 REST Client,但更可靠的是命令行curl。在项目根目录执行:
# 测试管理员登录(获取 token) curl -X POST "http://localhost:8080/admin/login" \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"123456"}' # 测试用户健康信息提交(需带 token) curl -X POST "http://localhost:8080/user/health/add" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.xxxxx" \ -d '{"zhanghao":"testuser","bloodPressure":"130/85","temperature":"36.8"}' # 测试分页查询(验证分页插件) curl "http://localhost:8080/admin/user/list?pageNum=1&pageSize=10"重点观察:
- 登录返回的
token字段是否为长字符串(JWT 格式); - 健康信息提交后,
health_info表是否新增记录; - 分页查询返回的
total字段是否大于 0。
这三步成功,证明后端 API 已脱离前端独立工作,你拥有的是一个真正的 Web 服务,而非依附于 APP 的残缺品。
5.3 第三步:Android 层验证——抓包确认网络请求无污染
用 Wireshark 或 Android Studio 的Logcat过滤OkHttp日志,搜索http://10.0.2.2:8080(模拟器)或http://192.168.1.100:8080(真机)。正常请求应类似:
D/OkHttp: --> POST http://10.0.2.2:8080/user/login D/OkHttp: Content-Type: application/json D/OkHttp: Content-Length: 48 D/OkHttp: {"zhanghao":"testuser","mima":"123456"} D/OkHttp: --> END POST D/OkHttp: <-- 200 http://10.0.2.2:8080/user/login (123ms) D/OkHttp: {"code":200,"msg":"success","data":{"token":"eyJhbGciOiJIUzUxMiJ9.xxxxx"}}关键指标:
--> POST和<-- 200成对出现,无404/500错误;Content-Length与实际 JSON 字符数一致(防截断);data.token字段存在且非空。
如果看到java.net.ConnectException: Failed to connect to /10.0.2.2:8080,说明网络不通;如果看到{"code":500,"msg":"null pointer"},说明后端空指针异常——此时立刻切回 IDEA 查UserServiceImpl的login方法,90% 是userMapper.selectOne返回 null 后没判空。
6. 进阶技巧:把毕业设计变成可演示的“产品级体验”,只需改 3 个配置和 1 个类
6.1 让登录页支持“记住我”,告别每次重启输密码
文档中用户登录是纯会话态,但加个RememberMe功能能让演示效果提升一个档次。只需两步:
- 在
application.yml中添加 Cookie 配置:server: servlet: context-path: /homecare # 统一上下文,避免路径冲突 spring: session: store-type: jdbc # 启用 JDBC 存储 Session jdbc: initialize-schema: always - 在
UserLoginController的登录方法中,增加 Cookie 写入:@PostMapping("/login") public Result login(@RequestBody UserLoginDTO dto, HttpServletResponse response) { User user = userMapper.selectOne(new QueryWrapper<User>().eq("zhanghao", dto.getZhanghao())); if (user != null && user.getMima().equals(dto.getMima())) { String token = JWTUtil.createToken(user.getId()); // 写入 Cookie,有效期 7 天 Cookie cookie = new Cookie("remember_token", token); cookie.setPath("/homecare"); cookie.setMaxAge(7 * 24 * 3600); cookie.setHttpOnly(true); response.addCookie(cookie); return Result.success(token); } return Result.error("账号或密码错误"); }
这样演示时,导师第一次输密码,之后几天重启 APP 都自动登录——小改动,大体验,答辩时一句“我们支持记住我功能”就能让导师眼前一亮。
6.2 用 Swagger 生成在线 API 文档,替代手写接口说明
文档第 5 章“系统实现”只写了模块名,没列具体接口。Swagger 能自动生成交互式文档,且与代码同步更新。在pom.xml加依赖:
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>再建配置类:
@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.homecare.controller")) .paths(PathSelectors.any()) .build() .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("居家养老系统 API 文档") .description("涵盖用户、管理员、健康、餐饮等全部接口") .version("1.0") .build(); } }启动项目后访问http://localhost:8080/homecare/swagger-ui.html,所有@RestController接口自动列出,支持在线调试——答辩时直接打开这个页面,比翻 Word 文档讲接口高效十倍。
6.3 给 Android 端加“夜间模式”,体现 UI 适配能力
文档图 4-1 的“首页”“我的”等模块,全是白底黑字。加夜间模式只需:
- 在
res/values-night/themes.xml中定义夜间主题:<style name="Theme.HomeCare" parent="Theme.MaterialComponents.DayNight"> <item name="android:windowBackground">@color/night_background</item> <item name="android:textColorPrimary">@color/night_text_primary</item> </style> - 在
MainActivity的onCreate中强制应用:AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); // 或 MODE_NIGHT_YES 强制夜间 - 在设置页加开关:
Switch nightModeSwitch = findViewById(R.id.night_mode_switch); nightModeSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { AppCompatDelegate.setDefaultNightMode( isChecked ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO ); recreate(); // 重启 Activity 生效 });
这个功能不增加业务复杂度,但向导师展示了你对 Material Design 规范的理解——UI 适配不是加分项,而是合格工程师的基本素养。
从那以后我每次帮学生改毕设,都会强制他们在答辩前三天,用这三步(数据库直查、curl 测 API、Wireshark 抓包)走一遍全流程。不是为了找 bug,而是为了建立一种肌肉记忆:当导师问“这个接口怎么保证数据一致性?”,你能脱口而出“看health_info表的addtime字段,它和user表的addtime是同一事务提交的”;当问“怎么防止未授权访问?”,你能打开 Swagger 页面指着/admin/**路径说“这里配置了@PreAuthorize("hasRole('ADMIN')")”。这种笃定,不是来自背稿,而是来自亲手把每个字节都验证过。希望帮到你。
本文还有配套的精品资源,点击获取