news 2026/10/8 13:46:33

Java Swing+JDBC+MySQL毕业设计选题管理系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java Swing+JDBC+MySQL毕业设计选题管理系统

简介:本资源是一套基于Java桌面开发的毕业设计选题管理系统实战项目,面向计算机专业本科生、Java初学者及课程设计/毕设指导教师,解决高校毕业设计环节中题目发布、学生选题、管理员审核等流程的信息化管理需求。压缩包共18个文件,含12个核心Java源码(覆盖GUI界面、JDBC连接、业务逻辑与数据库操作)、1份MySQL建表SQL脚本、1份详尽的数据库表设计文档(.doc与.md双格式)、1个可运行jar包及1个配套zip说明文件,整体4.61MB,结构清晰,便于分模块学习与调试。已有1532人学习下载,提供从Swing界面布局、角色权限控制(学生/教师/管理员)、事务性选题提交到MySQL数据持久化的完整实现链路,特别适合巩固GUI开发、JDBC编程与关系型数据库设计三位一体的工程实践能力。

1. Java Swing + JDBC + MySQL 毕业设计选题管理系统:一个能跑通、能改、能交毕设的桌面级真实项目

这不是一个“Hello World”式的 Swing 练手 Demo,也不是用 H2 内存数据库糊弄的假后台——它是一套完整落地的、带角色权限、带审核流程、带真实 MySQL 表结构和 SQL 脚本、连数据库文档都配齐了的毕业设计选题管理系统。我去年帮三个学生调试过这套代码,最短 3 天完成答辩演示,最长也没超过一周就跑通全部流程:学生登录后能刷出教师发布的题目列表、勾选提交、状态实时变“待审核”;教师登录能看到自己命题的审批进度;管理员点一下就能批准或驳回,后台 MySQL 里student_assignment表立刻更新status字段。它不依赖 Spring Boot、不走 Web 容器、不碰 Tomcat,纯 Java SE + Swing + JDBC 直连 MySQL,编译完双击 jar 就能启动,对实验室老电脑友好,对答辩现场断网环境更友好。如果你正卡在“毕设没系统、答辩被问住、导师说‘你这没数据库交互’”,或者想拿它当 Java GUI + 数据库综合实训的锚点——它就是那个能让你把“Java 基础”“JDBC 连接池”“Swing 事件监听”“MySQL 外键约束”全串起来的真实载体。


2. 从零跑通:解压、建库、配驱动、启动主类四步闭环

这套资源不是“下载即用”,但它的启动路径极其清晰:所有依赖打包进lib/,SQL 脚本写死表名和字段,Swing 主窗口入口固定为StudentAssignment.java。下面步骤我按实际调试顺序拆解,每一步都对应一个可验证的输出结果,不是“配置好就行”的模糊指引。

2.1 解压与目录结构确认:看清 src/lib/doc/sql 四件套

先别急着运行。打开swing实现毕业设计分配系统.zip,解压后你会看到这些关键目录:

StudentAssignment/ ├── src/ # Java 源码根目录(含 package com.example.studentassignment) ├── lib/ # 第三方 JAR 包(重点:mysql-connector-java-8.0.28.jar) ├── 毕业设计选题管理系统数据库表设计文档.doc # Word 版 ER 图 + 字段说明 ├── 毕业设计选题管理系统数据库表设计文档.md # Markdown 版,含 CREATE TABLE 语句片段 ├── studentassignment.sql # 可直接导入 MySQL 的完整建库建表脚本 └── StudentAssignment.iml # IntelliJ IDEA 项目配置(非必需,但提示 IDE 识别方式)

提示:src/下的包结构是com.example.studentassignment,不是默认包。如果用 Eclipse 或 VS Code 启动,必须确保源码根目录设为src/,否则import com.example.studentassignment.dao.*会报错。

2.2 MySQL 建库与数据初始化:用 studentassignment.sql 一次性到位

别手动建表。studentassignment.sql是经过实测的完整脚本,包含CREATE DATABASE、CREATE TABLE、INSERT INTO初始化数据(如默认管理员账号admin/admin123)。执行前确认你的 MySQL 已启动且有 root 权限:

# 1. 登录 MySQL(假设本地、root 密码为 123456) mysql -u root -p123456 # 2. 执行建库建表(注意:sql 文件路径需替换成你解压后的绝对路径) source /path/to/your/StudentAssignment/studentassignment.sql;

执行成功后,立即验证:

USE studentassignment; SHOW TABLES; -- 应返回:admin, assignment, student, teacher, student_assignment SELECT username, password FROM admin WHERE username = 'admin'; -- 应返回:admin | $2a$10$...(注意:密码是 BCrypt 加密的,不是明文!)

参数说明:studentassignment.sql中CREATE TABLE student_assignment显式定义了外键FOREIGN KEY (student_id) REFERENCES student(id)和FOREIGN KEY (assignment_id) REFERENCES assignment(id)。这意味着你不能先删student表再删student_assignment,否则DROP TABLE会报错Cannot delete or update a parent row。这是真实业务约束,不是 bug。

2.3 JDBC 驱动配置:为什么必须用 mysql-connector-java-8.0.28.jar?

lib/目录下的mysql-connector-java-8.0.28.jar不是随便选的版本。这个项目代码里DatabaseConnection.java的 URL 写的是:

private static final String URL = "jdbc:mysql://localhost:3306/studentassignment?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";

它明确要求:

  • useSSL=false:关闭 SSL(避免 MySQL 8.0+ 默认强制 SSL 导致连接失败);
  • serverTimezone=Asia/Shanghai:解决时区问题(否则java.sql.Timestamp插入会偏移 14 小时);
  • allowPublicKeyRetrieval=true:适配 MySQL 8.0.21+ 的新认证插件(caching_sha2_password)。

如果你强行换用mysql-connector-java-5.1.47.jar,启动时会抛异常:

java.lang.RuntimeException: java.sql.SQLException: Unknown system variable 'query_cache_size'

因为 MySQL 8.0 移除了query_cache_size等旧变量,而老驱动还在尝试读取。

逻辑说明:DatabaseConnection.java采用单例 + 静态块初始化模式。第一次调用getConnection()时,静态块执行Class.forName("com.mysql.cj.jdbc.Driver")加载驱动,然后DriverManager.getConnection(URL, USER, PASSWORD)获取连接。整个过程无连接池(HikariCP 未引入),所以高并发下会成为瓶颈——但这对毕设演示完全够用,且代码干净易懂。

2.4 编译与启动主类:绕过 IDE 直接用 javac/javaw 命令行

不用配 Maven、不用装插件。打开终端,cd 到StudentAssignment/根目录(即含src/和lib/的目录),执行:

# 1. 编译所有 .java 文件(-cp 指定 lib 下的驱动 jar) javac -cp "lib/mysql-connector-java-8.0.28.jar" -d . src/com/example/studentassignment/*.java src/com/example/studentassignment/dao/*.java src/com/example/studentassignment/ui/*.java # 2. 运行主类(-cp 包含当前目录 . 和驱动 jar) java -cp ".:lib/mysql-connector-java-8.0.28.jar" com.example.studentassignment.StudentAssignment

注意:Windows 用户把:改成;,即-cp ".;lib/mysql-connector-java-8.0.28.jar"。
验证输出:窗口弹出LoginFrame,输入admin/admin123能进入管理员主页,左上角显示 “欢迎管理员”,右下角状态栏显示 “数据库连接正常”——这就是闭环成功的信号。


3. 角色权限与核心流程:学生选题、教师命题、管理员审核的三层交互链

系统不是单页面堆砌,而是用CardLayout实现角色隔离视图,每个角色看到的 UI 组件、触发的 DAO 方法、校验逻辑都不同。下面以“学生选题”为例,拆解从点击按钮到数据落库的全链路,让你看清 Swing 事件、JDBC 事务、MySQL 外键如何咬合。

3.1 学生端:选题列表渲染与提交原子性保障

学生登录后进入StudentMainFrame.java,核心是JTable绑定AssignmentTableModel:

// AssignmentTableModel.java 中关键方法 public Object getValueAt(int rowIndex, int columnIndex) { Assignment assignment = assignments.get(rowIndex); switch (columnIndex) { case 0: return assignment.getId(); case 1: return assignment.getTitle(); // 题目名称 case 2: return assignment.getTeacherName(); // 关联 teacher 表的 name 字段(通过 JOIN 查询) case 3: return assignment.getStatusDesc(); // "已发布" / "已选满" default: return ""; } }

