news 2026/10/18 22:21:54

基于Java Swing+MySQL的学生选课管理系统完整课设方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Java Swing+MySQL的学生选课管理系统完整课设方案

简介:基于Java Swing和MySQL实现的学生选课管理系统,面向高校计算机相关专业课程设计与实训场景,适合需要完成数据库或Java GUI课程作业的开发者。系统分为系统管理、数据管理与数据查询三大部分:支持用户登录与密码修改,学生信息、课程信息及选课信息的增删改,以及多维度的信息查询,功能结构清晰,便于二次开发与学习。压缩包整体为RAR格式,共3个文件,含一个完整可运行的Eclipse/IDEA工程ZIP包、MySQL建库SQL脚本以及配套实训报告DOCX文档,包体大小3.34MB,轻量易下载。资源已在学习社区吸引268人浏览学习,可作为课程设计、期末项目或毕业设计的实用参考。下载后可根据实训报告说明,在JDK8及以上、MySQL5.7及以上的环境中快速部署运行,尤其适合初次接触Swing开发的人员理解业务分层与数据库交互逻辑。

1. 学生选课管理系统:从登录到选课落库的完整课设方案

每年到了课设季,Java 方向的学生选课管理系统总是热门题目,但真正能把 Swing 界面、JDBC 操作和 MySQL 数据落库串成一条完整链路的作业并不多。见过太多人卡在同一个地方:界面画好了,按钮一按却报空指针;数据库表建好了,中文却显示成乱码;甚至有人到答辩前一天才发现,选课功能居然能重复选同一门课。这套基于 Java Swing + MySQL 的学生选课管理系统,覆盖了系统管理、数据管理和数据查询三大核心部分,正好是一条可以让读者直接照着做、拿来改、拿去答辩的完整方案。无论你是正在做课程设计的学生,还是需要快速出一套参考模板的从业者,这套方案的代码结构、数据库脚本和实训报告都能直接复用。

2. 总体架构设计:登录校验、数据管理、查询统计三层怎么分工

2.1 功能模块划分:三个核心包对应三类操作

整套系统的功能并不复杂,但划分是否清晰直接决定了后续写代码和写报告能不能省力。按照常规课设的评分标准,通常会把系统拆成三个功能域:系统管理负责用户身份的合法性校验,包括密码设置、用户登录和退出三个动作;数据管理负责业务数据的增删改,包括学生管理、课程管理和选课管理三大模块,每个模块又各自带新增、删除、修改三个子功能;数据查询负责信息的检索与展示,包括查询学生信息、查询课程信息和查询选课信息三个查询入口。

这样的划分实际上是照着 MVC 的思路走的,虽然用的是 Swing,但依然把界面层、业务逻辑层和数据访问层做了物理隔离。系统管理里的用户登录是整个系统的门卫,所有操作都要经过登录窗口,用户表存放在数据库中的设计要预留管理员初始账号,通常在部署时需要手动执行 SQL 脚本初始化一条 admin 记录。数据管理和数据查询两个域之间没有直接依赖,查询模块只读,数据管理模块写操作,这样的好处是答辩时被问到“如果查询时数据不一致怎么办”可以给出清晰的解释。

2.2 数据库设计:三张核心表搞定全部业务

数据库文件名为 studb.sql,这是整套方案的地基。表结构设计通常只需要三张表,分别是学生表、课程表和选课表,如果系统管理里含用户登录,还需要一张用户表。学生表的核心字段包括学号、姓名、性别、班级,学号设为主键;课程表包括课程编号、课程名称、学分、授课教师,课程编号设为主键;选课表是学生表和课程表的关联表,包含选课编号、学号、课程编号和选课时间,其中学号和课程编号分别作为外键引用前两张表的主键。

在建表时有一个常见问题,就是选课表是否需要单独设置选课编号字段。通常的做法是给选课表设置一个自增主键,避免用联合主键导致后续做修改功能时难以定位到具体记录。数据库字符集建议统一设置为 utf8mb4,否则在插入中文姓名或课程名称时会报 Incorrect string value 错误,这在后文避坑章节会具体展开。JDBC URL 中也需要显式声明 characterEncoding=utf8 和 useSSL=false,否则在高版本 MySQL 驱动下会出现连接警告甚至连接失败。

以下是选课表的参考建表语句,其他两张表按同样的规范设置即可:

