☰
基于SpringBoot的疫情背景下宿舍管理系统设计与实现
2026/10/15 6:49:34 网站建设 项目流程

我们学校在特殊时期要求所有学生宿舍实行封闭式管理,每天要上报体温、登记出入、分配隔离房间,还要处理临时留观学生的住宿安排。那段时间宿管员的工作量暴涨,光靠纸笔和微信群根本顶不住。疫情结束后我复盘了一下,发现这套基于Java+SpringBoot的宿舍管理系统不仅解决了当时最急迫的管理需求,放到今天的智慧校园建设里也是完全能打的毕业设计选题。这篇文章我把完整的项目拆解思路、数据设计、核心接口实现和踩坑经验全部整理出来,给正在做同类课题的同学一点参考。

1. 疫情场景给宿舍管理增加了哪些必须落地的业务变化

很多同学拿到这个题目第一反应是“宿舍管理系统不就是CRUD吗,学生信息、宿舍信息、入住记录,完事了”。但如果你把“疫情背景”这四个字当真,就会发现传统的宿舍管理系统和这个项目之间隔着一整套业务逻辑的差距。

1.1 盘点疫情为宿舍管理新增的五个核心业务场景

我梳理了某高校在实行封闭管理期间的实际操作流程,真正的刚需场景是下面这五个:

  • 出入登记与归寝判定:学生进出楼栋必须扫码或刷卡登记,系统要自动判定该学生是否允许外出、是否在允许时段内返回、是否按时归寝。
  • 体温与健康状态上报:每日两次体温打卡,异常数据要触发预警,宿管员和辅导员能看到本楼栋本班级的填报率。
  • 隔离宿舍分配:出现发热或密接情况时,需要快速从空闲床位中分配隔离房间,并记录隔离起止时间。
  • 访客与跨楼栋流动管控:特殊时期非本楼栋人员禁止入内,确有需要的要审批并留痕。
  • 数据统计与上报:学校管理层需要实时掌握各楼栋入住率、隔离人数、异常人数、晚归名单等汇总数据。

这里面最难的不是“上报体温”这个动作本身,而是“异常数据如何流转”。体温超过37.3度之后,系统要自动通知谁、分配什么流程、记录哪些状态、最终由谁解除——这套状态流转逻辑才是疫情期间宿舍管理系统真正的核心价值所在。

1.2 从业务场景推导系统功能边界

结合上面五个场景,系统的功能模块可以划分为以下几块:

  • 基础信息管理:学生档案、宿舍楼栋、房间床位、入住退宿。
  • 日常管理:归寝登记、外出申请、晚归记录、访客登记。
  • 健康监测:每日体温上报、异常记录、填报统计。
  • 隔离管理:隔离宿舍分配、隔离期间状态追踪、解除隔离审批。
  • 消息通知:异常体温提醒、归寝提醒、审批结果反馈。
  • 统计看板:楼栋入住率、健康填报率、隔离人数、异常趋势。

一个合格的毕业设计不需要把所有模块做到极致,但至少要在“基础管理 + 健康监测 + 隔离管理”这三条主线上形成完整闭环,否则题目里的“疫情背景”就只是个无关紧要的装饰词。

1.3 系统的角色盘点与分析

宿舍管理系统的角色比普通的管理系统要多一层,因为宿舍场景天然涉及“学校—楼栋—学生”三级结构。我最终确定了四个角色:

  • 系统管理员:维护楼栋、房间、床位等基础数据,管理账号。
  • 宿管员:负责本楼栋的日常管理,包括登记、审批、异常处理。
  • 辅导员:查看本班学生的住宿与健康情况,处理异常预警。
  • 学生:每日健康打卡、进出登记、查看通知。

值得一提的是辅导员这个角色。很多做这个题目的同学会遗漏这一层,但实际业务流程里辅导员恰恰是疫情防控链条上最关键的一环——学生体温异常后,对接家长、安排就医、上报学院的往往是辅导员。系统里给辅导员单独的视图权限,既符合真实业务,也能在答辩时体现你对需求的理解深度。

2. 为什么选SpringBoot:技术栈选型背后的现实逻辑

2.1 课程设计与就业衔接的平衡

这个题目选Java+SpringBoot有非常现实的理由。一方面,高校Java课程体系里SpringBoot是绝对主线,用自己熟悉的技术做毕业设计,踩坑成本最低;另一方面,SpringBoot加Spring Security加MyBatis Plus的组合,几乎是目前中小型企业级应用的标配,做完这套项目你拿到的技术栈经验完全可以写进简历。

