☰
基于MySQL+Java+Swing的学生宿舍管理系统课程设计实战
2026/10/27 2:08:45 网站建设 项目流程

简介:这份资源面向高校计算机相关专业学生与Java初学者,提供一套可直接运行的MySQL课程设计项目——基于MySQL数据库、Java语言与Swing图形界面开发的学生宿舍管理系统,适合用于课程设计选题、期末项目提交或数据库与桌面应用的综合练习。压缩包共334个文件,约112.72MB,以class编译文件与java源码为主体,辅以png界面截图、xml配置、db数据库文件及jar依赖,另含少量C++工程残留文件,整体结构完整、便于导入IDE后二次修改。项目围绕管理员管理、宿舍管理、学生信息管理、学生宿舍分配等模块展开,源码中可见多个管理组件与接口类,配合图表与文档可帮助读者理解数据库表设计、界面布局与业务逻辑的对应关系。目前已有268人学习下载,适合需要一份可运行、可参考的MySQL课程设计范例的读者。

1. 从一次答辩被追问说起:这套宿舍管理系统到底要解决什么

去年帮一个学弟看课程设计,他做的是学生宿舍管理,答辩时老师只问了一句「你这个系统,宿管阿姨真的会用吗」,他当场卡住。问题不在功能少,而在他把系统做成了「数据库表的增删改查界面」,没想过真实场景里谁在用、按什么顺序用。这套基于 MySQL + Java + Swing 的学生宿舍管理系统,切入点就是把这个场景讲圆:宿管要能快速查房、登记入住退宿,辅导员要能按楼栋统计床位,学生信息要能批量导入而不是一条条敲。它适合两类人——正在做 Java 课程设计、需要一套能跑通又能讲清楚设计思路的完整参考的学生,以及想拿一个桌面端 CRUD 项目练手、把分层架构和数据库设计走一遍的入门开发者。整套东西的价值不在代码多花哨,而在「需求—表结构—模块—验收」这条线是闭合的,你照着改就能交。

2. 需求与技术选型:为什么是 Swing 而不是 Web

2.1 先把三类使用者的动作拆出来

做课程设计最容易翻车的地方,是一上来就画界面。我一般会先拿一张纸,把「谁、在什么情况下、做什么动作」列出来,再决定要几张表、几个窗口。这个项目的使用者其实就三类,动作也不复杂,但每类人的关注点完全不同。

角色核心动作关注点对应模块
宿舍管理员登记入住、办理退宿、调换宿舍、查空床位操作快、少填字段、能看整栋楼状态住宿管理、床位管理
辅导员/院系管理按楼栋/院系统计人数、导出名单数据准、能筛选、能导出统计报表、查询模块
系统管理员维护楼栋房间、导入学生、管理账号批量操作、权限隔离基础数据、用户管理

把这张表定下来,后面所有设计都有依据。比如「宿管关注操作快」,就决定了入住登记窗口不能有十几个必填项,学生信息应该从已有档案里选,而不是重新录入;「辅导员要导出」,就决定了查询结果必须支持导出成表格文件,而不是只能看。很多同学的系统做完发现「功能都有但不好用」,根子就在这一步没拆清楚,直接照着数据库字段生成界面,字段全但流程断。

2.2 桌面端选型的真实理由

网上课程设计一水儿的 Web 项目,为什么这套选 Swing?不是 Swing 更先进,而是在课程设计的约束下它更「划算」。Web 方案要配 Tomcat、要写前端页面、要处理跨域和会话,一个学生独立做完,光环境搭建就能耗掉一周,最后业务逻辑反而没时间打磨。Swing 是 JDK 自带的,一个main方法就能跑起来,答辩现场双击就能演示,不用赌机房网络。对于「把数据库设计、分层架构、业务逻辑讲清楚」这个课程目标来说,桌面端把复杂度压在了真正要考的地方。