CREATE TABLE `tb_course_select` ( `select_id` INT NOT NULL AUTO_INCREMENT COMMENT '选课编号', `student_id` VARCHAR(20) NOT NULL COMMENT '学号', `course_id` VARCHAR(20) NOT NULL COMMENT '课程编号', `select_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '选课时间', PRIMARY KEY (`select_id`), KEY `idx_student` (`student_id`), KEY `idx_course` (`course_id`), CONSTRAINT `fk_select_student` FOREIGN KEY (`student_id`) REFERENCES `tb_student` (`student_id`), CONSTRAINT `fk_select_course` FOREIGN KEY (`course_id`) REFERENCES `tb_course` (`course_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='选课信息表';

建表时有几个设计要点需要注意:第一,选课编号使用自增主键,这样在删除某条选课记录时能通过 select_id 精确定位;第二,学生表和课程表的外键约束能保证数据完整性,避免插入选课记录时引用到不存在的学号;第三,选课时间使用数据库默认值 CURRENT_TIMESTAMP,这样在插入时不需要手动传时间参数,代码层面少一个逻辑分支。

2.3 项目目录结构与代码分层

IDEA 版本的项目目录结构与 Eclipse 略有不同,主要体现在包名组织和资源文件路径上。推荐的包结构是 com.xxx.student 作为根包,下面分四个子包:view 存放所有窗口类,dao 存放数据库操作类,model 存放实体类,util 存放数据库连接工具类。入口类通常放在根包下,起名为 MainFrame 或 LoginFrame 都可以。这样的划分在写实训报告时也容易对应到“系统总体结构”这一章节。

在数据库连接部分,通常会在 util 包里建一个 DBUtil 类,统一管理驱动的加载、连接的创建与关闭。不建议在每个 DAO 类里重复写 Class.forName 和 DriverManager.getConnection 的代码,否则后期修改数据库密码时要改十几个位置,非常容易出现漏改导致部分功能正常、部分功能报错的情况。这种“改一处漏一处”的血泪经验在答辩时的排查经历里完全可以当作素材讲出来。

3. 核心功能实现:登录校验、增删改查与选课事务的落地写法

3.1 登录模块:PreparedStatement 防注入与密码校验

登录功能是系统管理的第一道关卡,Java Swing 界面通常由一个 JFrame 窗口加两个 JTextField、两个 JPasswordField 和一个 JButton 组成。点击登录按钮后,首先做非空校验,然后调用 UserDao 层的 login 方法查询数据库。这里有一个关键设计点:查询语句必须使用 PreparedStatement 而不是 Statement,原因有两点,一是避免 SQL 注入,二是免去手动拼接字符串时处理单引号转义的麻烦。

public User login(String username, String password) { String sql = "SELECT * FROM tb_user WHERE username=? AND password=?"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { User user = new User(); user.setUserId(rs.getInt("user_id")); user.setUsername(rs.getString("username")); return user; } } } catch (SQLException e) { e.printStackTrace(); } return null; }

这段代码有几个值得注意的细节:使用 try-with-resources 语法时,Connection、PreparedStatement 和 ResultSet 都会被自动关闭,避免在 finally 块里写繁琐的关闭逻辑,这个写法可以在实训报告中作为亮点展示。登录成功后通常会跳转到主界面并关闭登录窗口,跳转时把当前用户对象传递过去,主界面可以在状态栏显示当前登录用户,这个细节的成本很低但能提升答辩时的印象分。

3.2 学生管理模块:JTable 数据展示与增删改的操作闭环

学生管理是数据管理域里代码量最大的模块,界面一般由 JTable、JScrollPane 和上方的输入表单组成。比较常见的实现方式是北方位放输入表单,中间放 JTable 表格,下方放三个按钮“添加”“修改”“删除”。点击添加按钮时,从输入框取值,组装成 Student 模型,调用 StudentDao 的 add 方法插入数据库。

这里要特别提示一个新手容易翻车的点:JTable 默认不可编辑,但很多同学在实现修改功能时直接去表格里双击改写单元格,然后发现数据并没有更新到数据库。正确做法是点击表格行时把该行数据回填到上方输入框,用户修改输入框内容后再点击“修改”按钮执行更新。这种设计的好处是避免直接在表格中编辑导致误操作,同时代码逻辑也更简单。

以下是学生管理模块的查询方法,通过学号或姓名做模糊查询:

public List<Student> searchStudents(String keyword) { List<Student> list = new ArrayList<>(); String sql = "SELECT * FROM tb_student WHERE student_id LIKE ? OR student_name LIKE ?"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, "%" + keyword + "%"); ps.setString(2, "%" + keyword + "%"); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { Student stu = new Student(); stu.setStudentId(rs.getString("student_id")); stu.setStudentName(rs.getString("student_name")); stu.setGender(rs.getString("gender")); stu.setClassName(rs.getString("class_name")); list.add(stu); } } } catch (SQLException e) { e.printStackTrace(); } return list; }