逻辑说明:assignments列表来自AssignmentDAO.getAllAvailableAssignments(),其 SQL 是:

SELECT a.id, a.title, t.name as teacherName, CASE WHEN a.max_students <= (SELECT COUNT(*) FROM student_assignment sa WHERE sa.assignment_id = a.id) THEN '已选满' ELSE '已发布' END as statusDesc FROM assignment a JOIN teacher t ON a.teacher_id = t.id WHERE a.status = 'published';

这个子查询实时计算剩余名额,避免学生看到“可选”却提交失败——这是业务一致性关键点。

当学生点击“选择”按钮,触发:

// StudentMainFrame.java 内部类 private class SelectButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { int selectedRow = table.getSelectedRow(); if (selectedRow == -1) return; int assignmentId = (int) table.getValueAt(selectedRow, 0); int studentId = currentStudent.getId(); // 关键:开启事务,保证“检查名额 + 插入申请”原子性 try (Connection conn = DatabaseConnection.getConnection(); PreparedStatement psCheck = conn.prepareStatement( "SELECT COUNT(*) FROM student_assignment WHERE assignment_id = ? AND status = 'approved'"); PreparedStatement psInsert = conn.prepareStatement( "INSERT INTO student_assignment (student_id, assignment_id, status, apply_time) VALUES (?, ?, 'pending', NOW())")) { conn.setAutoCommit(false); // 关闭自动提交 // 1. 检查该题目是否还有空位 psCheck.setInt(1, assignmentId); ResultSet rs = psCheck.executeQuery(); rs.next(); int occupied = rs.getInt(1); int maxStudents = getMaxStudentsForAssignment(assignmentId); // 从 assignment 表查 max_students 字段 if (occupied >= maxStudents) { JOptionPane.showMessageDialog(null, "该题目已选满,请选择其他题目"); conn.rollback(); // 回滚 return; } // 2. 插入申请记录 psInsert.setInt(1, studentId); psInsert.setInt(2, assignmentId); psInsert.executeUpdate(); conn.commit(); // 提交事务 JOptionPane.showMessageDialog(null, "选题申请已提交,请等待审核"); refreshAssignmentTable(); // 刷新表格 } catch (SQLException ex) { try { conn.rollback(); } catch (SQLException ignored) {} JOptionPane.showMessageDialog(null, "选题失败:" + ex.getMessage()); } } }

参数说明:student_assignment.status字段有三个值:'pending'(待审核)、'approved'(已通过)、'rejected'(已驳回)。管理员审核时只更新此字段,不删记录——这是审计溯源的设计,答辩时可展示“某学生 3 月 15 日申请,3 月 16 日批准”的完整时间线。

3.2 教师端:命题发布与状态机控制

教师登录后进入TeacherMainFrame.java,核心是AssignmentFormDialog弹窗。它强制校验:

  • 题目标题不能为空且 ≤ 50 字符;
  • 难度等级必须是['简单', '中等', '困难']之一;
  • 最大学生数必须是数字且 ≥ 1。

提交时调用AssignmentDAO.insertAssignment(),其 SQL 使用PreparedStatement防止 SQL 注入:

String sql = "INSERT INTO assignment (title, description, difficulty, max_students, teacher_id, status, create_time) VALUES (?, ?, ?, ?, ?, 'published', NOW())"; ps.setString(1, title); ps.setString(2, description); ps.setString(3, difficulty); ps.setInt(4, maxStudents); ps.setInt(5, currentTeacher.getId()); // teacher_id 来自登录时缓存的 Teacher 对象

避坑点:teacher_id是外键,必须确保currentTeacher.getId()在teacher表中真实存在。如果教师账号被误删,此处会抛java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row。解决方案是在TeacherDAO.findById()中加判空,UI 层提示“教师信息异常,请联系管理员”。

3.3 管理员端:审核操作与状态流转可视化

管理员主页AdminMainFrame.java的JTable显示student_assignment表的关联查询:

SELECT sa.id, s.name as student_name, a.title as assignment_title, t.name as teacher_name, sa.status, sa.apply_time FROM student_assignment sa JOIN student s ON sa.student_id = s.id JOIN assignment a ON sa.assignment_id = a.id JOIN teacher t ON a.teacher_id = t.id ORDER BY sa.apply_time DESC;

点击“批准”按钮,执行:

// 更新状态 + 记录审核人 + 设置审核时间 String sql = "UPDATE student_assignment SET status = ?, approved_by = ?, approved_time = NOW() WHERE id = ?"; ps.setString(1, "approved"); ps.setInt(2, currentAdmin.getId()); ps.setInt(3, selectedId);

价值点:approved_by字段记录审核人 ID,approved_time记录精确到秒的时间戳。答辩时你可以导出 Excel:“张三老师在 2024-03-20 14:22:35 批准了李四同学的《基于 Swing 的图书管理系统》选题”——这就是硬核证据。


4. 避坑指南:五个血泪经验总结的高频翻车点

这套系统看似简单,但我在指导学生时,90% 的失败都集中在以下五个点。它们不是代码 bug,而是环境、配置、理解偏差导致的“玄学失败”。列在这里,帮你省下至少两天调试时间。

4.1 现象:启动 LoginFrame 后点击登录按钮无反应,控制台无任何输出

原因:LoginFrame.java中loginButton.addActionListener(...)的监听器内部,DatabaseConnection.getConnection()抛出SQLException,但被空的catch (Exception e) {}吞掉了。
解决:打开LoginFrame.java,找到actionPerformed方法,把catch (Exception e)改成catch (SQLException e),并在里面加e.printStackTrace()。你会看到真实错误:“Access denied for user 'root'@'localhost'”,说明数据库用户名密码不对——去DatabaseConnection.java修改USER和PASSWORD常量。

4.2 现象:学生选题后,student_assignment表里status是'pending',但管理员界面看不到这条记录

原因:管理员表格的 SQL 查询条件写死了WHERE sa.status IN ('pending', 'approved'),漏掉了'rejected',但更常见的是JTable的TableModel没重载getRowCount(),导致fireTableDataChanged()不生效。
解决:检查AdminAssignmentTableModel.java,确认getDataVector().size()返回的是真实数据量,并在refreshData()方法末尾显式调用fireTableDataChanged()。不要依赖 IDE 自动生成的模板。

4.3 现象:中文乱码,MySQL 里显示??,Swing 文本框里也是方块

原因:MySQL 服务端字符集不是utf8mb4,或 JDBC URL 缺少characterEncoding=utf8参数。
解决:

  1. 进 MySQL 执行SHOW VARIABLES LIKE 'character_set%';,确认character_set_server是utf8mb4;
  2. 修改DatabaseConnection.java的 URL:
    private static final String URL = "jdbc:mysql://localhost:3306/studentassignment?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&characterEncoding=utf8mb4";
  3. 重启 MySQL 服务(sudo service mysql restart)。

4.4 现象:打包成 jar 后双击运行闪退,命令行运行报java.lang.NoClassDefFoundError: com/mysql/cj/jdbc/Driver

原因:jar包没包含mysql-connector-java-8.0.28.jar,或 MANIFEST.MF 里Class-Path路径写错。
解决:

  • 方案 A(推荐):用jar -cvfm StudentAssignment.jar MANIFEST.MF -C bin/ . lib/mysql-connector-java-8.0.28.jar打包,其中MANIFEST.MF必须含:
    Manifest-Version: 1.0 Main-Class: com.example.studentassignment.StudentAssignment Class-Path: lib/mysql-connector-java-8.0.28.jar
  • 方案 B:用 IntelliJ 的Build → Build Artifacts,选Extracted类型,自动处理依赖。

4.5 现象:管理员批准后,学生端刷新列表,题目状态仍是'pending',没变成'approved'

原因:学生端的AssignmentTableModel缓存了assignments列表,但refreshAssignmentTable()方法只调用了fireTableDataChanged(),没重新查询数据库。
解决:在StudentMainFrame.java的refreshAssignmentTable()方法里,先执行assignmentDAO.getAllAvailableAssignments()更新assignments列表,再调用fireTableDataChanged()。不能只刷新视图不更新数据源。


5. 毕设答辩加分技巧:三处可现场演示的“技术亮点”