技术栈就三样,都是课程里学过的:Java SE 做业务和界面,JDBC 连数据库,MySQL 存数据。不引入 Spring、不引入 ORM 框架,不是不会,而是课程设计要展示「你自己会写 SQL、会管连接、会分层」,套框架反而把该展示的东西藏起来了。这个取舍在答辩时是加分项,老师问「为什么不用框架」,你能答出「课程目标是掌握 JDBC 和分层思想,框架会掩盖这部分实现」,比含糊其辞强得多。

2.3 环境与依赖的落地清单

环境这块踩坑最多,先把版本和依赖钉死,能省掉一半「跑不起来」的问题。

# 运行环境(课程设计常用组合,稳定优先) JDK 8 或 JDK 11 # Swing 在两者上都稳定,别用太新的版本 MySQL 5.7 或 8.0 # 8.0 注意驱动包和时区配置 mysql-connector-java # JDBC 驱动,版本与 MySQL 主版本对应 IDE:IntelliJ IDEA 或 Eclipse

驱动包要手动加到项目依赖里,这是新手第一个卡点。MySQL 8.0 的驱动类名是com.mysql.cj.jdbc.Driver,5.7 是com.mysql.jdbc.Driver,写错了启动就报ClassNotFoundException。连接串里 8.0 必须带时区参数,否则报时区错误:

// 数据库连接工具类核心片段 public class DBUtil { // 8.0 驱动类名带 cj,5.7 不带,这是最常见的翻车点 private static final String DRIVER = "com.mysql.cj.jdbc.Driver"; // useSSL=false 关掉 SSL 警告,serverTimezone 解决 8.0 时区报错 private static final String URL = "jdbc:mysql://localhost:3306/dorm_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8"; private static final String USER = "root"; private static final String PWD = "你的密码"; static { try { Class.forName(DRIVER); // 静态块只加载一次驱动 } catch (ClassNotFoundException e) { throw new RuntimeException("驱动加载失败,检查 jar 是否引入", e); } } public static Connection getConn() throws SQLException { return DriverManager.getConnection(URL, USER, PWD); } }

这段代码看着简单,但三个参数各有讲究:characterEncoding=utf8不写,中文姓名入库变问号;serverTimezone不写,8.0 直接抛异常;useSSL=false不写,控制台一堆警告干扰排查。我一般会把这个工具类单独放一个包,所有 DAO 都从这里拿连接,后面要换连接池也只改这一处。

3. 总体设计:四层结构与六张核心表的职责划分

3.1 分层架构怎么切才不糊

桌面项目最容易写成一锅粥——按钮的监听里直接写 SQL,改一个字段要翻遍所有窗口。这套方案按经典四层切:界面层(Swing 窗口和面板)、控制层(处理按钮事件、校验输入)、业务层(封装入住退宿等业务规则)、数据访问层(DAO,只管 SQL)。切分的判断标准很简单:界面层不出现Connection和SQLException,DAO 层不出现JFrame。只要守住这条线,代码就不会烂。

com.dorm ├── ui // 窗口、面板、表格模型 ├── controller // 事件监听、输入校验、调用 service ├── service // 业务规则:床位是否占用、退宿结算 ├── dao // 增删改查,纯 SQL ├── entity // 实体类,与表字段对应 └── util // DBUtil、日期工具、导出工具

这个包结构不是摆设。答辩时老师翻代码,看到ui里干干净净只有界面逻辑,dao里每个方法对应一条 SQL,会认为你理解了分层;反过来,如果ui里出现PreparedStatement,基本就暴露了「能跑就行」的心态。我带的项目里,凡是分层守住的项目,后期加功能都顺;分层破了的,加一个「调换宿舍」功能能改出三个 bug。

3.2 六张核心表与字段设计

表设计是这套系统的骨架,字段不多但要经得起追问。核心是六张表:学生表、楼栋表、房间表、床位表、住宿记录表、用户表。这里的关键设计决策是「床位单独成表」而不是在房间里存一个「已住人数」——因为要能查到具体哪个床位空着,宿管安排入住时才有得选。

