☰
Swing+MySQL医院挂号系统课设:核心代码与避坑指南
2026/9/24 22:44:13 网站建设 项目流程

简介:这套医院挂号系统是一份基于 Java Swing 与 MySQL 的高校课程设计项目源码,面向需要完成 Java 课设或快速上手图形界面数据库开发的同学,解决从需求分析到编码实现中的常见难题。系统涵盖患者挂号、医生看诊、管理员维护、号源查询与增删改查等功能模块,因来自真实接单项目,结构清晰且可正常运行,界面风格较为朴素,更契合本科课设验收要求。压缩包共 75 个文件,大小约 175KB,包含 14 个 Java 源文件、38 个 class 编译文件、12 张 png 界面素材、7 个 xml 配置文件,以及 1 份 MySQL 数据库脚本和登录账号密码,导入工程并配置好数据库即可运行。目前该资源已有 267 人浏览学习,是一份紧凑但完整的课设参考项目,可直接提交或在此基础上扩展预约排班、统计分析等功能。

1. 医院挂号系统课设资源:Swing + MySQL 能跑通的核心代码与数据库脚本

说个 Java 课设的现实:老师要的不是界面多精致,而是“能运行、有登录、有增删改查、连得通数据库”。医院挂号系统恰好把这四件事全占了,还多了一层多角色分发逻辑,是课设题里最典型的综合练习。这份资源做成了 Swing 桌面端,管理员、医生、用户三种角色分开登录,挂号、退号、按编号查、全量查、用户维护都在,源码 14 个 Java 文件平铺在 src 目录下,另配一份 yygh.sql 数据库脚本,导入即可用。它最打动我的点是“没过分美化”——界面保持在课设应有的朴素水平,作为课程设计的真实参考反而更有说服力。适合正在赶课设、想要一套稳定运行代码做比对的 Java 学生,也适合想搞明白 JDBC 怎么塞进 Swing 按钮事件里的初学者。下面从源码结构、运行复现、核心代码、常见坑四个角度拆开讲。

2. 源码结构拆解:14 个 Java 类如何撑起三端挂号业务

压缩包解开后的 src 目录是平铺结构,没有 package 层级。这对课设来说反而是好事,IDEA 打开不会因为包路径对不上而大量报红。我按文件的实际职责把它们分成四组:连接工具、登录入口、角色主窗体、业务操作类。理解这个分组,后面排查问题时能第一时间判断该找哪个文件。

2.1 按职责给 14 个 Java 文件分组定位

先看一组最核心的:JDBCUtils.java 是所有数据库操作的公共依赖,负责加载 MySQL 驱动、建立连接、关闭资源,其他类里的查询和增改都要先经它拿到 Connection。Login.java 是程序入口,也是业务的第一道关卡,只有通过了账号密码验证,后续窗体才有意义。

角色主窗体有 3 个:AdminMain.java 对应管理员端,DoctorMain.java 对应医生端,UserMain.java 对应患者端。这三个窗体是登录成功后按角色类型去实例化的,内部通常嵌入一个 JTable 表格组件,用来展示当前角色能看到的业务数据。剩下的业务操作类按功能归类,我用一张表把文件映射关系列出来:

分组文件职责
连接工具JDBCUtils.java驱动加载、连接建立、资源关闭
登录入口Login.java账号密码验证与角色跳转
角色主窗体AdminMain.java / DoctorMain.java / UserMain.java管理员、医生、用户三个端的主界面
挂号业务GHAdd.java / GHDelete.java新增挂号单、退号删除
通用 CRUDAdd.java / Delete.java / Update.java / SelectAll.java / SelectByNum.java通用增删改查与按编号查询
用户专属逻辑UserSelectAll.java / WenZ.java用户记录查询、问诊操作

这份地图对照表帮我省了很多逐个双击文件的功夫。需要注意,Add、Delete、Update 这些类名不带业务前缀,看不出操作对象是用户表还是挂号记录表,具体作用要看调用它的主窗体上下文。比如管理员端的 Add 大概率是新增用户账号,而医生端操作的对象则集中在挂号状态和问诊记录上。真正读代码时,先看窗体按钮绑定了哪个类,再看那个类里 SQL 操作的表名,职责马上就清楚了。

