☰
Java毕设实战:养老院管理系统架构设计与核心实现解析
2026/10/7 6:29:23 网站建设 项目流程

简介:面向计算机及相关专业毕业设计场景,一套基于Java的敬老院管理系统毕业设计资源包,涵盖源码、数据库、论文与操作演示视频,为开发者和学生提供一站式参考。系统围绕敬老院日常管理设计,包含系统管理员与护工两类用户,覆盖老人信息管理、床位分配、护工薪资、请假记录、事故记录等模块的增删改查,可快速搭建可运行的养老机构管理后台。压缩包共15个文件,大小约69.38MB,除源代码zip外,还包括sql数据库脚本、部署演示视频、功能讲解视频、毕业论文doc及毕业答辩PPT、中期检查表等,文件类型贯穿编码、建库、部署和答辩全流程。目前已有748人学习下载,适合需要完成毕业设计或课程项目的学生参考,可通过视频掌握部署与操作,结合源码和论文进行二次开发与论文撰写。

1. 养老院管理系统这个Java毕设:为什么值得你认真对待它

每年到毕设季,这种标题的压缩包都会被反复下载。它承诺的不只是一段能跑的代码,而是一套“源码+视频+数据库+论文”的完整交付物。敬老院管理系统本质上就是一个标准的管理信息系统:用Java把老人档案、床位分配、护理记录、费用收缴这几条业务线管起来,替代手工台账和Excel表格。系统本身并不复杂,但胜在业务完整、技术栈经典,所以成了Java Web入门和毕业设计里被复现最多的项目之一。适合两类人:一类是急着交毕设或课程设计的学生,另一类是想要一套真实业务来打通Java后端三层架构的自学者。

2. 架构与技术选型:先搞清这套系统的技术栈再动手

2.1 拆业务模块:先有需求边界,才有技术选型

我不建议拿到压缩包就直接去跑代码。先看它的功能列表,确认边界。绝大多数敬老院管理系统的模块划分是长这样的:登录认证(管理员、护理员、财务三种角色)、老人档案管理(基本信息、家属联系人、健康状态)、房间床位管理(楼栋—房间—床位三级结构)、入住退住办理(办入住、换床、退住结算)、护理记录(每日护理、用药提醒)、费用管理(床位费、护理费、伙食费收缴记录)。

为什么先拆模块?因为这决定了数据库要建几张表、Controller要写多少个接口,也决定了你后面改需求时动哪里。这正好是Java面向对象编程的设计思路:先抽象对象,再落库,再写操作逻辑。如果你一上来就盯着代码看,很容易被琐碎的增删改查淹没,看不到业务的骨架。

对于这个系统的业务量级,用单体的三层架构就足够了,不需要微服务、不需要Redis缓存,硬上反而会拖慢你理解业务的进度。这一点在论文的“可行性分析”章节里也站得住脚:技术选型匹配业务复杂度,本身就是设计能力。

2.2 拿到源码后,先确认它是SSM还是Spring Boot

标题里只写了“基于Java”,这没说到关键点上。同一套业务的Java实现,市面上既有SSM(Spring + Spring MVC + MyBatis)的老项目,也有Spring Boot + MyBatis的新项目,两种都叫“基于Java”。

怎么快速区分?我一般看三个地方。第一,看pom.xml的parent节点:如果引用的是spring-boot-starter-parent,就是Spring Boot;如果没有parent,只有一堆spring-webmvc、mybatis-spring坐标,就是SSM。第二,看配置文件名:Spring Boot是application.properties或application.yml;SSM是applicationContext.xml加spring-mvc.xml。第三,看启动方式:有没有一个带@SpringBootApplication注解的XxxApplication类。

我把两种技术栈的差异整理成一张表,方便你拿到压缩包后对号入座:

对比项SSM老项目Spring Boot项目
配置文件applicationContext.xml + spring-mvc.xml,配置分散在多个XMLapplication.yml或application.properties,集中管理
启动方式打成war包丢进Tomcat的webapps目录内嵌Tomcat,直接java -jar或右键main方法
静态资源放webapp/static,需要手动配置资源映射放src/main/resources/static,开箱即用
依赖管理坐标多且版本要自己对齐parent统一管理版本,坐标明显减少
适合人群想理解Spring老式XML装配的人想尽快跑通并用于毕业设计/面试讲解的人

