
简介这份资源是面向高校学生与Java初学者的医院挂号系统课程设计完整源码包采用Swing图形界面搭配MySQL数据库实现适合需要完成Java课设、课程作业或自学桌面应用开发的人群。系统涵盖登录验证、挂号管理、医生与管理员操作、用户信息增删改查等核心模块界面风格保持原始朴素更贴近学生实际水平便于顺利通过课设验收。压缩包共75个文件约175KB包含14个java源文件、38个class编译文件、12张png界面截图、7个xml配置、1个sql数据库脚本以及登录账号密码说明源码与数据库脚本齐全导入后即可运行调试。目前已有267人学习下载。读者可借此获得一套可直接交付的课设方案理解JDBC工具类封装、Swing事件处理与MySQL表结构设计并参考登录、挂号、查询等模块的代码组织方式快速完成环境搭建与功能扩展。1. 医院挂号系统用 Swing 还是 JavaFX课设选型的真实取舍如果你正在搜「Java课设 医院挂号系统 GUI Swing MySQL」大概率是三种处境之一明天要交课设、想找个能跑通的完整方案、或者被 Swing 的布局和 MySQL 连接折腾到怀疑人生。我当年第一次做这个题卡在 JDBC 驱动加载和窗口刷新上整整两天后来才发现问题根本不在代码而在选型和环境。这篇笔记就按我实际做过的路径把「医院挂号系统」从建库、连库、画界面到排错讲清楚适合要交课设的学生也适合想用 Swing 快速搭一个带数据库的桌面小系统的开发者。核心结论先放这Swing 做课设够用但布局和线程是两大翻车点MySQL 8 的连接串和时区参数必须写对否则报错能让你找一晚上。2. 建库建表挂号系统最少需要几张表2.1 从业务倒推表结构别一上来就写代码医院挂号系统的核心动作只有三个病人选科室、选医生、拿到一个号。围绕这三个动作最少需要四张表科室表、医生表、排班表、挂号记录表。很多同学一上来就打开 Navicat 建一堆字段结果写到一半发现排班和挂号对不上。我一般会先在纸上画一遍流程病人登录 → 查科室 → 查该科室医生 → 查医生可挂号时段 → 插入挂号记录 → 号源减一。这个流程决定了表之间的外键关系。科室表存科室名和简介医生表存姓名、职称、所属科室排班表存医生、日期、时段、剩余号源挂号记录表存病人、排班、挂号时间、状态。注意号源不要直接存在医生表里因为同一个医生不同日期号源不同必须单独一张排班表。这是新手最容易合并错的地方。2.2 建表 SQL 与字段类型选择下面是我实际用的建表脚本MySQL 8 直接跑。字段类型我特意选了能减少后期麻烦的组合主键用自增 int时间用 datetime状态用 tinyint。-- 创建数据库字符集用 utf8mb4避免中文乱码 CREATE DATABASE hospital_reg DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; USE hospital_reg; -- 科室表 CREATE TABLE department ( dept_id INT PRIMARY KEY AUTO_INCREMENT, dept_name VARCHAR(50) NOT NULL, intro VARCHAR(200) ); -- 医生表外键指向科室 CREATE TABLE doctor ( doc_id INT PRIMARY KEY AUTO_INCREMENT, doc_name VARCHAR(30) NOT NULL, title VARCHAR(20), dept_id INT, FOREIGN KEY (dept_id) REFERENCES department(dept_id) ); -- 排班表一个医生一天可能有上午/下午两个时段 CREATE TABLE schedule ( sch_id INT PRIMARY KEY AUTO_INCREMENT, doc_id INT, work_date DATE NOT NULL, period TINYINT NOT NULL, -- 1 上午 2 下午 total INT DEFAULT 0, -- 总号源 remain INT DEFAULT 0, -- 剩余号源 FOREIGN KEY (doc_id) REFERENCES doctor(doc_id) ); -- 挂号记录表 CREATE TABLE registration ( reg_id INT PRIMARY KEY AUTO_INCREMENT, patient VARCHAR(30) NOT NULL, sch_id INT, reg_time DATETIME DEFAULT CURRENT_TIMESTAMP, status TINYINT DEFAULT 1, -- 1 已挂号 2 已取消 FOREIGN KEY (sch_id) REFERENCES schedule(sch_id) );逻辑说明remain和total分开存是为了取消挂号时能把号源加回去只用一个字段做不到。status用 tinyint 而不是字符串查询和更新都更快。reg_time给默认值插入时不用手动传时间。参数说明utf8mb4必须显式指定否则中文姓名和科室名可能变问号。FOREIGN KEY在课设阶段建议保留能帮你发现插入顺序错误如果后期觉得约束太烦可以临时SET FOREIGN_KEY_CHECKS0但交作业前记得改回来。2.3 插入测试数据别等界面写完才发现没数据建完表立刻插几条测试数据这样后面调界面时下拉框才有内容。我见过太多人界面画完了一运行下拉框全空回头补数据又发现外键顺序不对。INSERT INTO department (dept_name, intro) VALUES (内科, 常见内科疾病诊治), (外科, 外科手术与创伤处理), (儿科, 儿童常见病); INSERT INTO doctor (doc_name, title, dept_id) VALUES (张医生, 主任医师, 1), (李医生, 副主任医师, 1), (王医生, 主治医师, 2); INSERT INTO schedule (doc_id, work_date, period, total, remain) VALUES (1, 2025-06-01, 1, 20, 20), (1, 2025-06-01, 2, 15, 15), (2, 2025-06-01, 1, 18, 18);插入顺序必须是科室 → 医生 → 排班因为外键依赖。日期用DATE格式字符串MySQL 会自动转换。如果报Cannot add or update a child row就是外键顺序错了先查父表有没有对应 id。3. Swing 界面搭建从登录窗到挂号主窗的最小闭环3.1 用 IDEA 建项目并引入 MySQL 驱动新建 Java 项目后第一件事不是写界面而是把 MySQL 驱动加进来。常见做法是在项目根目录建lib文件夹把mysql-connector-j-8.x.x.jar放进去然后在 IDEA 里右键Add as Library。如果你用 Maven直接在pom.xml加依赖更省事。dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId version8.0.33/version /dependency逻辑说明MySQL 8 的驱动类名是com.mysql.cj.jdbc.Driver不再是老版的com.mysql.jdbc.Driver。连接串里必须带时区和 SSL 参数否则控制台会刷一堆警告甚至直接连不上。参数说明serverTimezoneAsia/Shanghai解决时区报错useSSLfalse在课设环境关掉 SSL 省事allowPublicKeyRetrievaltrue在 MySQL 8 默认认证方式下需要否则报Public Key Retrieval is not allowed。3.2 封装一个数据库工具类别在每个按钮里写连接我见过最惨的课设代码是每个按钮的监听器里都复制一遍DriverManager.getConnection改一个密码要改二十处。正确做法是抽一个DBUtil类。import java.sql.*; public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/hospital_reg ?serverTimezoneAsia/ShanghaiuseSSLfalse allowPublicKeyRetrievaltruecharacterEncodingutf8; private static final String USER root; private static final String PWD 你的密码; // 静态块只加载一次驱动 static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConn() throws SQLException { return DriverManager.getConnection(URL, USER, PWD); } // 统一关闭资源顺序结果集 - 语句 - 连接 public static void close(ResultSet rs, Statement st, Connection conn) { try { if (rs ! null) rs.close(); } catch (Exception ignored) {} try { if (st ! null) st.close(); } catch (Exception ignored) {} try { if (conn ! null) conn.close(); } catch (Exception ignored) {} } }逻辑说明静态块保证驱动只加载一次getConn每次返回新连接课设并发量低不用连接池也够。close方法按结果集、语句、连接的顺序关反了会报错。参数说明characterEncodingutf8和建库时的utf8mb4配合防止中文乱码。密码不要硬编码在交作业的版本里至少改成从配置文件读这是加分项。3.3 登录窗与挂号主窗的布局要点Swing 布局是新手最大的玄学。我建议登录窗用GridBagLayout或简单的BorderLayout套JPanel主窗用BorderLayout北边放查询条件中间放JTable南边放操作按钮。不要用绝对定位setBounds换个分辨率就全乱。// 登录窗核心片段 JFrame login new JFrame(医院挂号系统 - 登录); login.setSize(350, 220); login.setLocationRelativeTo(null); // 居中别省这行 login.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel form new JPanel(new GridLayout(3, 2, 10, 10)); form.add(new JLabel(用户名)); JTextField userField new JTextField(); form.add(userField); form.add(new JLabel(密码)); JPasswordField pwdField new JPasswordField(); form.add(pwdField); JButton loginBtn new JButton(登录); form.add(new JLabel()); // 占位让按钮不贴边 form.add(loginBtn); login.add(form, BorderLayout.CENTER); login.setVisible(true);逻辑说明setLocationRelativeTo(null)让窗口屏幕居中不加这行窗口会跑到左上角。GridLayout(3,2)三行两列最后一行用空JLabel占位按钮就不会被拉伸。参数说明JPasswordField取密码用getPassword()返回 char 数组不要用getText()。登录按钮的监听器里查user表课设可以简化成固定账号但建议还是建一张用户表显得完整。3.4 挂号按钮的完整逻辑查号源、插记录、更新余量挂号按钮是整个系统的核心必须保证「查余量 → 有余量才插记录 → 余量减一」这三步。任何一步顺序错了都会出现超挂。// 挂号按钮监听器核心逻辑 int schId 选中的排班ID; Connection conn null; try { conn DBUtil.getConn(); conn.setAutoCommit(false); // 开启事务 // 1. 查剩余号源加行锁防止并发超挂 String checkSql SELECT remain FROM schedule WHERE sch_id? FOR UPDATE; PreparedStatement ps1 conn.prepareStatement(checkSql); ps1.setInt(1, schId); ResultSet rs ps1.executeQuery(); if (rs.next() rs.getInt(remain) 0) { // 2. 插入挂号记录 String insSql INSERT INTO registration(patient, sch_id) VALUES(?,?); PreparedStatement ps2 conn.prepareStatement(insSql); ps2.setString(1, patientName); ps2.setInt(2, schId); ps2.executeUpdate(); // 3. 余量减一 String updSql UPDATE schedule SET remainremain-1 WHERE sch_id?; PreparedStatement ps3 conn.prepareStatement(updSql); ps3.setInt(1, schId); ps3.executeUpdate(); conn.commit(); JOptionPane.showMessageDialog(null, 挂号成功); } else { conn.rollback(); JOptionPane.showMessageDialog(null, 号源已满); } } catch (Exception e) { try { if (conn ! null) conn.rollback(); } catch (Exception ignored) {} e.printStackTrace(); } finally { DBUtil.close(null, null, conn); }逻辑说明setAutoCommit(false)开启事务三步要么全成功要么全回滚。FOR UPDATE给该行加锁防止两个人同时挂最后一个号。课设单机跑看不出问题但这是写进报告里的亮点。参数说明patientName从输入框取schId从JTable选中行取。rollback在异常和号满时都要调否则连接归还时事务没结束。4. 避坑与排查Swing MySQL 课设最常见的 5 个翻车现场4.1 报错Public Key Retrieval is not allowed现象程序一启动连数据库就抛这个异常代码看着没问题。原因MySQL 8 默认用caching_sha2_password认证JDBC 需要显式允许公钥检索。解决连接串加allowPublicKeyRetrievaltrue或者把用户认证方式改成mysql_native_password。我一般直接改连接串不动数据库配置。4.2 中文变问号或乱码现象插入的中文姓名在 Navicat 里显示正常在 Swing 表格里是问号。原因建库、连接串、Swing 组件三处字符集不一致。解决建库用utf8mb4连接串加characterEncodingutf8JTable的DefaultTableModel不用额外设置。三处对齐后基本不会再乱。4.3 界面卡死按钮点不动现象点查询后窗口白屏几秒后才恢复。原因数据库查询写在EDT事件调度线程里Swing 所有界面更新都在这个线程阻塞了就卡。解决把查询放到SwingWorker的doInBackground里结果在done里更新表格。课设数据量小但这是面试常问的点写进报告加分。4.4JTable更新数据后界面不刷新现象挂号成功后余量列还是旧数字。原因直接改了List数据没有通知TableModel。解决用DefaultTableModel的setValueAt或fireTableDataChanged或者干脆重新查一遍数据setModel。我一般重新查简单不易错。4.5 外键约束导致插入失败现象插排班时报Cannot add or update a child row。原因doc_id在医生表里不存在或者插入顺序反了。解决先插科室再插医生最后插排班。调试时可以先SET FOREIGN_KEY_CHECKS0插数据确认逻辑后再打开约束重新跑一遍。5. 让课设从「能跑」到「能拿高分」的两个进阶技巧第一个技巧是给挂号记录加一个「取消挂号」功能并且用事务把余量加回去。这个功能看起来简单但能体现你对事务完整性的理解。实现时和挂号对称查记录状态 → 改状态为已取消 → 余量加一三步一个事务。注意要判断记录当前是不是「已挂号」已取消的不能再取消否则余量会多加。第二个技巧是用JTable的RowSorter给医生列表加排序再给查询条件加模糊匹配。代码只有几行但演示时效果很好。// 给表格加排序器点击表头即可排序 TableRowSorterDefaultTableModel sorter new TableRowSorter(tableModel); doctorTable.setRowSorter(sorter); // 按姓名模糊查询 String keyword nameField.getText().trim(); sorter.setRowFilter(RowFilter.regexFilter((?i) keyword, 1));逻辑说明RowFilter.regexFilter第二个参数 1 表示按第 1 列过滤(?i)表示忽略大小写。这样输入「张」就能筛出所有姓张的医生。参数说明setRowFilter(null)可以清除过滤恢复全量显示。查询按钮里先清空再设置避免条件叠加。验证方法挂号成功后去数据库SELECT * FROM registration看记录再看schedule.remain是不是减了 1取消挂号后再看是不是加回来了。两个方向都对事务才算写对。我自己的习惯是每写完一个功能就手动跑一遍完整流程不依赖单元测试因为课设的坑大多在界面和数据库的交互上不是单个方法能测出来的。数据库密码别写死在代码里交作业前把DBUtil里的密码改成从db.properties读这个小改动能让老师看出你有工程意识。希望帮到你。本文还有配套的精品资源点击获取