首页 / 资讯中心 / 文章详情

Java+MySQL+Swing宿舍管理系统:从数据库设计到图表导出完整实战

Java+MySQL+Swing宿舍管理系统:从数据库设计到图表导出完整实战 ★ FEATURED ARTICLE
简介一套基于MySQL数据库、Java语言和Swing图形界面开发的学生宿舍管理系统课程设计资源定位明确面向高校数据库及Java课程设计场景辅助学生快速完成项目。资源包共334个文件压缩后约112.72MB包含Java源码与编译后的class文件、设计图表和说明文档。文件类型兼顾代码与素材源码便于二次开发png图表可用于撰写课程设计报告xml等配置文件则帮助导入开发环境后直接运行。系统围绕宿舍管理核心业务展开覆盖学生管理、宿舍管理、管理员管理等模块组件划分清晰管理员管理组件、学生管理组件和宿舍管理组件相互独立适合逐模块分析学习。目前已有268人学习浏览该资源包对需要完整课程设计案例或源码参考的在校学生而言是一份结构完整、内容实用的学习资料。1. 一个课程设计标题背后是一整套 JavaMySQL 落地方案每年到了课程设计季总能在各种群里看到有人问“宿舍管理系统源码有没有”。其实这个题目之所以被翻来覆去地做是因为它足够典型一个 Java Swing 桌面客户端配一个 MySQL 数据库把学生、宿舍楼、入住记录、报修、卫生评分这几类数据管起来再补上图表展示和课程设计文档。技术栈不新但五脏俱全能完整检验你对 JDBC、事件监听、SQL 设计和文档撰写的掌握程度。这个标题真正的价值不在“源码”而在“图表文档”这两样容易被忽略的东西——图表说明你会把数据可视化文档说明你能把系统讲清楚。很多人的代码能跑但答辩时拿不出图表和报告最后分数上不去。这篇文章不会给你一份现成源码包那没有意义我要做的是把整条落地路径拆开数据库怎么设计、Swing 界面怎么搭、图表怎么出、文档怎么写、坑在哪里。适合正在做课程设计的学生也适合想快速搭一套桌面端管理 demo 的开发者。2. 先把数据库立住宿舍管理系统的表设计与 JDBC 连接配置2.1 为什么用 MySQL以及六张核心表怎么划分做课程设计数据库选型一般就在 MySQL 和 SQLite 之间选。SQLite 零配置但答辩时老师大概率会问“你的数据存在哪、怎么备份”SQLite 答起来比较单薄MySQL 是真实项目里最常见的组合服务端 客户端的架构更好讲也能体现你对连接配置、字符集、事务这些概念的理解。所以这个标题既然写明了 mysqlJavaswing那数据库就用 MySQL连接方式走 JDBC。表结构设计是数据库部分的得分点。我见过很多人的宿舍管理系统只建两张表一张管理员、一张学生这显然撑不起“系统”两个字。我一般建议按业务拆成六张表管理员表admin、学生表student、宿舍楼表building、房间表room、入住记录表occupancy、报修记录表repair。如果还想做卫生评分或晚归统计再加一张 score 表。六张表的状态如下adminid、username、password用于登录校验studentid、student_no、name、gender、phone、building_id、room_idbuildingid、name、floor_count、room_countroomid、building_id、room_no、bed_count、occupied_count、statusoccupancyid、student_id、room_id、check_in_date、check_out_daterepairid、room_id、description、status、create_time房间表和宿舍楼表拆分的好处是统计“每栋楼的入住率”时只需要关联 room 表的 occupied_count 和 bed_count不用去 student 表里 count 人数。入住记录表独立出来是为了支持“历史入住/退宿查询”这是图表数据的来源。字段类型上id 用 INT 自增主键student_no 用 VARCHAR(20)学号会有前导零phone 用 VARCHAR(11)日期用 DATE状态字段用 TINYINT0 表示未入住/未处理1 表示已入住/已处理不要用 Enum因为 JDBC 读取 Enum 要额外处理。2.2 建库建表 SQL直接复制的初始化脚本新建一个数据库dormitory_db字符集统一用utf8mb4。下面这份建表脚本可以直接在 Navicat 或 MySQL Workbench 里执行也可以在 Java 启动时用Statement批量执行。注意外键关系要先建主表再建从表否则 MySQL 会报“无法创建表”的错误。CREATE DATABASE IF NOT EXISTS dormitory_db DEFAULT CHARSET utf8mb4; USE dormitory_db; CREATE TABLE admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL ) ENGINEInnoDB; CREATE TABLE building ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, floor_count INT DEFAULT 6, room_count INT DEFAULT 0 ) ENGINEInnoDB; CREATE TABLE room ( id INT PRIMARY KEY AUTO_INCREMENT, building_id INT NOT NULL, room_no VARCHAR(20) NOT NULL, bed_count INT DEFAULT 4, occupied_count INT DEFAULT 0, status TINYINT DEFAULT 0, UNIQUE KEY uk_building_room (building_id, room_no), CONSTRAINT fk_room_building FOREIGN KEY (building_id) REFERENCES building(id) ) ENGINEInnoDB; CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(50) NOT NULL, gender TINYINT DEFAULT 0, phone VARCHAR(11), building_id INT, room_id INT, CONSTRAINT fk_student_room FOREIGN KEY (room_id) REFERENCES room(id) ) ENGINEInnoDB; CREATE TABLE occupancy ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL, room_id INT NOT NULL, check_in_date DATE NOT NULL, check_out_date DATE, CONSTRAINT fk_occ_student FOREIGN KEY (student_id) REFERENCES student(id), CONSTRAINT fk_occ_room FOREIGN KEY (room_id) REFERENCES room(id) ) ENGINEInnoDB; CREATE TABLE repair ( id INT PRIMARY KEY AUTO_INCREMENT, room_id INT NOT NULL, description VARCHAR(255), status TINYINT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_repair_room FOREIGN KEY (room_id) REFERENCES room(id) ) ENGINEInnoDB;这份脚本里值得注意的参数有两个一个是DEFAULT CHARSET utf8mb4不指定的话 MySQL 8 以下版本默认 latin1插入中文姓名和宿舍描述时会变成乱码另一个是UNIQUE KEY uk_building_room (building_id, room_no)它保证同一栋楼里不会出现重复房间号数据层面就堵住了重复录入的可能。外键用fk_前缀命名答辩时老师看表结构会认为你有规范意识。status TINYINT DEFAULT 0比直接存字符串更省空间查询时在 Java 里转成“已入住/空房”文案即可。2.3 JDBC 连接配置驱动、URL 三参数与封装方式写 JDBC 连接是每张表的 CRUD 都会用到的底层逻辑我建议不要在每个 DAO 类里重复DriverManager.getConnection()而是抽一个DBUtil工具类。第一次作业时很多人会漏掉Class.forName()在 MySQL 8.x 的驱动下其实不写也能连SPI 机制自动加载但写上更稳也能体现你理解驱动的加载机制。import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static final String DRIVER com.mysql.cj.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/dormitory_db ?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(MySQL驱动加载失败请检查依赖); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, java.sql.Statement stmt, java.sql.ResultSet rs) { try { if (rs ! null) rs.close(); } catch (SQLException ignored) {} try { if (stmt ! null) stmt.close(); } catch (SQLException ignored) {} try { if (conn ! null) conn.close(); } catch (SQLException ignored) {} } }这段代码有三个参数是你必须能说清楚的useSSLfalse是因为本地开发不需要加密连接加了反而可能在部分 MySQL 版本上报 SSL 握手警告serverTimezoneAsia/Shanghai解决 JDBC 驱动与 MySQL 服务器时区不一致导致的日期报错characterEncodingutf8保证从数据库读出的中文不乱码。这三个参数是课程设计里最常见的扣分点——不写时区参数Java 8 以上连 MySQL 8 会直接抛 SQLException 提示 CST 时区无法识别。另外PASSWORD里的123456是本地开发约定提交代码前记得改成自己的密码避免答辩时连不上库。3. 用 Swing 搭登录和主界面事件监听、表格绑定与 CRUD 的完整链路3.1 登录窗口从文本框到数据库校验的最小实现Swing 界面不需要做得多炫但登录窗口的交互逻辑必须完整文本输入、密码掩码、按钮监听、回车触发、失败提示、成功跳转。常见做法是用JFrame做主窗口JPanel做内容面板GridBagLayout做表单居中布局。密码框用JPasswordField取值时用getPassword()拿到的是char[]要转成 String 再传给 DAO 层校验。JFrame loginFrame new JFrame(宿舍管理系统登录); loginFrame.setSize(400, 300); loginFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); loginFrame.setLocationRelativeTo(null); JPanel panel new JPanel(new GridBagLayout()); GridBagConstraints gbc new GridBagConstraints(); gbc.insets new Insets(10, 10, 10, 10); JLabel userLabel new JLabel(用户名:); JTextField usernameField new JTextField(15); JLabel pwdLabel new JLabel(密码:); JPasswordField passwordField new JPasswordField(15); JButton loginBtn new JButton(登录); gbc.gridx 0; gbc.gridy 0; panel.add(userLabel, gbc); gbc.gridx 1; panel.add(usernameField, gbc); gbc.gridx 0; gbc.gridy 1; panel.add(pwdLabel, gbc); gbc.gridx 1; panel.add(passwordField, gbc); gbc.gridx 0; gbc.gridy 2; gbc.gridwidth 2; panel.add(loginBtn, gbc); loginBtn.addActionListener(e - { String username usernameField.getText().trim(); String password new String(passwordField.getPassword()); UserDao dao new UserDao(); if (dao.checkLogin(username, password)) { JOptionPane.showMessageDialog(loginFrame, 登录成功); loginFrame.dispose(); new MainFrame().setVisible(true); } else { JOptionPane.showMessageDialog(loginFrame, 用户名或密码错误); } }); loginFrame.setContentPane(panel); loginFrame.setVisible(true);这段代码的关键点是getText().trim()去掉用户名两端的空格避免用户误敲空格导致登录失败密码从char[]转 String 是因为JPasswordField.getText()已被标记为废弃虽然能用但会有删除线提示答辩时显得不专业。GridBagConstraints的gridwidth 2让按钮横跨两列居中。loginFrame.dispose()之后new MainFrame()不能写在 dispose 前面否则窗口会一闪而过。逻辑上按下登录按钮会调用UserDao.checkLogin()DAO 里执行SELECT COUNT(*) FROM admin WHERE username? AND password?返回大于 0 即通过。3.2 主界面与 JTable把学生列表装进表格的关键代码主界面是所有功能的入口左侧放功能导航右侧放数据表格。学生信息管理是这个系统最核心的模块做法是JTable绑定DefaultTableModel把 SQL 查询的结果集转换成二维数组灌进去。这里有个坑JTable默认不可编辑但DefaultTableModel默认是可编辑的如果你直接往里addRow表格单元格是可以点进去改的但改完没写回数据库就会出现界面和数据不一致。所以要重写isCellEditable返回 false。import javax.swing.*; import javax.swing.table.DefaultTableModel; import java.sql.*; public class StudentPanel extends JPanel { private JTable table; private DefaultTableModel model; public StudentPanel() { model new DefaultTableModel(new String[]{ID, 学号, 姓名, 性别, 电话, 楼栋, 房间}, 0) { Override public boolean isCellEditable(int row, int column) { return false; } }; table new JTable(model); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); JScrollPane scrollPane new JScrollPane(table); setLayout(new BorderLayout()); add(scrollPane, BorderLayout.CENTER); loadData(); } public void loadData() { model.setRowCount(0); String sql SELECT s.id, s.student_no, s.name, s.gender, s.phone, b.name AS building_name, r.room_no FROM student s LEFT JOIN building b ON s.building_id b.id LEFT JOIN room r ON s.room_id r.id; try (Connection conn DBUtil.getConnection(); Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(sql)) { while (rs.next()) { model.addRow(new Object[]{ rs.getInt(id), rs.getString(student_no), rs.getString(name), rs.getInt(gender) 1 ? 男 : 女, rs.getString(phone), rs.getString(building_name), rs.getString(room_no) }); } } catch (SQLException e) { JOptionPane.showMessageDialog(this, 加载学生数据失败: e.getMessage()); } } }这段代码里最值得讲的是那条LEFT JOIN查询学生列表时把building_id和room_id直接换成楼栋名和房间号不要在 Java 里先查学生再循环查楼栋名那样会产生 N1 查询问题数据量少时没感觉答辩时把数据量说到上千条就会被质疑。setRowCount(0)是重置表格的惯用方法比removeAllRows()更直接。try-with-resources语法会自动关闭 Connection、Statement、ResultSet不用手动调用close()方法。性别字段在数据库里存的是 TINYINT展示时在 Java 侧转成“男/女”SQL 里不要写CASE WHEN那样会把结果列变长表格对齐反而麻烦。3.3 增删改查的完整调用链从按钮事件到 SQL 再到结果回显课程设计里最容易翻车的就是“界面按钮点了没反应”或者“数据改了刷新不出来”。完整调用链是按钮点击 → 获取表单数据 → 调用 DAO 方法 → 执行 SQL → 提交事务 → 刷新表格。如果任何一个环节断了问题要么在 SQL 语句本身要么在刷新时机。public void addStudent(Student s) { String sql INSERT INTO student (student_no, name, gender, phone, building_id, room_id) VALUES (?, ?, ?, ?, ?, ?); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, s.getStudentNo()); ps.setString(2, s.getName()); ps.setInt(3, s.getGender()); ps.setString(4, s.getPhone()); ps.setInt(5, s.getBuildingId()); ps.setInt(6, s.getRoomId()); ps.executeUpdate(); JOptionPane.showMessageDialog(this, 添加成功); loadData(); } catch (SQLException e) { if (e.getMessage().contains(Duplicate)) { JOptionPane.showMessageDialog(this, 学号已存在); } else { JOptionPane.showMessageDialog(this, 添加失败: e.getMessage()); } } }使用PreparedStatement而不是Statement拼 SQL是我反复强调的一点。一是防止 SQL 注入课程设计的登录模块如果用字符串拼接答辩老师会让你当场演示注入二是?占位符让代码更整洁。ps.setInt的参数类型要和数据库字段类型严格对应比如building_id在数据库是 INT就别传 String。loadData()放在executeUpdate()之后是确保插入成功后表格立即刷新。Duplicate异常判断用contains是因为不同 MySQL 版本的错误信息措辞不同有的叫Duplicate entry有的叫Duplicate key name用contains(Duplicate)能统一捕获。4. 图表与文档导出把查询数据变成能答辩的成果物4.1 用 JFreeChart 做入住率统计从 ResultSet 到图表的转换标题里“图表”两个字是加分项。Java Swing 生态里做图表最省事的选择是 JFreeChart它支持柱状图、饼图、折线图输出 PNG 或直接嵌入 JFrame 都方便。习惯了 Web 前端 ECharts 的同学可能觉得 JFreeChart 丑但课程设计的重点是“你有这个意识并且数据链路是通的”而不是图表 UI 有多精致。import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.data.general.DefaultPieDataset; import org.jfree.data.category.DefaultCategoryDataset; public JPanel createPieChart() { DefaultPieDataset dataset new DefaultPieDataset(); String sql SELECT b.name, COUNT(s.id) AS cnt FROM building b LEFT JOIN student s ON s.building_id b.id GROUP BY b.id, b.name; try (Connection conn DBUtil.getConnection(); Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(sql)) { while (rs.next()) { dataset.setValue(rs.getString(name), rs.getInt(cnt)); } } catch (SQLException e) { e.printStackTrace(); } JFreeChart chart ChartFactory.createPieChart( 各宿舍楼入住人数分布, dataset, true, true, false); return new ChartPanel(chart); }这段代码要传达的核心是“图表的数据源依然是 SQL 查询结果”。LEFT JOIN加GROUP BY把每个楼栋的入住人数算出来饼图的每个扇区就是一个楼栋。createPieChart的五个参数分别是标题、数据集、是否显示图例、是否生成 tooltip、是否生成 URL——最后一个参数在桌面程序里传 false 即可传 true 是 Web 项目用的。还要注意ChartPanel直接继承JPanel所以可以像普通面板一样add()到主窗口的BorderLayout.CENTER不需要额外写渲染代码。4.2 用 POI 把台账导出成 Word 文档答辩报告的素材来源“文档”在标题里指两层意思一是课程设计报告本身二是系统功能里的一键导出。后者用 Apache POI 操作 XWPFDocument 就能实现把 JTable 里的数据循环写入 Word 表格。导出功能的意义在于向老师展示“系统能输出可归档的成果物”。import org.apache.poi.xwpf.usermodel.*; public void exportStudentToWord() { try (XWPFDocument doc new XWPFDocument()) { XWPFParagraph title doc.createParagraph(); title.setAlignment(ParagraphAlignment.CENTER); title.createRun().setText(学生宿舍管理系统 - 学生台账); XWPFTable table doc.createTable(model.getRowCount() 1, 7); String[] headers {ID, 学号, 姓名, 性别, 电话, 楼栋, 房间}; for (int i 0; i headers.length; i) { table.getRow(0).getCell(i).setText(headers[i]); } for (int row 0; row model.getRowCount(); row) { for (int col 0; col 7; col) { Object val model.getValueAt(row, col); table.getRow(row 1).getCell(col).setText(val null ? : val.toString()); } } try (java.io.FileOutputStream fos new java.io.FileOutputStream(学生台账.docx)) { doc.write(fos); } JOptionPane.showMessageDialog(this, 导出成功文件在当前目录下); } catch (Exception e) { JOptionPane.showMessageDialog(this, 导出失败: e.getMessage()); } }POI 的表格操作有一个明显的边界createTable(rows, cols)创建的表格是XWPFTable通过getRow(i).getCell(j).setText()写入内容。如果model.getRowCount()为 0也就是表格里没有数据你依然会得到一个只有表头的空 Word 表不会报错。文件名不要写绝对路径用相对路径“学生台账.docx”会生成在项目根目录答辩时容易找到。另外POI 依赖较大课程设计里不需要用到复杂的样式掌握createParagraph、createRun、createTable这三个 API 就足够应付。4.3 图表展示的三种方式与答辩时的数据验证图表除了嵌入 Swing 窗口还应该能单独导出 PNG这样在课程设计文档里也能贴图。用ChartUtils.saveChartAsPNG可以做到。答辩前我习惯把图表数据来源用一条 SQL 单独跑一遍和界面上显示的数字对比——如果对不上多半是loadData()没刷新或者 GROUP BY 条件写错了。File chartFile new File(入住率统计.png); ChartUtils.saveChartAsPNG(chartFile, chart, 600, 400);注意saveChartAsPNG的四个参数文件对象、图表对象、宽度、高度。600×400 是 Swing 窗口常见尺寸导出后在 Word 文档里排版也不会失真。还有一个细节JFreeChart 默认使用 AWT 字体绘制中文环境下标题可能显示成方块解决方案是注册中文字体比如FontUtil里设置chart.getTitle().setFont(new Font(微软雅黑, Font.BOLD, 16))饼图的标签字体也要单独设否则图例上的“男生/女生”会变成乱码。5. 避坑记录驱动加载失败、中文乱码与表字段冲突5.1 现象ClassNotFoundException: com.mysql.cj.jdbc.Driver这是第一次运行程序时最常见的报错。原因只有一个驱动 JAR 包没有真正加入项目依赖。不少同学把 mysql-connector-java 的 JAR 下载下来放在文件夹里但没在 IDE 里 Add to Classpath或者 Maven 项目里pom.xml写了依赖却没有刷新。解决确认项目的构建路径里有这个 JAR 包。如果是普通 Java 项目右键项目名 → Build Path → Add External JARs如果是 Maven 项目确认pom.xml的依赖坐标正确然后执行 Maven 的 Reload 操作。还可以做一个自检在代码里任意位置写Class.forName(com.mysql.cj.jdbc.Driver)能过就说明依赖到位不用等运行到连接数据库时才暴露问题。5.2 现象数据库里的中文显示正常但 Swing 界面上全是问号这个问题分成两种。一种是连接层面的乱码原因是 JDBC URL 里没有characterEncodingutf8参数另一种是表格显示层的乱码原因是 JTable 的默认字体不支持中文或者读取到的字节本身已经是乱码。前者改 URL后者改字体或改数据库字符集。解决先把排查范围缩小。在 MySQL 命令行里直接SELECT name FROM student如果命令行显示正常说明数据没问题问题在 JDBC 连接或 Swing 渲染如果命令行也乱码说明建库时字符集不对用ALTER DATABASE dormitory_db DEFAULT CHARSET utf8mb4修库再用ALTER TABLE student CONVERT TO CHARACTER SET utf8mb4修表。判断乱码方向最实用的招是看乱码形态全是问号多半是存储层丢了字节显示成菱形符号多半是读取时编码不一致。课程设计里统一用 utf8mb4 就能避免九成以上的中文问题。5.3 现象宿舍号是“101”这种纯数字但用字符串拼接查询查不出结果有一个容易被忽视的字段类型陷阱宿舍号room_no如果用 INT 类型存储“101”和“0101”会被当成同一个数而且宿舍楼里有地下室房间时编号规则会变得混乱。更隐蔽的问题是如果后续想支持“101A”这种带字母的房间号INT 字段直接废了。解决room_no一律用 VARCHAR(20)不要用 INT。这是一个数据建模层面的选择字段本身没有数学计算需求只是作为标识符使用就应该用字符串。同理学号字段也建议 VARCHAR(20)因为学号可能包含字母也可能有前导零。这个坑在写建表 SQL 时就要避开等数据填进去了再改类型会触发一堆外键冲突。5.4 现象程序运行正常但点“查询报修记录”时卡住无响应Swing 是单线程模型所有事件处理都在 EDTEvent Dispatch Thread上执行。如果你的查询 SQL 很慢或者ResultSet里数据量大到需要几秒处理界面就会冻结。课程设计的数据量不大所以不明显但答辩演示时如果数据库服务刚好在忙就会尴尬。解决耗时操作不要直接写在actionPerformed里。用SwingWorker或干脆先setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))提示用户。课程设计阶段不需要引入复杂的并发框架最简单的做法是大查询之前显示“正在加载…”查询结束在finally块里恢复光标。至少给用户一个反馈程序“慢”和“死”是两种完全不同的观感。5.5 现象两个窗口同时操作数据库后保存的覆盖了先保存的宿舍管理系统的场景是这样的管理员 A 修改了学生的房间号管理员 B 同时修改了同一名学生的电话后提交的那次操作会把前一次的修改覆盖掉。课程设计阶段一般不会要求做乐观锁但答辩老师可能会问“你怎么处理并发”。解决给 student 表加一个versionINT 字段每次 UPDATE 时带条件WHERE id? AND version?更新成功后version version 1。如果更新的影响行数为 0说明数据已被别人改过。这个方案叫乐观锁代码量不大但概念很加分。执行更新时用conn.setAutoCommit(false)开启事务UPDATE完成后commit()任何一步失败就rollback()——事务的引入会让系统的可靠性上一个档次。6. 从“能跑”到“能答辩”连接池接入与代码分层的几个技巧程序能跑只是第一步课程设计要拿高分代码结构一定要分三层界面层view、业务逻辑层service、数据访问层dao。这个标题下的很多参考代码把 SQL 直接写在按钮事件里三百行代码全挤在一个类中表面上能用但答辩时老师让你改一个功能你会无从下手。我在做这个题目时会把每个模块拆成独立类LoginFrame只负责收集输入LoginService负责校验逻辑UserDao负责执行 SQL。这样每层都能单独测试老师问“登录流程怎么走”时你也可以分层讲清楚。第二个进阶技巧是引入连接池。目前的DBUtil是每次操作数据库都新建连接用完就关这个设计在课程设计阶段够用但要体现“工程化”意识可以换成 HikariCP 连接池。配置很简单初始化一个HikariDataSource之后getConnection()从池里取。好处是连接复用、响应更快而且是真实项目里的标准做法。有一个细节要注意——HikariCP搭配 MySQL 8 时JDBC URL 里的时区参数依然要保持否则会报时区错误。最后一个答辩时能拉开差距的动作演示图表时不要只说“这是一个饼图”要说出图表对应的 SQL 是什么比如“这个饼图的数据来自 building 和 student 的 LEFT JOIN按楼栋分组统计人数”——这句话直接证明图表不是贴的假图而是真实联动的。我在课程设计的最后半天做了一件事把所有模块的入口和依赖关系画在一张 A4 纸上答辩前对照着跑一遍完整流程登录、添加学生、分配房间、查看图表、导出 Word。全程没有报错老师问“你的系统哪里最容易出问题”我直接指向报修模块的状态更新逻辑并现场演示了修复过程这比背稿有用得多。课程设计的评审逻辑从来不是“代码多高级”而是“你能不能把自己写的东西讲清楚”。把数据库设计、Swing 事件流、图表数据链路这三条线理通即使某些细节实现得朴素分数也不会低。希望这些经验能帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站