我不建议在这个题目里强行上微服务或者分布式中间件。宿舍管理系统的并发量、数据量和使用场景决定了单体应用完全够用,强行引入分布式架构只会让项目复杂度失控,答辩的时候被问到底层原理反而容易翻车。

2.2 同类方案对比:SpringBoot与Django、Node.js的取舍

我在做选型分析的时候也对比过其他方案,这里直接给结论:

对比维度SpringBootDjangoNode.js(Express)
类型安全强,编译期报错中等,动态类型弱,运行时排查
生态成熟度极高,文档丰富高高
与高校课程衔接最紧密部分院校使用较少
部署复杂度中(需要JDK环境)低低
答辩说服力强(企业级主流)中中

这三个方案都能实现这套系统,但从毕业设计的角度,SpringBoot是性价比最高的选择。特别是JPA或MyBatis Plus带来的开发效率提升,我后面会详细展开。

2.3 项目技术架构与整体结构

我这边的技术选型如下:

  • 后端框架:Spring Boot 2.7.x
  • 权限框架:Spring Security + JWT
  • ORM框架:MyBatis Plus
  • 数据库:MySQL 8.x
  • 前端:Vue 3 + Element Plus
  • 接口文档:SpringDoc OpenAPI

后端目录结构按功能模块分包,清晰是第一诉求:

com.university.dormitory ├── config/ // 配置类:Security、CORS、MyBatisPlus ├── controller/ // 接口层 ├── service/ // 业务逻辑层 ├── mapper/ // 数据访问层 ├── entity/ // 实体类 ├── dto/ // 请求响应对象 └── utils/ // 工具类:JWT工具、日期工具

这样的分包方式可能看起来普通,但好处是各层职责一目了然,写代码、调试、答辩讲架构都非常顺手。

3. 数据模型拆解:从实体关系到可落地的表结构

数据模型是整个系统最重要的地基。我见过太多同学一上来就写代码,写到后面发现隔离记录没地方存、晚归状态没法表示,只能推翻重来。所以这一节值得仔细看。

3.1 核心实体识别与关系梳理

先列一下我最终确定的实体清单:

  • 用户表(user):主键、用户名、密码、真实姓名、角色、手机号、关联学生ID。
  • 学生表(student):学号、姓名、性别、所属学院、班级、联系方式。
  • 宿舍楼栋表(building):楼栋编号、名称、楼层数、宿管员ID。
  • 宿舍房间表(room):房间号、所属楼栋、房间类型、床位数量。
  • 床位表(bed):所属房间、床位编号、状态(空闲/入住/隔离禁用)。
  • 入住记录表(stay_record):学生ID、床位ID、入住时间、退宿时间。
  • 出入登记表(access_record):学生ID、进出类型、时间、体温、登记方式。
  • 健康上报表(health_report):学生ID、上报日期、早间体温、晚间体温、健康状况。
  • 隔离记录表(isolation_record):学生ID、隔离床位ID、开始时间、预计结束时间、原因、状态。
  • 访客登记表(visitor_record):访客姓名、证件号、被访学生ID、来访时间、离开时间。
  • 通知表(notification):标题、内容、接收角色、发布时间。

实体之间的关系不复杂,关键在状态字段的设计上。比如床位不只是“有人/没人”,还要区分“被隔离占用”,这样分配隔离宿舍时才不会把正常住宿的学生挤出去。

3.2 关键表结构设计的细节说明

这里给出三张最关键的表的设计思路。

健康上报表的核心在于唯一约束,要确保一个学生一天只有一条记录:

CREATE TABLE health_report ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL, report_date DATE NOT NULL, morning_temp DECIMAL(4, 2), evening_temp DECIMAL(4, 2), health_status VARCHAR(20) COMMENT '正常/乏力/咳嗽/其他', is_abnormal TINYINT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_student_date (student_id, report_date) );

uk_student_date这个唯一索引是必须的。否则学生重复提交,你只能靠Java代码判断,并发场景下极容易出现重复数据。数据库层面的约束永远比代码层面的判断更可靠。

隔离记录表要重点设计状态流转:

CREATE TABLE isolation_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL, bed_id BIGINT NOT NULL COMMENT '隔离床位ID', start_time DATETIME NOT NULL, expected_end_time DATETIME, actual_end_time DATETIME, reason VARCHAR(255) COMMENT '发热/密接/其他', status TINYINT DEFAULT 0 COMMENT '0隔离中 1已解除 2已转院', handler_id BIGINT COMMENT '操作人ID', remark VARCHAR(500), create_time DATETIME DEFAULT CURRENT_TIMESTAMP );

actual_end_time和expected_end_time分开存储,是为了支持“提前解除”和“延长隔离”两种实际情况。很多项目只存一个结束时间,后面做统计报表时发现数据根本对不上。

3.3 学生状态机设计:正常、隔离、请假的状态流转

学生的宿舍状态不能直接用一个字符串字段存,因为状态之间是有流转关系的。我设计了下面这个状态机:

  • 在住(正常):默认状态,可出入登记,可发起外出申请。
  • 隔离观察:从“在住”通过“新增隔离记录”进入,期间禁止外出。
  • 请假外出:从“在住”发起申请,宿管员审批通过后进入。
  • 已退宿:从“在住”通过“办理退宿”进入,终态。

状态机的好处是逻辑清晰,权限判断也简单。比如学生保存体温异常之后,前端按钮直接置灰“申请外出”,后端接口也校验状态,双重保险。

一个状态机字段藏在学生主表里就行,不需要单独建表,但状态流转的操作日志一定要落库。后面答辩老师问起来,你能拿出完整的状态变化时间线,这项目的基本功就立住了。

4. 核心功能模块实现:重点接口的完整设计思路

这一节我挑最核心的三个模块讲实现思路,不贴全部代码,只讲设计逻辑,每个模块都带关键代码片段。

4.1 出入登记与归寝判定

出入登记在技术上很简单,就是一个INSERT操作加一个状态判断,但业务上有一个关键点:识别“这是出楼还是进楼”。我的方案是前端传type字段(IN/OUT),后端根据当前学生的宿舍状态做校验。

归寝判定比较有意思。系统需要结合宿舍楼的门禁时间规则,判断一条“IN”记录是否属于晚归。我当初的做法是在access_record表里冗余了一个is_late字段,由后端根据楼栋的归寝时间配置计算后写入,而不是在查询时临时计算,这样统计晚归名单时只需要一条SQL:

// 出入登记接口的校验核心逻辑 public AccessRecord registerAccess(AccessRegisterDTO dto) { Student student = studentMapper.selectById(dto.getStudentId()); // 1. 隔离状态不允许外出 if (student.getStatus() == StudentStatus.ISOLATED) { throw new BusinessException("隔离观察期间禁止外出"); } // 2. 登记出入记录 AccessRecord record = new AccessRecord(); record.setStudentId(dto.getStudentId()); record.setType(dto.getType()); record.setAccessTime(LocalDateTime.now()); // 3. 如果是进楼,判断是否晚归 if (dto.getType() == AccessType.IN) { record.setIsLate(checkLateReturn(record.getAccessTime())); } accessRecordMapper.insert(record); return record; }

4.2 健康上报与异常预警

健康上报是疫情期间使用频率最高的接口,设计上要特别注意幂等性和异常处理。

核心逻辑是:先根据student_id + report_date查是否已有记录,有则更新,无则插入。使用Redis分布式锁也可以,但对于毕业设计场景,数据库唯一索引加先查后插已经足够了。

异常预警的触发链是:保存上报记录时,如果晨检或晚检体温 >= 37.3度,系统自动做三件事——更新学生的宿舍状态为“待观察”、生成一条待处理预警记录、向辅导员发送站内通知。

这里有一个很小的设计细节值得分享:预警记录的表结构里,我加了一个processed字段和process_user_id字段,用来记录“哪个辅导员处理了这条预警”。因为一个学生可能对接多个辅导员(班主任、年级辅导员),如果不记录处理人,后续会出现责任推诿的情况。

4.3 隔离宿舍分配的核心逻辑

隔离宿舍分配不是简单的查空房,它有两个约束条件。

第一,要找的床位必须是“空闲且标记为可隔离”的床位,而不是所有空闲床位。实际场景中有些房间条件不适合做隔离间(比如没有独立卫生间),这部分房间在基础数据维护时要打上隔离可用标记。

第二,分配遵循“就近原则”。隔离房间要优先选学生所在楼栋的空闲房间,不要跨楼栋分配。跨楼栋转运本身就增加交叉感染风险,系统分配时要自动按这个优先级排序。

