
简介JavaSwingMySQL三件套组合实现的学校教务管理系统面向Java初学者、课程设计与期末大作业场景。项目涵盖学生信息管理、课程安排、成绩录入等核心模块难度适中适合学习者通过完整项目掌握Swing界面开发与MySQL数据库交互的实战流程。压缩包共39个文件以25个Java源码文件为主配合XML界面布局、SQL建库脚本、PNG资源及MD说明文档整体仅240KB轻量易部署。已有219人学习使用源码经本地编译验证可运行评审得分98分代码结构清晰、注释完整可直接导入IDE运行。对于需要完成课程设计或快速上手Swing项目的读者而言这是一份具备较强参考价值的完整范例。1. 用 JavaSwingMysql 做学校教务管理系统期末大作业的稳妥解如果你正在找 Java 课程设计源码大概率见过两种极端一种是 Spring Boot Vue 的“大厂风”跑起来要装 Node、配 Maven 镜像、连 Redis光环境就能折腾一下午另一种是纯 JSP Servlet 的老古董界面丑到答辩时没底气。JavaSwingMysql 实现学校教务管理系统恰好落在中间——启动依赖只有 JDK 和 MySQL界面用 JFrame 和 JTable 直接绘制增删改查的数据流肉眼可见断点打在事件监听器里就能讲清楚。这套资源是完整的 Maven 工程包含 pom.xml、educational_admin.sql 以及 src/test/main 目录本地编译过可运行评审分能到 98难度适中适合正在做期末大作业或课程设计的在校学生也适合想用 Swing 练 JDBC 事务和界面拆分的初学者。2. 数据模型先行从 educational_admin.sql 看懂五张表的教务关系拿到压缩包先别急着点运行第一件事是打开 educational_admin.sql。教务管理系统看起来功能多拆到数据库层面就是“人、课、成绩”三件事。这个 SQL 文件把关系理顺了后面所有 Swing 界面和 JDBC 代码都是围着它转。2.1 表结构拆解用户表、学生表、课程表、选课表与成绩表我先讲最核心的表结构设计。一个合格的教务系统最少需要五张表这套 SQL 里也是按这个思路拆的。表名核心字段作用sys_userid, username, password, role登录账号区分管理员和普通用户sys_studentid, student_no, name, gender, class_name学生基本信息sys_courseid, course_no, course_name, credit, teacher课程基本信息sys_student_courseid, student_id, course_id选课关系表sys_scoreid, student_course_id, score成绩记录挂在选课关系下这个拆法的关键是“选课关系表”独立存在。你可能会问为什么不把 score 直接存到 sys_student_course 里答案是成绩并不是选课的唯一信息一个学生选了一门课可能还没考试也可能补考两次单独一张成绩表后续查询和统计都更灵活。课程表不冗余存放学生姓名学生表也不冗余存放课程名全部通过 ID 关联这就是最基本的数据库范式设计答辩时老师问到“为什么这样拆”你可以从数据冗余和更新异常两个点去答。2.2 种子数据初始化admin 账号、测试密码与演示数据的边界SQL 文件后半段通常是初始化数据。教务系统登录入口是管理员账号初始化脚本里一般会预置一个 admin 用户。见下面这段常用写法CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, role TINYINT NOT NULL DEFAULT 1, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; INSERT INTO sys_user (username, password, role) VALUES (admin, MD5(123456), 0);逻辑说明sys_user 表把 password 设为 VARCHAR(64)是因为 MD5 加密后的字符串长度固定是 32 位64 位给后续升级留了余地。role 用 TINYINT 而不是字符串是因为程序里判断角色用数字比 equals 字符串性能更好也更简洁。创建时间直接给 DEFAULT CURRENT_TIMESTAMP省得每插入一条都要手动 new Date()。参数说明这里密码用 MD5 是演示项目的常见做法答辩时你能讲清楚 MD5 是不可逆哈希、数据库泄露后不能直接还原密码就已经达标了。如果以后做企业级项目换成 BCrypt加盐成本更高。要注意 MySQL 8.0 里ENGINEInnoDB DEFAULT CHARSETutf8mb4这两句建议保留utf8mb4 才能完整存储 emoji 和生僻字你用 utf8 的话学生姓名里带个“䶮”字就会报错或落库成乱码。3. Swing 界面层JFrame 主窗体、JTable 刷新与 JDialog 传值Swing 项目的核心难点不在语法而在“界面组件怎么和数据联动”。很多新手把 JFrame 当成一个死画板画完控件后就不知道怎么把数据库里的数据摆上去。这一章我从主窗体布局开始讲透三个高频操作。3.1 主窗体骨架JMenuBar 菜单栏与 CardLayout 卡片切换教务管理系统打开后左边是菜单右边是内容区。Swing 里实现“菜单点击切换页面”最顺手的方案是 JMenuBar 加 CardLayout 布局管理器。CardLayout 的工作原理是把多个面板叠在一起每次只显示其中一张切换时根据 key 找到对应面板。private JPanel cardPanel; private CardLayout cardLayout; private void initMenu() { JMenuBar menuBar new JMenuBar(); JMenu menu new JMenu(教学管理); JMenuItem itemCourse new JMenuItem(课程管理); itemCourse.addActionListener(e - switchPage(course)); menu.add(itemCourse); JMenuItem itemScore new JMenuItem(成绩录入); itemScore.addActionListener(e - switchPage(score)); menu.add(itemScore); menuBar.add(menu); setJMenuBar(menuBar); } private void switchPage(String key) { cardLayout.show(cardPanel, key); }逻辑说明每个 JMenuItem 绑定的 ActionListener 里只做一件事——调用 cardLayout.show()。switchPage() 接收的字符串是构造 cardPanel 时 add 面板用的标识名必须和 add(coursePanel, course) 里的 key 完全一致否则运行时会报 IllegalArgumentException。把菜单初始化和页面切换拆成两个方法是让你在后续扩展时只改 menu 部分不用动 switchPage。参数说明JMenuBar 放的是顶层菜单如果还想做工具栏按钮可以再加 JToolBar但这套课设项目用菜单栏就够了别把界面做复杂答辩演示时反而容易手忙脚乱。这里我一般会用 Lambda 表达式写 ActionListener代码短但老项目里习惯用匿名内部类的写法考试时如果老师要求 Java 8 之前的语法你需要知道两种写法等价。3.2 JTable 与 TableModel手动刷新翻车的高频现场JTable 是 Swing 项目里最常用的表格组件。新手最容易犯的错是查完数据库后直接调用 table.repaint()以为界面会自己更新结果表格纹丝不动。原因是 JTable 本身不存数据它只是负责把 TableModel 里的数据画出来数据变了必须让 TableModel 知道。DefaultTableModel model (DefaultTableModel) table.getModel(); model.setRowCount(0); String sql SELECT course_id, course_name, credit, teacher FROM sys_course; Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(sql); while (rs.next()) { model.addRow(new Object[]{ rs.getInt(course_id), rs.getString(course_name), rs.getInt(credit), rs.getString(teacher) }); }逻辑说明setRowCount(0) 的作用是清空表格原有行相当于重置数据源。然后逐条把 ResultSet 里的记录填进 model.addRow()。这里有个细节addRow 接收的是 Object[]所以 rs.getInt() 返回的 int 会自动装箱成 IntegerSwing 单元格能正常显示。如果不清空直接 addRow数据会无限累积每次点查询都会在表格底部追加一批重复行这是我见过翻车最多的点。参数说明JTable 默认的 TableModel 是 DefaultTableModel用(DefaultTableModel) table.getModel()强转的前提是你创建表格时没有自定义模型。如果你用new JTable(data, columnNames)构造过getModel() 返回的就是 DefaultTableModel可以直接转。这套项目里课程管理、学生管理、成绩管理三个页面都是同样的套路把查询方法和刷新表格封装成一个方法每次增删改后调用它这才是正解。3.3 JDialog 模态窗口新增与编辑如何把结果传回主界面“新增课程”或“编辑学生信息”这类功能Swing 里的标准做法是弹出一个 JDialog 子窗口。子窗口填完数据点保存主窗口的表格要立刻刷新。这涉及两个问题子窗口怎么关闭、主窗口怎么知道“操作成功了”。我一般用模态 JDialog 加一个布尔标志位解决。AddCourseDialog dialog new AddCourseDialog(this); dialog.setModal(true); dialog.setVisible(true); if (dialog.isSucceeded()) { refreshCourseTable(); }逻辑说明setModal(true) 让子窗口成为模态窗口代码执行到 setVisible(true) 时会阻塞直到子窗口关闭才继续往下走。isSucceeded() 是子窗口里的一个 getter保存按钮点击后、dispose() 之前把它设为 true。主窗口拿到 true 就刷新表格拿到 false 就不做任何操作。这个模式比用回调监听器更容易让答辩老师理解也规避了 Swing 线程问题——刷新操作始终在事件分发线程里执行不需要额外处理并发。参数说明AddCourseDialog 构造时传入 this 是把它挂到主窗口上这样最小化主窗口时对话框会一起最小化比较符合桌面应用习惯。子窗口里保存按钮的监听器要做两件事先执行 JDBC 插入成功后把 succeeded 置为 true再 dispose()。顺序别颠倒否则会出现结果是 false 但数据已经写进数据库的诡异问题。4. JDBC 细节连接串参数、PreparedStatement 与事务提交边界Swing 界面做得再漂亮和 MySQL 打交道这一层出了问题是看不见摸不着的。这一章聚焦 JDBC三个高频问题连接串参数配不对、SQL 拼接出漏洞、事务没提交导致数据丢失。教学项目中这三个点也是评分差异所在。4.1 MySQL 连接串的三件套useSSL、serverTimezone、characterEncoding我见过太多课设代码把连接串写成一行裸的jdbc:mysql://localhost:3306/xxx在 MySQL 5.7 上跑得通换到 MySQL 8.0 就报时区异常换到带 SSL 的服务器上又报证书错误。这段连接串参数值得你抄进笔记String url jdbc:mysql://localhost:3306/educational_admin ?useSSLfalse serverTimezoneAsia/Shanghai characterEncodingutf8; String user root; String password 123456; Class.forName(com.mysql.cj.jdbc.Driver); Connection conn DriverManager.getConnection(url, user, password);逻辑说明useSSLfalse 是关闭 SSL 加密通道本地开发 MySQL 默认没配证书不关会报 SSL 相关警告甚至连接失败。serverTimezoneAsia/Shanghai 是给 MySQL 8.0 用的8.0 对时区敏感不指定会报 “The server time zone value CST” 的运行时异常。characterEncodingutf8 是让 JDBC 客户端和 MySQL 服务端用统一的字符集传输中文少了它数据库中即使存的是 UTF-8查询出来的中文也可能是问号。参数说明MySQL 5.7 和 8.0 的驱动类名不同8.0 用的是com.mysql.cj.jdbc.Driver老项目里写的com.mysql.jdbc.Driver在 8.0 驱动下已经标记过期部分版本会直接报 ClassNotFoundException。所以 pom.xml 里如果引的是 mysql-connector-java 8.xClass.forName 必须写带 cj 的那个类。4.2 PreparedStatement 防拼接不只是防注入登录功能最常见的写法是把用户名密码直接拼进 SQL 字符串然后 Statement 执行。这在课设源码里很常见但属于明确的扣分点。用 PreparedStatement 改一下代码量没有增加安全性完全不一样。String sql SELECT * FROM sys_user WHERE username ? AND password ?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); ResultSet rs ps.executeQuery(); if (rs.next() rs.getInt(role) 0) { // 管理员登录成功 } else { // 密码错误或无权限 }逻辑说明PreparedStatement 先把 SQL 模板发给 MySQL 预编译然后用 setString 把参数值单独传进去。这样即使 username 里含有单引号或OR 11也会被当作纯字符串字面量而不是 SQL 代码。除了防注入预编译还能让数据库缓存执行计划同一条 SQL 连续执行多次时性能比 Statement 高这在导入上千条学生成绩时能直接感受到差别。参数说明setString 的下标从 1 开始不是 0写错会报 index out of range。用户名和密码的取值来自 Swing 里 JTextField.getText() 和 JPasswordField.getPassword()注意 JPasswordField 拿到的是 char[] 而不是 String这是刻意设计——字符串是不可变的会留在内存里char[] 用完可以手动清空。4.3 事务边界批量改课表时忘记 commit 的后果批量录入成绩或者批量调整课表如果每一条都是自动提交中途某条失败前面成功的部分就留在数据库里了数据和演示都对不上。事务的正确姿势是在连接层面关掉自动提交执行完后再统一 commit。conn.setAutoCommit(false); try { for (ScoreItem item : scoreList) { PreparedStatement ps conn.prepareStatement( UPDATE sys_score SET score ? WHERE id ?); ps.setInt(1, item.getScore()); ps.setInt(2, item.getId()); ps.executeUpdate(); } conn.commit(); } catch (SQLException e) { conn.rollback(); throw e; } finally { conn.setAutoCommit(true); }逻辑说明setAutoCommit(false) 是事务的开关。循环执行完所有 UPDATE 后调用 commit()数据才真正落库。如果循环到第 10 条时数据库连接断开或者 SQL 写错catch 块中的 rollback() 会把前面 9 条执行过的操作全部撤销数据库回到开始前的状态。这个机制保证“要么全部成功要么全部失败”。finally 里的 setAutoCommit(true) 是必须的避免归还连接池时把非自动提交状态带到下一个使用者。参数说明事务范围要控制在这个循环内别把用户登录、窗口打开等无关操作也包进来否则连接占用时间过长多窗口并发操作时会出现锁等待超时。这套教务系统的成绩录入场景一次事务只处理一个班级的成绩列表是合理的边界。5. 避坑排查ClassNotFoundException、中文乱码、启动秒退与表格不刷新这一章把课设过程中最容易踩的五个坑列出来每条都按“现象 → 原因 → 解决”写。我先说结论这些坑大部分不是代码逻辑问题而是环境配置和组件使用方式问题因此打包源码时环境说明和代码文件一样重要。5.1 现象启动主类后秒退控制台报 ClassNotFoundException双击运行一个带界面的 jar 包窗口一闪就消失控制台报java.lang.NoClassDefFoundError: com/mysql/cj/jdbc/Driver。第一次遇到时我也懵了很久后来才发现是 MySQL 驱动 jar 没有打进 classpath。原因你在 IDEA 里运行没问题是因为 IDEA 把你项目里的 lib 目录加入了编译路径打成 jar 或者直接命令行运行时驱动包没有被包含进去。解决在 pom.xml 里显式声明 mysql-connector-java 依赖用 Maven 的 assembly 插件把依赖打进去如果项目没走 Maven把驱动 jar 放在项目根目录的 lib/ 文件夹里然后在 IDEA 的 Project Structure 里选中该 jar点击 “Add as Library”。最直接验证是否成功的方式是在代码里临时打印驱动版本号看到输出再继续。5.2 现象界面上中文正常但 MySQL 里存的是问号乱码表里中文全部变成??或者查询出来变成乱码。原因这是典型的字符集链路不一致。MySQL 客户端、数据库表、JDBC 连接串、Java 源文件四个环节只要有一个不是 UTF-8中文就会出问题。解决按顺序排查四个点。MySQL 建库时用CREATE DATABASE ... CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci连接串加 characterEncodingutf8IDEA 的 Settings 里把 File Encoding 改为 UTF-8最重要的一步是在 MySQL 命令行里执行SHOW VARIABLES LIKE character_set%确认 character_set_client 和 character_set_results 都是 utf8mb4。最容易被忽略的是 Java 源文件本身的编码IDEA 在中文 Windows 上默认可能用 GBK编译后字符串直接乱。你可以在还没运行前先看一眼代码里中文是否正常显示不正常就立即在右下角切换编码。5.3 现象连接 MySQL 8 报时区错误或者 SSL 连接错误控制台出现The server time zone value CST is unrecognized或者SSL connection error: protocol error。原因MySQL 8.0 默认时区是系统时区驱动要求明确指定SSL 握手因为没有证书而失败。解决在 JDBC URL 上补齐两个参数serverTimezoneAsia/Shanghai和useSSLfalse。注意参数之间用符号连接在 XML 或 properties 文件里写时要转义成amp;这个细节能卡你半小时。5.4 现象JTable 点了新增按钮但表格不更新甚至调用 repaint 无效新增了一条课程数据数据库里确认有这条记录了但界面上表格没有任何变化。原因JTable 的数据源是 TableModelrepaint 只触发界面重绘不会重新查询数据库。你调table.repaint()只是让屏幕刷新数据模型没有变表格自然不变。解决把“清空模型 重新查询 填充模型”封装成一个方法refreshData()在任何数据变更操作执行后调用它而不是调 repaint。方法内部用上一章讲过的 setRowCount(0) addRow 循环。如果你在新增、修改、删除三个模块都走了这个方法就不会出现界面和数据库对不上的情况。5.5 现象登录时用同一套用户名密码有人能登录有人不能管理员账号能登录学生账号登录后没有操作权限或者直接提示密码错误。原因:sys_user 表里的 role 字段区分了不同角色但登录的 SQL 只校验了用户名和密码没有校验 role另一种可能是初始化数据里有两行相同 username 但不同 role 的记录导致查询结果集指向错误的那行。解决登录 SQL 增加AND role ?条件初始化 SQL 里把 admin 账号的 username 设成唯一索引可防止重复账号。登录代码里查出记录后先判断rs.next()是否存在再读取 role 转发到对应主界面顺序不能反否则空指针在角色判断时等着你。6. 答辩交付数据一致性验证与单机 JAR 打包降级方案把源码跑通只是第一步课设最终要交付的是一个“换台电脑也能运行”的成果。这里分享两个我自己的习惯验证清单和打包方案。先讲打包。你辛辛苦苦写完 Swing 程序答辩时不能用 IDEA 现场跑因为老师机器上未必装了 JDK 或者 MySQL 驱动。最省事的方案是把项目打成可执行 JAR然后把驱动 jar 也放进同一个目录。用一个启动脚本直接拉起来echo off chcp 65001 java -Dfile.encodingUTF-8 -jar educational-admin.jar pause这段内容是 Windows 下的 bat 启动脚本。chcp 65001把控制台代码页切成 UTF-8避免中文路径打印乱码-Dfile.encodingUTF-8是给 JVM 的启动参数保证 Swing 界面按 UTF-8 读取资源pause防止工程错误时窗口秒退。如果你在 macOS 或 Linux 上演示把 bat 换成 sh 脚本内容就是java -Dfile.encodingUTF-8 -jar educational-admin.jar加上执行权限。打包时用 IDEA 的 Build Artifact 功能主类选择教务系统的入口 JFrame注意 Manifest 文件里 Main-Class 路径不要带包名前缀错误。打包完成后我建议你强制走一遍交付前的自查第一用干净的 MySQL 库重新执行一遍 educational_admin.sql从零初始化你的数据第二清空本机 Maven 缓存用mvn clean package重新构建一次确认依赖解析没问题第三换一台没有装 IDEA 的机器只装 JRE 和 MySQL跑一遍登录、添加课程、录入成绩、退出四个核心流程。如果这四个流程在两台机器上都顺畅你的课设已经超过了大多数只会在 IDEA 里 F5 的同学。在答辩演示前我还习惯把 JTable 的字体调大一行table.setRowHeight(28); table.setFont(new Font(微软雅黑, Font.PLAIN, 14));这个小细节能让投影仪下的表格数据清晰可见避免老师只看到蚂蚁一样的字。从那以后我每次提交课设都强制自己走一遍“干净环境启动 全流程操作 字体可读性检查”三道步骤这套思路也让几个学弟在答辩时少踩了不少没必要的坑。希望帮到你。本文还有配套的精品资源点击获取