简介:基于Java Swing的实验室管理系统课程设计源码包,带GUI界面,含完整数据库,适合高校学生或初级Java开发者作为课程设计参考。系统涵盖文件、维修管理、管理员助理信息、实验室课程查询预约、系统设置、帮助六大模块,其中维修管理实现设备报修、故障表、状况登记与运行状况查询,管理员助理信息含楼层分工、规章制度和值日排班,实验室课程查询预约便于安排课表,整体功能贴近实际教学楼实验室管理场景。压缩包内共1344个文件,以htm帮助文档、java源码、class编译文件、图片及sql数据库文件为主,另含jar、css等辅助资源,包体仅6.35MB,目录结构清晰易检索。目前已有123人学习下载,可通过源码与数据库直观理解Java Swing的界面布局、事件监听、JDBC数据库操作等关键点,对完成类似管理系统设计或二次开发具有直接参考价值。
1. 课程设计里的 Java Swing 实验室管理系统:你以为的“简单交差”其实是个完整闭环
一门 Java 基础课的收尾,常常落到这个标题上:基于 Java Swing 带 GUI 界面的实验室管理系统。解开压缩包,里面通常是一整套从界面到数据库的校园课设产物。它不是算法题,也不是控制台练习,而是把 Java 的面向对象思想、Swing 的事件驱动机制和数据库的增删改查缝合在一起的可运行系统。准备直接交差的人,要看懂它怎么启动、怎么连数据库;打算改成自己课题的人,需要知道哪些类管界面、哪些类管数据;只想去面试时说清项目的人,更要抓住分层、事务、查询优化这几个能开口讲的技术点。这份课设源码的价值,不在于代码量有多惊人,而在于它把“界面操作 -> 业务逻辑 -> 数据库记录”这条完整链路摆在了你面前。下面这篇笔记,顺着从解压到建库、再到跑通主界面的路径,把这类 Swing 项目的常规范式拆开讲。
2. 拆开源码包之前:看懂 Swing 课设的分层逻辑和数据库选型
在动手跑代码之前,先回答一个问题:包里的代码究竟怎么组织,为什么这样组织。搞清楚了再动手,后面的改动才不会像无头苍蝇。
2.1 实验室管理系统要管什么:角色、功能与数据模型
先定义边界。大多数课设里的实验室管理系统,核心就是三个角色:管理员、教师、学生。三个角色共用同一个登录入口,登录成功后看到的界面菜单按角色裁剪。管理员负责维护基础数据;教师和学生是设备与实验室的使用者。
再列出功能。一份能上台面的课设至少要覆盖这些:用户管理(新增账号、改密码、按角色分配权限)、实验室管理(实验室名称、位置、可容纳人数、开放时间)、设备管理(设备编号、名称、数量、状态)、预约管理(选定实验室与时间段,提交预约申请)、借用归还(记录谁在什么时间借走了哪台设备,归还时更新状态)、查询统计(按设备名模糊查询、按用户查借用历史)。
这串功能清单其实就是数据库建表清单的答案。最典型的表至少有 t_user、t_lab、t_equipment、t_borrow 四张,预约单可能拆成 t_reserve,也可能并进借用记录。表之间是普通的主外键关系:t_borrow 里的 user_id 指向 t_user.id,equipment_id 指向 t_equipment.id。归纳成一条 SQL,就是所有查询的公共骨架:
SELECT b.id, u.username, e.name AS equipment_name, b.borrow_time, b.return_time FROM t_borrow b JOIN t_user u ON b.user_id = u.id JOIN t_equipment e ON b.equipment_id = e.id;这条语句值得记住,因为它涵盖了课设最少要会写的三种能力:多表连接、别名、把用户名和设备名称这种冗余字段暴露给 JTable 展示,而不用在 Java 层再做二次查询。任何一份实验室管理系统源码,你把 DAO 里的查询逐条看一遍,会发现绝大多数都长这样。看得懂这条 SQL,就等于看懂了半份业务代码。
2.2 Swing 为什么是课设“安全牌”:和 JavaFX、Web 方案怎么比
先说结论:Swing 是一个稳妥的选择。它是 JDK 自带的,只要安装了 JDK,就不需要额外装任何前端运行时。这对课程设计很关键——答辩机器不一定装了 Node、装了 Maven,但几乎一定装了 JDK。
| 方案 | 额外依赖 | 上手曲线 | 适合什么场景 |
|---|---|---|---|
| Swing | 无 | 低,组件资料多 | 传统 Java 课设,网上源码最多的方向 |
| JavaFX | JDK 9 以后需要单独引入 javafx 模块 | 中 | 界面视觉要求高,且机器环境可控 |
| Web(Spring Boot + Thymeleaf/Vue) | JDK + Maven + Node,链路长 | 高 | 毕业设计、软件工程综合实践 |
Swing 的短处也明显:外观吃老本,控件布局写起来啰嗦,长列表渲染性能一般。但课设评分看的是功能完整度、代码整洁度、答辩能否讲清楚,这几项 Swing 都够用。数据库选型同样遵循“环境可移植”原则,最常见的是 MySQL:几乎所有课设源码包里的 .sql 脚本都是 MySQL 语法,网上问答多,出错容易被检索到解决方案。
如果你的包附带的是 SQLite 单文件数据库,说明它更在意“免安装”,但这种做法的坏处是 SQL 语法有差别,比如日期函数和自增主键写法。教一个判断方法:看包内脚本建表语句用的是 ENGINE=InnoDB 还是 AUTOINCREMENT,前者是 MySQL,后者多半是 SQLite。遇到后者,JDBC 驱动要换成 sqlite-jdbc,URL 也不是 jdbc:mysql://,而是 jdbc:sqlite:lab.db——这是第一处容易踩坑的地方。
2.3 包结构和类划分:一份 Swing 源码怎么读最快
拿到任何源码包,先不要急着搜 main 方法,先看目录结构。一个规范的 Swing 课设,目录通常是这样的:
src/ com.lab.model 实体类:User、Equipment、LabRoom、BorrowRecord com.lab.dao JDBC 访问层:UserDao、EquipmentDao、BorrowDao com.lab.service 业务层:登录校验、预约时间冲突判断(部分课设没有) com.lab.view 窗口类:LoginFrame、RegisterDialog、MainFrame、EquipmentDialog com.lab.util 工具类:DBHelper、StringUtils Main.java 程序入口 db/ lab.sql 建库建表脚本 + 初始化数据 lib/ mysql-connector-java-*.jar不同包的文件名会有出入,但按这个层次去对应,很快能定位三样东西:入口、连接、SQL。入口看 view 和 Main,连接看 util 或 db 下的配置,SQL 看 dao。如果发现 dao 目录下只有一个类文件、其它逻辑全堆在 view 里,说明这份源码没有分层,改写时别照抄它的结构。
数据流向通常是单向的:Main 创建 LoginFrame,LoginFrame 调用 UserDao 做登录,成功后跳 MainFrame,MainFrame 里的按钮监听器再调 EquipmentDao、BorrowDao 刷新表格。这种单向依赖是 Swing 课设的干净形态。连接管理方面,同类项目最常见的工具类是 DBHelper:
public class DBHelper { private static final String DRIVER = "com.mysql.cj.jdbc.Driver"; private static final String URL = "jdbc:mysql://localhost:3306/lab_manager" + "?useUnicode=true&characterEncoding=utf8" + "&useSSL=false&serverTimezone=Asia/Shanghai"; private static final String USER = "root"; private static final String PASSWORD = "123456"; public static Connection getConnection() throws SQLException { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { throw new SQLException("JDBC 驱动类找不到,请检查 lib 目录", e); } return DriverManager.getConnection(URL, USER, PASSWORD); } }四个参数按顺序解释:DRIVER 是驱动类全名,MySQL 8 用 com.mysql.cj.jdbc.Driver,MySQL 5.x 用 com.mysql.jdbc.Driver,写反一定会抛 ClassNotFoundException;URL 里的 localhost 指本机,3306 是 MySQL 默认端口,lab_manager 是数据库名;characterEncoding=utf8 让驱动以 UTF-8 方式传输字符串;serverTimezone 是 MySQL 8 的强制要求,不设置会报时区错误。PASSWORD 是最常改动的位置,它对应你自己机器上的 MySQL root 密码。把这段配置理解透,后面所有“连不上”的报错都能绕回来查它。
3. 本地跑起来:JDK、建库脚本与启动主窗体的完整链路
3.1 环境准备:JDK 版本和 IDE 编码先对齐
课设源码用 JDK 8 写的概率最大,因为 JDK 8 是教学主力版本,兼容性最好。用 JDK 8 或 11 跑基本没问题;如果你只有 JDK 17,也不必换环境,Swing 核心 API 没有移除,但要注意两点:一是源码里如果用了 javax.xml.bind 这类被移除的扩展包,需要自己补依赖;二是不建议在 JDK 17 上再叠加其它语言特性,纯 Java 最安全。
IDE 层面建议 IDEA 或 Eclipse 二选一。IDEA 打开项目最常见的坑是编码:源码是 GBK 编码而 IDEA 默认用 UTF-8 读,注释乱码,字符串字面量含中文时可能直接编译失败。解决办法是 Settings -> File Encodings 里把 Global Encoding 和 Project Encoding 都改成 GBK,或者统一转成 UTF-8 后保存。
Eclipse 的坑少一点,导入别人项目时选 File -> Import -> General -> Existing Projects into Workspace,不要用 Open。导入后右键项目 -> Properties -> Java Build Path -> Libraries,把 lib 目录里的 MySQL 驱动 jar 加进去,再做一次 Clean。很多“明明有 jar 怎么还报驱动找不到”的问题,都出在 Build Path 没加全上。
3.2 初始化数据库:SQL 脚本的三种执行方式
解开压缩包后,数据库脚本通常叫 lab.sql 或 db.sql,放在 db 目录下。执行前先确认本地 MySQL 服务是启动状态,mysql -u root -p 能正常连接。然后选一种执行方式:
方式一,命令行直接导入:
mysql -u root -p < db/lab.sql输入 root 密码后,脚本里的 CREATE DATABASE、CREATE TABLE、INSERT 会依次执行。如果脚本里没有 CREATE DATABASE 语句,需要手动建库再指定库名:
mysql -u root -p -e "CREATE DATABASE lab_manager DEFAULT CHARSET utf8mb4;" mysql -u root -p lab_manager < db/lab.sql方式二,用 MySQL Workbench 的 Data Import,选 “Import from Self-Contained File” 再选这个 .sql。注意 Workbench 对脚本里 DROP 语句的顺序有要求:脚本先 drop 了有外键依赖的表会直接报错。遇到这种报错不用慌,把 DROP 语句注释掉,或者手动先删子表再删父表。
方式三,用 IDEA 自带的 Database 面板:新建 MySQL 连接,指定库名后打开 Console,直接粘贴脚本执行。这个方法对课设最友好,报错会定位到脚本具体行,还能立刻看建出来的表结构。执行完之后验证三件事:表数量对不对、初始化账号在不在、字符集是不是 utf8mb4:
USE lab_manager; SHOW TABLES; SELECT id, username, role FROM t_user; SHOW CREATE TABLE t_user;如果 SHOW CREATE TABLE 显示 latin1,说明脚本建表时没指定字符集,后续插入中文大概率变问号。补救办法是执行 ALTER TABLE,把表和关键列都改成 utf8mb4。
3.3 从 main 方法到登录窗体:启动路径和事件线程
数据库就绪后,看入口。大多数 Swing 课设的入口类叫 Main.java,只有 main 方法,负责三件事:设置外观、弹登录窗体、把界面创建交给事件分发线程。
public class Main { public static void main(String[] args) { try { // 用当前系统的窗体外观替换默认的 Metal,观感立刻不一样 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { e.printStackTrace(); } // Swing 界面对象必须在 EDT 上创建,而不是在 main 线程里直接 new EventQueue.invokeLater(() -> { LoginFrame loginFrame = new LoginFrame(); loginFrame.setVisible(true); }); } }第一段 try-catch 是很多课设忽略的可调参数。默认外观是 Metal,换成本机 Windows 或 macOS 风格后,界面观感立刻提升,答辩时是个加分细节。第二段 EventQueue.invokeLater 把登录窗体的创建和显示投递到 EDT 上,这是 Swing 线程模型的核心理念:界面创建之后,所有组件操作都应当发生在 EDT 上。有些课设把 new LoginFrame() 直接写在 main 里,跑起来没报错,但后续查询代码一多,界面假死的概率很高。看到 invokeLater 就保留它,别为了“简化”删掉。
登录窗体可见后,输入初始账号密码(脚本里通常是 admin/admin123 或 admin/123456),点击登录按钮触发监听器。典型写法是:
private void doLogin() { String username = usernameField.getText().trim(); String password = new String(passwordField.getPassword()); // 上面这行特意用 getPassword 而不是 getText,避免 char[] 密码被日志或内存池扫到 User user = userDao.findByUsernameAndPassword(username, password); if (user != null) { MainFrame mainFrame = new MainFrame(user); mainFrame.setVisible(true); dispose(); // 登录窗体使命结束,释放资源 } else { JOptionPane.showMessageDialog(this, "用户名或密码错误"); } }留意 getPassword() 返回的是 char[] 而不是 String,这是 Swing 的安全设计。虽然课设不会把密码写日志,但面试问到 JPasswordField 时,能说出这一点就是加分项。逻辑本身很直白:DAO 查不到就弹窗,查到了就传 User 对象进主窗体。很多课设卡在“登录成功但界面不跳转”,原因往往是忘记调用 dispose(),或者在 setVisible(true) 之后又执行了一大堆初始化代码把 EDT 占住了。
到这里,系统已经能跑起来。“能跑”和“能调”是两回事,下一章把课设里必动的几处代码列出来,按着调一遍,遇到问题就知道先碰哪里。
4. 课设里最值得调的四处代码:连接参数、查询语句、表格刷新与事务边界
4.1 JDBC 连接参数:驱动类、URL 和账号密码调哪里
DBHelper 是课设的“配置中心”,90% 的运行问题都在这里。不同情况对应不同改动:
| DBHelper 里的常量 | 什么时候调 | 为什么 |
|---|---|---|
| PASSWORD | 本机 root 密码不是 123456 | 最常见的第一改动项 |
| URL 中 3306 端口 | MySQL 用了自定义端口 | 不动会报 connection refused |
| URL 中 lab_manager 库名 | 与 .sql 创建的库名不一致 | 不匹配会报 Unknown database |
| DRIVER 类名 | MySQL 5.x 换 8.x | 版本不匹配报 ClassNotFoundException |
| characterEncoding / serverTimezone | 中文乱码 / 时区错误 | MySQL 8 的 UTF-8 和时区处理是硬要求 |
改动后先不急着跑程序,在 DBHelper 里临时加一个 main 方法做连通性测试:
public static void main(String[] args) throws SQLException { Connection conn = getConnection(); System.out.println("连接成功:" + conn.getCatalog()); conn.close(); }这一步能过滤掉一大半环境问题。连接成功再进界面,连不上就先看报错落在哪个参数上。课设阶段不需要连接池,DriverManager 每次新建连接足够用,但至少要做到 finally 里关闭连接。
4.2 登录校验:为什么查询不要拼接字符串
课设里最容易被挑毛病的代码风格,就是字符串拼接 SQL。反例长这样:
// 反例:字符串拼 SQL,用户名输 ' or '1'='1 就能绕过 String sql = "SELECT * FROM t_user WHERE username = '" + username + "' AND password = '" + password + "'"; Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(sql);正例是 PreparedStatement,这也是 java 面试题里高频出现的基础点:
String sql = "SELECT * FROM t_user WHERE username = ? AND password = ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); ResultSet rs = ps.executeQuery();两个参数的含义:索引从 1 开始,第一个问号对应 username,第二个对应 password;ps.setString 会把值当作参数而不是 SQL 片段,单引号、or 这类注入词就失效了。另一个好处是 MySQL 会复用已编译的执行计划,同一句 SQL 循环执行多次时性能更好。课设里凡是涉及用户输入的查询,都应该写成这个形态。
4.3 JTable 数据填充:从 ResultSet 到 DefaultTableModel 的刷新套路
JTable 不直接吃 ResultSet,中间要经过 TableModel。最常见的套路是 DefaultTableModel:
public void fillEquipmentTable(JTable table) { // 先定义列名,再建一个 0 行的模型,逐行 addRow String[] columns = {"ID", "名称", "数量", "状态"}; DefaultTableModel model = new DefaultTableModel(columns, 0); try (Connection conn = DBHelper.getConnection(); PreparedStatement ps = conn.prepareStatement("SELECT id, name, quantity, status FROM t_equipment"); ResultSet rs = ps.executeQuery()) { while (rs.next()) { model.addRow(new Object[]{ rs.getInt("id"), rs.getString("name"), rs.getInt("quantity"), rs.getString("status") }); } } catch (SQLException e) { JOptionPane.showMessageDialog(null, "查询设备失败:" + e.getMessage()); } table.setModel(model); }三个点要注意:try-with-resources 让连接、语句、结果集自动关闭,比手动 finally 省事;addRow 接收一个 Object[],每一列的类型要和列名对得上;每次刷新都创建新模型再 setModel,比往旧模型里塞行干净,不会出现旧数据残留。
如果你还要保留“操作结果”这一列,比如最后加一个“删除”按钮,那需要重写 DefaultTableModel 的 isCellEditable 返回 false,不然 JTable 默认允许双击改单元格,数据会被改得面目全非。
4.4 增删改查的事务边界:借出设备时两条 SQL 不能分开执行
“借出”这个动作在数据库层面至少是两条语句:设备数量减一、插入借用记录。如果先减了库存再插记录时程序崩溃,设备就凭空消失了。正确的做法是把两条 SQL 放进同一个事务:
Connection conn = null; try { conn = DBHelper.getConnection(); conn.setAutoCommit(false); String updateEquip = "UPDATE t_equipment SET quantity = quantity - 1 WHERE id = ? AND quantity > 0"; String insertBorrow = "INSERT INTO t_borrow (user_id, equipment_id, borrow_time) VALUES (?, ?, NOW())"; try (PreparedStatement ps1 = conn.prepareStatement(updateEquip)) { ps1.setInt(1, equipmentId); ps1.executeUpdate(); } try (PreparedStatement ps2 = conn.prepareStatement(insertBorrow)) { ps2.setInt(1, userId); ps2.setInt(2, equipmentId); ps2.executeUpdate(); } conn.commit(); } catch (SQLException e) { if (conn != null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); } finally { try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } }参数说明集中在业务语义上:setAutoCommit(false) 之后,两条语句到 commit 才一起生效;执行到 rollback 时,前面的 UPDATE 会被撤销;executeUpdate 返回受影响的行数,如果设备数量已经是 0,ps1.executeUpdate() 返回 0,这时可以主动抛出异常让事务回滚。这段代码答透,等于把数据库增删改查和事务两个得分点同时拿下。
5. 避坑清单:从解压到答辩最容易翻车的 5 个地方
5.1 ClassNotFoundException:驱动 jar 没进 Build Path 或版本写反
现象:运行 main 方法,控制台第一行 java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver,程序直接退出。
原因:两种常见情况——lib 目录里有 jar 但 IDE 没把它加进 ClassPath;或者 jar 是 MySQL 5.x 的,而代码里驱动类名写成了 MySQL 8 的 com.mysql.cj.jdbc.Driver。5.x 的驱动类是 com.mysql.jdbc.Driver,前缀少了 .cj,两者不通用。
解决:先在 IDE 里确认 jar 出现在模块依赖列表;再用 jar tf 命令查看 jar 内部 Driver.class 的实际包路径,把 DBHelper 里的 DRIVER 改成匹配的类名。Eclipse 是右键 jar -> Build Path -> Add to Build Path,IDEA 是 Project Structure -> Modules -> Dependencies -> 加号选择 jar。
5.2 中文全部变成问号或乱码
现象:登录后下拉框、表格、弹窗里的中文全是 ??? 或乱码。
原因:三个层级,按序排查——建库建表字符集不是 utf8mb4;JDBC URL 没带 characterEncoding=utf8;IDE 的源文件编码和 .java 实际编码不一致。
解决:先执行补救 SQL:
ALTER DATABASE lab_manager CHARACTER SET utf8mb4; ALTER TABLE t_user CONVERT TO CHARACTER SET utf8mb4;再确认 URL 里是 useUnicode=true&characterEncoding=utf8,缺了就补。如果乱码只在编译期出现,把源文件统一转成 UTF-8,同时把 IDE 项目编码改成 UTF-8,让源码、驱动、数据库三层编码一致。这个坑的特点是“移植时必出现”,在实验室做没问题、拷回宿舍就乱码,本质是环境差异而不是代码逻辑错。
5.3 登录或查询后界面假死
现象:点击登录或查询按钮后,窗题栏变“无响应”,界面拖不动,几秒后恢复;操作数据库越慢卡得越久。
原因:耗时操作直接写在 ActionListener 的 actionPerformed 里,跑在事件分发线程 EDT 上,把整个界面堵死。Swing 组件只允许 EDT 更新,但查询数据库这样的阻塞操作不应该占用 EDT。
解决:把耗时操作放子线程,拿到结果再切回 EDT 更新界面:
btnLogin.addActionListener(e -> new Thread(() -> { User user = userDao.findByUsernameAndPassword(name, pwd); EventQueue.invokeLater(() -> { if (user != null) { openMainFrame(user); } else { JOptionPane.showMessageDialog(LoginFrame.this, "用户名或密码错误"); } }); }).start());这个片段在课设里完全够用。你想要更规范,可以用 SwingWorker,但时间紧张时用“子线程 + invokeLater”就是正确方向。注意不要在子线程里直接 setText 或 setVisible,凡涉及组件的调用都要包进 invokeLater。
5.4 换一台电脑运行报 Communications link failure
现象:项目复制到另一台电脑,源码没动,运行时报 Communications link failure 或 Access denied for user 'root'@'localhost'。
原因:课设用的 MySQL 数据库没有迁移过去,或者新机器 root 密码和 DBHelper 写的不一致,极端情况是新机器根本没装 MySQL。
解决:在新机器上装 MySQL,执行一遍 db/lab.sql 导入数据;确认 root 密码后改 DBHelper。检查顺序固定:MySQL 服务是否启动 -> 密码是否一致 -> 库名是否存在 -> 驱动是否匹配。这类问题不是代码 bug,是环境移植问题,写 README 时把“环境要求”列清楚,此后拷到哪台机器都能快速复原。
5.5 答辩追问三个问题:PreparedStatement、事务、表结构设计
问题一:“为什么这套代码里几乎全是 PreparedStatement?”回答结构:防 SQL 注入、预编译有性能收益、代码可读性更好。能加一句“Statement 拼字符串时,用户名输入一个 ' or '1'='1 就能绕过登录”,就是加分项。
问题二:“减库存和加借出记录为什么放在一个事务里?”答案是 4.4 节的逻辑:原子性,要么都成功,要么都回滚。说出 conn.setAutoCommit(false)、commit、rollback 三个方法的用途就够了,隔离级别不用展开。
问题三:“这两张表为什么没建外键?”很多课设为了省事只做逻辑关联,没建 FOREIGN KEY。别慌,先承认是简化设计,再补一句:如果建了外键,插入借用记录时数据库会保证 user_id 必须真实存在,只是课设为了演示方便,把约束从数据库层挪到了 Java 层校验。这个回答把弱点变成了设计取舍,还显得你考虑过方案的边界。
6. 交差之外:三个小改造,把课设从“能跑”做到“能讲”
6.1 密码从明文改成加盐哈希
大多数课设里 t_user 的 password 字段直接存明文,老师打开数据库就能看到,这也是课设里最明显的低分点。改成 SHA-256 加盐只需一个工具类:
public static String sha256WithSalt(String raw, String salt) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(salt.getBytes(StandardCharsets.UTF_8)); byte[] digest = md.digest(raw.getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); } return sb.toString(); }改动点:注册时把随机盐存进用户表单独一列,登录时先查出盐,再拼接计算哈希做比对。答辩时能讲清楚“为什么加盐而不直接哈希”——相同密码在不同盐下摘要不同,防止彩虹表攻击,这一点比“我会写 MD5”更显功底。
6.2 加一个导出 CSV 的系统维护功能
课设最怕演示到一半数据库崩了、数据被同学误删。与其祈祷数据库稳定,不如加一个务实的导出功能。在管理员的系统维护菜单里做一个“导出设备列表为 CSV”,只需要把 JTable 当前页数据落盘:
try (BufferedWriter writer = Files.newBufferedWriter( Paths.get("equipment_backup.csv"), StandardCharsets.UTF_8)) { for (Equipment e : equipmentList) { writer.write(e.getId() + "," + e.getName() + "," + e.getQuantity()); writer.newLine(); } } catch (IOException e) { JOptionPane.showMessageDialog(frame, "导出失败:" + e.getMessage()); }这个功能不复杂,但演示效果直观:先查出一条设备,再导出,用文本编辑器打开给人看。它代表的是工程化习惯——数据要有出口,不能永远躺在数据库的黑匣子里。
6.3 演示走查脚本:给自己留 5 分钟“后悔药”
答辩前给自己准备一个固定走查路线:启动登录(admin 账号)-> 新增一台设备 -> 查询设备 -> 借出 -> 归还 -> 退出。每步都确认表格变化,比如借出后库存减一、状态从“在库”变成“借出”。还要检查两个边界:查询无结果时空表格而不是报错;退出时弹出确认框,选“取消”窗体不关闭。最后这一点最容易被忽略——setDefaultCloseOperation 设置成 EXIT_ON_CLOSE,点关闭就直接退;改成 DO_NOTHING_ON_CLOSE 再由确认弹窗控制退出,行为才可控。
每年我都会帮人看几份 Swing 课设,印象最深的不是代码多华丽,而是运行没问题、自己却讲不清楚。想避免这种尴尬,就从这三个改造里挑一处亲手做完,把它变成答辩时真正能开口讲的技术点。希望帮到你,也让这份课程设计从“交差”变成你知识体系里一段能复用的底气。
本文还有配套的精品资源,点击获取