ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java+Swing+MySQL学生成绩管理系统:课程设计实战与避坑指南

Java+Swing+MySQL学生成绩管理系统:课程设计实战与避坑指南 简介这是一套面向高校计算机相关专业学生的Java课程设计/期末大作业完整方案采用Java Swing做桌面界面、MySQL做数据存储实现学生成绩管理系统。项目难度适中源码经本地编译可运行评审分达98分内容经助教老师审定适合需要完成课程设计、期末大作业或自学Swing桌面开发与JDBC数据库编程的读者参考。压缩包共18个文件约3.32MB以7个java源文件为核心涵盖登录、学生菜单、教师菜单、表格渲染与查询结果封装等模块另含4个sql脚本用于建库建表1个mysql-connector驱动jar、1份pdf报告、若干png/jpg界面截图及README说明结构清晰便于按模块阅读。目前已有85人学习下载。读者可据此获得一套可直接运行的完整项目源码、数据库脚本与配套报告快速理解Swing界面布局、事件处理与数据库增删改查的整合思路并对照报告梳理设计流程与排错方法。1. 从一份能跑通的学生成绩管理系统说起JavaSwingMySQL 到底解决什么问题很多同学做课程设计时第一反应是去搜「学生成绩管理系统源码」下载下来发现要么跑不起来要么数据库连不上要么界面丑得没法看。这个标题里的 JavaSwingMySQL 组合本质上是一套「桌面端 本地数据库」的经典教学项目架构Java 负责业务逻辑Swing 负责图形界面MySQL 负责数据持久化。它解决的核心问题是——让你在一个不依赖浏览器、不依赖服务器部署的环境里完整走一遍「增删改查 成绩统计 报表导出」的闭环。适合谁适合正在做 Java 课程设计、毕业设计开题、或者想用一个小项目把 JDBC、Swing 事件模型、MySQL 基础操作串起来的人。不适合谁不适合想学 Spring Boot 或 Web 开发的人因为这套技术栈和现代企业级开发有代差。但如果你连一个能跑起来的桌面管理系统都没写过直接上框架只会让你更懵。这一章先把「这是什么、能解决什么、适合谁」讲清楚后面几章我会按实际动手顺序把环境搭建、数据库设计、Swing 界面绑定、成绩统计逻辑和避坑点全部拆开。提示标题里的「PDF 报告」通常指课程设计报告内容一般包括需求分析、E-R 图、用例图、核心代码说明和测试截图。这部分我会在最后一章讲怎么把代码和报告对应起来避免报告和源码两张皮。2. 环境搭建与 MySQL 建库从安装到建表的完整命令2.1 JDK 与 MySQL 的版本选择我一般会选 JDK 8 或 JDK 11MySQL 选 5.7 或 8.0。为什么不是最新版因为 Swing 在 JDK 8 上最稳MySQL 8.0 的驱动包和 5.7 的语法差异不大但 8.0 默认的caching_sha2_password认证插件会让老版本 JDBC 驱动直接报错。如果你搜「mysql安装教程8.0」或「mysql 5.7.44 安装过程详细」注意安装时勾选「Use Legacy Authentication Method」或者装完后手动改用户认证方式。安装 MySQL 时记住 root 密码端口默认 3306。安装完成后用命令行验证mysql -u root -p # 输入密码后进入 mysql 命令行 SHOW DATABASES;如果报mysql ssl连接错误大概率是驱动和 SSL 配置不匹配。在 JDBC URL 后面加?useSSLfalseserverTimezoneAsia/Shanghai就能绕过。这不是生产环境的最佳实践但本地课程设计够用。2.2 建库建表学生、课程、成绩三张核心表学生成绩管理系统的数据模型不复杂但设计不好后面统计逻辑会很难写。我一般用三张表student、course、score。score表用联合主键(student_id, course_id)避免同一个学生同一门课有多条成绩记录。CREATE DATABASE student_score_db DEFAULT CHARACTER SET utf8mb4; USE student_score_db; CREATE TABLE student ( student_id VARCHAR(20) PRIMARY KEY, name VARCHAR(50) NOT NULL, gender ENUM(男,女) DEFAULT 男, class_name VARCHAR(50), major VARCHAR(50) ); CREATE TABLE course ( course_id VARCHAR(20) PRIMARY KEY, course_name VARCHAR(100) NOT NULL, credit DECIMAL(3,1) DEFAULT 0.0 ); CREATE TABLE score ( student_id VARCHAR(20), course_id VARCHAR(20), score DECIMAL(5,2) DEFAULT 0.00, exam_time DATE, PRIMARY KEY (student_id, course_id), FOREIGN KEY (student_id) REFERENCES student(student_id), FOREIGN KEY (course_id) REFERENCES course(course_id) );逻辑说明student_id用 VARCHAR 而不是 INT是因为学号通常有前导零或字母。score用 DECIMAL(5,2) 而不是 FLOAT避免浮点精度问题。外键约束保证成绩不会挂到不存在的学生或课程上。参数说明utf8mb4支持中文和特殊字符ENUM(男,女)限制性别输入减少脏数据。注意如果导入数据时报Cannot add or update a child row说明外键对应的主表没有对应记录。先插student和course再插score。3. Swing 界面与 JDBC 打通登录、主窗口和表格绑定3.1 用 JDBC 封装一个可复用的数据库工具类Swing 里直接写 JDBC 代码会到处都是try-catch我一般先封装一个DBUtil类提供getConnection()和close()方法。驱动类名和 URL 写在静态常量里改数据库时只改一处。import java.sql.*; public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/student_score_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 你的密码; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, Statement stmt, ResultSet rs) { try { if (rs ! null) rs.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (stmt ! null) stmt.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (conn ! null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }逻辑说明静态代码块加载驱动只执行一次。close()方法按ResultSet → Statement → Connection顺序关闭避免资源泄漏。参数说明characterEncodingutf8防止中文乱码serverTimezone不设会报时区错误。3.2 登录窗口与主界面的跳转逻辑登录窗口用JFrameJPanelGridLayout两个输入框和一个按钮。点击登录时查student表或单独的user表。我一般单独建一张user表存管理员账号避免和学生表混在一起。import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.sql.*; public class LoginFrame extends JFrame { private JTextField userField new JTextField(15); private JPasswordField passField new JPasswordField(15); public LoginFrame() { setTitle(学生成绩管理系统 - 登录); setSize(350, 200); setDefaultCloseOperation(EXIT_ON_CLOSE); setLocationRelativeTo(null); JPanel panel new JPanel(new GridLayout(3, 2, 10, 10)); panel.add(new JLabel(用户名)); panel.add(userField); panel.add(new JLabel(密码)); panel.add(passField); JButton loginBtn new JButton(登录); loginBtn.addActionListener(this::doLogin); panel.add(new JLabel()); panel.add(loginBtn); add(panel); setVisible(true); } private void doLogin(ActionEvent e) { String username userField.getText().trim(); String password new String(passField.getPassword()).trim(); String sql SELECT * FROM user WHERE username? AND password?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); ResultSet rs ps.executeQuery(); if (rs.next()) { dispose(); new MainFrame(); } else { JOptionPane.showMessageDialog(this, 用户名或密码错误); } } catch (SQLException ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(this, 数据库连接失败); } } public static void main(String[] args) { SwingUtilities.invokeLater(LoginFrame::new); } }逻辑说明用PreparedStatement而不是Statement防止 SQL 注入。SwingUtilities.invokeLater保证界面在事件调度线程中创建。参数说明setLocationRelativeTo(null)让窗口居中EXIT_ON_CLOSE关闭登录窗口时退出程序。3.3 用 JTable 展示成绩并支持按学号查询主界面用JTable展示score表关联查询的结果。我一般写一个ScoreTableModel继承AbstractTableModel把ListScore塞进去这样增删改后刷新方便。import javax.swing.*; import javax.swing.table.AbstractTableModel; import java.sql.*; import java.util.*; class ScoreTableModel extends AbstractTableModel { private String[] columns {学号, 姓名, 课程, 成绩, 考试时间}; private ListObject[] data new ArrayList(); public void loadData(String keyword) { data.clear(); String sql SELECT s.student_id, st.name, c.course_name, s.score, s.exam_time FROM score s JOIN student st ON s.student_id st.student_id JOIN course c ON s.course_id c.course_id WHERE s.student_id LIKE ? OR st.name LIKE ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, % keyword %); ps.setString(2, % keyword %); ResultSet rs ps.executeQuery(); while (rs.next()) { data.add(new Object[]{ rs.getString(student_id), rs.getString(name), rs.getString(course_name), rs.getBigDecimal(score), rs.getDate(exam_time) }); } } catch (SQLException e) { e.printStackTrace(); } fireTableDataChanged(); } Override public int getRowCount() { return data.size(); } Override public int getColumnCount() { return columns.length; } Override public String getColumnName(int col) { return columns[col]; } Override public Object getValueAt(int row, int col) { return data.get(row)[col]; } }逻辑说明loadData支持按学号或姓名模糊查询fireTableDataChanged()通知表格刷新。参数说明LIKE ?配合%keyword%实现模糊匹配getBigDecimal保留成绩精度。提示如果表格显示中文乱码检查数据库连接 URL 是否带characterEncodingutf8以及 Swing 组件是否用了默认字体。Windows 下默认字体通常没问题Linux 下可能需要手动设置UIManager。4. 成绩统计与导出平均分、排名和 CSV 文件生成4.1 用 SQL 聚合函数算平均分和排名成绩统计不要用 Java 循环算直接交给 MySQL。AVG、SUM、COUNT、RANK()窗口函数都能用。MySQL 8.0 支持窗口函数5.7 需要用变量模拟排名。-- 每个学生的总分和平均分 SELECT st.student_id, st.name, SUM(s.score) AS total, AVG(s.score) AS avg_score FROM score s JOIN student st ON s.student_id st.student_id GROUP BY st.student_id, st.name ORDER BY total DESC; -- 每门课程的平均分和最高分 SELECT c.course_name, AVG(s.score) AS avg_score, MAX(s.score) AS max_score FROM score s JOIN course c ON s.course_id c.course_id GROUP BY c.course_name;逻辑说明GROUP BY配合聚合函数一次查询拿到统计结果。参数说明ORDER BY total DESC按总分降序方便做排名。如果 MySQL 是 5.7 版本RANK()不可用可以用rank : rank 1变量方式但要注意变量初始化和排序顺序。4.2 把统计结果导出成 CSV 文件导出功能用BufferedWriter写 CSV注意中文用UTF-8编码Excel 打开时可能需要 BOM 头。import java.io.*; import java.sql.*; public class ExportUtil { public static void exportScoreCsv(String filePath) { String sql SELECT s.student_id, st.name, c.course_name, s.score, s.exam_time FROM score s JOIN student st ON s.student_id st.student_id JOIN course c ON s.course_id c.course_id; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery(); BufferedWriter writer new BufferedWriter( new OutputStreamWriter(new FileOutputStream(filePath), UTF-8))) { writer.write(\uFEFF); // BOM 头防止 Excel 中文乱码 writer.write(学号,姓名,课程,成绩,考试时间\n); while (rs.next()) { writer.write(rs.getString(student_id) ,); writer.write(rs.getString(name) ,); writer.write(rs.getString(course_name) ,); writer.write(rs.getBigDecimal(score) ,); writer.write(rs.getDate(exam_time) \n); } writer.flush(); } catch (Exception e) { e.printStackTrace(); } } }逻辑说明\uFEFF是 UTF-8 BOMExcel 识别后不会乱码。BufferedWriter比FileWriter效率高。参数说明filePath建议用System.getProperty(user.home) /Desktop/score.csv避免权限问题。4.3 成绩修改与删除的事务处理修改成绩时先UPDATE再刷新表格。删除学生时因为有外键约束要先删score再删student否则报错。我一般把这两个操作放在一个事务里。public void deleteStudent(String studentId) { String deleteScore DELETE FROM score WHERE student_id?; String deleteStudent DELETE FROM student WHERE student_id?; try (Connection conn DBUtil.getConnection()) { conn.setAutoCommit(false); try (PreparedStatement ps1 conn.prepareStatement(deleteScore); PreparedStatement ps2 conn.prepareStatement(deleteStudent)) { ps1.setString(1, studentId); ps1.executeUpdate(); ps2.setString(1, studentId); ps2.executeUpdate(); conn.commit(); } catch (SQLException e) { conn.rollback(); throw e; } } catch (SQLException e) { e.printStackTrace(); } }逻辑说明setAutoCommit(false)开启事务两个删除都成功才commit否则rollback。参数说明studentId从表格选中行获取注意判空。5. 避坑与排查从驱动报错到界面卡死的 5 个血泪经验5.1 现象启动时报No suitable driver found for jdbc:mysql原因没有把 MySQL 驱动 jar 包加到 classpath或者Class.forName的类名写错。MySQL 8.0 驱动类名是com.mysql.cj.jdbc.Driver5.7 是com.mysql.jdbc.Driver。解决在 IDEA 的 Project Structure 里把mysql-connector-java-8.0.xx.jar加到 Libraries或者 Maven 项目加依赖。5.2 现象中文存入数据库变成???原因数据库、表、连接 URL 三处字符集不一致。解决建库时用utf8mb4连接 URL 加characterEncodingutf8Swing 界面不需要额外设置。如果还是乱码检查 MySQL 配置文件my.ini里的character-set-server。5.3 现象点击按钮后界面卡死按钮一直处于按下状态原因在事件调度线程EDT里执行了耗时数据库查询。Swing 是单线程模型所有界面更新和事件处理都在 EDT 里。解决把数据库操作放到SwingWorker的doInBackground()里done()里更新表格。这是 Swing 新手最容易翻车的地方。5.4 现象Cannot add or update a child row: a foreign key constraint fails原因插入score时student_id或course_id在对应主表里不存在。解决先插学生和课程再插成绩。或者临时SET FOREIGN_KEY_CHECKS0但不推荐会留下脏数据。5.5 现象导出的 CSV 用 Excel 打开全是乱码原因Excel 默认用 GBK 解析 CSV而文件是 UTF-8。解决在文件开头写\uFEFFBOM 头或者导出时直接指定 GBK 编码。我一般用 BOM 头兼容性更好。6. 把源码和 PDF 报告对应起来让课程设计拿高分的几个技巧最后一章不讲新功能讲怎么让这份「JavaSwingMySQL 学生成绩管理系统」在课程设计或毕业设计里拿高分。核心思路是报告里的每一张图、每一段代码说明都能在源码里找到对应文件。先看报告结构。常见的高分报告目录是需求分析 → 系统设计E-R 图、用例图、功能模块图→ 数据库设计表结构→ 详细实现核心代码→ 测试截图→ 总结。你的源码目录应该和「详细实现」章节一一对应。比如报告里写「登录模块」源码里就有LoginFrame.java报告里写「成绩统计模块」源码里就有ScoreTableModel.java和对应的 SQL。再看用例图。搜「学生成绩管理系统用例图」的人很多但很多人画完用例图就不管了。我的习惯是用例图里的每个用例在源码里至少有一个按钮或菜单项对应。比如「查询成绩」对应主界面的查询按钮「导出成绩」对应导出菜单。这样答辩时老师问「你这个用例怎么实现的」你能直接打开对应代码。数据库表结构在报告里通常用表格呈现我一般会加一列「对应源码字段」比如字段名类型说明源码对应student_idVARCHAR(20)学号Student.studentIdnameVARCHAR(50)姓名Student.namescoreDECIMAL(5,2)成绩Score.score这样报告和代码就绑定了。测试截图部分不要只截一个主界面要截「登录失败提示」「查询结果为空」「导出成功后的 CSV 文件」这些边界场景。老师看的就是你有没有考虑异常情况。最后说一个我踩过的坑报告里的代码和源码不一致。很多人报告里贴的是网上抄的代码源码里是自己写的答辩时被问到就露馅。我的习惯是报告里的核心代码直接从源码复制只删掉无关的 import 和注释保证能对应上。如果你时间紧至少把类名、方法名、SQL 语句对齐。提示PDF 报告导出时代码块用等宽字体行号可加可不加。E-R 图用 draw.io 或 ProcessOn 画导出 PNG 插入 Word 再转 PDF比直接截图清晰。这套方案值不值得做如果你需要一个小项目把 Java 基础、JDBC、Swing 和 MySQL 串起来它值得。但不要指望它能写进简历去面 Java 开发岗面试官更关心 Spring Boot 和分布式。把它当成一个「能跑通、能讲清楚、能写进报告」的课程设计足够了。希望帮到你。本文还有配套的精品资源点击获取
返回列表