在执行删除操作时,我一般会先弹一个 JOptionPane 确认框,让用户二次确认是否删除,这个交互习惯可以在答辩时体现出系统的规范性。删除学生时需要注意选课表中是否还存在该学生的选课记录,由于建表时设置了外键约束,直接删除学生会导致外键冲突报错,所以通常的处理方式是在删除学生前先删除其选课记录,或者使用级联删除,这个细节在模块实现描述和答辩时有很大讲头。

3.3 选课模块:事务控制与重复选课校验

选课管理是整个系统里最有技术含量的部分,因为涉及两张表的关联操作和事务控制。选课界面通常左侧显示学生列表,右侧显示课程列表,选中一个学生和一门课程后点击“选课”按钮完成业务。核心逻辑有两件事:先在选课表中查一下该学生是否已经选了该课程,如果已存在则提示“不能重复选课”;如果不存在则执行插入操作。

这里要特别注意,整个过程必须放在同一个数据库连接的事务里:先查询校验,再执行插入,任何一步失败都要回滚。如果查询和插入各自使用了独立的连接,在查询时发现没有重复选课,但在插入前另一个线程已经插入了相同记录,就可能出现并发问题。虽然单机课设不太可能有真正的并发场景,但这种写事务的规范意识是评分和答辩时的加分项。

public boolean addCourseSelect(String studentId, String courseId) { Connection conn = null; try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); // 校验是否重复选课 String checkSql = "SELECT COUNT(*) FROM tb_course_select WHERE student_id=? AND course_id=?"; try (PreparedStatement ps = conn.prepareStatement(checkSql)) { ps.setString(1, studentId); ps.setString(2, courseId); try (ResultSet rs = ps.executeQuery()) { rs.next(); if (rs.getInt(1) > 0) { return false; // 重复选课 } } } // 执行插入 String insertSql = "INSERT INTO tb_course_select(student_id, course_id) VALUES(?, ?)"; try (PreparedStatement ps = conn.prepareStatement(insertSql)) { ps.setString(1, studentId); ps.setString(2, courseId); ps.executeUpdate(); } conn.commit(); return true; } catch (SQLException e) { if (conn != null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); return false; } finally { DBUtil.close(conn); } }

上述代码里,setAutoCommit(false) 是事务开启的标志,commit 和 rollback 分别对应提交与回滚。很多初学者容易漏掉 setAutoCommit 这一行,导致事务没有真正生效,一旦插入语句执行失败后没有回滚,数据库里可能会残留半条脏数据。在写实训报告时,可以把这个方法单独拿出来作为“系统关键技术”章节的例证,讲解事务的 ACID 特性在选课场景中的实际应用。

3.4 数据查询模块:三种查询结果的展示方式

数据查询域的三个查询功能在实现上可以复用同一个查询模板:从下拉框选择查询条件或直接在文本框输入关键字,点击查询按钮后刷新 JTable 的数据模型。查询学生信息的常见做法是支持按学号精确查询和按姓名模糊查询,查询课程信息类似,查询选课信息则通过 JOIN 关联三张表,把学生姓名和课程名称一起展示出来。

选课信息的查询 SQL 是三个查询里唯一涉及多表关联的,典型的写法如下:

SELECT s.student_id, s.student_name, c.course_id, c.course_name, c.credit, cs.select_time FROM tb_course_select cs JOIN tb_student s ON cs.student_id = s.student_id JOIN tb_course c ON cs.course_id = c.course_id

在 Swing 里展示多表查询结果时,只需要把结果集封装成 List<String[]> 或使用自定义 TableModel 即可。这里有一个常见的取舍问题:让 JTable 直接显示数据库字段还是显示关联后的业务字段。没有经验的实现往往会直接显示学号和课程编号,导致用户看不出是谁选了哪门课,而关联查询后的结果表可读性更强,答辩演示时也更直观,所以建议从设计上就走 JOIN 路线。

4. 常见问题与避坑指南:课设里最容易翻车的四个玄学现场

4.1 中文显示成问号或乱码

现象是界面里输入的中文一旦写入数据库再查出来就变成???,或者直接在数据库客户端里看到乱码。原因是建库时字符集默认不是 utf8mb4,以及 JDBC 连接串没有声明字符集参数。解决办法是先检查建库语句是否指定了字符集,再确认 JDBC URL 末尾追加了 ?characterEncoding=utf8&useSSL=false,最后检查表字段的 collation 是否为 utf8mb4_unicode_ci。这三个环节有一个漏了就会出问题,而且是典型的“从入门到放弃”级别的玄学问题,但其实就是字符集没配齐。