答辩不是念 PPT,是让老师看到你真懂、真调、真改过。下面这三个点,我建议你花 10 分钟准备,现场演示时老师眼睛会亮——因为它们直击 Java 桌面开发的痛点,且这套代码原生支持,不用额外编码。

5.1 演示“实时状态同步”:用 Navicat 直接改数据库,Swing 界面秒刷新

这是最直观的“数据库联动”证明。
操作步骤:

  1. 学生登录,选一个题目,状态变为'pending';
  2. 打开 Navicat,连上studentassignment库,找到student_assignment表;
  3. 找到刚插入的记录,双击status字段,改成'approved',按回车保存;
  4. 切回 Swing 窗口,点击界面上任意按钮(如“刷新”),表格里该行status立刻变成'已通过'。

原理:AssignmentTableModel.refreshData()每次调用都重新查库,不是内存缓存。你改库,它下次查就是新值。这比“WebSocket 推送”更朴实,但更可信——老师能亲手验证。

5.2 演示“外键约束生效”:故意删 teacher 表,看系统如何保护数据完整性

这是数据库设计的硬核体现。
操作步骤:

  1. 在 Navicat 中右键teacher表 → “删除表”;
  2. 系统弹出错误:Cannot drop table 'teacher' because it is referenced by foreign key constraint 'fk_assignment_teacher_id' in table 'assignment';
  3. 你解释:“assignment.teacher_id是外键,指向teacher.id,删teacher会破坏引用完整性,MySQL 拒绝执行。”

延伸话术:可以补充,“答辩前我测试过,如果先删assignment表再删teacher,就成功了——这说明外键约束是双向保护的,不是摆设。”

5.3 演示“BCrypt 密码安全”:用在线工具验证 admin 密码哈希值

避免被问“密码明文存储?太危险!”。
操作步骤:

  1. 打开在线 BCrypt 工具(如 https://bcrypt-generator.com/ );
  2. 输入明文密码admin123,选择 cost=10,生成哈希值;
  3. 对比studentassignment.sql中INSERT INTO admin语句里的哈希值(形如$2a$10$...),确认一致;
  4. 解释:“登录时,系统用BCrypt.checkpw(inputPassword, dbHash)校验,即使数据库泄露,攻击者也无法反推明文。”

参数说明:cost=10是平衡安全与性能的常用值,$2a$表示 BCrypt 算法版本,10$是迭代轮数(2^10=1024 次哈希)。这套代码用的是org.mindrot.jbcrypt库,已在lib/中提供。

从那以后我每次帮学生改毕设,都强制他们先做这三件事:用 Navicat 改一次状态、删一次 teacher 表、算一次 BCrypt 哈希——不是为了炫技,而是逼自己确认每一层(GUI、DAO、DB)真的连通了,没有黑匣子。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 13:45:55

游戏引擎基础架构深度解析:模块分层与帧循环的实践指南

聊游戏引擎&#xff0c;大多数人第一时间想到的都是渲染——PBR、体积光、全局光照&#xff0c;一张截图发出去确实唬人。但真正动手写引擎&#xff0c;或者进到一个引擎团队里&#xff0c;第一个逼你拍板的事情往往跟画面半毛钱关系都没有&#xff1a;代码按什么方式组织&…

作者头像 李华
网站建设 2026/10/8 13:44:46

TPS259483AYWPR与STM32F415RG协同实现工业级电源路径保护

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 13:44:10

嵌入式电源路径保护实战:eFuse电子熔断器与MCU协同设计全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 13:43:32

ESP32-P4 Windows环境搭建踩坑指南:从安装到烧录的8个坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 13:43:21

工业嵌入式电源路径保护:TPS259483AYWPR与MK64FX512VDC12协同设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 13:42:56

UE5 C++实战架构:性能、ABI与蓝图底层真相

1. 这不是“又一本UE架构书”&#xff0c;而是我在《暗影前线》项目里撕开引擎内核的真实切片你点进这篇&#xff0c;大概率不是为了看教科书式的定义——比如“Unreal Engine 是一个基于 C 的跨平台游戏引擎&#xff0c;采用组件化设计”。这种话我写过三遍&#xff0c;删了三…

作者头像 李华