WenZ.java 在文件列表里比较特殊,从命名习惯推断是“问诊”的拼音缩写,承担医生说诊结果录入或查看的功能。UserSelectAll.java 是用户端的查询类,与 SelectAll.java 的区别在于它查询的范围通常被限制为当前登录用户自己的记录,而不是全表。GHAdd.java 和 GHDelete.java 是挂号业务的增和删,GH 对应“挂号”首字母,一个负责新增挂号单,一个负责退号删除。

2.2 yygh.sql 的建表逻辑:挂号单和用户信息的关系设计

yygh.sql 是这份资源里最不能丢的文件。out 目录和 .idea 配置删了能重建,脚本丢了就得重写。用 Navicat 或 IDEA 数据库面板打开脚本,看到的表结构通常是用户表和挂号记录表两类。用户表一般命名为 usr 或 user,字段至少包含 id、username、password、type——type 用来区分管理员、医生、患者三个角色。挂号记录表的字段围绕挂号业务展开,大致是挂号编号、患者姓名、科室、医生、挂号时间、状态这几项。

表之间的关联方式,课设项目常见做法是直接冗余患者姓名字段,省去联表查询。虽然不符合第三范式,但对于单机课设来说,界面展示时少一次 JOIN 就意味着少一层出错可能。我在同类项目里也一直沿用这个思路——课设代码的首要目标是稳定、易懂,不是设计模式考试。打开脚本后你会看到类似这样的建表骨架:

CREATE TABLE IF NOT EXISTS `usr` ( `id` INT NOT NULL AUTO_INCREMENT, `username` VARCHAR(50) DEFAULT NULL, `password` VARCHAR(50) DEFAULT NULL, `type` INT DEFAULT NULL COMMENT '1-管理员 2-医生 3-用户', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `gh` ( `gh_id` INT NOT NULL AUTO_INCREMENT, `patient_name` VARCHAR(50) DEFAULT NULL, `dept` VARCHAR(50) DEFAULT NULL, `doctor` VARCHAR(50) DEFAULT NULL, `gh_time` DATETIME DEFAULT NULL, `gh_status` VARCHAR(20) DEFAULT '待就诊', PRIMARY KEY (`gh_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

上面这段是此类课程设计最标准的表结构骨架,真实脚本里字段名和注释可能有出入,以文件里的实际建表语句为准。看表结构时重点盯两处:一是 type 字段的注释,这决定了角色的常量约定;二是 gh_status 的默认值,后续所有状态流转都围绕着它做判断。脚本末尾通常还有几条 INSERT 语句,用于预置管理员、医生和测试患者的账号,这是运行后第一次登录的凭证来源。

导入脚本的时候有个顺序问题要注意:很多图形化工具选中某个库再执行外部 SQL 文件时,会自动跳过 CREATE DATABASE 语句,结果就是后续建表报 Unknown database。最稳的做法是手动先建库再导表。表名和字段名的反引号不要删,MySQL 8.0 环境下部分字段名如 order、status 不带反引号会直接冲突报错。

2.3 登录后的跳转链路:账号类型决定打开哪个主窗体

登录流程是整条业务链路的咽喉。Login.java 拿到界面输入的账号密码后,通过 JDBCUtils 建立连接,在用户表里比对记录,查到后取出 type 字段,再用判断语句分发:type 为 1 就打开 AdminMain,为 2 打开 DoctorMain,为 3 打开 UserMain。这里“传用户信息”有两种常见实现:构造方法传参,或者把当前用户信息存成静态变量。构造方法传参更符合面向对象习惯,但课设里大量使用静态变量存当前登录对象,因为所有子窗体都能直接访问,不用层层传递。

两种方案在这个体量的项目里都完全够用,区别在于答辩时怎么说。构造方法传参可以讲“职责清晰、状态不再全局可见”,静态变量则可以讲“符合单例思想、减少了参数传递复杂度”。我建议选一种自己真正理解的,老师追问时能自圆其说就行。

这个链路里藏着一个隐蔽的坑:部分课设会把角色判断直接拼进 SQL 的 WHERE 子句,同时比对 username、password、type 三个条件。问题在于账号错误、密码错误、角色不存在时返回的都是同一个“查询结果为空”,用户根本不知道具体错在哪。如果你后续调试遇到“谁登录都提示账号或密码错误”,优先怀疑这里是不是把角色条件也拼进去了,拆开单独查账号密码,问题立刻暴露。

3. 本地复现:JDK + MySQL 从零跑通整套课设

这一章是动手环节,目标是让项目在你电脑上运行起来:看到登录窗口、以三种角色登录、验证数据能增能删能查。如果 JDK、IDEA、MySQL 已经装好,可以跳过 3.1 直接从 3.2 开始。整个过程大概二十分钟,其中一大半时间花在数据库导入和依赖配置上。

3.1 环境版本选型:为什么 JDK 8 + MySQL 5.7 最不容易出问题

这套代码用的是纯 JDBC + Swing,没有引入 Maven 或 Gradle,环境要求很低。JDK 1.8 是首选,Swing 在 JDK 8 里是内置组件,不需要额外配置;JDK 11 以上虽然也能编译,但高版本 JDK 对 Swing 的默认外观和字体渲染有细微变化,界面效果可能会和资源里的截图不一致,答辩时容易被老师追问。MySQL 选 5.7 或 8.0 都行,但驱动连接参数有差异:MySQL 5.7 用 mysql-connector-java 5.x 版本,8.0 则需要更细的连接串配置。

有一个常见的认知误区:代码里写 Class.forName("com.mysql.jdbc.Driver"),在 MySQL 8.0 下依然能加载,因为驱动做了兼容映射。真正会翻车的是连接 URL 缺少 serverTimezone 参数时,8.0 驱动会抛 The server time zone value 异常。解决办法是在 URL 末尾加 serverTimezone=Asia/Shanghai。至于驱动 jar 包,它不在项目源码里,需要单独下载,5.1.49 版本适配 JDK 8 和 MySQL 5.7,兼容性最好。

MySQL 安装也多说一句:Windows 上直接去官网下载 mysql-installer,安装时选 Server only,端口默认 3306,密码设成好记的。装完打开服务管理器确认 MySQL 服务处于“正在运行”状态。我处理过很多“代码连不上数据库”的报错,排查到最后发现服务根本没启动,这类基础问题最费时间。

3.2 导数据:命令行导入 yygh.sql 的正确姿势

拿到 SQL 脚本后,第一件事不是打开源码,而是把数据库建好。推荐用命令行导入,步骤最干净。打开终端,先登录 MySQL:

mysql -u root -p123456

这里的 -p 后面直接跟你的密码,如果密码含特殊字符,改成交互式输入比较稳妥。登录后依次执行:

CREATE DATABASE IF NOT EXISTS yygh DEFAULT CHARSET utf8mb4; USE yygh; SOURCE D:/workspace/yygh.sql;

SOURCE 后面写 yygh.sql 的实际路径,Windows 下正反斜杠都行,路径含空格时要用引号包起来。执行完以后用 SHOW TABLES; 确认表是否生成。如果表存在了,顺手查询一条数据:

SELECT * FROM usr;

能看到预置的用户记录,说明数据已就位。用 Navicat 或 DataGrip 导入也行,但要注意图形工具默认在当前选中的数据库上执行 SQL,脚本里如果没有 CREATE DATABASE 语句,你必须手动先建一个 yygh 库再运行脚本。相比起来,命令行一次性执行原生脚本最不容易出错。

导入时遇到 Incorrect datetime value 报错,是 MySQL 的 sql_mode 不允许零日期值。两个解决办法:一是把脚本中的日期改成 '2023-01-01 08:00:00' 这类标准格式,二是在 MySQL 配置文件的 [mysqld] 段去掉 NO_ZERO_DATE 模式后重启服务。课设场景我建议直接改脚本日期值,改配置影响全局,容易引发其他不必要的故障。

3.3 改配置:JDBCUtils 连接参数必须对齐本机环境

数据库导好了,代码里的连接信息还是作者本机的。打开 JDBCUtils.java,需要重点关注的就是 URL、USER、PASSWORD 三个常量:

private static final String URL = "jdbc:mysql://localhost:3306/yygh?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8"; private static final String USER = "root"; private static final String PASSWORD = "123456";

URL 里的 localhost:3306 是默认的本地地址和端口,如果你的 MySQL 改了端口,这里要同步修改。USER 和 PASSWORD 改成你自己安装 MySQL 时设置的账号密码。这三个值任一个不对,运行任何功能都会在第一次数据库操作时报 Access denied 或 Communications link failure。

注意 URL 后半段参数:useSSL=false 关掉了安全连接校验,本地开发可以不要证书;characterEncoding=utf8 保证中文写入不乱码;serverTimezone=Asia/Shanghai 是给 MySQL 8.0 驱动用的时区声明。没有这三个参数,常见的问题就是中文乱码和时区报错。改完这三个参数后,还要确认驱动 jar 是否已被 IDEA 识别:右键 jar 包选择 Add as Library,弹出对话框确认模块是当前项目,这样 IDEA 构建时才会把 jar 带上。

3.4 运行与验证:从 Login 主类启动并检查三种角色

IDEA 里打开项目根目录,等索引完成。在 src 目录下找到 Login.java,右键选择 Run 'Login.main()'。正常情况下会弹出 Swing 登录窗口。窗口没弹出来时,看 Run 面板的红色堆栈:报 ClassNotFoundException 是缺驱动;报 SQLException 是连接参数不对;报 Access denied 是账号密码不匹配。这三种报错都有明确的修复路径,按 3.1 到 3.3 的步骤排查即可。

登录用的账号密码在 SQL 脚本的 INSERT 语句里,打开脚本搜索 INSERT INTOusr,能看到管理员、医生、测试患者的明文记录。课设项目里密码基本是明文存储,这个没有安全性问题,因为数据是自己录的测试数据。首次登录建议先用管理员账号,管理员界面能看到全部挂号记录,配合表格里是否有数据来验证整条链路。登录进去后如果表格有数据,说明从 Java 到 MySQL 的全部通路已经打通。

能走到这一步,项目基本已经跑起来了。剩下的工作就是换上自己院系的信息、改成自己系统的名字,准备答辩素材了。

4. 核心业务代码走读:登录验证、挂号增删与查询的实际写法

这一章沿着“登录 → 主窗体 → 业务操作”的执行流,挑四个最有代表性的文件拆开讲。课设代码没有抽象层、没有工厂模式,所有逻辑都直接压在类和方法里,作为初学者顺着执行流走一遍是最快的学习方式。下面的代码片段是这类课设最典型的写法,真实源码的变量命名和顺序可能有差异,但核心流程高度一致。

4.1 JDBCUtils:驱动加载、连接建立与资源关闭的三板斧

JDBCUtils 是这份代码里唯一的基础设施类,其他所有类的数据库操作都依赖于它。核心逻辑可以概括为三件事:静态代码块加载驱动、getConnection 返回连接、close 关闭资源。代码骨架如下:

public class JDBCUtils { private static final String DRIVER = "com.mysql.jdbc.Driver"; private static final String URL = "jdbc:mysql://localhost:3306/yygh?useSSL=false&characterEncoding=utf8"; private static final String USER = "root"; private static final String PASSWORD = "123456"; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, Statement stmt, ResultSet rs) { try { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }

这段是 JDBC 的经典三段式。Class.forName(DRIVER) 把驱动类加载进 JVM,DriverManager 在 getConnection 时自动匹配已注册的驱动。close 方法值得注意的是关闭顺序:先关 ResultSet,再关 Statement,最后关 Connection。数据库资源从里到外依次释放,顺序搞反会导致连接未完全释放,长期运行可能出现连接耗尽。

这个类里没有连接池,每个操作都是即用即连、用完即关。课设项目的并发量几乎为零,这种写法完全够用,而且比连接池更容易让答辩老师理解。调用方只需要在 finally 块里调用 close,不需要关心驱动的生命周期。有一个细节可以注意:e.printStackTrace() 在课设代码里是标配,虽然生产环境不推荐,但课设阶段它就是最高效的排查方式,看到控制台堆栈比看日志文件直观得多。

4.2 Login.java:登录验证的 SQL 拼接与角色分发

Login.java 的登录按钮事件处理是整条业务链的起点。逻辑分为两步:查用户表得到账号密码匹配结果,然后根据 type 值分发到不同主窗体。典型写法如下:

String sql = "SELECT * FROM usr WHERE username = '" + username + "' AND password = '" + password + "'"; stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); if (rs.next()) { int type = rs.getInt("type"); if (type == 1) { new AdminMain().setVisible(true); } else if (type == 2) { new DoctorMain().setVisible(true); } else if (type == 3) { new UserMain().setVisible(true); } loginFrame.dispose(); } else { JOptionPane.showMessageDialog(null, "账号或密码错误"); }

字符串拼接 SQL 是课设代码的常态,但它的隐患很明显:用户输入的内容可以改变 SQL 语义。例如用户名输入 1' OR '1'='1,拼接后 WHERE 条件恒成立,不用密码也能登录。这在单机课设里没有实际攻击风险,但用 PreparedStatement 替代只需要多写两行代码:

String sql = "SELECT * FROM usr WHERE username = ? AND password = ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); ResultSet rs = ps.executeQuery();

同样的业务效果,但带参方式避免用户输入破坏 SQL 结构。建议你拿到源码后顺手把拼接改成 PreparedStatement,成本极低,答辩时还能作为一条加分项:“我考虑了 SQL 注入问题所以用了预编译语句”。这个细节在课设答辩里非常加分。

角色分发的逻辑同样值得品读:type == 1,2,3 对应三个不同主窗体,这是一种硬编码的策略分发。想让代码更有弹性,可以用 switch 或工厂方法,但课设阶段 if-else 足够。真正要注意的是 new AdminMain().setVisible(true) 之后,登录窗体要 dispose 掉,否则会出现两个窗口叠加的视觉混乱。

4.3 GHAdd 与 GHDelete:挂号、退号两条增删链路

挂号在业务上就是“往挂号表里插入一条新记录”。GHAdd.java 的事件处理逻辑:从窗体文本框取出科室、医生、患者姓名、联系电话,执行 INSERT 语句,然后用受影响行数判断是否成功:

String sql = "INSERT INTO gh (patient_name, dept, doctor, gh_time, gh_status) VALUES (?, ?, ?, NOW(), '待就诊')"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, patientName); ps.setString(2, dept); ps.setString(3, doctor); int rows = ps.executeUpdate(); if (rows > 0) { JOptionPane.showMessageDialog(null, "挂号成功"); } else { JOptionPane.showMessageDialog(null, "挂号失败,请重试"); }

这段代码里 gh_time 用了 MySQL 的 NOW() 函数,数据库服务端生成当前时间,省去了 Java 端格式化日期的代码。gh_status 字段直接插入字符串“待就诊”,是挂号业务的初始状态。后续医生在 DoctorMain 里执行 UPDATE 把它改成“已就诊”,构成系统最简单的状态流转。

GHDelete 对应退号操作,核心是一条 DELETE 语句,常见实现是根据挂号编号删除:

String sql = "DELETE FROM gh WHERE gh_id = ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, ghId); int rows = ps.executeUpdate(); if (rows > 0) { JOptionPane.showMessageDialog(null, "退号成功"); refreshTable(); }

executeUpdate 返回的是受影响的行数,增删改操作成功与否就以它为准。refreshTable 是手动调用的表格刷新方法,退号后界面要同步更新,否则表格里还是旧数据。GHDelete 这类代码有个常见缺陷:没有二次确认弹窗,按钮一点数据就没了。建议补一段 JOptionPane.showConfirmDialog 做确认,这个很容易实现,但在答辩中能展现你考虑过数据误删风险。

4.4 SelectByNum 与 SelectAll:查询结果如何灌进 Swing 表格

SelectAll 执行的是全表查询,管理员登录后主窗体表格展示全部挂号记录。Java 端读取结果集并填充到表格的写法如下:

String sql = "SELECT * FROM gh"; stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); while (rs.next()) { Object[] row = { rs.getInt("gh_id"), rs.getString("patient_name"), rs.getString("dept"), rs.getString("doctor"), rs.getString("gh_status") }; DefaultTableModel model = (DefaultTableModel) table.getModel(); model.addRow(row); }

这段代码把 ResultSet 的每一行转换为 Object 数组,追加到 DefaultTableModel 中,Swing 的 JTable 会感知模型变化并自动重绘。这里有一个类型对应关系:数据库 INT 列对应 rs.getInt,VARCHAR 列对应 getString,类型不匹配会在运行时抛异常。常见的错误是把 INT 字段用 getString 取,虽然 MySQL 驱动会自动转换,但不一致的类型映射在复杂报表场景下会有隐患。

SelectByNum 在查询条件上多了 WHERE 限定:

SELECT * FROM gh WHERE gh_id = ?

如果需求改成按患者姓名模糊查询,就换成 LIKE 写法:

SELECT * FROM gh WHERE patient_name LIKE CONCAT('%', ?, '%')

注意这里用 CONCAT 拼接通配符,而不是直接写 '%?%',后者会把问号当成字面量匹配。UserSelectAll 和 SelectAll 的区别同样体现在 WHERE 条件上,UserSelectAll 多了一个用户范围限制,把结果限定在当前登录用户自己的记录。这就是课设项目里最原始的数据隔离方式——不引入权限框架,就在 SQL 条件上做文章。

5. 避坑指南:课设跑起来之前必查的五个点位

拿到别人源码跑不通,多数情况不是代码坏了,是环境和数据没对齐。下面五条是我处理 Swing + MySQL 课设时最常碰到的坑,按出现概率排序。每条都是实际踩过的记录,照着排除能省下大量排查时间。

5.1 ClassNotFoundException:mysql 驱动 jar 没有进入项目依赖

现象:一运行 Login 就报 java.lang.ClassNotFoundException: com.mysql.jdbc.Driver,Run 面板红色堆栈直接指向 JDBCUtils 的静态代码块。

原因:项目是纯源码形式交付,MySQL 驱动 jar 没有被打进项目依赖。IDEA 打开项目时,只会识别 src 目录下的 Java 源文件,lib 目录如果存在但未右键添加,编译能过,运行时类加载失败。

解决:下载 mysql-connector-java 的 jar 包,版本建议 5.1.49,放到项目根目录的 lib 文件夹。右键 jar 选择 Add as Library,弹出对话框确认作用范围是 Module 级别,重新运行即可。验证是否真的加载成功:展开 IDEA 右侧的 External Libraries,能看到 mysql-connector 条目才算完事。

5.2 Access denied:JDBCUtils 账号密码与本机 MySQL 不一致

现象:运行后第一次点登录按钮,控制台报 java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)。

原因:JDBCUtils 里写死的账号密码是作者本机环境的,你本机 MySQL 设置的密码不同。源码作者的环境密码大概率是 123456,而你自己装的 MySQL 可能设了更复杂的密码。

解决:先在 MySQL 客户端确认自己能正常登录,然后在 JDBCUtils 里把 USER 和 PASSWORD 改成你自己的。改完顺手检查两处:一是密码前后有没有意外空格,二是输入的密码是不是在中文输入法状态下打的。有一次我排查了半小时,最后发现冒号后面多了个不可见空格。

5.3 中文乱码:连接参数和表字符集要一起查

现象:登录后表格里的中文全是 ?? 或者方块,英文和数字正常。

原因:字符集问题有两层,一层是连接字符串里没有指定 characterEncoding=utf8,另一层是建表时默认字符集不是 utf8。只改其中一处,乱码问题依然存在,这是最容易迷惑人的地方。

解决:第一步在 JDBCUtils 的 URL 末尾加上 characterEncoding=utf8;第二步执行 SHOW CREATE TABLE gh; 看 CHARSET 是否为 utf8 或 utf8mb4,如果是 latin1,执行 ALTER TABLE gh CONVERT TO CHARACTER SET utf8mb4; 两个地方都改完,重新运行,乱码会彻底消失。注意 utf8mb4 是 utf8 的超集,支持存储 emoji 表情,建新表时优先选它。

5.4 Unknown column:Java 代码字段名和建表语句对不上

现象:运行某个具体查询功能时,报 java.sql.SQLSyntaxErrorException: Unknown column 'xxx' in 'where clause'。

原因:代码里 getString("字段名") 或 SQL 里的列名与建表语句不一致。这种不一致常见于字段改名后 Java 代码没同步更新,或者复制别人代码时只改了 SQL 没改 Java 层的字段映射。

解决:打开 SQL 脚本找到建表语句,把表结构的字段清单列出来,和 Java 代码里的字段引用逐一比对。我一般用文本编辑器的查找替换功能,先把所有表字段名找出来列在纸上,然后再逐个对照 Java 文件。这个过程枯燥但有效,这类错误属于低级 bug,解决后基本不会再犯。

5.5 窗口显示不全:Windows 缩放下 Swing 不自动适配

现象:Swing 窗口弹出来了,但界面只显示一半,底部的按钮被截断,鼠标点不到。

原因:Windows 系统的显示缩放比例不是 100%,比如 125% 或 150%。Swing 基于 AWT 的布局在高 DPI 环境下不会自动缩放,坐标是按 100% 缩放计算的,导致界面被裁剪。

解决:最简单的方式是在运行配置的 VM options 里加上 -Dsun.java2d.dpiaware=false。也可以在 main 方法第一行写入 System.setProperty("sun.java2d.dpiaware", "false"); 强制关闭高 DPI 感知,界面会稍微模糊但保证完整显示。答辩演示时优先用缩放 100% 的电脑,能彻底避开这个问题。

6. 更稳的验证手法:改一个挂号状态字段,观察整条数据流

第一轮跑通只说明环境没问题,不代表业务逻辑正确。我拿到任何课设源码,都会再做一次数据链路的穿透验证:正向从数据库改数据看界面刷新,反向从界面操作看数据库落库。两个方向各花两分钟,能把界面层、逻辑层、数据层之间的断点全部暴露出来。

6.1 正向验证:改库表数据,看前端刷新表现

先从 MySQL 客户端执行一条 UPDATE,把某条挂号记录的状态从“待就诊”改成“已就诊”:

UPDATE gh SET gh_status = '已就诊' WHERE gh_id = 1;

回到 Swing 界面,在管理员主窗体的表格区域触发一次刷新。如果改动正确反映到表格里,说明从数据库读取、ResultSet 解析、DefaultTableModel 填充到表格重绘这条链路是通的。如果没有任何变化,优先检查刷新按钮是否绑定了查询方法——很多课设界面上有一个“查询”按钮,但事件监听代码可能是空的,或者调用了错误的方法名。

6.2 反向验证:从界面操作,查数据库落库结果

反向验证同样直接:在界面上新增一条挂号记录,填写患者姓名、科室、医生,点保存。然后去 MySQL 客户端执行:

SELECT * FROM gh ORDER BY gh_id DESC LIMIT 1;

如果查到刚才那条记录,说明 INSERT 链路完整。如果界面上弹了“挂号成功”但数据库里查不到,问题大概率出在事务提交上。课设代码里通常不会显式写事务,但如果有 setAutoCommit(false) 而没有 commit(),数据就会被回滚。还有一个隐蔽场景:刷新或新增操作里调用了错误的 DAO 方法,比如按钮绑定的是 SelectAll 而不是 GHAdd,这种情况界面表现和数据库状态完全对不上,最迷惑人。

两个方向的验证加一起不到五分钟,却能把三层架构的每一段连接都检验一遍。从那以后,我每次拿到课设源码,第一遍跑通后都强制走一遍“改字段→看界面→改界面→查数据库”的闭环,数据双向通路确认没问题,再去谈业务优化和功能扩展。这个习惯让我少踩了很多演示现场翻车的坑,希望也能帮到你。

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

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

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

立即咨询