简介:面向高校计算机相关专业学生和Java初学者,这份学生宿舍管理系统源码可作为毕业设计与课程实训的完整参考项目。系统前端基于Bootstrap搭建页面,后端采用SpringBoot框架与MySQL数据库,并按管理员、宿管、学生三类角色划分权限:管理员负责学生、楼宇、宿舍、入住、宿管及管理员信息的管理,并支持数据导入和Excel表格导出;宿管和学生则按各自权限范围查看、维护学生信息、宿舍信息和入住信息,登录账号均存于数据库。压缩包共661个文件,约72.37MB,以js、css等前后端页面资源和Java、class源码为主体,另附sql建库脚本、xml配置、少量说明文档和演示视频,目录结构清晰。已有469人学习,适合读者对照理解角色权限设计,以及增删改查、导入导出的实现思路。
1. 需求先立住:宿舍管理不是“增删改查”,难在四类角色同时在线
每年做课程设计或毕业设计选题时,“基于 Java 的学生宿舍管理系统”几乎是最容易被低估的一个。很多同学第一反应是:不就是学生、宿舍、床位三张表,再加几个增删改查页面?真动手才发现,难点根本不在写 CRUD,而在于四类角色要同时在线——学生要看自己的床位和报修进度,宿管员要排寝和查卫生,辅导员要统计晚归和违规,管理员要管楼栋与权限。任何一处数据不一致,比如同一张床位被分配给两个学生,整个方案的可信度就没了。
这套方案要解决的就是这类“看起来简单、做起来容易翻车”的场景:用 Java 技术栈把宿舍资源、住宿分配、日常检查、报修处理、权限控制串成一条完整链路,适合正在做课程设计、毕业设计,或者需要给学校交付一套可运行管理系统的开发者。下面按需求、架构、模块实现、避坑、验收五段推进,结构可以直接套用。
2. 总体架构设计:分层结构与权限模型的职责划分
2.1 为什么选 Spring Boot 而不是纯 Servlet
学生宿舍管理系统的业务量不大,但模块多、角色多、状态流转多。纯 Servlet 或 JSP 直连数据库的写法,前期上手快,后期每加一个“报修审批”就要在三四个文件里改 SQL,维护成本陡增。我一般会选 Spring Boot + MyBatis 的组合,原因有三点:一是依赖注入让 Service 层可以独立测试,床位分配这种核心逻辑能单独写单元测试;二是 MyBatis 的 XML 映射对复杂查询更友好,比如“查询某楼栋所有空床位并按楼层排序”,用注解反而啰嗦;三是 Spring Security 或自研拦截器都能平滑接入权限校验。
分层上按 Controller → Service → Mapper → 数据库四层组织,DTO 与实体分离。Controller 只做参数校验和响应封装,Service 承载业务规则,Mapper 只写 SQL,不允许在 Controller 里直接调 Mapper。这条约束看着教条,但它是后期能不能加功能的分水岭。
// BedAllocationService.java —— 床位分配核心逻辑,业务规则集中在 Service 层 @Service public class BedAllocationService { @Autowired private BedMapper bedMapper; @Autowired private StudentMapper studentMapper; /** * 为学生分配床位 * @param studentId 学生 ID * @param bedId 目标床位 ID * @return 分配结果 */ @Transactional(rollbackFor = Exception.class) public Result allocate(Long studentId, Long bedId) { // 1. 校验学生是否存在且未分配 Student student = studentMapper.selectById(studentId); if (student == null || student.getBedId() != null) { return Result.fail("学生不存在或已有床位"); } // 2. 校验床位空闲,使用行锁防止并发重复分配 Bed bed = bedMapper.selectForUpdate(bedId); if (bed == null || bed.getStatus() != 0) { return Result.fail("床位不可用"); } // 3. 双向更新:床位标记占用,学生记录床位号 bedMapper.updateStatus(bedId, 1, studentId); studentMapper.updateBedId(studentId, bedId); return Result.ok("分配成功"); } }上面这段代码的关键不在语法,而在两个设计点:@Transactional保证两次更新要么都成功要么都回滚;selectForUpdate加行锁,防止两个宿管员同时点“分配”导致一床两人。参数说明上,bed.getStatus()约定 0 为空闲、1 为占用、2 为维修中,这个状态字典要提前定死写进文档,不然后面每个模块各写一套枚举,联调时对不上。分配失败时优先看两点:事务是否回滚、行锁是否生效,这两处是并发问题的黑匣子。
2.2 四类角色的权限模型怎么落地
角色划分建议做成“角色—菜单—操作”三级,而不是简单的角色判断。学生只能看自己的住宿信息、提交报修、查看卫生评分;宿管员可以排寝、录入检查记录、处理报修;辅导员可以跨楼栋查看统计报表;管理员管楼栋、用户、权限。实现上用拦截器 + 注解的方式,在方法上标注所需权限码,拦截器解析当前登录用户的权限集合做比对。
// 权限注解与拦截器配合,方法级控制比 URL 级更细 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RequirePerm { String value(); // 权限码,如 "bed:allocate" } // 拦截器中的核心判断 String perm = handlerMethod.getMethodAnnotation(RequirePerm.class).value(); Set<String> userPerms = permissionService.getPermsByUserId(currentUserId); if (!userPerms.contains(perm)) { throw new BizException("无操作权限"); }这里踩坑最多的是“权限码硬编码在页面里”。前端按钮显隐按权限码判断没问题,但后端必须再校验一次,否则改个请求参数就能越权。数据库里建议三张表:sys_user、sys_role、sys_permission,中间用关联表打通,角色变更走配置不走代码,答辩时也方便演示。
3. 核心模块实现:住宿分配、日常检查与报修闭环
3.1 住宿分配与床位状态机
床位是这套系统里状态最复杂的实体:空闲、已占用、维修中、预留。分配、退宿、调寝、维修四个动作会驱动状态流转。实现上建议把状态流转规则收敛到一个枚举类里,用方法判断“当前状态能否执行某动作”,而不是在各处写 if-else。
public enum BedStatus { FREE(0), OCCUPIED(1), REPAIRING(2), RESERVED(3); private final int code; BedStatus(int code) { this.code = code; } public int getCode() { return code; } // 判断是否允许分配:只有空闲和预留可以分配 public static boolean canAllocate(int current) { return current == FREE.code || current == RESERVED.code; } // 判断是否允许退宿:只有占用状态可以退 public static boolean canCheckout(int current) { return current == OCCUPIED.code; } }调寝是最容易出问题的动作:学生从 A 床换到 B 床,必须先释放 A 再占用 B,顺序反了会出现“一人两床”,顺序对了但中途失败会出现“一人无床”。解决办法是把调寝拆成“退宿 + 分配”两个事务步骤,在同一事务内先释放再占用,失败整体回滚。退宿时还要同步清除学生表里的bed_id,这一点很多初版会漏,导致学生已退宿但系统仍显示有床位。
3.2 卫生检查与评分记录的录入
日常检查包括卫生评分、晚归登记、违规记录三类,数据结构相似,可以抽成一张inspection_record表,用type字段区分。检查记录要绑定楼栋、房间、检查人、检查时间、分值或描述。查询侧最常见的需求是“某学生本学期卫生平均分”和“某房间最近三次检查记录”,前者用聚合查询,后者用分页加排序。
-- 某学生本学期卫生平均分,注意按学号关联而非姓名 SELECT s.student_no, s.name, AVG(i.score) AS avg_score, COUNT(*) AS times FROM inspection_record i JOIN student s ON i.student_id = s.id WHERE i.type = 'HYGIENE' AND i.check_time >= #{termStart} GROUP BY s.student_no, s.name ORDER BY avg_score ASC;参数说明上,termStart由前端选择学期传入,不要在 SQL 里写死日期;按student_no分组而不是姓名,避免重名合并。检查记录一旦提交不建议物理删除,改为逻辑删除或作废标记,否则统计报表会出现“分数凭空消失”的玄学问题。宿管员录错分值是高频场景,所以录入界面要有二次确认,后端保留修改日志。
3.3 报修流程与消息状态流转
报修是学生端使用频率最高的功能,流程是:学生提交 → 宿管员受理 → 派单给维修 → 完成并回填 → 学生确认。状态建议定为待受理、已受理、维修中、已完成、已取消五态。每次状态变更写一条流转日志表,记录操作人、前后状态、时间、备注,这张日志表在答辩演示和后期排查时价值极高。
// 报修状态变更,必须校验前置状态,防止跳步 public Result changeStatus(Long repairId, String target, String remark) { RepairOrder order = repairMapper.selectById(repairId); if (!RepairStateMachine.canTransfer(order.getStatus(), target)) { return Result.fail("当前状态不允许该操作"); } repairMapper.updateStatus(repairId, target); repairLogMapper.insert(new RepairLog(repairId, order.getStatus(), target, remark)); return Result.ok(); }RepairStateMachine.canTransfer内部维护一张状态转移表,比如“待受理”只能转“已受理”或“已取消”。不做这层校验,前端页面绕过去就能把“已完成”改回“维修中”,数据就乱了。学生端提交报修时还要限制频率,同一房间同一天重复提交要做提示,否则宿管端会被刷屏。
4. 常见问题排查:数据、并发与权限的三类翻车点
4.1 床位重复分配
现象:两个学生显示同一床位,或者床位表状态为占用但学生表没有对应记录。原因一般是分配逻辑没有事务包裹,或者缺少行锁。解决:分配方法加@Transactional,查询床位时用SELECT ... FOR UPDATE,并在数据库层给“床位 ID + 占用状态”加唯一约束兜底。上线前用并发脚本压一遍分配接口,比事后补救省事得多。
4.2 权限越权访问
现象:学生角色直接调管理员的接口能成功。原因多是只在页面隐藏了按钮,后端接口没做权限校验。解决:所有 Controller 方法统一走拦截器校验,接口路径不按角色做前缀区分,权限判断只认权限码。自测时用普通账号手动改请求参数,能过才算通过。
4.3 统计报表数据对不上
现象:辅导员看到的住宿率与管理员看到的差几个百分点。原因通常是统计口径不一致:一边算“已占用床位/总床位”,另一边算“已分配学生/总人数”,维修中的床位归属没约定。解决:把统计口径写进设计文档,维修中床位统一算“不可用”且不计入分母,或者单独列出,前后端共用一套 SQL 视图。
4.4 报修流程卡死
现象:报修单停在“维修中”无法推进,或者学生看不到已完成记录。原因多半是状态流转校验过严但缺少回退入口,或者查询条件漏了状态。解决:给管理员保留“强制流转”入口并记日志,学生端查询不按单一状态过滤,改为按时间倒序展示全部。
4.5 中文乱码与时间偏差
现象:检查记录里的备注出现乱码,或者报修时间比实际差 8 小时。原因是数据库字符集不是 utf8mb4,或 JDBC 连接未指定时区。解决:建库时统一utf8mb4,连接串加上serverTimezone=Asia/Shanghai,实体类时间字段用LocalDateTime,序列化格式在全局配置里定死。
5. 验收与答辩:怎么证明这套系统真的能用
验收阶段最忌讳只演示“页面能点开”。我一般按三条线走:功能线、数据线、异常线。功能线覆盖四类角色的主流程各一遍,学生报修到完成、宿管排寝到退宿、辅导员查报表、管理员改权限;数据线检查关键表的约束是否生效,比如床位唯一约束、外键关联、逻辑删除字段;异常线专门制造错误输入,重复分配、越权请求、非法状态跳转,看系统是否给出明确提示而不是 500 错误。
答辩演示建议准备一份固定脚本,按“登录不同角色 → 走一条完整业务闭环 → 展示数据库变化”的顺序讲,比逐页翻菜单有说服力。演示数据提前准备好,至少包含两个楼栋、若干空床与占用床、几条不同状态的报修单,这样任何提问都能现场查。下面这张表可以直接放进答辩 PPT 的验收页:
| 验收项 | 验收方法 | 合格标准 |
|---|---|---|
| 住宿分配 | 并发调用分配接口 | 无重复分配,失败有提示 |
| 权限控制 | 学生账号调管理员接口 | 返回无权限,不暴露数据 |
| 报修闭环 | 走完五态流转 | 每步有日志,状态不可跳步 |
| 统计报表 | 对比手工核算结果 | 口径一致,误差为零 |
| 数据完整性 | 删除楼栋后查关联 | 有外键约束或业务拦截 |
有一点血泪经验值得说:答辩前一定要把数据库初始化脚本跑一遍全新环境。我见过太多次在自己机器上一切正常、换台电脑建表就缺字段的情况,原因是表结构是用图形工具改的,没同步到脚本。从那以后我每次交付前都强制走一遍“空库建表 → 导入初始数据 → 跑主流程”的流程,宁可多花半小时,也不在演示现场找后悔药。希望这套结构和验收清单能帮到你,照着改就能变成你自己的方案。
本文还有配套的精品资源,点击获取