-- 学生表:档案信息,与住宿记录分离,一个学生可有多条历史住宿记录 CREATE TABLE student ( stu_id VARCHAR(20) PRIMARY KEY, -- 学号做主键,业务唯一 name VARCHAR(30) NOT NULL, gender CHAR(1) NOT NULL, -- 男/女 college VARCHAR(50), -- 院系,统计用 phone VARCHAR(20), status TINYINT DEFAULT 1 -- 1在校 0离校 ); -- 床位表:核心设计,一个床位一行,占用状态直接查 CREATE TABLE bed ( bed_id INT AUTO_INCREMENT PRIMARY KEY, room_id INT NOT NULL, bed_no VARCHAR(10) NOT NULL, -- 如 1号床、2号床 is_occupied TINYINT DEFAULT 0, -- 0空 1占用,入住退宿只改这个 FOREIGN KEY (room_id) REFERENCES room(room_id) ); -- 住宿记录表:谁在什么时候住了哪个床位,退宿写离宿时间 CREATE TABLE accommodation ( record_id INT AUTO_INCREMENT PRIMARY KEY, stu_id VARCHAR(20) NOT NULL, bed_id INT NOT NULL, check_in DATE NOT NULL, check_out DATE, -- 为空表示在住 FOREIGN KEY (stu_id) REFERENCES student(stu_id), FOREIGN KEY (bed_id) REFERENCES bed(bed_id) );

床位表这个设计是整套系统的关键。很多同学图省事,在房间表里放一个current_num字段记录已住人数,结果要查「3 号楼还有哪些空床」时,只能算出总数却不知道具体哪张床空着,宿管没法安排。把床位拆成独立行,is_occupied一查就清楚,入住时把对应床位改成 1、退宿改回 0,逻辑简单且不会出现「人数对不上床位」的脏数据。住宿记录表则保留了历史,学生退宿后记录还在,辅导员查「上学期谁住过这间」有据可查,这也是答辩时容易被问到的点。

3.3 业务规则放在哪一层

分层定了,还要想清楚「入住」这个动作到底做了什么。它不是简单往住宿记录插一行,而是一个事务:检查床位是否空闲、插入住宿记录、把床位标记为占用,三步要么全成要么全败。这种规则必须放业务层,不能散在界面里。

// 业务层:入住是一个事务,三步必须一起成功 public boolean checkIn(String stuId, int bedId) { Connection conn = null; try { conn = DBUtil.getConn(); conn.setAutoCommit(false); // 关闭自动提交,开启事务 // 1. 校验床位是否仍空闲(防止并发或界面数据过期) if (!bedDao.isFree(conn, bedId)) { conn.rollback(); return false; } // 2. 插入住宿记录 accommodationDao.insert(conn, stuId, bedId, new Date()); // 3. 更新床位占用状态 bedDao.occupy(conn, bedId); conn.commit(); // 三步都成功才提交 return true; } catch (SQLException e) { try { if (conn != null) conn.rollback(); } catch (SQLException ex) { } return false; } finally { try { if (conn != null) conn.setAutoCommit(true); } catch (SQLException ex) { } } }

这段代码的重点不是语法,而是「为什么要有事务」。如果只写插入和更新两条 SQL 而不开事务,中间任何一步失败,就会出现「记录有了但床位没占」或者「床位占了但没记录」的脏数据,查房时对不上账。课程设计里能主动用事务并说清楚原因,是很实在的加分点。参数上conn在 DAO 方法间传递,是为了让多个操作共用同一个连接和事务,这也是为什么 DAO 方法要设计成接收Connection而不是自己内部获取。

4. 关键模块实现:从登录到统计的落地细节

4.1 登录与权限:一个字段区分两种人

登录模块看着简单,但权限没做好,后面全是漏洞。这套系统用用户表的一个role字段区分管理员和宿管,登录成功后把角色存进会话对象,主界面按角色决定显示哪些菜单。核心是「登录只做认证,权限判断在进入功能前做」,不要把权限判断塞进每个按钮的监听里。

// 登录校验:密码做 MD5 后再比对,不存明文 public User login(String username, String password) { String sql = "SELECT * FROM sys_user WHERE username=? AND password=?"; try (Connection conn = DBUtil.getConn(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, MD5Util.encode(password)); // 入库前统一加密 ResultSet rs = ps.executeQuery(); if (rs.next()) { User u = new User(); u.setUserId(rs.getInt("user_id")); u.setRole(rs.getInt("role")); // 1管理员 2宿管 return u; } } catch (SQLException e) { e.printStackTrace(); } return null; // 返回 null 表示认证失败 }