4.2 IDEA 中运行报错 java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

现象是代码写好了,一运行就抛出找不到 MySQL 驱动类。原因通常是 jar 包没有导入到项目的依赖里,或者导入到了磁盘目录但 IDEA 没有识别为库。在 IDEA 里的正确操作是:把 mysql-connector-java 的 jar 包放到项目根目录下新建的 lib 文件夹中,然后右键 jar 包选择 Add as Library。检查是否成功的标志是 External Libraries 目录下能看到该 jar 包。另外高版本 MySQL 驱动类的名称是 com.mysql.cj.jdbc.Driver,而不是旧版的 com.mysql.jdbc.Driver,如果你的驱动是 8.x 版本,Class.forName 里的字符串要写对。

4.3 新建连接时出现 Public Key Retrieval is not allowed

现象是用 MySQL 8.x 驱动连接数据库时报这个错,看起来很吓人但实际上只是连接串没有指定允许获取公钥。原因是 MySQL 8 默认使用 caching_sha2_password 认证方式,客户端第一次连接时需要获取服务端公钥。解决办法是在 JDBC URL 上追加 allowPublicKeyRetrieval=true,即完整的连接串为 jdbc:mysql://localhost:3306/studb?useSSL=false&characterEncoding=utf8&allowPublicKeyRetrieval=true。如果不想加这个参数,也可以修改 MySQL 用户的认证插件为 mysql_native_password,但一般不推荐在课设里去动数据库的全局配置。

4.4 主键冲突或外键约束导致删除失败

现象是在数据管理里想删除某个学生,但系统直接报错说无法删除。原因前面提过,选课表通过外键引用了该学生的学号,存在关联记录时数据库会拒绝删除父表记录。解决办法有两种方案,各有取舍:方案一是做事务控制,先删除选课表中该学生的记录,再删除学生记录,代码稍复杂但符合业务逻辑;方案二是在建表时不设物理外键,只用普通索引,这样删除学生时不会报错,但数据完整性需要靠代码保证。对课设来说,我一般建议采用方案一,因为外键约束本身是数据库课程的重要知识点,能讲清楚它带来的限制和解决办法,答辩时反而能成为加分项。

5. 验收演示与答辩准备:功能逐条过、提问逐项答

5.1 功能验收清单:按用例走一遍

验收环节不能只是把程序跑起来给老师看一眼,要按照功能用例逐步演示,并记录每一步的结果。通常来说,我会按以下顺序过一遍:先打开 MySQL 服务端,运行 studb.sql 初始化数据库,确认三张表结构完整;再启动登录界面,输入错误的密码验证系统能拦截,输入正确密码验证能进入主界面;然后进入学生管理页面,依次执行添加学生、查询学生、修改学生、删除学生,每一步退出程序重新查询数据库确认数据真正写入;再进入课程管理页面重复同样步骤;最后进入选课管理页面,先做一次正常选课,再对同一学生同一课程重复选课,验证系统弹出重复选课提示。

这里有一个容易被忽略的验收点,就是实训报告里写了什么功能,演示时就必须点什么功能。如果报告里写了“支持按姓名模糊查询”,但代码里实现的是精确匹配,被老师问到时就会很尴尬。建议在写代码阶段就拉一张报告功能清单,逐项打勾确认,这样演示时能做到心中有数,避免翻车。

验收时还建议准备一份简短的数据准备脚本:提前往数据库里插入几条有代表性的学生和课程记录,比如不同班级的学生、不同学分的课程,这样演示时不用现场敲键盘输入数据,流程更流畅。这也是从带项目的习惯里保留下来的经验,每次演示前都强制走一遍完整操作,确认无误后再开始。

5.2 答辩问题与应答策略

课设答辩最常见的问题集中在四个方向:为什么选 Swing 而不是 JavaFX 或 Web 技术、数据库表关系怎么设计的、选取和删除操作会不会破坏数据一致性、遇到过什么坑是怎么解决的。针对第一个问题,可以回答 Swing 是 Java 基础课程里覆盖最完整的技术栈,JDK 自带无需额外引入框架,而且对事件监听机制和 GUI 布局的教学目标契合度最高;针对第二个问题,可以画出三张表的关系图,讲清楚外键约束和关联查询的 JOIN 条件;针对第三个问题,直接拿选课模块的事务代码说明 commit 和 rollback 的使用场景即可。

