
简介基于Java Swing与MySQL的医院预约挂号系统源码包面向正在学习Java桌面应用和数据库开发的计算机专业学生及初级开发者。项目采用MVC分层架构围绕预约挂号信息管理覆盖主界面、医生管理、用户管理、挂号信息维护等模块并借助视图切换监听器处理界面组件状态变化能够帮助读者理解桌面管理系统的完整开发链路。压缩包共172个文件整体约3.54MB以73个Java源文件和86个编译后class文件为主另有jar依赖库、properties配置、png界面截图和md说明文档源代码与编译结果并存便于阅读源码、导入运行和对照界面效果。当前已有62人学习/下载适合课程设计、毕业设计或项目实训参考。资源代码注释详细、命名规范DAO实现类完整展示了数据访问层的写法读者可借此掌握Swing组件布局与事件监听、MySQL数据库连接与增删改查操作以及MVC各层之间的职责划分与调用关系。1. 医院预约挂号系统源码它其实是半个“业务系统”拿到这个标题的时候大多数人第一反应是“又一个 JavaSwing 课设”但真把它当课设抄一遍你会发现坑全在数据库和流程上。这个系统的本质是用 JavaSwing 把桌面界面画出来用 MySQL 存业务数据中间靠 JDBC 串起来——思路看着简单可一旦在预约冲突、退号状态、并发挂号和中文乱码上翻车整个项目就从“能跑”变成“能废”。它适合课程设计、毕业设计也适合想在一个完整业务流里练手 Swing 和 JDBC 的开发者。它的价值不在界面多花哨而在于你在一套代码里同时看到三层东西界面层、数据访问层、业务状态流转。我见过很多同学把挂号系统做成“往表里 INSERT 一条记录”看起来功能齐全实际连患者重复挂同一时段都拦不住。所以这篇文章我按“读懂结构 → 拆数据库 → 跑通源码 → 踩坑排查 → 二次开发”的顺序讲你照着走至少能少熬三个通宵。2. 看懂三层结构胜过囫囵复制代码界面、服务与数据怎么咬合很多源码包一打开就是几十个.java文件新手容易直接懵。其实这类系统的组织套路非常固定viewSwing 窗口、daoJDBC 数据访问、model实体类三层。别急着改界面先把这几个包路径看懂你改起来才有方向。2.1 JavaSwing 界面的主窗口与事件监听代码是这样组织起来的Swing 程序是从main方法里一个JFrame开始的窗口里放按钮、表格、输入框然后给这些组件挂ActionListener。预约挂号的界面通常分成左右两块左边是科室和医生列表右边是挂号表单和预约记录表格。// MainFrame.java - 主窗口骨架关键结构 public class MainFrame extends JFrame { private JTable doctorTable; // 医生列表表格 private JComboBoxString deptBox; // 科室下拉框 private JTable appointmentTable; // 预约记录表格 private AppointmentService service; public MainFrame() { setTitle(医院预约挂号系统); setSize(900, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); initUI(); service new AppointmentService(); } private void initUI() { // 常见做法是顶部放科室筛选 查询按钮 // 中间放医生列表底部放预约表单和操作按钮 } }这段代码里值得注意的不是界面布局而是AppointmentService service这行。你拿到源码后先搜这个类它决定业务逻辑放在哪。界面只管收集用户输入和展示结果真正干活的在 Service 和 DAO 层。如果你一打开发现某个类里面既写JButton又写Connection、Statement说明这个源码结构很糙后面改起来会非常痛苦。2.2 DAO 层负责拼 SQL连接、增删改查都归它管DAO 层的核心就两件事拿数据库连接、执行 SQL。这套系统里一般会有一个DBUtil类统一管连接所有 DAO 都通过它拿Connection。连接参数写死在.java文件里你要改的是 MySQL 的用户名、密码、库名和时区。// DBUtil.java - 数据库连接工具类 public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/hospital_db ?useUnicodetruecharacterEncodingutf8 useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD 123456; public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }参数说明localhost:3306是 MySQL 默认地址和端口如果你用 Docker 启动 MySQL这里要改成容器映射的端口或主机名characterEncodingutf8保证中文不乱码useSSLfalse避免 8.0 版本 SSL 握手报错serverTimezoneAsia/Shanghai解决时区差 8 小时的问题。这三项是你后面最容易踩的坑后面第五章专门讲。2.3 自测思路先跑通一个最小登录流程别一上来就测试完整挂号流程。最省事的验证方式是启动程序不进主界面先把登录表单填了然后去 MySQL 里看user表有没有对应的记录。如果登录能卡住大概率不是界面问题而是user表的密码字段加密方式和你前端校验逻辑对不上——这是这类源码最常见的“暗病”。我的习惯是在 IDEA 里直接把main方法所在类跑起来看 Console 报什么错。如果报ClassNotFoundException: com.mysql.jdbc.Driver说明 MySQL 驱动 JAR 没放进项目依赖如果报Access denied for user说明DBUtil里的账号密码不对如果什么都没错但界面卡死那要看是不是在事件回调里做了耗时数据库操作把 Swing 的事件分发线程EDT占死了。3. 用 mysql 设计预约挂号核心表建表顺序、主外键和防重复预约你在源码包里通常会看到一个.sql文件但直接双击导入不一定能成功因为建表顺序有讲究先建没有外键依赖的表再建有外键的表。预约挂号系统至少要五张核心表用户表、科室表、医生表、患者表、预约记录表。表结构设计合不合理直接决定你的系统“看上去像样”还是“数据库课设入门级”。3.1 五张核心表的字段清单与关键 SQL-- 1. 用户表 CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, role VARCHAR(20) DEFAULT admin -- admin / patient ); -- 2. 科室表先建因为医生表外键要引用它 CREATE TABLE department ( id INT PRIMARY KEY AUTO_INCREMENT, dept_name VARCHAR(100) NOT NULL, location VARCHAR(100) ); -- 3. 医生表 CREATE TABLE doctor ( id INT PRIMARY KEY AUTO_INCREMENT, dept_id INT NOT NULL, name VARCHAR(50) NOT NULL, title VARCHAR(50), -- 职称 max_appointments INT DEFAULT 30, -- 每时段号源数 FOREIGN KEY (dept_id) REFERENCES department(id) ); -- 4. 患者表挂号记录的外键来源 CREATE TABLE patient ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, phone VARCHAR(20), id_card VARCHAR(18) UNIQUE -- 身份证号唯一 ); -- 5. 预约表 CREATE TABLE appointment ( id INT PRIMARY KEY AUTO_INCREMENT, patient_id INT NOT NULL, doctor_id INT NOT NULL, appointment_date DATE NOT NULL, time_slot VARCHAR(20) NOT NULL, -- 上午/下午 status TINYINT DEFAULT 0, -- 0未就诊 1已就诊 2已退号 create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (patient_id) REFERENCES patient(id), FOREIGN KEY (doctor_id) REFERENCES doctor(id) );你拿到源包后可以把 SQL 打开跟我这份“标准答案”对比一下。如果appointment表里没有status字段用的是 DELETE 删记录那就得在退号功能上小心因为删除记录会让历史统计变成黑匣子。UNIQUE约束在patient.id_card上能避免一个患者被录两次在appointment表上加联合唯一约束能直接从数据库层面拦住“同一病人重复挂同一医生同一天同一时段”。3.2 预约记录为什么要加 status 字段而不是直接删除很多课设源码一做“退号”就是DELETE FROM appointment WHERE id ...。当时跑起来痛快后面统计“这个医生爽约率是多少”“今天实际到诊几个”的时候数据全没了。所以生产向的写法一定是软删除把status改成2代表退号改1代表已就诊。界面列表只查status 2但管理员做统计的时候能拿到全量历史。这个字段的另一个价值是“后悔药”。患者打电话说退错了号管理员只要把status改回0预约就恢复了。如果当时 DELETE 了那患者的信息就得重新录挂号记录的时间也对不上。我接手过的源码里凡是做软删除的后面都好改凡是直接 DELETE 的基本都靠手工往数据库插数据来补救。3.3 唯一约束与事务避免“同一时段被挂两次”的硬手段防重复预约的“硬手段”是数据库约束不是前端判断。前端按钮只能防普通用户解决不了两个人同时点提交。正确做法是给appointment加联合唯一索引ALTER TABLE appointment ADD UNIQUE KEY uk_patient_slot (patient_id, doctor_id, appointment_date, time_slot);加了这条约束以后同一患者对同一医生同一时间段的第二次插入会被 MySQL 直接拒绝报Duplicate entry错误。Java 层要捕获这个异常并提示“您已预约该时段请勿重复挂号”。另一个典型场景是退号再挂一个患者退了号另一个患者要抢这个号。这时候需要事务先 UPDATE 释放号源再 INSERT 预约记录两步要么全成要么全不成。JDBC 事务的写法是connection.setAutoCommit(false)try里执行完所有语句后commit()任何一步异常就rollback()。源码里如果只看到INSERT没有事务控制这系统在同号并发场景下一定会挂。4. 本地跑通这套源码JDK、mysql安装配置到 IDEA 导入的完整路径源码拿到手不等于能跑。我见过太多人卡在环境上——Mysql 装的是 8.0代码里却用 5.x 的驱动JDK 用 17Swing 项目里却用着过时的setDefaultCloseOperation之外的废弃 API。在本地跑通这套系统核心是三件事环境版本选对、数据库导入对、连接配置改对。4.1 环境版本怎么选JDK 8 MySQL 5.7 最省心JavaSwing 在 JDK 8 上运行最稳定新版本 JDK 虽然也能跑但有些源码用了com.sun.*内部包新版 JDK 由于模块化会直接拒绝编译。MySQL 优先选 5.7 或 8.0但要注意驱动类名的变化5.x 用com.mysql.jdbc.Driver8.0 用com.mysql.cj.jdbc.Driver。很多源码里写的是 5.x 的老驱动你要么把 MySQL 装成 5.7要么在项目里换成 8.0 的驱动 JAR 并修改驱动类名。mysql 安装配置这边Windows 上最简单的是下.msi安装包全程 Next但记得设置 root 密码时别用复杂符号因为后面要写进 Java 代码里、!、#在 URL 里都要特殊处理。Linux 上习惯用包管理器装 MySQL 5.7.44装完以后跑一下sudo mysql_secure_installation把匿名账号和测试库清掉否则 Java 连接时会撞到权限问题。4.2 建库、导表、改连接三连避免“空表白屏”我把常见步骤固定在三条命令里。假设你的源码包里有个hospital_db.sql打开命令行执行# 1. 建库注意 utf8mb4避免中文乱码 mysql -u root -p -e CREATE DATABASE IF NOT EXISTS hospital_db DEFAULT CHARSET utf8mb4; # 2. 导入表结构和初始数据 mysql -u root -p hospital_db hospital_db.sql # 3. 验证表是否导入成功 mysql -u root -p -e USE hospital_db; SHOW TABLES;第三步如果列出五张以上的表说明 SQL 文件没问题。如果一张表都没有别急着检查 SQL先.sql文件头部是不是包含CREATE DATABASE语句——有些文件自带了建库命令你再执行一次建库会冲突。解决方式是打开 SQL 文件删掉顶部CREATE DATABASE和USE语句只保留建表和插入语句。这一条操作卡住过很多人。数据库导好以后回到DBUtil.java改连接参数。尤其注意serverTimezoneMySQL 8.0 默认时区和本地差 8 小时不设这个参数你插入的create_time会差 8 个小时查出来永远对不上。改完参数后用一个小测试类验证连接// TestConnection.java - 验证数据库连接 public class TestConnection { public static void main(String[] args) { try (Connection conn DBUtil.getConnection()) { System.out.println(连接成功 conn.getCatalog()); } catch (SQLException e) { System.err.println(连接失败 e.getMessage()); } } }如果打印出hospital_db环境就通了。这一步把以前要碰运气的问题全部显性化——连接失败的错误信息已经能告诉你是密码、驱动、端口还是时区的问题。4.3 从 zip 解压到跑出登录界面我习惯的编译启动步骤解压源码包后先看目录结构是否包含.idea或.classpath。如果是 Eclipse 工程IDEA 里直接File - Open选中目录等它自动识别成项目如果是纯.java文件手动建一个普通 Java 项目把src目录标记为 Source Root把 MySQL 驱动 JAR 加到依赖里。用 IDEA 跑繁琐但最稳因为它会把编译错误以中文或者英文列表展示出来。常见的错误是编码问题——.java文件是 UTF-8 编码而控制台 GBK 输出出现乱码不算错但编译报错里的行号要认真看。还有一种情况是源码里用了System.out.printf中文占位符这在某些 Windows 环境的控制台会显示问号但不影响运行。如果更习惯命令行可以这样编译和启动# 编译所有 java 文件 javac -encoding UTF-8 -cp mysql-connector-java-8.0.x.jar -d out src/**/*.java # 启动主类 java -cp out;mysql-connector-java-8.0.x.jar com.hospital.app.MainFrame注意-encoding UTF-8必须加否则 Windows 默认 GBK 读你的 UTF-8 源码中文字符串全变乱码。启动命令里的-cp分隔符Windows 用分号macOS/Linux 用冒号这是新手最容易忽略的差异。跑出界面后第一件事不是点挂号而是点开“用户管理”看看表格里有没有数据如果空说明 SQL 导入有问题回看 4.2。5. 部署与运行的避坑笔记乱码、驱动、连接池与黑屏这一章全是血泪经验。写这个话题不是为了吓你而是这些坑我看过太多人踩过同样的版本你把下面五条存下来跑通成功率能提高一半。5.1 现象界面全是乱码窗口标题正常但表格内容“锟斤拷”原因Java 源码文件是 UTF-8 编码但编译时用了系统默认字符集Windows 下是 GBK导致中文字符串在字节转换时损坏或者 MySQL 表/连接字符集不是 UTF-8。解决编译参数加-encoding UTF-8确认 MySQL 数据库、表都是utf8mb4DBUtil连接 URL 加useUnicodetruecharacterEncodingutf8。三个环节全部改缺一不可。这不算玄学是 JDK 和 MySQL 对字符集默认行为不同导致的。5.2 现象启动直接报ClassNotFoundException: com.mysql.jdbc.Driver原因源码里写的是老驱动包名com.mysql.jdbc.Driver但你项目里引入的是 MySQL 8.x 驱动。解决要么把驱动 JAR 换成 5.1.49 版本那么类名不用变要么保留下当前驱动把源码里的Class.forName字符串改成com.mysql.cj.jdbc.Driver。ClassNotFoundException还有一种可能驱动 JAR 根本没放进 classpath。IDEA 里需要右键 JAR 文件选Add as Library这一步漏了启动必报 NoClassDefFoundError。5.3 现象连接 MySQL 8.0 时报SSL connection error或Public Key Retrieval is not allowed原因MySQL 8.0 默认开启 SSL 和 caching_sha2_password 插件而 JDBC 驱动在握手时不知道是否该获取服务器公钥。解决在DBUtil的 URL 上加useSSLfalseallowPublicKeyRetrievaltrue。前者关闭 SSL但注意如果你的 MySQL 确实配置了证书加密关闭 SSL 属于降级仅适合本地开发后者允许客户端在认证时检索公钥能绕开“公钥获取被拒”的报错。5.4 现象双击打包好的 jar 包没任何反应原因Swing 程序双击启动时如果有异常系统只是静默退出你根本看不到错误堆栈。解决不要双击用控制台启动java -jar hospital.jar这样错误信息会直接打到屏幕上。另一个常见问题是MANIFEST.MF里没有指定Main-Class打包时 IDEA 的Build Artifact没勾选Main-Class或者指定错了类名。检查java -jar运行后是否出现界面没有就看看 manifest 里的类路径是不是全限定名。5.5 现象使用 Docker 启动 MySQLJava 客户端报Communications link failure原因连接地址写的是localhost:3306但容器里的 MySQL 把 3306 映射到了宿主机的另一个端口或者容器内 MySQL 绑定了特定 IP。解决先docker ps看端口映射。如果宿主机是0.0.0.0:3306-3306/tcp那 Java 端可以连localhost:3306不需要特判开防火墙如果映射到3307Java 端就要写jdbc:mysql://localhost:3307/...。另外容器重启后 IP 可能变但localhost映射不受影响所以尽量用端口映射别在 Java 里写容器的 IP 地址。以上五条前三条你已经提前看过就不会踩。第四条和第五条是环境问题排查顺序建议先看 Java 端报错信息再 ping 端口最后用数据库客户端工具Navicat、DataGrip测试连接。如果客户端工具能连、Java 连不上问题一定在 Java 端的 URL 参数或驱动。6. 二次开发的正确顺序先把业务闭环验出来再谈加功能源码跑通只是第一步真正评估这套系统值不值得深入要看业务闭环通不通。我建议你按这个顺序自测注册一个患者账号 → 管理员添加科室和医生 → 患者分别挂两个医生 → 退其中一个号 → 再挂回同一个时段验证唯一约束 → 到医生界面标记“已就诊”。每一步执行完去 MySQL 里查对应表的状态变化。这五步全通过说明核心业务没硬伤。验证通过后再考虑加功能。常见做法是增加“号源管理”给doctor表加一个remaining字段每次挂号成功后UPDATE doctor SET remaining remaining - 1退号再加回来。要注意这字段不能只在前端减数据库要做条件和操作比如UPDATE doctor SET remaining remaining - 1 WHERE id ? AND remaining 0这样能挡住超挂。修改时同步要动四个文件entity/Doctor.java加属性、dao/DoctorDao.java加 SQL 更新、view/DoctorPanel.java加界面显示、service/AppointmentService.java做扣减调用。少改一个功能就会悬空。如果想把系统做得更稳把预约记录查询改成预编译PreparedStatement防止 SQL 注入。很多课设源码的习惯是用字符串拼接 SQL这是最危险的写法。一条参数注入能直接删掉你的预约表。无谓的教训我在接手别人的源码后习惯先做一次全局搜索凡是出现Statement拼接的地方全部替换成PreparedStatement半小时工作量换来的是整个系统敢拿到公开环境用。这套 JavaSwing MySQL 的挂号系统不复杂但它把桌面端、关系型数据库、事务与约束串成一个完整产品。你跑通它等于把 JavaSE 最后一块拼图补上了你改造它等于摸到了业务系统设计的门道。希望这篇笔记帮你在跑通和改好的路上少走几个弯路。本文还有配套的精品资源点击获取