这里用PreparedStatement而不是字符串拼接,是防 SQL 注入的基本功,答辩时被问到「怎么防注入」能直接指这段。密码存 MD5 虽然不算强安全,但课程设计层面能体现「不存明文」的意识,比明文入库强。登录成功后主窗口根据role隐藏「用户管理」菜单,宿管看不到账号维护入口,这就是最朴素的权限隔离。

4.2 入住退宿界面:表格模型与数据联动

Swing 里展示数据用JTable,但新手常犯的错是把数据一条条addRow到表格里,数据一多就卡,而且和数据库对不上。正确做法是自定义TableModel,让表格直接持有查询结果集转换后的列表,界面刷新就是重新查一次数据。

// 自定义表格模型:列名固定,数据来自 DAO 查询结果 public class BedTableModel extends AbstractTableModel { private final String[] cols = {"床位号", "房间", "状态", "在住学生"}; private List<BedVO> data = new ArrayList<>(); public void reload(List<BedVO> list) { this.data = list; fireTableDataChanged(); // 通知表格整体刷新,比逐行增删高效 } @Override public int getRowCount() { return data.size(); } @Override public int getColumnCount() { return cols.length; } @Override public String getColumnName(int c) { return cols[c]; } @Override public Object getValueAt(int r, int c) { BedVO b = data.get(r); switch (c) { case 0: return b.getBedNo(); case 1: return b.getRoomNo(); case 2: return b.getOccupied() == 1 ? "已占用" : "空闲"; case 3: return b.getStuName() == null ? "-" : b.getStuName(); default: return ""; } } }

用fireTableDataChanged()整体刷新,而不是fireTableRowsInserted逐行通知,是因为入住退宿后床位状态和学生在住信息会同时变,整体刷新最省心。BedVO是个视图对象,把床位、房间、学生三张表关联查询的结果拼在一起,界面层不用再关心表关系。这个 VO 的设计是「界面要什么就查什么」,一条关联 SQL 搞定,避免界面里多次查库。

4.3 统计与导出:一条分组 SQL 解决辅导员的需求

辅导员要的「按楼栋统计入住人数」,本质是一条GROUP BY查询,不需要在 Java 里循环累加。把统计逻辑压到 SQL 里,既快又准,还展示了你会写聚合查询。

-- 按楼栋统计总床位、已占用、空余,一条 SQL 出结果 SELECT b.building_name AS 楼栋, COUNT(bed.bed_id) AS 总床位, SUM(bed.is_occupied) AS 已占用, COUNT(bed.bed_id) - SUM(bed.is_occupied) AS 空余 FROM building b JOIN room r ON r.building_id = b.building_id JOIN bed ON bed.room_id = r.room_id GROUP BY b.building_id, b.building_name ORDER BY b.building_name;

SUM(bed.is_occupied)这个写法利用了「占用为 1、空闲为 0」的设计,求和就是占用数,比COUNT(CASE WHEN...)简洁。查询结果直接喂给JTable展示,导出时遍历表格模型写文件即可。导出功能建议用简单的 CSV 而不是 Excel 二进制格式,CSV 用BufferedWriter逐行写,不依赖第三方库,课程设计里够用且不容易出兼容问题。导出路径让用户用JFileChooser选,别写死到某个盘符,换台机器就找不到文件。

5. 避坑与排查:五个最容易翻车的点

5.1 中文乱码:从建库到连接串要全链路一致

现象是学生姓名入库变问号、界面显示方块。原因通常是三处编码不一致:数据库建库没指定字符集、连接串没带characterEncoding、Swing 字体不支持中文。解决顺序是先查库:SHOW CREATE DATABASE dorm_db;确认是utf8mb4;再查连接串是否带characterEncoding=utf8;最后确认界面用的字体是「微软雅黑」这类中文字体而不是默认逻辑字体。三处对齐,乱码基本消失。