我自己的习惯是:如果拿到的是SSM老包,且你只是想交作业,优先按SSM原样跑通,不要中途换框架;如果你要拿这套系统去面试讲项目,建议花两周迁到Spring Boot,因为现在Java开发工程师面试题里问Spring Boot的频率远高于SSM,你讲项目时用Spring Boot也更贴近当前岗位的主流需求。

2.3 JDK、MySQL、Tomcat版本搭配:先对齐再运行

这类压缩包最容易翻车的不是代码,是版本环境。我看过很多同学因为JDK版本不对,Tomcat直接变成黑匣子,日志里全是看不懂的字节码异常。给你一套我常用的、兼容性最好的搭配:

组件推荐版本说明
JDK8老项目里大量jar对JDK 17不兼容,尤其cglib和旧版Tomcat
MySQL5.7或8.05.7对老项目最省事,8.0需换驱动类名,见第5章
Tomcat8.5或9.0不要上Tomcat 10,javax.servlet会被替换成jakarta.servlet,老代码直接编译不过
Maven3.6.3对老仓库兼容性最好
开发工具IDEA 2021及以上自带Maven与Git支持,开箱即用
数据库工具Navicat或DBeaver用来核对数据字典和执行SQL脚本

注意一个关键点:如果项目里用的是JSP,那必须配外置Tomcat;如果是前后端分离(后面章节会讲改造方案),Tomcat只是内嵌资源服务器,二者的部署路径完全不一样。这一点决定了你能不能从“跑起来”走向“部署到服务器上给答辩老师演示”。

2.4 数据库连接配置:让MyBatis正确找到MySQL

不管是SSM还是Spring Boot,第一步都是先把数据库连上。Spring Boot的application.yml长这样:

server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/jinglao?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.jinglao.entity

逻辑说明:先把端口定为8080,datasource节点告诉Spring Boot去哪找MySQL。mybatis.mapper-locations指向XML文件的位置,type-aliases-package让实体类在XML里写resultType时不用带全限定类名。这套配置是这个项目的命门,连不上数据库时九成问题出在url参数上。

参数说明:url里有三个参数值得记。useUnicode=true&characterEncoding=utf8,防止存入的中文变成问号;useSSL=false,本地开发关掉SSL握手,否则MySQL 8会打印一堆警告甚至连接失败;serverTimezone=Asia/Shanghai,MySQL 8对时区敏感,不加会直接报时区错误。

如果是老SSM项目,上面内容对应在jdbc.properties里,键名不同但参数完全一样。改完之后,先用Navicat手工连接一次数据库,确认账号密码没问题,再去启动项目。这一步能隔离掉很多“代码看起来没问题但就是连不上”的玄学问题。

3. 数据库设计:敬老院业务的核心是“人、床、护理、费用”四条线

3.1 表结构拆解:八张核心表,四条业务线

整个敬老院系统,本质上就管理四件事:人、床位、护理、费用。对应到数据库里,八张核心表就能把这四条线完全撑起来。

人线有三张表:user(登录用户,也是员工)、old_person(老人)、family(家属)。有的系统会把家属的联系方式直接塞进old_person表里,省掉family,这样做不是不行,但老人有多个子女时数据就冗余了,家属信息改动还要去改老人表,耦合严重。

床位线有三张表:room(房间)、bed(床位)、check_in(入住记录)。注意room和bed分开建,不要只用bed.room_no字符串表示房间,否则统计“哪个房间住了几个人”时要靠字符串截取,这是典型的低质量设计。

护理线和费用线各一张核心表:nursing_record(护理记录)和pay_record(缴费记录)。再加上一张可选的health_record(健康档案)用于存放体检和用药信息,这套系统的库表设计就完整了。

3.2 老人和床位为什么要用check_in表解耦

这是整个表设计里最关键的决策点,也是论文里最好写的设计亮点。新手最容易犯的错误是:在old_person表里加一个bed_id字段,表示老人当前睡哪张床。

看起来简单,但遇到换床就麻烦:老人从301搬到302,你得UPDATE old_person,而且历史记录丢了,当初谁住过这张床完全查不到。如果哪天要统计床位周转率,你得靠日志或者翻台账,数据库里没有痕迹。

正确做法是引入check_in入住关系表。一个老人可以有多条入住记录,每条入住记录指向一张床和一个时间段。同一时间段内一张床不能分配给两个人——这个约束在Service层校验,而不单纯靠数据库。这种设计在表关系上就是old_person与bed之间的多对多,通过check_in解耦成一对多。

