
简介基于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 中也需要显式声明 characterEncodingutf8 和 useSSLfalse否则在高版本 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) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 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 ListStudent searchStudents(String keyword) { ListStudent 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 里展示多表查询结果时只需要把结果集封装成 ListString[] 或使用自定义 TableModel 即可。这里有一个常见的取舍问题让 JTable 直接显示数据库字段还是显示关联后的业务字段。没有经验的实现往往会直接显示学号和课程编号导致用户看不出是谁选了哪门课而关联查询后的结果表可读性更强答辩演示时也更直观所以建议从设计上就走 JOIN 路线。4. 常见问题与避坑指南课设里最容易翻车的四个玄学现场4.1 中文显示成问号或乱码现象是界面里输入的中文一旦写入数据库再查出来就变成???或者直接在数据库客户端里看到乱码。原因是建库时字符集默认不是 utf8mb4以及 JDBC 连接串没有声明字符集参数。解决办法是先检查建库语句是否指定了字符集再确认 JDBC URL 末尾追加了 ?characterEncodingutf8useSSLfalse最后检查表字段的 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 上追加 allowPublicKeyRetrievaltrue即完整的连接串为 jdbc:mysql://localhost:3306/studb?useSSLfalsecharacterEncodingutf8allowPublicKeyRetrievaltrue。如果不想加这个参数也可以修改 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 实训报告的写作顺序与素材留存整套方案里附带的课程设计报告是一个独立的文档资源写报告时建议按照“需求分析、总体设计、详细设计、系统实现、系统测试、总结”六个章节推进。其中系统测试章节很容易被忽略但这是评分时区分高低分的重要依据。测试部分不要只写“经测试系统运行正常”而要列出测试用例表写明输入数据、预期结果、实际结果和是否通过。比如输入一个不存在的学号进行查询预期结果应该是弹出提示或显示空表格实际结果如果弹出异常堆栈那就说明代码缺少异常捕获。关于素材留存我个人的习惯是每完成一个模块就顺手截图存档包括界面运行图、数据库表结构图、代码关键片段图这些图片在写报告时直接拖进文档即可不用后期再重新把系统跑起来补截图效率会高很多。从那以后我每次做课设或带新人做项目都强制走一遍“功能清单打勾、演示录像留存、报告截图同步”这三步省下的时间远超想象。这套方案本身就是按这个思路整理的希望帮到你。本文还有配套的精品资源点击获取