
简介基于EclipseJavaSwingMySQL构建的学生成绩管理系统是一份面向高校Java课程设计的高分参考项目适用于需要完成期末大作业或课设的计算机相关专业学生。系统涵盖学生端与管理员端两大模块学生可登录并浏览成绩管理员可进行班级添加与维护、学生信息添加与维护等功能界面采用Swing绘制交互直观结构清晰。资源包共126个文件包含16个Java源码、48个编译后class文件、SQL建表脚本、Eclipse工程配置及大量界面截图与图标资源png/jpg压缩后仅3.03MB便于下载与二次开发。项目已通过导师审核取得95分成绩代码完整、运行稳定。当前已有396人学习使用。对于缺乏项目经验、希望获得完整可运行代码并快速理解业务分层与Dao交互的同学而言这套资源能直接提供可借鉴的模块划分、DAO数据访问方式以及基于MySQL的持久化思路省去从零搭建的繁琐过程。1. 课设写作背后的三个坑这一篇全给你拆完很多人拿到“基于EclipseJavaSwingMysql的学生成绩管理系统”这种题第一反应是找个源码改改交差。但真正被导师卡住的地方往往不是功能不够而是三个说不出口的问题Swing界面为什么这么难看、Mysql连接为什么在本机好使换台机器就报错、以及答辩护盘时“这个类是干什么的”一问三不知。这套系统我一直留着就是因为它在结构上把Dao、Frame、Entity分层做得很规矩登录判断、班级维护、学生增删改查都齐了不是那种一个文件写到底的作业。把它当课设交或者拿它当SwingMysql的入门项目拆着玩都很合适。下面按我自己的复盘顺序来写先看懂分层和实体再解决环境与连接然后过一遍管理员和学生两条主流程最后把容易翻车的细节和答辩点放在收尾。2. 项目结构拆解从.class反推SwingMysql的分层设计拿到手一堆.class文件第一件事不是急着运行而是先搞明白每个类在系统里扮演什么角色。这套系统里能看到LoginFrame、MainstudentFrame、StudentManagerFrame、ClassTypeManagerFrame、StudentAddFrame、ClassTypeAddFrame、StudentUserFrame这些界面类以及StudentDao、UserDao两个数据访问类加上Student实体类。说白了三层界面层负责交互Dao层负责和Mysql对话实体类负责承载一行数据。2.0.1 界面类拆分原则Swing写课设最容易犯的错是几百行代码全堆在一个JFrame里事件监听、SQL语句、组件初始化挤在一起。这个项目把它拆成了多个Frame每个窗口只做一件事。比如LoginFrame只处理登录验证验证通过后根据角色跳转到MainstudentFrame管理员主界面或者StudentUserFrame学生界面。班级相关的单独拆了ClassTypeManagerFrame和ClassTypeAddFrame学生相关的拆了StudentManagerFrame和StudentAddFrame。这样拆的好处是每个类的职责清楚答辩被问到“新增一个班级功能去哪里改”时你直接说改ClassTypeAddFrame和ClassTypeManagerFrame比说“在那个大文件里找”要体面得多。2.0.2Student实体类的字段设计不能乱Student不是简单装几个属性它的字段要跟Mysql表结构对齐。以这套系统的常见设计为例学生表大概长这样CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, student_no VARCHAR(20) NOT NULL UNIQUE COMMENT 学号, name VARCHAR(30) NOT NULL COMMENT 姓名, class_id INT NOT NULL COMMENT 班级ID关联班级表, score DOUBLE DEFAULT 0 COMMENT 成绩, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 录入时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;对应Java端Student类的字段就是id、studentNo、name、classId、score、createTime。这里有个容易被忽略的点classId是int类型对应Mysql的INT不要写成String。成绩用double还是BigDecimal课设场景用double没问题但如果你打算扩展成真实项目建议改BigDecimal防精度丢失。StudentDao里的方法基本围绕这个实体转add(Student s)、deleteById(int id)、update(Student s)、findByNo(String no)、findAll()。这五个方法覆盖了教师和管理员最常见的操作。2.0.3UserDao与登录验证的分工UserDao负责用户表一般表结构就是id、username、password、role。角色字段建议用String存admin或student别用int存0和1——答辩时导师问“为什么不用int”你解释“字符串可读性好而且角色数量如果以后增加扩展不用改代码逻辑”。登录验证逻辑不放在LoginFrame的按钮事件里写死SQL而是调用UserDao.findByUsernameAndPassword(username, password)返回User对象或null。返回null就弹JOptionPane.showMessageDialog提示用户名或密码错误返回非空就判断角色然后dispose()当前窗口new MainstudentFrame()或new StudentUserFrame()。这种写法把SQL隔离在Dao层界面里看不到Statement和ResultSet既整洁又方便单元测试。3. EclipseMysql环境搭建从JDBC驱动到连接池的几个必踩点课设答辩现场最常见的事故是开发者在自己笔记本上运行得好好的换到教室电脑上就报ClassNotFoundException: com.mysql.jdbc.Driver或者Communications link failure。这两个错基本都是环境问题不是代码问题。提前把环境弄扎实比多写十个功能都重要。3.0.1 JDBC驱动版本与Mysql版本匹配Mysql 5.x用com.mysql.jdbc.Driver没问题但如果你用的是Mysql 8.x驱动类名要换成com.mysql.cj.jdbc.DriverURL也要加上时区参数。这套系统的源码里写的是老驱动名所以建议直接在项目里改用Mysql 8驱动一行代码的事Class.forName(com.mysql.cj.jdbc.Driver); String url jdbc:mysql://localhost:3306/student_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; String user root; String password your_password; Connection conn DriverManager.getConnection(url, user, password);serverTimezone不写Mysql 8会报The server time zone value???: unrecognizedcharacterEncodingutf8不写中文录入到数据库大概率变问号。这两项属于经验值课设文档里最好提一句“为解决中文乱码和时区问题在URL显式声明”这能加分。3.0.2 Eclipse中导入外部Jar的两种姿势项目里如果没有lib文件夹要自己把mysql-connector-java-8.0.x.jar放进去。常见做法是在项目根目录建lib目录把jar复制进去然后右键jar -Build Path-Add to Build Path。注意Build Path里看到的是“Referenced Libraries”不是项目里那个lib文件夹别搞混。如果换机器打开项目报找不到驱动先看Build Path里是否还引用着原来那个jar路径Eclipse经常因为路径变了丢引用。3.0.3 数据库连接封装别在每个Frame里重复写连接原项目里每个Dao都在方法里调DriverManager.getConnection()这确实能跑但答辩时如果你能主动提出“连接代码重复可以用一个DBUtil工具类统一管理”印象分就出来了。我给你一个课设够用的版本import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static final String DRIVER com.mysql.cj.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/student_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }static块在类加载时执行一次确保驱动只注册一次。getConnection()每次调用都新建连接对课设的并发量完全没问题。如果被问到“为什么不复用连接”你可以说“课设场景单用户操作连接开销可接受生产环境我会用HikariCP连接池”一来显得你知道连接池二来也说明你分得清场景。3.0.4 Mysql 8的密码加密方式坑老教程里经常配mysql_native_password但Mysql 8默认是caching_sha2_passwordJDBC驱动8.x其实支持但如果你用5.x驱动就会报Unable to load authentication plugin caching_sha2_password。解决办法要么升级驱动要么在Mysql里把用户改成老密码方式ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456;这个坑在答辩演示时尤其致命。建议提前在答辩机器上跑一次System.out.println(DBUtil.getConnection())验证连接别等到打开登录窗口才报错。4. 主流程实战从登录到班级与学生维护的完整操作路径系统分管理员和学生两种角色操作路径完全不一样。管理员登录后进MainstudentFrame能看到班级管理和学生管理两大块学生登录后只能进StudentUserFrame看自己的成绩。下面把这两条路径的关键代码逻辑拆开讲。4.0.1 登录验证的代码怎么写才稳妥LoginFrame里一般是一个JTextField、一个JPasswordField、一个登录按钮。按钮事件里要处理三个分支输入为空提示、用户不存在提示、密码错误提示。别把“用户不存在”和“密码错误”合并成一个提示导师可能会问“为什么不能用同一个提示”——你可以说“为了用户体验明确告诉用户是账号问题还是密码问题如果你担心安全生产系统应该统一提示”。这属于开放性回答。核心验证代码String username userField.getText().trim(); String password new String(passField.getPassword()); User user userDao.findByUsernameAndPassword(username, password); if (user null) { JOptionPane.showMessageDialog(this, 用户名或密码错误); return; } if (admin.equals(user.getRole())) { dispose(); new MainstudentFrame(username).setVisible(true); } else if (student.equals(user.getRole())) { dispose(); new StudentUserFrame(username).setVisible(true); } else { JOptionPane.showMessageDialog(this, 未知角色); }new String(passField.getPassword())是从JPasswordField取密码的标准写法不要用passField.getText()——那个方法已过时而且会以明文方式把密码留在内存里。传username给下一个窗口是为了在界面上显示“当前登录人xxx”也是后续学生查询自己成绩的过滤条件。4.0.2 班级添加与维护窗口间传值靠什么ClassTypeManagerFrame打开时会从Mysql查全部班级装进JTable或JComboBox。新增班级入口在MainstudentFrame的按钮事件里一般写成new ClassTypeAddFrame(ClassTypeManagerFrame.this).setVisible(true);把父窗口传进去是为了子窗口保存成功后能调用父窗口的refreshTable()方法刷数据。这种“父子窗口回调刷新”在Swing课设里很常见。ClassTypeAddFrame保存时执行INSERT INTO class_type(name, remark) VALUES(?, ?)用PreparedStatement占位符不要字符串拼接不然字符里带单引号直接崩String sql INSERT INTO class_type(name, remark) VALUES(?, ?); try (PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, nameField.getText().trim()); ps.setString(2, remarkArea.getText().trim()); int rows ps.executeUpdate(); if (rows 0) { JOptionPane.showMessageDialog(this, 添加成功); } } catch (SQLException e) { e.printStackTrace(); }try-with-resources会自动关闭PreparedStatement和Connection这是Java 7以后的特性比写finally关连接更清爽。executeUpdate()返回影响行数大于0说明插入成功。这是标准写法也是答辩时高频提问点。4.0.3 学生添加学号唯一性怎么校验学生添加窗口字段多学号、姓名、班级下拉框、成绩。最容易出问题的时学号重复。数据库层面已经建了UNIQUE索引但代码层面也要先查一次否则会直接抛Duplicate entry异常。规范的逻辑是先用SELECT COUNT(*) FROM student WHERE student_no ?查一下如果大于0就弹提示并返回不再执行插入。这里有个细节班级下拉框装的是班级对象不是班级ID选择后取selectedItem再强转成ClassTypeClassType ct (ClassType) classCombo.getSelectedItem(); int classId ct.getId();如果你直接往JComboBox里addItem(计科1班)那取出来是String再映射班级ID就麻烦了。所以常见做法是给ClassType重写toString()返回班级名这样下拉框显示文字拿到的却是对象本身。4.0.4 学生维护JTable的选中行与数据同步StudentManagerFrame里一般放一个JTable下面有“修改”“删除”“刷新”按钮。删除逻辑常见的坑是用户没选中任何行结果getSelectedRow()返回-1代码直接崩溃。所以要判空int row studentTable.getSelectedRow(); if (row 0) { JOptionPane.showMessageDialog(this, 请先选择一行); return; } int studentId (int) studentTable.getValueAt(row, 0);getValueAt(row, 0)取的是表格第一列的值所以建表时第一列最好放ID但如果你不想把ID显示给用户就把它隐藏掉用TableColumn.setMinWidth(0)或setMaxWidth(0)。删除时调studentDao.deleteById(studentId)然后刷新表格。刷新表格的常见方式是把查询结果重新DefaultTableModel.setDataVector()。这里注意setDataVector会自动清空旧数据不需要先setRowCount(0)。4.0.5 学生端成绩浏览只查自己的数据学生登录后StudentUserFrame里做得不是把所有学生成绩都查出来而是根据登录用户名学号过滤。比如登录名是2021001那就执行SELECT s.student_no, s.name, c.name AS class_name, s.score FROM student s LEFT JOIN class_type c ON s.class_id c.id WHERE s.student_no ?用LEFT JOIN把班级名带出来而不是在Java里二次查询。StudentDao对应方法返回ListStudent再转成DefaultTableModel。这里可以顺带展示一个加分点用JOIN查询而不是在Student实体里再塞一个className字段然后手动赋值。答辩时说“我通过关联查询把班级名直接查出来避免N1问题”导师一听就知道你真写过代码。5. 运行不起来三个高频报错和对应的验证方法课设答辩现场和平时练习报错就那么几类。提前把报错信息记下来现场能少一半紧张。5.0.1java.sql.SQLSyntaxErrorException表名或字段名写错这个错多半是SQL里用了Mysql关键字比如class是保留字你不能建一张表叫class要叫class_type或t_class。字段名同理desc也是保留字别拿它当“描述”字段。如果原项目里用了这些名字改表结构或者SQL里加反引号SELECT desc FROM class_type;但反引号是Mysql专属沾了Mysql的方言换到别的数据库就不兼容。课设无所谓但你在答辩时可以说“我知道这是Mysql方言如果要做跨数据库我会改名”。5.0.2java.sql.SQLNonTransientConnectionException连接数或网络问题Communications link failure嘛常见原因有三个Mysql服务没启动、端口被占用、防火墙拦了3306。快速验证步骤netstat -ano | findstr :3306有LISTENING说明服务在跑。如果没有打开服务管理器启动Mysql。注意课设机房的Mysql服务可能没设自动启动每次开机要手动起。另外如果你在代码里把localhost改成了127.0.0.1效果一样。如果Mysql装的是免安装版还要确认my.ini里的port是不是默认的3306。5.0.3 数据库中文乱码三个层面都要统一乱码问题先看Mysql客户端工具里直接插中文显示是否正常。如果工具里正常说明数据库和表都没问题问题出在JDBC连接URL少了characterEncodingutf8。如果工具里就乱码那要改my.ini里的character-set-serverutf8mb4然后重启Mysql。这里有个小的验证技巧在StudentDao.findByName里打印SQL和参数看传进去的中文是不是正常就能定位是URL层还是数据库层的问题。我一般建议整套系统统一用utf8mb4因为utf8mb4能存Emojiutf8不行——虽然课设用不上Emoji但显得你考虑过编码层级。5.0.4 答辩验证清单一张表说清自检项检查项操作预期结果数据库初始化执行student_db.sql无报错student和class_type表存在JDBC连接运行DBUtil.getConnection()控制台无异常能拿到连接对象管理员登录admin / admin123进入主界面班级管理可见学生登录2021001 / 123456进入学生界面仅显示本人成绩添加班级输入“软件工程1班”列表刷新出现新班级添加学生学号填已有学号弹出“学号已存在”提示删除学生选中某行点删除二次确认后该行消失网关防火墙关闭或放行3306远程连接正常这份清单我自己每次调试前都会过一遍能快速把问题圈定在某一块。你交作业前照着走一遍比临时翻源码强得多。6. 答辩加分技巧把Swing线程、设计模式和异常处理说清楚最后一个部分讲几个容易被忽视但导师爱问的细节。如果你还有余力把这几条补进项目里课设评价会明显不一样。6.0.1 Swing事件分发线程EDT与耗时操作的取舍Swing的组件更新必须跑在事件分发线程上。现在课设里点“查询”按钮直接在主线程里执行SQL数据量大时界面会卡死。虽然课设数据量小没什么感觉但你主动写出SwingUtilities.invokeLater(() - { // 更新JTable的代码 });导师会认为你懂Swing的单线程模型。更规范的写法是用SwingWorker做后台查询查询完把结果publish回EDT。你不需要真改代码但答辩时说“我知道这把查询放在EDT里会阻塞UI课设里数据量小所以没影响生产环境我会用SwingWorker”就足够。6.0.2 Dao层接口与实现分离如果原项目StudentDao是个类你可以顺手提一句更好的设计是抽个接口IStudentDaoStudentDaoImpl实现它。好处是以后想换个持久层框架比如MyBatis业务层不用改。课设里两层就够了但话要能接上。导师追问“你怎么做单元测试”时你答“如果Dao是接口可以mock一个假实现不用连数据库就能测上层逻辑”这比说“我没写过测试”强得多。6.0.3 异常处理别只printStackTrace课设代码里到处e.printStackTrace()很常见但这确实不是好习惯。答辩时你指出“生产环境我会用log框架记录异常并向上层抛业务异常”这是亮点。如果不想大改可以把关键方法里的异常包装一下catch (SQLException e) { throw new RuntimeException(数据库操作失败 e.getMessage(), e); }这样调用方Frame层能拿到用户能看懂的信息而不是一坨堆栈。注意RuntimeException不需要在方法签名上throws调用方吞掉也不会编译报错——但更好的是在Frame层捕获后弹提示框。这个细节很多工作两三年的都不一定做得好你写在答辩PPT里属于“超过课设预期”的水平。6.0.4 一个能马上验证的最终技巧导出数据备份答辩前最后一步导出一份Mysql的数据备份万一现场电脑的数据库被人清了你能在5分钟内恢复mysqldump -uroot -p student_db student_db_backup.sql恢复时mysql -uroot -p student_db student_db_backup.sql把student_db_backup.sql放到项目根目录和源码一起打包。现场恢复只需要两条命令比打开Mysql Workbench点导入快得多。这一招看起来简单但很多做课设的人不知道结果现场手忙脚乱重建表。你把这个写进演示准备步骤里就是一个实实在在的“工程意识”体现。本文还有配套的精品资源点击获取