答辩时还可以准备一个“技术亮点”清单,比如登录模块使用了 PreparedStatement 防注入、选课模块使用了事务控制、数据库连接封装在 DBUtil 工具类中统一管理、GUI 层不直接操作 SQL 而是通过 DAO 层中转。这些点在实训报告中最好有专门的章节展开,答辩时口头概括即可,不要占用太多时间。

5.3 实训报告的写作顺序与素材留存

整套方案里附带的课程设计报告是一个独立的文档资源,写报告时建议按照“需求分析、总体设计、详细设计、系统实现、系统测试、总结”六个章节推进。其中系统测试章节很容易被忽略,但这是评分时区分高低分的重要依据。测试部分不要只写“经测试系统运行正常”,而要列出测试用例表,写明输入数据、预期结果、实际结果和是否通过。比如输入一个不存在的学号进行查询,预期结果应该是弹出提示或显示空表格,实际结果如果弹出异常堆栈,那就说明代码缺少异常捕获。

关于素材留存,我个人的习惯是每完成一个模块就顺手截图存档,包括界面运行图、数据库表结构图、代码关键片段图,这些图片在写报告时直接拖进文档即可,不用后期再重新把系统跑起来补截图,效率会高很多。从那以后我每次做课设或带新人做项目,都强制走一遍“功能清单打勾、演示录像留存、报告截图同步”这三步,省下的时间远超想象。这套方案本身就是按这个思路整理的,希望帮到你。

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

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

Flutter Slider自定义形状:用Shape实现菱形/宝石滑块

如果你接手过一个“把滑块改成菱形”的需求&#xff0c;大概率和我一开始一样&#xff0c;先找找有没有thumbColor、borderRadius之类的参数&#xff0c;结果发现无论怎么调&#xff0c;滑块始终是那个标准的圆。我前几个月在一个画板类项目里就遇到过这种事&#xff1a;UI 给的…

作者头像 李华
网站建设 2026/10/18 22:19:42

VTK中文指南避坑指南:术语校验、章节精读与源码联动

简介&#xff1a;本资源为VTK&#xff08;Visualization Toolkit&#xff09;官方《Users Guide》第11版中文翻译PDF&#xff0c;面向科学可视化、医学影像、计算流体力学及三维图形开发领域的工程师与高校研究者&#xff0c;解决VTK系统性学习门槛高、英文文档阅读成本大的核心…

作者头像 李华
网站建设 2026/10/18 22:17:38

WebUI工程化实践:从组件拆分到性能调优的避坑指南

简介&#xff1a;一份以WebUI为主题的完整源码压缩包&#xff0c;围绕HTML结合CSS与JavaScript&#xff0c;展示从页面骨架搭建、内容结构化到样式美化与交互响应的全过程。包内含156个文件&#xff0c;html负责页面结构&#xff0c;css控制布局外观&#xff0c;js处理事件与DO…

作者头像 李华
网站建设 2026/10/18 22:17:03

VC++调用COM接口生成桌面快捷方式:IShellLink与IPersistFile完整实践

我们团队在做一个内部工具时&#xff0c;需要在安装流程里给主程序生成一个桌面快捷方式。当时第一个念头是直接复制一份exe到桌面——反正程序也不大&#xff0c;但一测试就发现不对劲&#xff1a;程序位置一旦变动&#xff0c;这个“假快捷方式”就失灵&#xff1b;而且它没有…

作者头像 李华
网站建设 2026/10/18 22:14:01

AIGC胶片质感指南:影调、颗粒、halation、暗角如何一起成立

想要胶片质感&#xff1f;那我就加个“颗粒感”。好了&#xff0c;你一加&#xff0c;就露馅。别急着反驳。你放大看。缩略图里像那么回事。人物、天空、高光边缘一放大&#xff0c;颗粒像贴纸&#xff0c;光源顶着一样宽的光圈&#xff0c;假不假&#xff1f;降饱和、压暗、加…

作者头像 李华
网站建设 2026/10/18 22:13:40

LoRa SX1276实战:寄存器配置、FIFO管理与射频调试避坑指南

简介&#xff1a;面向物联网开发者的利尔达射频Lora技术资料&#xff0c;围绕SX1276芯片&#xff0c;系统解析长距离扩频通信原理和低功耗设计要点&#xff0c;适合智慧城市、智能农业、物流追踪等项目的软硬件工程师使用。资料覆盖频率规划、扩频因子、信道带宽、发射功率等关…

作者头像 李华