1. 为什么选这个题目养老服务平台的真实需求与毕设定位每年到了毕设选题季总有一批人会盯着“管理系统”类题目反复纠结。说实话传统的图书管理、宿舍管理、会议室预约这类题目已经做到近乎饱和代码开源满天飞答辩时老师一眼就能看出是第几手资料。我见过太多因为选题老旧而在答辩环节被追问到崩溃的例子——不是功能没做完而是老师问“你这个系统解决了什么实际问题”时支支吾吾答不上来。养老服务平台这个方向恰恰能绕开这个死穴。为什么因为它的需求场景足够真实、足够具体、足够有社会背景支撑。我国老龄化进程加快社区养老、居家养老、机构养老这三种模式并存但大量中小型养老机构、社区服务站的信息化水平还停留在纸质台账阶段。老人基本信息靠手填健康记录靠本子记家属想了解老人近况得打电话问护工。你去做一个基于SpringBoot的养老服务平台本质上是把一个真实的业务痛点搬到了系统里老师一听就知道你不是在“为了做系统而做系统”。从毕设评审的角度看这个题目还有几个天然优势。第一业务链条完整能覆盖多个角色——管理员、护工、老人家属甚至老人本人简化版角色不同权限不同正好考察你对Spring Security或拦截器的掌握程度。第二数据模型有层次老人档案、健康评估、护理记录、床位管理、费用统计这些表之间关系复杂但清晰适合展示数据库设计能力。第三功能可深可浅基础版做信息管理加简单统计就能毕业进阶版可以做健康数据可视化、护理计划自动生成、异常预警推送往上加难度完全看个人时间精力和学习能力。我自己的经验是这类题目最怕的是“什么都想做最后什么都没做好”。所以选题之后的第一件事不是急着写代码而是先想清楚你的核心用户是谁核心流程是哪条做到什么程度算“完成”这篇文章我会把整个项目的设计思路、表结构、核心功能实现、调试运行中常见的坑以及答辩时容易被追问的点全部拆开讲清楚。无论你是想直接照着一个完整方案做还是想借鉴思路自己设计应该都能从中拿到想要的东西。2. 需求分析与角色权限设计先把业务边界划明白2.1 四个核心角色和他们各自的“不爽”做养老服务平台的第一个认知是要从“能做什么功能”切换到“谁在用、他烦什么”。我梳理下来这个系统里至少有四类人会跟它打交道系统管理员通常是机构负责人或IT维护人员。他烦的是全院信息分散在不同Excel里老人台账、员工排班、床位状态、收费记录各自为政他要的是一个大盘能看清全院运营状况比如入住率、收费欠费情况、护工工作量分布。护工/护理人员一线工作者。他们烦的是纸质记录繁琐、交接班信息不同步、老人突发状况没法快速上报他们要的是移动端或者快速表单能随手记录老人饮食、用药、体温、情绪变化下班时能一键生成交接班摘要。老人家属远程关注者。他们烦的是不知道老人今天吃得好不好、睡得好不好、有没有按时吃药他们要的是一个微信端或网页端的家属面板能看到护理记录、健康评估结果、费用账单最好还能在线提交探访预约。老人本人简化场景很多养老平台的设计会把老人排除在系统之外理由是“老人不会用”。但至少在自助查询机上老人应该有查看自己当日餐单、活动安排、一键呼叫护工的能力。毕设能做到这一步是明显的加分项。2.2 权限模型怎么设计才不会被答辩老师问倒权限设计是这类系统的隐藏考点。很多同学的方案是给User表加一个role字段登录后靠拦截器判断一下“是不是管理员”这种做法在小型Demo里能跑但老师一追问“如果角色膨胀怎么办、前端页面按什么控制、接口层面靠什么兜底”就容易露怯。这里我建议采用RBAC基于角色的访问控制模型虽然听起来唬人但落地非常简单。核心是五张表用户表sys_user、角色表sys_role、菜单表sys_menu、用户角色关联表、角色菜单关联表。登录成功后后端根据用户ID查出角色再根据角色查出可访问的菜单和权限标识前端用权限标识控制按钮显隐后端接口用Spring Security的PreAuthorize(hasAuthority(health:record:add))做二次校验。权限标识的命名建议采用“资源:操作”的格式比如elder:info:view 老人信息查看 elder:info:edit 老人信息编辑 health:record:add 健康记录新增 health:record:export 健康记录导出 fee:bill:audit 费用账单审核这样做的好处是如果将来要扩展一个“值班管家”角色只需要在角色菜单关联表里插入新的关联记录不用改代码逻辑。我在做项目时习惯把所有权限初始数据写成一个data.sql在SpringBoot启动时自动执行这样无论是本地跑还是部署到服务器数据库初始化都只需要一键完成。2.3 核心业务流程一次完整的“老人入住”需要走哪些步骤需求分析不能停留在“能增删改查”要画出关键业务链路。一个养老服务平台最核心的流程是“老人入住-评估-护理-收费”这条线我在需求文档里把它拆成了九个步骤家属通过官网或线下提交入住申请登记老人基本信息、既往病史、家属联系方式。机构管理员审核申请确认床位是否空闲分配房间号和床位号。系统创建老人正式档案状态为“试住”或“在住”。护理主管发起入院评估填写生活自理能力吃饭、穿衣、洗澡、如厕等维度、认知能力、情绪状态评分生成评估等级。根据评估等级自动推荐护理等级和基础护理计划如一级护理、二级护理。护工按计划执行每日护理任务记录执行情况。系统根据评估等级、护理天数、额外服务项目自动生成月度费用账单。家属在线查看账单并缴费财务人员核对到账状态。老人退住时系统归档健康档案和费用记录释放床位。这条链路覆盖了至少五张核心表的联动入住申请表 - 老人档案表 - 评估记录表 - 护理计划表 - 费用账单表。答辩时如果你能画着这张流程图把数据流转讲清楚业务完整性这一项基本就稳了。3. 核心技术选型为什么是SpringBoot MyBatis-Plus MySQL3.1 SpringBoot 3.x还是2.x这是个选择题现在网上大多数教学视频还在用SpringBoot 2.xJDK 8这让我在带项目时挺纠结的。如果现在开始做新项目我更推荐SpringBoot 2.7.x JDK 8作为毕设基准组合原因是生态最稳定、资料最多、遇到问题更容易搜到答案。SpringBoot 3.x虽然新但它强制要求JDK 17而且部分老版本的依赖兼容性需要额外处理对毕设这种“求稳不求新”的场景反而增加了不必要的风险。不是说不能上3.x前提是你要有足够的排错能力和时间预算。我自己在某个模拟项目里试过把核心代码从2.7迁移到3.2GaBase团队踩坑记里光javax.servlet改jakarta.servlet的包名替换就花了大半天。毕设有明确的截止日期不建议在这种地方赌运气。3.2 MyBatis-Plus为什么比纯MyBatis省心数据访问层我强烈建议用MyBatis-Plus而不是原生MyBatis。原因很简单这个项目的单表操作占了80%以上比如老人的基本信息管理、护工信息管理、床位管理基本都是单表的增删改查用MyBatis-Plus的BaseMapper直接继承连SQL都不用写public interface ElderInfoMapper extends BaseMapperElderInfo { // 复杂的多表查询自己写XML或注解SQL }需要自定义复杂查询的地方比如“统计每个护理等级的入住人数”“查询最近7天的新增入住趋势”再单独在Mapper里写SQL。这种“单表靠封装的、多表靠手写”的组合是这个项目里效率最高的搭配。MyBatis-Plus的另一个杀手锏是分页插件。养老服务平台里“老人档案列表”“费用账单列表”这种页面有天然的分页需求用它的PaginationInnerInterceptor配置好之后传入PageElderInfo对象返回的IPage直接就能拿到总记录数、当前页数据、总页数省去了手写LIMIT和COUNT的麻烦。3.3 前端方案Thymeleaf还是Vue分离这是我能预料到的最多同学纠结的问题。两种方案我都试过客观对比一下维度Thymeleaf Bootstrap前后端分离Vue2/3 Element UI学习成本低会写HTMLCSS就能上手中高需要理解Vue生命周期、Axios、跨域开发效率中后端同学能独立搞定高但需要前后端同时构建答辩加分一般较明显因为技术栈更现代部署复杂度低打包成一个Jar直接跑中前端要打包成静态文件放到后端或单独Nginx适合人群后端为主、时间紧的同学愿意多学一层技术栈的同学我自己在学生项目里会鼓励有余力的采用前后端分离因为答辩时“我用了Vue做了组件化页面”比“我用了模板引擎”更能体现工程化意识。但如果你是零基础起步或者只剩三四周时间用Thymeleaf把功能全部打通、把核心精力放在业务逻辑上也完全够用。记住一条原则项目完成度永远大于技术炫度。3.4 数据库连接池、Swagger、Lombok这些“标配”别落下一个能顺利跑起来的项目背后往往藏着一堆“看起来不起眼但少了就难受”的依赖。我在项目里通常固定带上这几件套Druid连接池带监控页面能看SQL执行耗时调试慢查询时非常有用。Lombok用Data注解省去getter/setter实体类简洁一大截。Swagger/Knife4j自动生成接口文档测试接口不再靠Postman手动填参数答辩时演示接口文档也是一种加分。Hutool工具库处理日期、生成随机编号、Bean拷贝都方便。写pom.xml时要注意版本之间的兼容性特别是MyBatis-Plus、Druid、Knife4j 三者的SpringBoot适配版本。这些坑我在第五节会详细讲很多项目跑不起来不是代码问题就是版本号之间互相打架。4. 数据库表结构设计从老人档案到费用账单的完整落地方案4.1 核心表概览十二张表如何组织我设计这个系统的数据库时总共规划了十二张核心表。下面用一份总览表格把每张表的职责说清楚表名中文含义核心字段关联说明sys_user系统用户表username, password, status所有角色账号统一存这里sys_role角色表role_name, role_code管理员、护工、家属、老人sys_menu菜单/权限表parent_id, menu_name, perms菜单树权限标识elder_info老人档案表name, gender, birth_date, id_card, room_no, status平台的业务核心表elder_assessment入院评估表elder_id, life_score, cognition_score, care_level关联elder_infocare_plan护理计划表elder_id, plan_name, plan_detail, start_date根据评估等级生成care_record护理记录表elder_id, staff_id, record_type, content, record_date护工日常打卡bed_info床位信息表room_no, bed_no, status, elder_id与elder_info双向关联fee_bill费用账单表elder_id, fee_type, fee_amount, bill_status按月生成activity_info活动安排表activity_name, activity_date, location, sign_up_status老人参与文体活动visit_appointment探访预约表elder_id, visitor_name, visit_time, audit_status家属在线提约sys_login_log登录日志表username, login_ip, login_status, login_time记录安全日志看这张表你会发现我把“老人入住评估”拆成了elder_info和elder_assessment两张表而不是把评估分数直接塞进老人档案里。这样做的意义是评估是可多次发生的——老人入住三个月后能力变化了需要复评复评记录和初始记录可以并存而且能通过assessment_time字段对比变化趋势。这种设计在答辩时如果被问到“为什么要拆表”你就有了合理解释遵循数据库范式避免数据冗余同时支持业务的历史追溯。4.2 老人档案表与床位表之间的关系一对一的特殊处理在这十二张表里elder_info和bed_info的关系最容易被同学设计错。常见错误是把bed_no直接做成elder_info的一个字符串字段比如elder_info.bed 3栋502-1。表面看省事但实际上你没法查“哪些床位是空的”“哪个房间住满了”“这个床位的历史入住人是谁”。正确的做法是让bed_info表独立存在用elder_id字段标识当前入住人CREATE TABLE bed_info ( id BIGINT PRIMARY KEY AUTO_INCREMENT, room_no VARCHAR(50) NOT NULL COMMENT 房间号如3栋502, bed_no VARCHAR(20) NOT NULL COMMENT 床位号如A1, bed_type VARCHAR(20) COMMENT 床位类型单人间/双人间/多人间, status TINYINT COMMENT 0-空闲 1-占用 2-维护, elder_id BIGINT COMMENT 当前入住老人ID空闲时为NULL, create_time DATETIME, UNIQUE KEY uk_room_bed (room_no, bed_no) ) COMMENT 床位信息表;为了支持历史追溯我还会额外建一张bed_change_log表记录每次入住/退住/换床操作但这张表不一定在基础版中实现。至少从表结构上你要能回答“一个床位当前住了谁”和“一个老人当前住哪个床”这两个问题。4.3 费用账单表的逻辑按月生成还是按次生成费用设计往往是同学们容易忽略的环节但它偏偏是答辩老师喜欢追问的地方——“你这个费用是怎么算出来的”。我在设计fee_bill表时把费用分成了三类基础床位费根据房间类型和护理等级按月计算比如单人间加一级护理月费是固定公式。按次服务费老人额外享受的理发、康复治疗、陪同外出等服务每次记录后计入账单。一次性费用入院时收取的床上用品费、押金等。为了不让账单计算逻辑全堆在Java代码里我建了一张fee_config配置表存放各项费用的计算规则CREATE TABLE fee_config ( id BIGINT PRIMARY KEY AUTO_INCREMENT, item_name VARCHAR(50) COMMENT 费用项目名称, fee_type VARCHAR(20) COMMENT 床位费/服务费/一次性, calc_type VARCHAR(20) COMMENT 固定金额/按天计算/按次计算, unit_price DECIMAL(10,2), remark VARCHAR(255) );月度账单的生成就是遍历当月入住天数、护理等级和额外服务记录汇总出一个总额。我在项目里写了一个BillGenerateTask定时任务用Spring自带的Scheduled(cron 0 0 2 1 * ?)在每月1号凌晨2点自动生成上月账单。这个设计既体现了业务理解又顺便展示了你对定时任务这块的掌握答辩时是实打实的加分项。5. 核心功能模块的实现拆解从前端页面到后端接口的完整链路5.1 登录认证与验证码用一个统一过滤器解决反复登录这个系统的用户角色多登录入口是统一的——所有用户走同一个/api/login接口后端根据用户名查库验证密码推荐用BCrypt加密存储成功后返回一个Token我这里用的是JWT。前端拿到Token后存到localStorage之后每次请求在请求头带上Authorization: Bearer token。具体实现流程可以拆成下面几步用户提交用户名、密码、验证码。后端先校验验证码用Redis存验证码设置5分钟过期。再根据用户名查询用户表比对BCrypt密码哈希。如果密码正确查询用户角色和权限标识封装进JWT的claims里。返回给前端token、userInfo、roles、permissions。后端有一个自定义的JwtAuthenticationFilter继承OncePerRequestFilter在每次请求进来时解析Token把用户信息塞进SecurityContextHolder。这样后续的Controller方法只要用AuthenticationPrincipal或SecurityContextHolder.getContext().getAuthentication()就能拿到当前操作人。验证码这里有个小提醒毕设项目不一定要接第三方验证码服务自己画一个图片验证码就行。我常用的是Hutool的CaptchaUtil工具生成一个线性验证码图片Base64编码后返回给前端。Redis如果没有单独部署也可以把验证码存在ConcurrentHashMap里不过有Redis尽量用Redis因为它还能顺便承接Token黑名单功能用户退出时把Token加入黑名单防止已退出用户继续访问。5.2 老人档案管理一张列表页面的“增删改查与条件检索”组合拳老人档案管理是这个系统里最“日常”的模块界面由三部分组成搜索区、数据表格、操作按钮。搜索区提供的检索条件至少要有老人姓名模糊、入住状态下拉、护理等级下拉、房号。这看起来简单但落到后端实现时要处理好一个细节查询条件是动态的用户可能只输入了姓名也可能只选择了状态SQL判断条件不能写死。用MyBatis-Plus实现动态查询非常顺手用它的LambdaQueryWrapper拼条件LambdaQueryWrapperElderInfo wrapper Wrappers.lambdaQuery(); wrapper.like(StringUtils.hasText(name), ElderInfo::getName, name) .eq(status ! null, ElderInfo::getStatus, status) .eq(careLevel ! null, ElderInfo::getCareLevel, careLevel) .like(StringUtils.hasText(roomNo), ElderInfo::getRoomNo, roomNo) .orderByDesc(ElderInfo::getCreateTime);这四个条件中StringUtils.hasText方法会判断前端传的参数是否为空为空就不拼这个条件从而实现“可选条件查询”。列表页面翻到第二页时前端要把当前的查询条件一起传回来否则会出现“搜索之后翻页就变回全部数据”的经典Bug。解决方案是前端在分页组件里把查询表单的数据对象也存下来每次翻页请求都带着它。5.3 健康评估与护理计划评分量表如何转化为自动推荐的护理等级入院评估模块是这个平台里最能体现“业务深度”的功能。我在设计评估量表时参考了日常生活活动能力量表的思路包含五个维度进食、穿衣、洗澡、如厕、行走能力。每个维度设置3到5个选项对应0到10分。总分算出后按照阈值自动映射护理等级评分区间护理等级说明45分及以上自理级基本能自理提供基础生活照料30分 - 44分介助级需要部分帮助如协助洗澡、穿衣15分 - 29分介护级大部分生活事项需要帮助15分以下全护级完全卧床或严重认知障碍需要24小时照护前端是一套问卷式的表单每道题用单选框组提交时把所有评分项作为一个JSON字符串存到assessment_detail字段同时把加权计算出的总分存到total_score字段。后端在保存评估记录的后置逻辑里调用一个CarePlanGenerator组件根据评估等级自动生成对应的护理计划——比如全护级的计划会包含“每2小时翻身一次”“每日鼻饲护理”“压疮风险评估”等项目并把这些项目插入care_plan和care_plan_item两张表。在这个组件里我用了一个简单的策略模式避免if-else套娃。定义一个CarePlanStrategy接口四个实现类对应四个护理等级public interface CarePlanStrategy { String getCareLevel(); ListCarePlanItem generatePlan(ElderAssessment assessment); }调用时通过MapString, CarePlanStrategy按等级匹配代码清爽后续如果新增“认知障碍专项护理”策略直接加一个实现类就可以。5.4 护理记录与交接班时间轴设计如何支撑“家属可视化”护理记录是护工使用频率最高的模块。每天早晚两次护工要为每一位在住老人记录体温、血压、饮食情况、情绪状态、用药情况以及特殊情况。我设计的care_record表用record_type区分记录类型取值包括temp、pressure、diet、mood、medication、special。为了支撑前端展示“某位老人最近一周的护理情况时间轴”接口层面我这样设计GetMapping(/elder/{elderId}/care/records) public Result getCareRecords(PathVariable Long elderId, RequestParam(required false) String startDate, RequestParam(required false) String endDate) { // 按日期倒序查询返回该老人指定时间段的全部护理记录 }前端拿到数据后按record_date分组用时间轴组件展示。家属端看到的页面是“今天08:00 体温36.5℃ 正常08:05 早餐进食半碗稀饭09:30 情绪平稳”。这种颗粒度的信息传达比单纯一句话“护理完成”要有说服力得多。还有一个实用细节护理记录提交时后端用当前登录用户的ID作为staff_id写入这样交接班时可以按“班次护理员”维度去查“今天哪个护工还没提交记录”。我在系统里做了一个非常简单的小统计接口查询当天已提交与未提交记录的护工数量这个数据用在管理端首页的“今日护理完成情况”卡片上。5.5 家属端与探访预约在线申请和审核的完整闭环家属端的核心功能是“看”护理记录、健康评估、费用账单和“约”探访预约。因为家属往往没法访问管理端的复杂菜单我单独做了一个简化的家属端界面登录后只展示三个页面我的老人、健康与护理、费用账单。探访预约的流程是家属选择老人、选择探访时间、填写到访人数。系统检查该时段是否已有其他家属预约防止探访时段过于拥挤。提交后生成待审核状态消息推送给管理端。管理员审核通过后系统更新状态为“已通过”家属端可见审核结果。这个流程在后端涉及两个核心逻辑一是“时段冲突检测”我会用visit_time和一个duration_minutes字段算出时间段范围查当前老人在该时间段内是否有status in (待审核, 已通过)的预约记录二是“审核状态机”我用一个auditStatus字段0待审核 1通过 2驳回在管理端只允许对“待审核”的记录进行操作从状态上避免重复审核。6. 调试、打包、部署全流程记录那些能让你省一周时间的坑6.1 版本兼容性pom.xml里面的隐形炸弹我做项目时给一个模拟项目X配置依赖树踩过最悬的一幕是MyBatis-Plus和Druid同时引入导致的启动报错——druid-spring-boot-starter和SpringBoot自动配置的DataSource初始化顺序冲突导致项目启动时反复报数据源初始化失败。这个问题排查了很久最后定位到的原因是Druid的starter和SpringBoot的DataSourceAutoConfiguration冲突需要手动排除后者的自动配置SpringBootApplication(exclude {DataSourceAutoConfiguration.class})或者干脆不用Druid的starter只引入druid核心包然后在配置文件里手动声明DruidDataSource的Bean。这里不展开所有细微差异具体的版本组合建议如下以SpringBoot 2.7.18为基准dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdcom.github.xiaoymin/groupId artifactIdknife4j-openapi2-spring-boot-starter/artifactId version4.4.0/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.20/version /dependency这个组合我跑过多台机器兼容性基本稳定。如果你用SpringBoot 3.x那要去找对应的3.x适配版本不要拿2.x的starter硬塞。6.2 环境与数据库配置一个不小心就卡半小时的小细节很多同学在自己的电脑上项目跑得好好的发给老师或放到另一个电脑上就报Access denied for user rootlocalhost。排除用户名密码错误后最可能的原因是MySQL的驱动版本和数据库服务端版本不一致或者mysql-connector-java的groupId在不同版本有变化。在SpringBoot 2.7.x里推荐用dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId version8.0.33/version /dependency注意artifactId已经不是老版的mysql-connector-java了。另一个坑是application.yml里的时区配置不配置的话日期字段插入数据库后小时数会差8小时spring: datasource: url: jdbc:mysql://localhost:3306/elder_care_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai我见过太多同学因为忘记serverTimezoneAsia/Shanghai导致前端展示时间比实际晚8小时然后怀疑是FastJson解析问题排查半天结果只是数据库时区。这种低级bug一旦出现很影响心态。6.3 前端跨域与静态资源加载切换接口联调模式时的注意点如果你采用前后端分离前端页面运行在http://localhost:8080后端接口在http://localhost:9090那就必须处理跨域问题。解决方案很多我习惯在后端配置一个全局跨域过滤器Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); config.addAllowedOriginPattern(*); config.addAllowedHeader(*); config.addAllowedMethod(*); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }如果前端用Nginx托管那更推荐在Nginx层做反向代理来避免跨域这样前端只请求同源地址后端接口通过/api/前缀转发。部署时把前端build出来的dist目录放到Nginx的html目录下Nginx配置里加上location /api/ { proxy_pass http://127.0.0.1:9090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }6.4 打包部署从mvn package到服务器上运行项目开发调试完成后打包部署是答辩前必须做的一项演练。后端打包命令mvn clean package -DskipTests打包成功后target目录下会生成一个可执行Jar包在服务器或本机上运行java -jar elder-care-server.jar --spring.profiles.activeprod如果服务器资源紧张可以用-Xms256m -Xmx512m限制JVM堆内存避免被系统杀掉进程。数据库初始化的时候我是用SpringBoot的spring.sql.init配置自动执行schema.sql和data.sql的但要注意data.sql里的中文注释和特殊字符文件编码必须是UTF-8否则启动时报乱码或语法错误。如果你要给答辩老师演示建议提前准备两种运行方式一是本机IDE启动方便现场改代码和看日志二是打包好的Jar包放桌面万一IDE出问题双击命令行就能跑起来。这两种方式都验证过现场才叫“稳定”。7. 从毕设到可用产品还有哪些值得扩展和深挖的方向7.1 数据可视化运营驾驶舱的BI图表怎么做基础版做完很多同学的下一步是加图表。管理端的首页如果能放几张统计图展示“当前入住人数”“今日护理记录数”“近7日费用收入趋势”“护理等级分布饼图”整个系统的完成度立刻上一个档次。实现方式有两种。第一种是后端用GetMapping(/dashboard/summary)一次性返回聚合数据前端用ECharts渲染。比如近7日收入趋势可以用下面的SQL查出来SELECT DATE(bill_date) AS day, SUM(fee_amount) AS total_amount FROM fee_bill WHERE bill_date DATE_SUB(CURDATE(), INTERVAL 6 DAY) GROUP BY DATE(bill_date) ORDER BY day;另一种是后端直接生成图片用Hutool的ChartUtil或JFreeChart不过图片方式交互感差不如ECharts。我自己的习惯是后端只管出数据前端拿ECharts画图灵活性最高。7.2 消息通知与异常预警从“被动记录”到“主动干预”养老场景里最有价值的不是“录入了数据”而是“数据能触发行动”。比如老人的血压记录连续三天高于阈值或者当天某位老人没有护理记录系统应该主动提醒护工组长或家属。这个功能在毕设里可以做得很轻量在care_record表新增记录时后端判断血压值是否超过预警线如果超过就在alert_message表插入一条预警记录并标记is_read0。管理端首页循环展示未读预警消息家属端同步展示对应老人的健康预警。触发方式可以是在Service层主动判断也可以是做一个定时任务扫描“前一天无护理记录”的老人列表。虽然这个模块不复杂但它体现了“业务闭环”的思维——数据采集、逻辑判断、行动触达三个环节链路完整。答辩时把这个例子讲出来比单纯说“我的系统能查询”有说服力得多。7.3 移动端适配与小程序方向厚度还是单点突破关于移动端我不建议纯毕设阶段去碰小程序或者App因为工作量大且容易被微信审核、打包签名等环境问题拖累。如果一定要做可以退而求其次把前端管理页面用响应式框架做适配至少保证家属端在手机上能显示完整或者做一个极简的移动端HTML页面只包含“查看今日护理动态”和“探访预约”两个功能。这样在答辩中提及“考虑了移动端场景”即可不需要真的做到全面移动化。7.4 代码质量与注释规范答辩老师的隐形评分项最后提一个最容易被人忽略、但在答辩中直接影响印象分的点代码质量。老师翻项目源码时第一眼看的是三个地方——命名规不规范、注释有没有、异常处理是否统一。所以这几个习惯我从项目一开始就会刻意养成实体类、Mapper、Service、Controller按分包组织不搞一堆类全扔在一个包。ServiceImpl里的业务方法至少写一行方法级注释说明“这个方法是干什么的、有没有返回值、可能抛什么异常”。Controller统一返回Result对象包括code、msg、data三个字段前端判断code200才能拿data避免到处散落Map结构。所有查询接口都做参数校验需要分页的就用分页参数不要一次全查出来返给前端。这些看起来都是小事但它们决定老师在翻代码时是“一目十行地扫”还是“停下来细看、觉得你还挺专业”。我见过不少功能完成度很高但代码乱成一锅粥的项目最后只拿到中等评分真的很可惜。8. 实操经验分享我从这个项目里学到的三件事第一件把一个业务链路完整走通比堆砌一堆孤立的CRUD有价值得多。我做这个养老服务平台最深的体会是真正的难点不在某个技术点本身而在于“评估完了怎么联动生成计划”“生成计划后怎么关联日常护理记录”“有了护理记录怎么自动算费用”这些跨表联动。每一个联动都不难但串起来的时候需要对业务有整体理解。毕设做完简历上写“熟悉养老服务业务流程和系统设计”这句话的分量就是从这些联动里来的。第二件版本兼容性和环境问题会吃掉你大半的调试时间。我在6.1里提到的Druid和MyBatis-Plus的冲突还有MySQL时区问题都不是代码逻辑上的疑难杂症但任何一个都能卡住半天。所以现在我做任何项目都有一个固定动作先把pom.xml里的所有依赖版本号写死然后用一个最小启动类测试数据库连接和日志输出确认基础环境通畅后再开始写业务代码。这个步骤虽然浪费十分钟但能防止整个项目做到一半才暴露环境问题。第三件主动展示自己的思考比被动完成功能更能拿到高分。答辩时老师不会只看运行效果他还想知道“为什么选这个方案”“有没有考虑过其他方案”“这个表为什么这样设计”。你如果在代码里、文档里、答辩PPT里主动埋好了这些答案的分支比如“为什么评估分数要单独建表而不是存字符串”“为什么探访预约要做状态机”讲出来就是亮点等着被点名问再回答气势就矮了一截。我的建议是不要把这个项目当成一个例行的“增删改查作业”来做。养老这个场景是有真实温度的你在设计护理记录时间轴、家属探访预约这些功能时如果能带着“真的有一个护工在用我做的系统记录老人的体温”“真的有一个家属在看我做的页面了解家里老人的日常”这样的画面去写代码你会自然而然地去关注那些“小而重要”的细节——比如记录提交后有没有给家属端即时反馈比如老人档案导出Excel时中文文件名会不会乱码。这些细节恰恰是让一个系统从“能用”走向“好用”的分水岭。