这也是“面向对象”思想落到关系数据库的经典例子:对象之间有复杂的关联关系,不该用加外键字段的方式硬塞,而是抽出一张关系表来承载生命周期。答辩时老师如果问“你的数据冗余在哪里、重复入住怎么处理”,这段话可以直接用。

3.3 核心建表SQL:给出一份可直接执行的DDL

下面是这套系统里老人类、床位表、入住表的核心DDL。表名和字段名我都刻意避开了MySQL关键字,你照抄或者照着改都行。

CREATE TABLE old_person ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '老人ID', name VARCHAR(50) NOT NULL COMMENT '姓名', gender TINYINT NOT NULL DEFAULT 1 COMMENT '性别 1男 2女', id_card VARCHAR(18) UNIQUE COMMENT '身份证号', phone VARCHAR(20) COMMENT '联系电话', health_status VARCHAR(200) COMMENT '健康状况描述', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '建档时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='老人信息表'; CREATE TABLE bed ( id INT PRIMARY KEY AUTO_INCREMENT, room_no VARCHAR(20) NOT NULL COMMENT '房间号,如A-301', bed_no VARCHAR(20) NOT NULL COMMENT '床位号', status TINYINT NOT NULL DEFAULT 0 COMMENT '0空闲 1占用', UNIQUE KEY uk_room_bed (room_no, bed_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='床位表'; CREATE TABLE check_in ( id INT PRIMARY KEY AUTO_INCREMENT, old_person_id INT NOT NULL COMMENT '老人ID', bed_id INT NOT NULL COMMENT '床位ID', check_in_time DATETIME NOT NULL COMMENT '入住时间', check_out_time DATETIME DEFAULT NULL COMMENT '退住时间,NULL表示在住', charge_type TINYINT DEFAULT 1 COMMENT '1自理 2半护理 3全护理', KEY idx_person (old_person_id), KEY idx_bed (bed_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='入住记录表';

逻辑说明:old_person用utf8mb4是因为要存生僻字和特殊符号,身份证号加UNIQUE约束防止重复建档。bed表里room_no和bed_no组合唯一,保证同一房间内床位号不重复。check_in的核心是check_out_time设为NULL表示在住,这样查“当前哪些老人住在哪张床”就变成一条WHERE check_out_time IS NULL语句,非常高效。

参数说明:VARCHAR(18)对应二代身份证的18位;TINYINT存性别和状态,比枚举和INT更省空间;DATETIME默认值用CURRENT_TIMESTAMP,插入时就不用手动填时间。charge_type这个字段很关键,它决定老人的收费标准,费用模块要根据它来计算每月应收。

3.4 字段类型、索引与建表后的修改

我见过大量这种项目的建表SQL,有几个通病帮你提前排掉。金额不用FLOAT或DOUBLE,用DECIMAL(10,2),浮点算钱会精度出错,这是财务模块的底线。性别不用VARCHAR存“男”“女”,用TINYINT加注释,展示层再翻译,这也是后端开发规范。状态字段不要用NULL表示“否”,用0和1,NULL在统计COUNT时会漏数据,逻辑判断也容易出bug。

外键约束可加可不加,但索引一定要加。身份证号、床位状态、入住时间这几个字段的查询频率极高,不加索引到数据量上万时会明显卡顿。如果你的老人在500人左右的规模,可能感受不到差别,但论文里写“针对高频查询字段建立索引”是实打实的设计点。

如果拿到别人的建表脚本想改结构,用ALTER TABLE,比如我给老人表加一个紧急联系人字段,给入住表加一个入住时间索引:

ALTER TABLE old_person ADD COLUMN emergency_contact VARCHAR(50) COMMENT '紧急联系人'; ALTER TABLE check_in ADD INDEX idx_in_time (check_in_time);

这种“mysql数据库修改结构”的操作,在调整数据字典的时候几乎每天都要做。但有一个坑必须提醒你:改完数据库一定要同步更新实体类和Mapper的ResultMap,否则MyBatis查出来的字段全是NULL,而且是那种不报错、纯靠肉眼对比才能发现的诡异问题。

4. 核心功能实现:登录、档案、入住三条代码链路

4.1 登录与权限:拦截器比注解更适合这类单体系统

登录是老生常谈,但实现方式的选择有讲究。Spring Boot项目里最常用的有三种做法:拦截器HandlerInterceptor、过滤器Filter、注解加AOP。对于这种角色少、页面多的单体系统,我一般选拦截器,理由很实际:配置简单,路径匹配直观,而且面试被问“登录拦截怎么实现”时,HandlerInterceptor是标准答案。