核心代码逻辑可以抽象成三步:

public IsolationRecord assignIsolationBed(Long studentId, String reason) { // 1. 查学生当前所在楼栋 StayRecord currentStay = stayRecordMapper.findCurrentByStudentId(studentId); // 2. 优先同楼栋、可隔离、空闲的床位 Bed bed = bedMapper.findAvailableIsolationBed(currentStay.getBuildingId()); if (bed == null) { // 3. 同楼栋没有再扩大到全校,但要标记为跨楼栋 bed = bedMapper.findAvailableIsolationBedGlobally(); } // 占床、更新学生状态、生成隔离记录... }

4.4 统计看板的数据查询技巧

管理端的统计看板需要展示入住率、填报率、隔离人数等指标。最忌讳的做法是每个指标都单独写一条查询语句然后在前端拼接,系统一卡就是上百条SQL。

我的做法是在dashboard模块里用一个聚合查询搞定主要指标。以“楼栋健康统计”为例:

SELECT b.id AS building_id, b.name AS building_name, COUNT(DISTINCT s.id) AS total_students, COUNT(DISTINCT CASE WHEN hr.is_abnormal = 1 THEN hr.student_id END) AS abnormal_count, COUNT(DISTINCT ir.id) AS isolation_count FROM building b LEFT JOIN room r ON b.id = r.building_id LEFT JOIN bed bd ON r.id = bd.room_id LEFT JOIN stay_record sr ON bd.id = sr.bed_id AND sr.leave_time IS NULL LEFT JOIN student s ON sr.student_id = s.id LEFT JOIN health_report hr ON s.id = hr.student_id AND hr.report_date = CURDATE() LEFT JOIN isolation_record ir ON s.id = ir.student_id AND ir.status = 0 GROUP BY b.id, b.name;

这条语句有些复杂,但跑出来的结果正好就是楼栋管理页面顶部那张卡片的全部数据。看板页面打开时只调一次后端接口,体验非常流畅。

5. 权限与安全设计:多角色系统的控制粒度

宿舍管理系统涉及学生隐私数据(体温、隔离记录),权限设计不能只做前端按钮隐藏,后端接口必须做真实校验,否则某个学生调用接口就能看到全校同学的体温信息,这在答辩时是致命的硬伤。

5.1 三种核心角色的权限边界

权限矩阵我做了这么一套设计:

功能学生宿管员辅导员系统管理员
查看个人信息自己本楼栋本班级全部
健康上报本人---
查看健康数据本人本楼栋汇总本班级全部
出入记录本人本楼栋本班级全部
隔离管理查看本人楼栋内操作只读全部
基础数据维护---全部

关键在于“数据范围”的限定,而不是简单用角色区分能不能访问。同一个账号角色都为“宿管员”,A楼的宿管员就不应该查到B楼的数据。这个需求可以基于MyBatis Plus的拦截器实现数据权限,给查询SQL自动追加building_id = 当前用户所属楼栋的条件。

5.2 后端实现:Spring Security + JWT 的配置细节

Spring Security + JWT在校园项目里已经是标配了,但有几个细节特别容易踩坑。

第一个是密码存储。直接用MD5存储是错误示范,至少要加盐,更合理的方案是使用BCryptPasswordEncoder。Spring Security内置了BCrypt支持,用起来就是一行配置。

第二个是JWT过期时间的设置。我看过很多同学把过期时间设成7天甚至30天,对于宿舍管理系统来说太长了。学生可能共用一台电脑或者被别人借用账号,token有效期建议控制在2小时左右,配合前端刷新机制使用。

// JWT工具类核心方法 public String generateToken(Long userId, String role) { return Jwts.builder() .setSubject(String.valueOf(userId)) .claim("role", role) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 2 * 60 * 60 * 1000)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); }

第三个坑是Security的放行规则。很多同学会把/api/**全部拦截,导致前端无法匿名访问登录接口。正确的做法是:放行登录、验证码、健康上报等少量公开接口,其余全部走认证。CORS配置也要单独写好,否则前端本地调试时请求直接被浏览器拦截。

5.3 数据越权与水平权限漏洞的防御

垂直越权和水平越权在答辩中是最容易被问到的安全知识点。垂直越权好理解——学生不能调用管理员接口;水平越权则是同一个角色内,学生A不能查看学生B的数据。

防御水平越权最朴素的方案是,在每个查询接口里强制要求当前登录用户ID与查询目标ID一致或存在归属关系。举个例子,查询学生体温记录的接口:

@GetMapping("/health/{studentId}") public Result getHealthRecord(@PathVariable Long studentId) { // 获取当前登录用户 LoginUser currentUser = SecurityUtils.getCurrentUser(); // 校验:学生只能查自己,宿管员只能查本楼栋,辅导员只能查本班级 if (!dataPermissionService.canViewStudent(currentUser, studentId)) { return Result.fail("无权访问该学生数据"); } // 正常查询... }

这样即使前端泄露了某个学生的ID,攻击者也调不通接口。数据权限校验统一收敛到一个 service 里,比在控制器里散落着写判断更容易维护。

6. 实测中遇到的坑与调优经验

做这个项目前后花了大概两个月,过程中踩了不少坑,挑几个最有代表性的分享出来,都是文档里不会写的细节。

6.1 高峰期填报体温时的接口性能问题

第一次联调测试时,模拟300个学生同时提交体温上报,数据库连接池直接被打满,大量请求超时。排查后发现两个问题:一是每来一个请求都新建数据库连接,二是健康上报的SQL包含太多无用的字段查询。

解决方案有两个层面。第一,配置HikariCP连接池参数,把最大连接数调到合理值(我最终设的是maximum-pool-size: 50);第二,对库存表数据做缓存,上报时先更新数据库再更新Redis缓存,查询走缓存优先。宿舍管理系统的查询量远大于写入量,引入缓存后看板页面和健康日报的打开速度提升非常明显。

6.2 时间处理不当导致晚归判定错误

这个坑特别隐蔽。服务器部署在云上时默认时区是UTC,而校园应用场景是中国标准时间(UTC+8),如果不显式设置时区,数据库存的时间会比实际时间少8小时,晚上11点的归寝记录会被判定为第二天下午3点,晚归功能就完全失效了。

解决方式是在数据库连接字符串和JVM启动参数两处同时指定时区:

# application.yml spring: jackson: time-zone: GMT+8 datasource: url: jdbc:mysql://localhost:3306/dormitory?serverTimezone=Asia/Shanghai

另外,涉及日期的字段建议统一使用LocalDateTime,不要用java.util.Date。LocalDateTime配合Jackson的@JsonFormat注解,前后端的时间解析问题能省掉一大半。

6.3 前端展示大量列表数据时的分页规范

宿舍管理系统的列表页非常多:出入记录、健康上报、隔离记录、访客记录。写分页接口时有个细节:MyBatis Plus的分页插件和自定义SQL联查时,容易因为分页拦截器没有正确配置导致查出来的总条数不对。

我的经验是,配置分页插件时把DbType.MYSQL显式指定上,自定义SQL里避免在select语句里面强行拼接limit,统一交给分页插件处理。下面这个配置几乎可以用于所有后续项目:

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }

6.4 答辩演示时的几个隐藏加分项

最后说几个答辩演示时的隐藏加分项。

第一个是异常演示要提前准备好数据。答辩时不要现场去创建一个发热学生的数据,提前造好一条“体温37.5度且已生成隔离记录”的数据,演示时直接点开列表展示状态流转。

第二个是权限控制的现场演示。登录学生账号,故意访问一个只有辅导员能看的接口,展示返回“403无权限”,这一下就能证明你真正做了后端权限校验,而不只是画了页面。

第三个是日志系统。在关键操作(分配隔离宿舍、解除隔离、审批外出)加上操作日志记录,答辩时被问到“这个操作是谁在什么时间做的”,你能当场展示日志列表,比任何口头解释都有说服力。

第四个是异常处理要友好。前后端联调时,后端抛出的异常不要直接返回500堆栈,统一通过@RestControllerAdvice做全局异常处理,返回统一的错误码和提示信息。这个细节很多同学不做,但你做了,答辩老师一看就知道你是有工程经验的。

做完这套系统,我最大的感受是:毕业设计的核心不在于用了多少高大上的技术,而在于你是否真正想清楚了业务场景里的每一个流程节点。疫情背景下的宿舍管理系统,表面上是信息管理,实际上是一套完整的应急响应流程。把这套流程想透了,做出来的系统自然有深度,答辩也自然有底气。希望这篇拆解能帮你少走一些弯路。

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

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

立即咨询