5.2 界面卡死:耗时操作不能放在事件线程里

现象是点「批量导入」后窗口白屏、按钮点不动。原因是 Swing 的事件处理都在事件分发线程(EDT)上跑,导入几千条数据时主线程被占住,界面自然不响应。解决办法是把耗时操作放到SwingWorker的doInBackground里执行,完成后在done方法里刷新表格。这是 Swing 的经典坑,答辩演示时如果导入卡死,观感很差,提前用SwingWorker包一层就能避免。

5.3 连接泄漏:每个 DAO 方法都要关资源

现象是系统用一会儿就报「too many connections」。原因是Connection、PreparedStatement、ResultSet用完没关,连接池或数据库连接数被耗尽。解决是用 try-with-resources 语法,让资源自动关闭:

// try-with-resources 自动关闭,顺序是 ResultSet -> Statement -> Connection try (Connection conn = DBUtil.getConn(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { // 处理结果 } catch (SQLException e) { e.printStackTrace(); }

注意事务场景下连接不能提前关,要在finally里统一处理,这也是为什么业务层的事务方法要手动管理连接生命周期。

5.4 外键约束报错:删除顺序和数据依赖

现象是删学生时报「Cannot delete or update a parent row」。原因是住宿记录表还引用着这个学生。解决不是简单关掉外键检查,而是按业务顺序处理:先确认该学生没有在住记录(check_out为空),有就先办退宿,再删档案;或者设计成逻辑删除,status置 0 而不物理删除。课程设计里推荐逻辑删除,既避免外键冲突,又保留历史数据,答辩时还能讲「为什么不做物理删除」。

5.5 演示环境翻车:数据库没初始化

现象是换台电脑演示,程序连不上库或表不存在。原因是只拷了代码没带建库脚本。解决是把建表语句和数据初始化写成一个init.sql,随项目一起交付,演示前先执行一遍。我一般还会在DBUtil里加一个启动自检,连不上库时弹窗提示「请先执行 init.sql 初始化数据库」,而不是抛一堆堆栈让人懵。

6. 验收与答辩:怎么证明这套系统真的能用

验收不是把功能点一遍就完事,要按「场景走查 + 数据核对 + 代码抽查」三步来。场景走查选一条完整业务链:新建楼栋房间 → 导入学生 → 办理入住 → 查空床位 → 办理退宿 → 看统计报表,每一步都核对界面显示和数据库里的实际数据是否一致。数据核对重点看三个地方:床位is_occupied和住宿记录check_out是否同步、统计数字和明细是否对得上、删除操作后关联数据是否处理干净。代码抽查让老师随机指一个功能,你能从界面层一路讲到 DAO 的 SQL,分层清晰就是最好的证明。

答辩时高频问题集中在设计决策上,提前准备好这几条的回答:

可能被问回答要点
为什么床位单独建表要查具体空床位,房间存人数只能得总数,无法安排入住
入住为什么用事务插记录和改床位状态必须同时成功,否则数据对不上账
为什么不用框架课程目标是掌握 JDBC 和分层,框架会掩盖这部分实现
并发入住同一床位怎么办入住前在事务内二次校验床位状态,校验失败回滚
密码为什么存 MD5不存明文是基本意识,课程层面够用,生产环境应加盐

演示环节有个小技巧:提前准备好一份「脏数据」场景,比如故意留一个已退宿学生的记录,现场演示查历史住宿,证明系统不是只能处理干净数据。这比单纯点按钮有说服力。另外把init.sql和一键启动脚本放在项目根目录,换机器演示前先跑一遍,别赌现场环境。

我带课程设计这些年,最深的教训是:功能做得再多,讲不清「为什么这么设计」就白搭。从那以后我每次帮人看项目,都强制让对方先用三分钟把「谁用、解决什么、关键设计取舍」讲一遍,讲不顺的地方就是设计没想透的地方。这套宿舍管理系统的价值也在这里——它不大,但每个模块背后都有能讲的理由。希望帮到你。

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

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

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

立即咨询