先写一个登录接口:

@RestController @RequestMapping("/api/user") public class LoginController { @PostMapping("/login") public Result login(String username, String password, HttpSession session) { // 实际项目里密码要加盐哈希,这里为了演示判断逻辑简化 User user = userService.findByUsernameAndPassword(username, password); if (user == null) { return Result.error("用户名或密码错误"); } session.setAttribute("loginUser", user); return Result.success(user); } }

再写一个拦截器:

public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); User user = (User) session.getAttribute("loginUser"); if (user == null) { // 未登录跳转到登录页,而不是返回JSON response.sendRedirect("/login.html"); return false; } return true; } }

逻辑说明:Result是一个通用返回体,success和error两个静态工厂方法分别返回成功和失败消息。登录成功后把User对象放进Session,拦截器从Session里取,取不到就重定向到登录页,起到保护所有页面的作用。注册拦截器时,需要放行登录接口和静态资源路径,否则会出现“自己都进不去”的死循环。

参数说明:sendRedirect是重定向,浏览器地址栏会变成登录页地址。如果你用response.setStatus(401),前端拿到的是无样式JSON,对传统的JSP页面不友好。如果你想让不同角色看到不同菜单,就在拦截器里再判断user.getRole()后再决定放行还是拒绝,单靠登录拦截还不够,但在这个体量下已经够用。

4.2 老人档案的增删改查:完整的三层架构写法

老人档案是整个系统最基础的功能,也是论文里“系统实现”章节的主体。我给出从Mapper到Controller的一整条链路,这是任何Java管理系统的标准范式。

先是实体类,字段要和数据库一一对应,不要多也不要少:

public class OldPerson { private Integer id; private String name; private Integer gender; private String idCard; private String phone; private String healthStatus; private LocalDateTime createTime; // getter/setter 略,IDE生成即可 }

Mapper接口只写方法签名:

public interface OldPersonMapper { int insert(OldPerson person); int updateById(OldPerson person); int deleteById(Integer id); List<OldPerson> selectList(String keyword); }

对应的XML里,增删改查各一条SQL。给你看两个关键的:

<insert id="insert" parameterType="com.jinglao.entity.OldPerson" useGeneratedKeys="true" keyProperty="id"> INSERT INTO old_person (name, gender, id_card, phone, health_status) VALUES (#{name}, #{gender}, #{idCard}, #{phone}, #{healthStatus}) </insert> <select id="selectList" resultType="com.jinglao.entity.OldPerson"> SELECT * FROM old_person <where> <if test="keyword != null and keyword != ''"> name LIKE CONCAT('%', #{keyword}, '%') </if> </where> ORDER BY create_time DESC </select>

逻辑说明:useGeneratedKeys让数据库自增主键回填到实体的id字段,插入后立刻getId()就能拿到新纪录的ID,后续做关联操作时特别有用。select里的where标签是MyBatis动态SQL,条件为空时整段被去掉,keyword只做模糊搜索,搜索条件是动态拼出来的。

参数说明:LIKE的CONCAT写法能防止SQL注入,不要直接传“%”加keyword加“%”拼接。ORDER BY create_time DESC让新建档的排前面,管理端体验好。如果你要把关键字改成同时匹配姓名、身份证号、手机号,就在if标签里多加两个OR条件,查出来的结果集更实用。

Service层再做业务校验,比如身份证号不能重复、姓名不能为空,然后调用Mapper。Controller只管接收参数、调Service、返回Result。这一套写下来,你就把Spring容器里常说的“依赖注入”“组件职责”这些概念对上了:Controller依赖Service,Service依赖Mapper,全部交给Spring管理。

4.3 入住办理:为什么必须加事务

入住不是一个insert就能完事的事。一次入住动作,在业务上要完成三件事:把床位状态改为占用、插入一条check_in入住记录、给该老人生成初始护理计划。这三件事要么全成功,要么全失败。

Java里用@Transactional解决。我习惯加到Service实现类上,而不是Controller,因为事务边界属于业务逻辑,不属于接口层。这里的关键点是:换床、退住、费用结算这些动作都要同样处理。

@Service public class CheckInService { @Transactional(rollbackFor = Exception.class) public void checkIn(CheckInDTO dto) { // 1.查床位是否空闲 Bed bed = bedMapper.selectById(dto.getBedId()); if (bed == null || bed.getStatus() == 1) { throw new BizException("床位不存在或已被占用"); } // 2.床位改为占用 bed.setStatus(1); bedMapper.updateById(bed); // 3.写入住记录 CheckIn checkIn = new CheckIn(); checkIn.setOldPersonId(dto.getOldPersonId()); checkIn.setBedId(dto.getBedId()); checkIn.setCheckInTime(LocalDateTime.now()); checkInMapper.insert(checkIn); // 4.初始化护理计划,对应nursing_record表 nursingMapper.initPlan(dto.getOldPersonId()); } }

逻辑说明:第一步先查再改,是为了避免把已占用的床位再分给别人,这是并发控制的第一道防线。第2到第4步在同一个事务内,任何一个抛异常,数据库都会回滚,床位不会被莫名占用,入住记录也不会出现“只有一半”的脏数据。

参数说明:rollbackFor=Exception.class的意思是所有异常都触发回滚,包括运行时异常和受检异常。如果你只写@Transactional不写rollbackFor,默认只在RuntimeException下回滚,受检异常比如文件找不到就不会回滚,这是很多“数据被写坏”的隐藏原因。

这里要提醒:普通业务系统里不建议在事务里做耗时操作,比如发短信、调远程接口,事务要短平快。宿管系统如果有定时任务给老人推送用药提醒,那就单独拆一套流程,别塞进checkIn事务里,否则一个慢接口能把整个数据库连接池拖垮。

5. 部署与避坑:把这套Java系统跑起来的五个常见问题

这一章是全文性价比最高的一章,全是帮别人跑这类Java毕设项目时踩过的坑。每个问题都按“现象-原因-解决”写,你按顺序排查能省下至少一个下午。

5.1 MySQL 8的驱动类名和url参数

现象:项目启动后报java.lang.ClassNotFoundException: com.mysql.jdbc.Driver,或者是Communications link failure。

原因:老项目里的驱动是mysql-connector-java 5.x,类名是com.mysql.jdbc.Driver;MySQL 8的驱动类名改成了com.mysql.cj.jdbc.Driver。如果你本地装的是MySQL 8却用旧驱动,连不上是必然的。另一个常见原因是url里缺serverTimezone,MySQL 8对时区敏感,直接抛异常。

解决:驱动坐标升级到8.0.x,driver-class-name改成com.mysql.cj.jdbc.Driver,url加上serverTimezone=Asia/Shanghai。第2.4节里的yml配置直接抄即可。Maven坐标从mysql:mysql-connector-java改成com.mysql:mysql-connector-j,版本用8.0.33这类稳定版。

提示:如果你必须用老驱动连新数据库,也不是完全不行,但要在连接参数里额外处理SSL和时区,出了问题排查成本极高,不如直接升级依赖。

5.2 页面中文乱码,三层都要查

现象:页面显示的中文全是问号,或者数据库里存进去是好的、查出来却在页面上变乱码。

原因:乱码是编码链路上某一层断了。JSP页面本身不是UTF-8、Spring的CharacterEncodingFilter没配、JDBC url没有characterEncoding=utf8、MySQL表不是utf8mb4,四层里有任何一层不对就乱。

解决:依次检查四个地方。JSP页面顶部的charset;Spring Boot里用配置类注册CharacterEncodingFilter,或用server.servlet.encoding配置项;数据库url里带characterEncoding=utf8;建表语句里的CHARSET设为utf8mb4。任何一层都不能漏。我之前遇到过最隐蔽的:Tomcat的server.xml里Connector没加URIEncoding="UTF-8",页面表单GET提交的中文全乱,怎么查都觉得代码没问题。

修复后重启Tomcat、清浏览器缓存,再验证一次。乱码问题一旦出现就是全站性的,优先排查环境配置,不要先怀疑业务代码。

5.3 字段名踩了MySQL关键字

现象:执行INSERT或SELECT报You have an error in your SQL syntax,反复检查SQL都觉得写得很对。

原因:字段名或表名命中了MySQL关键字,比如desc、order、group、condition、rank。这类系统里最常踩的雷是描述字段叫desc,排序字段叫order,这些恰好是SQL关键字。

解决:优先改名,desc改成description,order改成sort_order,一劳永逸。改不了时用反引号把字段名包起来,但反引号会降低SQL可读性,而且换了一个数据库方言就失效。更推荐直接改数据库字段,不要留雷给后人踩。

提示:同一套系统里,建表SQL建议开局就避开全部关键字。否则论文里的数据字典和实际数据库对不上时,整改成本很高,既要改SQL又要改XML又要改实体类。

5.4 Tomcat启动成功但页面404,静态资源全丢

现象:Tomcat启动没报错,首页能打开,但CSS、JS、图片全部404,页面跟没穿衣服一样。

原因:SSM项目和Spring Boot对静态资源的默认路径约定不一样。SSM习惯把静态资源放webapp/static,由DefaultServlet处理。如果Spring MVC配置里把DispatcherServlet映射到/,又没有加资源映射,静态资源就被拦截了。

解决:Spring Boot项目把静态资源放src/main/resources/static、public或resources下,三选一即可。SSM项目在spring-mvc.xml里加一行:

<mvc:resources mapping="/static/**" location="/static/"/>

逻辑说明:mapping指定浏览器访问时的URL前缀,location指定实际文件目录。这样浏览器请求/static/css/style.css时,Spring MVC不会把它当成Controller路径,而是直接去webapp/static/css/下找文件。换成Spring Boot后这个配置内置了,但偶尔会有新版IDE把资源放错目录的情况,优先检查resources根目录。

这类问题不报错,纯靠肉眼排查,是典型的“黑匣子”排错体验。一个实用技巧是打开浏览器F12看Network面板里失败请求的URL路径,对比实际文件目录就能快速定位。

5.5 LocalDateTime返回JSON报错

现象:接口返回的数据里,createTime字段直接报错,或者格式变成一串数字。

原因:Java 8的LocalDateTime不是java.util.Date,老版Jackson默认不支持序列化,需要jsr310模块。很多这种毕业设计项目的依赖恰好没加。

解决:加jackson-datatype-jsr310依赖,版本跟着Spring Boot的parent走,不用手写版本号。然后对时间字段统一配置格式,实体类上可以加@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss"),接口返回给前端的就是可读的字符串。

提示:数据库层面尽量用DATETIME存时间,不要用TIMESTAMP。TIMESTAMP的范围只到2038年,DATETIME的范围大得多,而且DATETIME不受时区影响,做报表统计时更安全。这也是在设计论文数据字典时容易被追问的点。

6. 答辩前的验证与进阶:把“设计”讲成加分项

这一章不谈功能,谈怎么让这套系统在答辩时立住。评审老师最反感的是“能跑但说不清为什么这样设计”,反过来,能把设计理由讲明白的,即使代码有小瑕疵也比纯会跑分高。

先给出一张我用过的功能验证清单,答辩前一晚按清单把每个动作亲手点一遍,能挡住大多数演示翻车:

模块操作预期结果
登录输入错误密码页面提示用户名或密码错误,不进入主界面
档案新增老人,身份证重复系统拒绝入库并提示身份证已存在
入住选择占用中的床位提示床位不可用,数据不被写入
退住办理退住结算床位状态变空闲,check_out_time写入
护理为未入住老人添加记录系统提示先办理入住
统计费用汇总与逐条缴费明细对账一致

再加一个让代码显得有分量的分页技巧。很多这个体量的系统一次性把全部数据查出来,20条数据没问题,500条就卡。用MyBatis的PageHelper分页,三行代码解决:

PageHelper.startPage(pageNum, pageSize); List<OldPerson> list = oldPersonMapper.selectList(keyword); PageInfo<OldPerson> pageInfo = new PageInfo<>(list);

逻辑说明:PageHelper是MyBatis的分页插件,startPage传入页码和每页条数,插件会自动拦截下一条SQL并拼接LIMIT语句。PageInfo里封装了总条数、总页数、当前页数据列表,前端渲染分页栏时直接取这些字段。

参数说明:pageNum从1开始,pageSize设为10或20比较合适。如果接口还要求返回总条数用于前端显示“共xx条”,PageInfo.getTotal()直接取。

如果还有时间,可以把JSP换成Vue做前后端分离。后端接口不用大改,只是把返回JSON的Controller保留,前端用Vue脚手架搭一个管理界面,通过接口对接。这个改造在面试讲项目时可以当亮点:“我做的是Java后端,前端用Vue,通过Restful接口对接。”这句话在Java开发工程师面试里的说服力比“我会JSP”高不少。

最后说点我自己的教训。我最早写这类系统时,恨不得把报表、权限、定时任务全堆进去,结果bug全出在那些“炫技”的地方。后来我把重心改成把入住和退住的事务边界、索引设计、参数校验这些基本功做到位,反而答辩时每个问题都能接得住。管理系统拼的从来不是技术新,而是边界清楚、数据经得起追问。希望帮到你。

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

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

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

立即咨询