ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

社区空巢老人照管系统毕业设计:Spring Boot+Vue完整实现与部署指南

社区空巢老人照管系统毕业设计:Spring Boot+Vue完整实现与部署指南 1. 项目背景与整体设计思路1.1 这个毕设到底在做什么社区空巢老人照管系统这个词乍一看有点长但拆开就很好理解面向城市社区场景用一套信息化的工具把独居、空巢老人的基础档案、健康状态、走访记录、家属联系方式这些散落的信息统一管起来让社区工作人员不再靠Excel和纸质台账过日子。我在帮不少同学梳理毕业设计时发现这类题目的痛点是相通的。你说它复杂吧它本质上就是几套增删改查的叠加你说它简单吧如果只做一堆孤立的CRUD页面答辩时被老师追问业务闭环又会被堵得说不出话。所以这个项目的关键点不在代码量而在你是否把“照管”这件事讲明白了——谁在管、管什么、怎么发现问题、怎么通知家属、怎么留痕。从题目自带的“部署教程可完整运行源码数据库”这几个关键词也能看出这类毕设的交付物不只是源码而是一套别人能拿过去直接跑起来的东西。也就是说你不仅要写代码还要写清楚怎么把环境搭起来、数据库怎么导入、前端怎么启动这也是很多零基础同学最容易卡住的地方。1.2 核心用户与功能模块拆解做这个系统之前先别急着写代码你得像项目经理一样盘一遍用户。这个系统按我惯用的思路会拆成三类角色系统管理员、社区工作人员、老人家属。管理员负责账号分配和数据兜底工作人员负责日常走访、健康记录、服务工单的维护家属可以查看自己老人的基础照管状态有些毕设里家属端不做登录通过工作人员的分享链接或导出报告代替这个看你课题要求。对应的功能模块大概有六个老人档案管理、健康信息管理、走访/服务记录管理、提醒事项管理、数据统计看板、系统管理用户/角色/菜单。把这六个模块列出来你的系统骨架基本就立住了剩下的都是往里面填血肉。我特别建议在健康信息管理里加一个“健康异常标记”字段。很多同学只做体检数据、血压血糖的录入和展示但社区工作人员真正需要的是一眼看出这个老人今天是否需要重点关注。有了异常标记再配合一个“待回访列表”整个系统的业务感马上就出来了答辩时老师也会觉得你确实思考过实际场景而不是只会写CRUD。1.3 技术选型为什么这么定毕业设计的技术栈我的建议永远是“稳妥优先别玩花活”。这套系统我推荐用最经典的前后端分离组合后端Spring Boot 2.7.x MyBatis Plus MySQL 8.0前端Vue 2 Element UI。Spring Boot让项目结构和依赖管理变得非常简单不需要像早期SSH那样写一大堆XML配置MyBatis Plus能把单表的增删改查压缩到极致适合毕设这种以业务功能展示为主、没有复杂SQL优化的项目Vue 2 Element UI则是因为网上资料多遇到问题搜一下就有一堆解决方案。为什么不用Spring Boot 3因为Spring Boot 3强制JDK 17部分老电脑或学校机房环境装的是JDK 8直接踩版本坑。为什么不用Vue 3不是不行是Composition API和Element Plus的学习成本比Vue 2高一截对于需要快速把功能堆出来的毕设来说Vue 2的Options API配合Element UI写起来更顺手模板示例也多。记住一个原则毕业设计的核心是完整度不是技术新度。2. 数据库设计与核心表结构2.1 数据库设计的原则与思路有些同学一上来就建二三十张表表之间外键拉满觉得自己设计得很“全面”结果后期自己写SQL都绕晕了。数据库表设计要跟着页面走页面上要展示哪些字段表里就落哪些字段反过来页面展示需要的字段如果表里没有再考虑是加字段还是加关联表。这个系统的表设计我的方案是七张核心表加两张辅助表。核心表包括用户表admin/staff两类账号、老人信息表、家属表、健康记录表、走访/服务记录表、提醒事项表、通知公告表。辅助表包括字典表存放性别、健康异常级别、服务类型这类枚举值和操作日志表。这个量级的表对于毕设来说刚好太少了撑不起功能展示太多了维护成本高老师问起来你还要花大量时间解释每张表的作用。关于外键我的建议是逻辑外键不要物理外键。什么意思比如老人信息表里的社区字段你不需要真的去建一个外键约束只需要在逻辑维护的时候保证数据一致即可。物理外键在删除数据、批量导入的时候特别容易报错而毕设项目里数据量不大逻辑外键完全够用还能让你的SQL活很多。2.2 老人信息表与健康记录表的核心字段老人信息表是整个系统的数据底座字段设计直接决定后面功能好不好写。我列一下核心字段你们参考时根据自己的课题调整即可。CREATE TABLE elder_info ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键, name varchar(32) NOT NULL COMMENT 姓名, gender tinyint(1) DEFAULT 1 COMMENT 性别 1男 2女, age int(11) DEFAULT NULL COMMENT 年龄, id_card varchar(18) DEFAULT NULL COMMENT 身份证号, phone varchar(20) DEFAULT NULL COMMENT 联系电话, address varchar(255) DEFAULT NULL COMMENT 居住地址, community varchar(64) DEFAULT NULL COMMENT 所属社区, health_status varchar(16) DEFAULT 正常 COMMENT 健康状态 正常/关注/高风险, emergency_contact varchar(64) DEFAULT NULL COMMENT 紧急联系人, emergency_phone varchar(20) DEFAULT NULL COMMENT 紧急联系电话, elder_type varchar(32) DEFAULT NULL COMMENT 老人类型 空巢/独居/失能, remark varchar(500) DEFAULT NULL COMMENT 备注, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 COMMENT老人信息表;健康记录表主要记录每次走访或体检时老人的血压、血糖、心率等指标然后关联老人ID。这里有个细节健康指标的计量单位一定要写清楚血压的mmHg、血糖的mmol/L不然以后做数据统计时数值单位对不上出来的图表没法看。另外建议加一个“记录来源”字段标注是系统录入还是家属填写便于追溯。2.3 初始化数据与常见坑点数据库脚本除了建表语句一定要带上初始化数据。至少要有一个管理员账号admin / admin123密码建议MD5或BCrypt加密后的值、一个工作人员账号、三五个老人演示数据以及对应的健康记录和走访记录。这样部署方导入SQL后一打开系统就能看到数据不用自己手动造。很多所谓的“完整源码”数据库是空的演示效果大打折扣也显得开发者不专业。导入SQL时容易出的问题有两个。第一是字符集建库语句里最好明确指定utf8mb4CREATE DATABASE eldercare_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;不然你中文数据导入MySQL后全是问号。第二是SQL执行顺序如果在MySQL客户端里直接粘贴执行包含多个表的脚本要确保表之间没有循环引用否则会报“无法创建外键”的错误。我提供的逻辑外键方案从根源上就规避了这个坑。3. 后端核心实现与源码导读3.1 项目目录结构拿到源码先看哪里拿到一份完整源码最忌讳的就是CtrlF到处找文件找不到就慌。你要先看目录结构。这套系统后端用的是标准的Maven结构src/main/java/com/eldercare ├── common # 通用工具类、统一返回结果、异常处理 │ ├── Result.java │ ├── ResultCode.java │ └── GlobalExceptionHandler.java ├── config # 配置类包括跨域、MyBatis Plus分页插件 ├── controller # Controller层接收前端请求 ├── entity # 实体类对应数据库表 ├── mapper # MyBatis Plus的Mapper接口 ├── service # Service接口 └── service/impl # Service实现类拿到项目后第一步先看application.yml它包含了端口、数据库连接信息、MyBatis Plus日志配置等最关键的运行参数。第二步看common/Result.java弄明白接口的统一返回结构是什么。第三步找一个完整的Controller从入口开始捋一遍请求是怎么走的。这三步走下来你对这个项目的理解能达到70%。3.2 登录鉴权与拦截器的实现逻辑登录鉴权如果你用Spring Security光各种配置和过滤器链就能折腾一整天对毕设来说性价比不高。我更推荐用JWT 拦截器的方案既好讲清楚原理代码量也不大。思路是这样的用户拿着账号密码请求登录接口后端校验通过后用JWT工具类生成一个token把用户ID和用户名塞进去返回给前端。前端每次请求都在header里带上Authorization: Bearer token。后端写一个拦截器拦截所有/api/**请求放行登录接口在拦截器里解析token解析失败就返回401。public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; // 放行预检请求 } String token request.getHeader(Authorization); if (token null || token.isEmpty() || !JwtUtil.validateToken(token.replace(Bearer , ))) { response.setStatus(401); response.getWriter().write({\code\:401,\message\:\未登录或登录已过期\}); return false; } return true; } }这里有个细节值得在答辩时讲清楚为什么要放行OPTIONS请求。因为当前端和后端在不同的端口时比如前端8080、后端9090浏览器跨域访问会先发一个预检请求如果你把OPTIONS也拦截了前端真实请求根本到不了后端控制台报的全是跨域相关错误。这个问题我们在第5章部署时会再次遇到。3.3 老人档案模块的增删改查是怎么写的用MyBatis Plus写单表CRUD是真的省力。实体类继承BaseEntity后Mapper接口只需继承BaseMapperElderInfoService实现类继承ServiceImpl你甚至不需要写一行SQL基础方法就全有了。RestController RequestMapping(/api/elder) public class ElderInfoController { Autowired private ElderInfoService elderInfoService; GetMapping(/list) public Result list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, String name, String healthStatus) { LambdaQueryWrapperElderInfo wrapper new LambdaQueryWrapper(); if (StringUtils.hasText(name)) { wrapper.like(ElderInfo::getName, name); } if (StringUtils.hasText(healthStatus)) { wrapper.eq(ElderInfo::getHealthStatus, healthStatus); } wrapper.orderByDesc(ElderInfo::getId); PageElderInfo page elderInfoService.page(new Page(pageNum, pageSize), wrapper); return Result.success(page); } PostMapping(/save) public Result save(RequestBody ElderInfo elderInfo) { elderInfoService.saveOrUpdate(elderInfo); return Result.success(); } DeleteMapping(/delete/{id}) public Result delete(PathVariable Long id) { elderInfoService.removeById(id); return Result.success(); } }注意我把新增和修改整合成了一个saveOrUpdate接口。为什么这么设计因为前端页面上新增弹窗和编辑弹窗长得一模一样提交时前端只需要判断一下当前有没有ID有ID就带上ID请求同一个接口后端通过ID是否存在决定插入还是更新。这样做可以减少前端冗余代码也避免了两套接口的维护成本。这个设计同样可以在答辩时作为经验点讲。3.4 健康异常提醒的核心筛选逻辑前面提到的“待回访列表”听起来很有业务感但实现其实就是一个条件查询。我在健康记录表里加了一个abnormal_flag字段当工作人员录入健康记录时如果某项指标超出正常范围就把它标记为1。然后写一个查询接口关联老人信息表和健康记录表过滤出近7天内有过异常标记的记录同时排除掉状态已经是“高风险”或“已处理”的老人。用SQL表达就是先把健康记录表按老人ID分组取最新的一条保留异常标记为1的再和老人信息表关联。这个查询用MyBatis Plus的LambdaQueryWrapper也能做但字段多的时候直接写SQL注解更清晰。说到底业务功能的亮点不需要复杂的算法只要你的筛选逻辑贴合实际管理工作流效果就很好。4. 前端页面与交互设计4.1 前端项目结构与路由设计前端项目我用的是Vue 2 Element UI Axios。目录结构如下src ├── api # 接口请求封装按模块拆分文件 ├── assets # 静态资源 ├── components # 公共组件 ├── layout # 整体布局包括侧边栏、顶栏 ├── router # 路由配置 ├── store # Vuex状态管理 └── views # 页面视图 ├── elder # 老人档案 ├── health # 健康记录 ├── visit # 走访记录 ├── dashboard # 数据看板 └── system # 系统管理路由设计上我用的是静态路由 动态菜单。也就是说动态菜单是用后端返回的菜单列表渲染出来的路由表则提前在router里全部配好只是通过菜单的isShow字段控制是否显示。为什么这么做因为真正的动态路由需要在用户登录后根据权限addRoute加载逻辑比较复杂。毕设阶段用菜单显隐控制就能达到“不同角色看到不同功能”的展示效果也够用了。4.2 老人档案列表页的核心代码列表页是后台管理系统出现频率最高的页面形态我直接贴一段最核心的表格 分页代码你们参考时替换成自己的接口即可。template div el-form :inlinetrue el-form-item label老人姓名 el-input v-modelquery.name placeholder请输入姓名 clearable / /el-form-item el-form-item label健康状态 el-select v-modelquery.healthStatus placeholder请选择 clearable el-option label正常 value正常 / el-option label关注 value关注 / el-option label高风险 value高风险 / /el-select /el-form-item el-form-item el-button typeprimary clickloadData查询/el-button /el-form-item /el-form el-table :datatableData border stripe el-table-column propname label姓名 width90 / el-table-column propage label年龄 width60 / el-table-column propcommunity label所属社区 / el-table-column prophealthStatus label健康状态 template slot-scopescope el-tag :typescope.row.healthStatus 高风险 ? danger : warning {{ scope.row.healthStatus }} /el-tag /template /el-table-column el-table-column label操作 width200 template slot-scopescope el-button typetext clickopenEdit(scope.row)编辑/el-button el-button typetext clickshowDetail(scope.row)详情/el-button el-button typetext classdanger clickdeleteElder(scope.row.id)删除/el-button /template /el-table-column /el-table el-pagination current-changehandlePageChange :current-pagequery.pageNum :page-sizequery.pageSize :totaltotal layouttotal, prev, pager, next / /div /template页面本身没什么难度重点在于接口封装。我习惯把每个模块的请求单独放到src/api/elder.js里统一使用一个axios实例baseURL指向/api然后在Vue项目的根目录配置一个代理把/api转发到后端地址。这样做的好处是开发时后端端口怎么变前端代码完全不用动只要改代理配置就行部署时也能灵活切换。4.3 前后端联调、跨域与代理配置前后端联调最大的敌人是跨域但问题本身并不难解决。开发阶段我推荐用Vue CLI的devServer.proxy解决而不是在后端代码里写CrossOrigin。因为CrossOrigin是后端允许跨域访问生产环境部署时如果前后端同域反而多了一层奇怪逻辑用前端代理则只是开发阶段有效部署后无残留。// vue.config.js module.exports { devServer: { port: 8080, proxy: { /api: { target: http://localhost:9090, changeOrigin: true } } } };这样配置后前端发出的/api/elder/list请求在开发环境会被代理到http://localhost:9090/api/elder/list。注意后端Controller的映射是RequestMapping(/api/elder)也就是说代理只转发了域名和端口路由路径在后端仍然是完整的/api/**两边统一带/api前缀是约定别在中间随意增删前缀。5. 本地部署教程从零到可完整运行5.1 环境准备与版本对应关系部署这个项目环境这一关能拦住一半以上的人。不是说安装环境本身多难而是版本之间相互不兼容装完了启动时才报错排查起来没有头绪。我列一下这套系统最稳妥的环境组合你们照抄即可。开发工具和后端环境方面JDK 1.8这是Spring Boot 2.7的默认适配版本、Maven 3.6.x、IntelliJ IDEA 2020及以上社区版也可。MySQL建议8.0以上5.7也能跑但一些SQL语法和驱动配置会有差异用8.0省事。前端环境Node.js 14到16之间的版本npm会随Node自动安装。如果Node版本太高比如18、20以上部分旧依赖在编译时可能报错。数据库客户端推荐Navicat学校机器普及率高可视化操作简单。如果用的DataGrip或MySQL Workbench也行核心操作都是新建数据库、运行SQL脚本、查看表数据。5.2 后端部署详细步骤后端从零到启动我用五步总结。先别急着点绿三角运行按顺序检查一遍能避免大量无谓报错。第一步导入项目。打开IDEA选择File - Open选中项目根目录的pom.xml导入方式选“作为Maven项目”。IDEA会开始下载依赖这一步需要联网如果等了很久没动静检查IDEA的Maven配置是否指向了国内镜像可以用阿里云Maven仓库镜像。第二步创建数据库并导入SQL脚本。在Navicat里新建数据库名字和application.yml里的database参数保持一致。然后右键数据库选择“运行SQL文件”选中项目根目录下的sql/eldercare.sql执行完毕后刷新能看到所有表和初始化数据。第三步修改配置文件。打开application.yml逐一核对端口号、数据库地址、用户名、密码。重点关注server.port和spring.datasource.url数据库URL里注意时区参数MySQL 8.0必须带serverTimezoneAsia/Shanghai否则会报时区相关的错误。第四步启动入口类。在项目结构里找到EldercareApplication.java右键运行。启动成功的标志是控制台出现Spring Boot的启动日志并且最后的启动时间旁边没有ERROR字样。初次启动如果有报错90%是数据库连接的问题按第三步继续排查。第五步验证接口。浏览器访问http://localhost:9090/api/elder/list如果返回JSON数据说明后端已经就绪。如果返回404别慌大概率是接口路径写错了去Controller里核对一下RequestMapping注解与数据库数据。这里要明确一点后端启动没有任何页面反馈是正常的因为这是前后端分离项目页面得靠前端跑。5.3 前端部署详细步骤前端部署比后端简单但坑也不少。同样是五步。第一步用IDEA或VS Code打开前端目录elder-web。如果你是第一次打开项目里还没有node_modules文件夹别急这是正常的。第二步在项目根目录打开终端执行npm install。这一步会安装所有依赖根据网络速度通常要两三分钟到十几分钟不等。如果中途报各种红字错误往下看5.4节的处理方法。第三步确认vue.config.js里的代理配置正确然后执行npm run serve。启动成功后控制台会显示本地访问地址一般是http://localhost:8080。第四步浏览器打开http://localhost:8080用初始化数据里的管理员账号登录如果能进去看到数据面板说明前后端对接成功。第五步确认登录接口能通。打开浏览器F12开发者工具点一下登录按钮看Network面板里登录请求的响应状态。200说明正常401说明token或账号不对500说明后端报错根据状态码再定位问题。5.4 我踩过的部署Bug汇总第一个Bugnpm install极慢或卡住。解决办法是先设置npm淘宝镜像源npm config set registry https://registry.npmmirror.com再重试。如果项目里某些包被墙或版本冲突删除package-lock.json后再install。第二个BugMySQL连接报Access denied for user rootlocalhost。这通常不是你密码错了而是MySQL授权的host匹配问题。最简单的解决办法是用root账号重新授权一下选做授权前确认你清楚自己在做什么或者直接在Navicat里新建一个专门给项目用的账号和密码然后把application.yml改成新账号。第三个Bug后端启动成功前端页面死活加载不出数据。先确认前端代理是否生效方法是在Network面板看请求实际发到了哪个地址。如果请求直接发到了http://localhost:8080/api/...并且报404说明代理可能没重启。Vue.config.js修改后必须重启npm run serve改动才会生效。这个坑我踩过不下三次每次都是改完代理忘了重启。第四个BugElement UI 的图标不显示。通常是main.js里没有引入图标库或者主题文件路径不对。处理方案是检查main.js是否引入了element-ui/lib/theme-chalk/index.css和element-ui/lib/theme-chalk/fonts目录静态资源。必要时把字体文件放到public目录下。6. 答辩准备和代码二次扩展建议6.1 功能演示怎么讲才不冷场答辩时间一般只有五到十分钟别照着页面从头到尾念一遍。我建议按“业务痛点 → 核心流程 → 亮点功能”的顺序来。开场先花30秒讲清楚背景社区空巢老人数量上升纸质台账管理效率低、发现问题不及时所以做了这个系统。然后演示一个完整闭环新增老人档案 → 录入健康记录并触发异常标记 → 在待回访列表看到老人 → 生成走访记录 → 通知家属。走通这一条线比你罗列十个功能页面都管用。因为评委老师真正关心的是你有没有把需求吃透、数据怎么流转、遇到问题怎么思考。业务闭环能回答第一个问题数据库表和接口能回答第二个问题而你准备的那一串踩坑记录就是回答第三个问题的弹药。6.2 老师最爱问的几个问题根据历年答辩反馈关于这套系统的高频提问集中在三块。第一块是权限控制“不同角色的权限是怎么实现的”你只要回答用户表有role字段后端拦截器校验角色前端菜单用v-if配合角色字段控制显隐就够了不要扯到RBAC太深。第二块是数据安全“管理员密码是明文存储的吗”如果你用了MD5或BCrypt就如实说明并展开两句如果没做加密答辩前最好加上这属于安全性问题被问到就露怯了。第三块是设计理由“为什么健康记录不直接建在老人表里”这个问题也是送分题你回答“因为健康记录和老人是一对多关系一个老人会有多条历史健康记录拆表方便做历史趋势和数据分析”老师一般不再追问。6.3 代码还能怎么扩展出亮点如果做完上述功能还有余力我推荐按难度从低到高扩展设计。低难度是给老人档案模块加一个批量导入Excel功能使用EasyExcel或POI一般在刷新页面后看不到现象但老师现场让你演示时效果出人意料的好。中难度是加一个ECharts可视化看板把老人的年龄段分布、健康状态占比、各社区老人数用饼图柱状图展示出来。ECharts这种数据可视化内容天然有视觉冲击力演示的时候打开一个图表大盘比展示十个表格管用得多。前端实现也不复杂Vue中引入echarts组件在mounted钩子里请求后端统计接口把数据塞进setOption里即可。高难度是接入RabbitMQ或定时任务做每日健康提醒。比如每天早上九点自动给社区工作人员推送今天的走访提醒清单。这个功能能展示你对异步处理的理解但如果你之前没接触过消息队列不建议临答辩前突击引入容易翻车。7. 写在最后的几点体会做这类照管系统的毕设我个人的感受是最终答辩成绩往往不取决于你的技术有多深而取决于你能不能把自己的设计讲成一个让人信得过的故事。技术方面Spring Boot加Vue这套组合管够真正拉开差距的是你说清楚了这个系统能为真实的社区工作带来什么变化。如果你拿到源码后感觉一团乱麻我的建议是先别碰代码花一下午画三张图一张角色用例图、一张功能结构图、一张核心业务的流程图。三张图画完整个项目在你脑海里就会长成一个可以随意进出的房子而不是一堆乱七八糟的房间。之后无论改代码、写论文、做PPT、应付答辩你都有清晰的脉络。最后再分享一个小技巧部署时一定要把application.yml里的数据库密码和你本机的MySQL密码保持一致这个看起来最不起眼的地方卡住的人其实最多。你先把环境跑通再回头研究源码整个过程会顺畅很多。
返回列表