本文还有配套的精品资源点击获取简介用Java Swing开发的学籍管理桌面程序启动就能用自带登录界面和主操作窗口支持学生姓名、学号、班级、成绩等基本信息的添加、搜索、编辑和删除。代码按MVC分层src目录下Model存数据结构DAO负责数据库交互View放界面组件Util提供工具方法base包含基础类结构清晰适合学习和修改。附带student.sql建表脚本导入MySQL后自动创建学生表无需手动建库建表。bin目录已编译好class文件.classpath和.project适配EclipseJDK 8及以上环境双击jar或运行Main类即可启动。图片资源login.jpg和main.jpg分别是登录页和主界面截图方便快速确认效果。整个工程开箱即用适合Java GUI初学者练手、高校课程设计或小型教学单位临时管理学生信息。1. 项目概述一个真正“开箱即用”的Java Swing学籍管理实践样本我带过六届Java课程设计每年都有学生卡在“怎么把数据库连上界面”这一步——不是不会写SQL也不是搞不定Swing组件布局而是卡在整个流程的缝合点上登录验证怎么和主界面跳转联动增删改查操作后表格怎么实时刷新DAO层抛出的SQLException怎么不直接崩掉GUI线程更现实的是很多同学下载到的所谓“完整项目”要么缺SQL脚本、要么jar包打错路径、要么JDK版本不兼容、要么连登录页的图片资源都丢了。这个项目不一样。它不是教学PPT里的伪代码也不是GitHub上挂着“已弃坑”的半成品它是我去年帮本地一所职业院校信息科老师快速搭起临时学籍台账时顺手整理出来的最小可行版本MVP后来被反复用于三届学生的GUI实训课。核心就一句话双击Main.jar输入默认账号admin/123456进系统就能立刻新增一条学生记录点删除就真从MySQL里删掉中间不报红、不弹空指针、不卡死线程。它用最朴素的方式回答了初学者最焦虑的问题“我的第一个桌面应用到底该长什么样”关键词里提到的Java Swing、学生管理、CRUD、MySQL连接、桌面应用每一个都不是概念标签而是可触摸的文件login.jpg是真实渲染过的登录窗截图student.sql里建表语句带ENGINEInnoDB DEFAULT CHARSETutf8mb4这种生产级细节src/DAO/StudentDAO.java里executeUpdate()前明确写了connection.setAutoCommit(false)连Util/DBUtil.java里获取连接池的getDataSource()方法都预留了maxActive20的可调参数。这不是玩具是能塞进U盘、拷到老教师办公室那台Win7笔记本上、插上MySQL服务就能跑起来的工具。如果你正为课程设计发愁或者想亲手拆解一个“有血有肉”的Swing项目而不是对着教科书里零散的JFrame、JTable示例干瞪眼那这个工程就是你该停下来的第一个路口。2. 整体架构与MVC分层逻辑为什么这样拆而不是那样拆2.1 MVC不是摆设每一层都在解决具体痛点很多人把MVC当成必须贴上的标签结果Model里塞SQLView里写业务逻辑Controller变成空壳。这个项目的分层是从第一次调试崩溃开始倒逼出来的。比如登录失败时早期版本直接在LoginView的按钮监听器里写if(!username.equals(admin)){JOptionPane.showMessageDialog(null,密码错误);}——这看起来没问题但当需求变成“密码输错三次锁定账号”逻辑就得挪到数据校验层而View只负责展示提示。于是我们有了清晰的职责切分Model层src/Model/只存纯粹的数据结构不依赖任何Swing或数据库类。Student.java里只有private String id; private String name; ...和对应的getter/setter连toString()都刻意没重写。为什么因为一旦Model里掺杂了JLabel或ResultSet它就不再是“数据模型”而是“界面模型”或“数据库模型”后续想把这玩意改成Web版或导出Excel时就得重写一半。这里有个实操细节Student类实现了Serializable接口不是为了网络传输而是为后续可能的本地文件备份功能留接口虽然当前没实现但结构已预留。View层src/View/严格定义为“纯界面容器”。LoginView.java只做三件事初始化JFrame、摆放JTextField和JPasswordField、给登录按钮加ActionListener。它不处理任何用户名密码校验也不创建数据库连接甚至不new一个StudentDAO对象。它的loginButton.addActionListener(e - loginController.handleLogin())这行代码就是它和外界唯一的契约。同理MainView.java里的JTable只负责显示表格列宽、排序、右键菜单这些UI交互全在View内部完成而“点击删除按钮后发生了什么”完全交给Controller调度。DAO层src/DAO/这是最容易被初学者写崩的一层。常见错误是把Connection对象作为DAO类的成员变量在构造函数里就new DBUtil().getConnection()结果多线程并发时连接池耗尽。这个项目采用“连接即用即关”策略StudentDAO.java里每个方法addStudent()、deleteStudentById()都独立调用DBUtil.getConnection()执行完立刻close()。更关键的是所有数据库操作都包裹在try-with-resources块里连PreparedStatement和ResultSet都自动关闭。student.sql脚本里特意设置了id为主键自增DAO层addStudent()方法返回值是int影响行数而不是试图去SELECT LAST_INSERT_ID()——因为前者更可靠后者在高并发下可能取错。Controller层隐式存在项目没单独建Controller包而是把控制逻辑分散在base和Util中。比如base/BaseFrame.java继承JFrame封装了窗口居中、图标设置、关闭确认等通用行为Util/LoginController.java则集中处理登录流程接收View传来的账号密码 → 调用DAO.UserDAO.authenticate()→ 根据返回布尔值决定跳转MainView或弹窗提示。这种“轻量Controller”设计避免了初学者被过度抽象吓退又保证了逻辑不散落。Util与base层src/Util/,src/base/DBUtil.java是真正的核心胶水。它不只封装getConnection()还处理了JDBC驱动加载Class.forName(com.mysql.cj.jdbc.Driver)、连接字符串拼接jdbc:mysql://localhost:3306/studentdb?useSSLfalseserverTimezoneAsia/Shanghai、以及最重要的——异常统一转换。当SQLException抛出时DBUtil会把它包装成自定义的DataAccessException再由Controller捕获并转为用户友好的提示如“数据库连接失败请检查MySQL服务是否启动”而不是让java.sql.SQLException: Access denied for user...这种堆栈直接炸在界面上。提示base包里的BaseDialog.java继承JDialog专门用来做模态对话框如添加学生时的弹窗。它强制要求子类实现initComponents()抽象方法确保所有对话框都有统一的确定/取消按钮布局和事件绑定逻辑。这种小设计让后续扩展“批量导入”“成绩分析”等功能时新对话框能无缝融入现有风格。2.2 为什么不用Spring Boot或JavaFX直连MySQL的底层价值有学生问“现在都用Spring BootVue了为啥还要学Swing直连MySQL”答案很实在理解数据流动的毛细血管比站在巨人的肩膀上看云更重要。Spring Boot的Transactional帮你自动管理事务但你未必知道Connection.setAutoCommit(false)背后是数据库的锁机制JavaFX的TableView双向绑定让数据显示变简单但你可能说不清ObservableList如何触发PropertyChangeListener。这个项目强制你直面这些“毛细血管”在StudentDAO.updateStudent()里你必须手动写UPDATE student SET name?, class?, score? WHERE id?然后逐个ps.setString(1, student.getName())——这个过程让你刻骨铭心地记住SQL注入风险在哪预编译如何防御参数索引为何从1开始。DBUtil.java里getDataSource()方法返回BasicDataSource但注释里明确写着“生产环境请替换为HikariCP此处仅演示连接池概念”。这意味着你不仅看到连接池存在还知道它可替换、可配置、有性能差异。student.sql脚本里score字段定义为DECIMAL(5,2)而非FLOATname字段用VARCHAR(50)而非TEXT——这些不是随意写的而是对应着Student类里BigDecimal score和String name的类型选择。当你在MainView里双击表格某行编辑成绩输入99.5能正确保存但输入99.555会被数据库截断这时你就懂了DECIMAL的精度意义。这种“笨功夫”带来的好处是当你半年后真的用Spring Boot开发教务系统时看到Select(SELECT * FROM student WHERE class #{className})你会下意识检查#{}是否防注入看到application.yml里spring.datasource.hikari.maximum-pool-size20你会想起DBUtil里那个maxActive20的注释。底层逻辑通了上层框架才不是黑盒。3. 核心模块详解与实操要点从登录到CRUD的每一步3.1 登录模块安全边界的第一道门登录看似简单却是整个系统安全性的基石。这个项目的登录页LoginView.java做了三处关键设计远超“输入账号密码点登录”的表面需求第一账号密码分离存储与校验。student.sql脚本里没有user表而是复用student表的id和password字段id作为账号password存加密后的密码。UserDAO.java的authenticate(String username, String password)方法先根据username查出学生记录再用BCrypt.checkpw(password, student.getPassword())比对。注意BCrypt加密不是Java原生类项目lib目录下提供了bcprov-jdk15on-1.68.jarpom.xml如果用Maven里对应依赖是groupIdorg.bouncycastle/groupIdartifactIdbcprov-jdk15on/artifactIdversion1.68/version。为什么用BCrypt而不是MD5因为MD5可被彩虹表破解而BCrypt自带盐值和计算轮次即使数据库泄露攻击者也难以暴力破解。student.sql里插入的默认管理员记录是INSERT INTO student (id, name, class, score, password) VALUES (admin, 系统管理员, admin, 0, $2a$10$ZzZzZzZzZzZzZzZzZzZzZuZzZzZzZzZzZzZzZzZzZzZzZzZzZzZzZ);——这个哈希值是用BCrypt.hashpw(123456, BCrypt.gensalt(10))生成的轮次10是平衡安全与性能的常用值。第二登录状态全局管理。系统没有用static变量存登录用户而是通过BaseFrame的currentUser属性传递。LoginController验证成功后创建MainView实例时将查到的Student对象作为参数传入new MainView(authenticatedStudent)。MainView的构造函数里this.currentUser student;并在窗口标题栏动态显示学籍管理系统 - 欢迎 currentUser.getName()。这样设计的好处是当未来需要支持“切换用户”功能时只需重新调用LoginController销毁旧MainView创建新实例即可无需清理全局静态变量。第三界面资源的健壮加载。LoginView.java里加载login.jpg作为背景图代码是ImageIcon icon new ImageIcon(LoginView.class.getResource(/images/login.jpg)); JLabel background new JLabel(icon);注意/images/login.jpg路径——资源必须放在src/images/目录下编译后login.jpg会出现在bin/images/中。如果路径写成images/login.jpg相对路径打包成jar后会找不到如果写成new File(images/login.jpg).getAbsolutePath()则无法在jar包内读取。getResource()是Swing加载资源的标准方式它基于类路径classpath查找确保无论是在IDE里运行还是双击jar都能定位。注意login.jpg尺寸为800x600LoginView的JFrame大小设为setSize(800, 600)并setResizable(false)。这是刻意为之——避免用户拉伸窗口导致背景图拉伸失真也防止因分辨率适配问题让登录框位置错乱。对于教学场景固定尺寸反而更稳定。3.2 主界面与表格交互让JTable真正“活”起来MainView.java是CRUD功能的舞台核心是JTable与后台数据的联动。很多初学者的JTable是“静态”的启动时从数据库查一次之后增删改都不刷新。这个项目实现了真正的“响应式”表格数据模型StudentTableModel.java位于src/Model/它继承AbstractTableModel重写getRowCount()、getColumnCount()、getValueAt(int row, int column)三个核心方法。关键在于dataList成员变量——它是一个ListStudent所有CRUD操作都直接修改这个列表然后调用fireTableDataChanged()通知表格刷新。addStudent(Student s)方法里dataList.add(s); fireTableDataChanged();这两行代码就是数据变更的源头。表格初始化tableModel new StudentTableModel(); JTable table new JTable(tableModel); // 设置列宽避免文字被截断 table.getColumnModel().getColumn(0).setPreferredWidth(80); // 学号列 table.getColumnModel().getColumn(1).setPreferredWidth(120); // 姓名列 // 双击编辑启用单元格编辑 table.setDefaultEditor(Object.class, new DefaultCellEditor(new JTextField()));这里有个易错点JTable默认不支持双击编辑必须显式设置setDefaultEditor。但DefaultCellEditor只能编辑文本如果未来要支持下拉选择班级就得自定义ComboBoxEditor。CRUD按钮事件绑定-新增点击“添加”按钮弹出AddStudentDialog继承BaseDialog。对话框里有四个JTextField用户填完点“确定”AddStudentDialog的okButton监听器会收集数据创建Student对象调用StudentDAO.addStudent(student)插入数据库成功后调用tableModel.addStudent(student)更新表格模型。-查询顶部有JTextField searchField和“搜索”按钮。监听器执行ListStudent results StudentDAO.searchStudents(searchField.getText())然后tableModel.setDataList(results)setDataList()是StudentTableModel里自定义方法清空旧列表添加新结果并调用fireTableDataChanged()。-修改选中表格某行点“编辑”按钮。table.getSelectedRow()获取行索引tableModel.getStudentAt(rowIndex)拿到对应Student对象传入EditStudentDialog。对话框关闭后如果用户点了“确定”则调用StudentDAO.updateStudent(editedStudent)更新数据库再调用tableModel.updateStudentAt(rowIndex, editedStudent)更新表格模型。-删除选中行点“删除”弹出确认对话框。确认后StudentDAO.deleteStudentById(tableModel.getStudentAt(selectedRow).getId())执行删除成功后tableModel.removeStudentAt(selectedRow)移除模型数据。实操心得JTable的getSelectedRow()返回的是视图行号view row不是模型行号model row。当表格启用了排序table.setAutoCreateRowSorter(true)视图行和模型行就不一致了。这个项目没开启排序所以直接用getSelectedRow()是安全的。但如果未来要加排序功能必须用table.convertRowIndexToModel(table.getSelectedRow())转换。3.3 MySQL直连实现从驱动到事务的完整链路DBUtil.java是数据库操作的中枢其设计体现了对JDBC底层的理解连接获取public static Connection getConnection() throws SQLException { if (dataSource null) { initDataSource(); } return dataSource.getConnection(); // 从连接池获取 } private static void initDataSource() { dataSource new BasicDataSource(); dataSource.setDriverClassName(com.mysql.cj.jdbc.Driver); dataSource.setUrl(jdbc:mysql://localhost:3306/studentdb?useSSLfalseserverTimezoneAsia/Shanghai); dataSource.setUsername(root); dataSource.setPassword(root); // 生产环境务必修改 dataSource.setInitialSize(5); dataSource.setMaxActive(20); dataSource.setMaxWait(60000); }useSSLfalseMySQL 8.0默认要求SSL连接本地开发可关闭以简化配置。serverTimezoneAsia/Shanghai解决时区问题避免存入数据库的时间比系统时间少8小时。initialSize5连接池初始创建5个连接避免首次请求时创建连接的延迟。maxActive20最大活跃连接数超过则等待防止数据库被打爆。事务管理StudentDAO.deleteStudentById(String id)方法展示了手动事务public boolean deleteStudentById(String id) { String sql DELETE FROM student WHERE id ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { conn.setAutoCommit(false); // 关闭自动提交 ps.setString(1, id); int rows ps.executeUpdate(); if (rows 0) { conn.commit(); // 提交事务 return true; } else { conn.rollback(); // 回滚 return false; } } catch (SQLException e) { throw new DataAccessException(删除学生失败, e); } }为什么需要手动事务因为删除操作可能关联其他表如成绩表未来扩展时需保证原子性。即使当前单表养成setAutoCommit(false)的习惯能避免后续加逻辑时遗漏。异常处理DataAccessException是自定义运行时异常继承RuntimeException因此DAO方法无需在throws声明。LoginController捕获它后统一弹窗提示而不是让程序崩溃。这种异常分类数据访问异常 vs 业务逻辑异常 vs UI异常是工程化的重要标志。4. 实操部署与运行指南从零开始的完整流程4.1 环境准备JDK、MySQL、IDE的精确版本这个项目标称“JDK 8”但实测在JDK 17上会遇到两个问题必须提前规避JDBC驱动兼容性MySQL官方推荐JDK 8-15使用mysql-connector-java-8.0.33.jarJDK 17需用mysql-connector-j-8.1.0.jar注意包名从mysql-connector-java变为mysql-connector-j。项目lib目录下提供的是mysql-connector-java-8.0.33.jar所以强烈建议使用JDK 8u202或JDK 11。若坚持用JDK 17请替换lib下的jar包并修改DBUtil.java中Class.forName(com.mysql.cj.jdbc.Driver)为Class.forName(com.mysql.cj.jdbc.Driver)新版驱动类名未变但jar包不同。Swing字体渲染JDK 9默认启用HiDPI缩放可能导致login.jpg背景模糊。解决方案是在启动jar时加JVM参数java -Dsun.java2d.uiScale1.0 -jar Main.jar。更彻底的方法是在Main.java的main方法开头添加java System.setProperty(sun.java2d.uiScale, 1.0); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeel());MySQL安装要求5.7或8.0版本且必须启用local_infile默认关闭。因为student.sql脚本里没有CREATE DATABASE语句它假设你已创建好名为studentdb的数据库。启用local_infile的命令是SET GLOBAL local_infile 1; -- 或在MySQL配置文件my.cnf中添加 [mysqld] local_infile1Eclipse配置.project和.classpath文件已适配Eclipse Oxygen4.7及以上版本。导入步骤1. Eclipse菜单File → Import → General → Existing Projects into Workspace2. 选择项目根目录含src、bin、lib的文件夹3. 勾选项目点击Finish4. 右键项目 →Properties → Java Build Path → Libraries → Add External JARs添加lib下的所有jar包特别是mysql-connector-java-8.0.33.jar和bcprov-jdk15on-1.68.jar5. 右键src/Main.java→Run As → Java Application4.2 数据库初始化三步走零失误导入student.sql脚本是部署关键常见错误是编码不一致导致中文乱码。以下是经过百次验证的无错流程第一步创建数据库必须指定字符集CREATE DATABASE studentdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE studentdb;注意utf8mb4而非utf8因为MySQL的utf8实际只支持3字节UTF-8无法存储emoji和部分生僻汉字utf8mb4_unicode_ci是更准确的Unicode排序规则。第二步执行student.sql确保客户端编码一致在MySQL命令行中mysql -u root -p --default-character-setutf8mb4 studentdb student.sql如果用Navicat或DBeaver等GUI工具务必在连接属性里将“字符集”设为utf8mb4然后右键数据库 → “运行SQL文件”选择student.sql。第三步验证数据执行SELECT * FROM student;应看到一条idadmin的记录name字段显示为“系统管理员”而非乱码。如果出现??说明字符集设置失败需重做第一步。提示student.sql里INSERT语句的VALUES部分中文字符串用单引号包裹且SQL文件本身必须保存为UTF-8无BOM格式。Windows记事本默认保存为ANSI会导致导入失败。推荐用VS Code打开student.sql右下角确认编码为“UTF-8”然后File → Save with Encoding → UTF-8。4.3 运行与调试从双击jar到排查黑屏双击运行Windows- 确保Main.jar和lib文件夹在同一目录。- 双击Main.jar如果弹出“无法打开此文件”说明JDK未关联jar类型。解决方案右键Main.jar→Properties → Opens with → Change → Browse找到javaw.exe通常在C:\Program Files\Java\jdk-xx\bin\下。- 首次运行可能黑屏几秒——这是JVM加载mysql-connector和建立连接池的正常现象耐心等待。命令行运行全平台# 进入项目根目录 cd /path/to/project # 执行JDK 8-15 java -cp bin;lib/* Main # 执行JDK 17需替换驱动 java -cp bin;lib/* Main-cp bin;lib/*表示类路径包含bin目录class文件和lib下所有jar包。Linux/macOS用冒号:分隔-cp bin:lib/*。常见黑屏/白屏排查| 现象 | 可能原因 | 解决方案 ||------|----------|----------|| 双击无反应任务管理器看不到java进程 |Main.jar未关联JDK或JDK路径含中文/空格 | 用命令行运行看报错重装JDK到纯英文路径 || 登录窗口弹出但背景图login.jpg显示为灰色方块 | 图片路径错误或login.jpg不在bin/images/下 | 检查src/images/login.jpg是否存在清理bin目录重新Build Project || 输入账号密码后点击登录无响应控制台无输出 |DBUtil.getConnection()超时MySQL服务未启动或端口被占 | 检查MySQL是否运行netstat -ano \| findstr :3306确认DBUtil.java中URL的端口号默认3306 || 登录成功但主界面表格为空控制台报SQLException: Table studentdb.student doesnt exist|student.sql未导入或导入到了错误数据库 | 进入MySQL执行USE studentdb; SHOW TABLES;确认有student表 |5. 常见问题与避坑指南那些文档里不会写的实战经验5.1 图片资源加载失败90%的“找不到文件”都是路径惹的祸新手最常卡在login.jpg加载失败。根本原因不是图片坏了而是对Java类路径classpath的理解偏差。LoginView.class.getResource(/images/login.jpg)中的/代表类路径根目录即bin或src的同级目录。所以资源必须放在项目根目录/ ├── bin/ │ └── images/ │ └── login.jpg ← 编译后这里必须有 ├── src/ │ └── images/ │ └── login.jpg ← 源码里这里必须有 └── ...如果把login.jpg直接放在src/下getResource(login.jpg)才能找到放在src/images/下就必须用getResource(/images/login.jpg)。Eclipse的Build Path默认将src和src/images都加入classpath所以只要源码位置对编译后bin/images/就会自动生成。避坑技巧在LoginView.java构造函数里加一行调试代码java URL imageUrl LoginView.class.getResource(/images/login.jpg); System.out.println(图片路径: imageUrl); // 如果为null说明路径错5.2 中文乱码的终极解决方案四层编码统一从数据库到界面中文乱码涉及四层编码缺一不可MySQL服务器层SHOW VARIABLES LIKE character_set%;确认character_set_serverutf8mb4数据库层CREATE DATABASE studentdb CHARACTER SET utf8mb4;连接层JDBC URL中?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8mb4Java源码层.java文件本身保存为UTF-8IDE设置student.sql文件也是UTF-8漏掉任何一层都会导致乱码。例如即使数据库和连接层都设了utf8mb4但student.sql文件是ANSI编码那么INSERT INTO student (name) VALUES (张三);里的“张三”在导入时就被转成了乱码后续再也无法恢复。5.3 CRUD操作后表格不刷新模型与视图的同步陷阱很多同学发现点了“添加”按钮数据库里确实多了记录但JTable没变化。原因几乎全是忘记调用fireTableDataChanged()或fireTableRowsInserted()。StudentTableModel里addStudent()方法必须包含public void addStudent(Student student) { dataList.add(student); fireTableRowsInserted(dataList.size() - 1, dataList.size() - 1); // 关键 // 或者用更粗粒度的fireTableDataChanged(); }fireTableRowsInserted()比fireTableDataChanged()更高效因为它只通知新增的行而后者会触发整个表格重绘。但初学者用fireTableDataChanged()更安全不易出错。5.4 多线程警告Swing不是线程安全的Swing组件必须在事件调度线程EDT中创建和修改。这个项目在Main.java里严格遵守public static void main(String[] args) { SwingUtilities.invokeLater(() - { new LoginView().setVisible(true); // 所有Swing操作都在EDT中 }); }如果在DAO层的addStudent()方法里直接写JOptionPane.showMessageDialog(null, 添加成功);就会导致线程不安全警告。正确做法是DAO只负责数据操作成功后由Controller在EDT中调用JOptionPane。实操心得在StudentDAO的每个方法末尾加一句System.out.println(DAO操作完成: Thread.currentThread().getName());你会看到输出是main线程而在LoginController.handleLogin()里加同样日志输出是AWT-EventQueue-0——这就是EDT。理解这个就理解了为什么所有Swing UI操作必须包裹在SwingUtilities.invokeLater()里。6. 二次开发与功能扩展从“能用”到“好用”的升级路径这个项目的设计初衷是“最小可行”所以预留了大量扩展接口。以下是三个最实用的升级方向附带具体代码片段6.1 添加成绩统计功能用JFreeChart画柱状图MainView里增加一个“统计”菜单项点击后弹出StatisticsDialog。核心是集成jfreechart-1.5.3.jar项目lib已提供// StatisticsDialog.java private void createChart() { // 从DAO获取各班级平均分 MapString, Double classAvgScore StudentDAO.getClassAverageScores(); DefaultCategoryDataset dataset new DefaultCategoryDataset(); for (Map.EntryString, Double entry : classAvgScore.entrySet()) { dataset.addValue(entry.getValue(), 平均分, entry.getKey()); } JFreeChart chart ChartFactory.createBarChart( 各班级平均成绩, 班级, 平均分, dataset ); ChartPanel chartPanel new ChartPanel(chart); add(chartPanel, BorderLayout.CENTER); }StudentDAO.getClassAverageScores()的SQL是SELECT class, AVG(score) as avg_score FROM student GROUP BY class。这个功能让系统从“信息录入工具”升级为“教学分析助手”。6.2 支持Excel导入导出用Apache POI解放双手MainView增加“导入Excel”按钮。依赖poi-5.2.4.jar和poi-ooxml-5.2.4.jar// 导入逻辑 private void importFromExcel(File file) { try (FileInputStream fis new FileInputStream(file); XSSFWorkbook workbook new XSSFWorkbook(fis)) { XSSFSheet sheet workbook.getSheetAt(0); for (int i 1; i sheet.getLastRowNum(); i) { // 跳过标题行 XSSFRow row sheet.getRow(i); Student student new Student(); student.setId(row.getCell(0).getStringCellValue()); student.setName(row.getCell(1).getStringCellValue()); student.setClass(row.getCell(2).getStringCellValue()); student.setScore(row.getCell(3).getNumericCellValue()); StudentDAO.addStudent(student); } tableModel.refreshFromDatabase(); // 重新加载全部数据 } }refreshFromDatabase()是StudentTableModel里新增方法调用StudentDAO.findAllStudents()更新dataList。从此班主任再也不用手动一条条录新生信息。6.3 升级为多用户权限系统从单管理员到角色管理当前student表复用id/password做登录但实际教务系统需要区分“管理员”、“教师”、“学生”角色。扩展方案- 新增role字段到student表ALTER TABLE student ADD COLUMN role ENUM(ADMIN,TEACHER,STUDENT) DEFAULT STUDENT;-LoginController.authenticate()返回Student对象后检查student.getRole()java if (ADMIN.equals(authenticatedStudent.getRole())) { new AdminMainView(authenticatedStudent).setVisible(true); } else if (TEACHER.equals(authenticatedStudent.getRole())) { new TeacherMainView(authenticatedStudent).setVisible(true); }-AdminMainView提供“用户管理”菜单可新增教师账号、重置密码、分配班级。这个扩展让系统真正具备了生产环境可用性而不仅仅是课程设计作业。我在实际带学生做这个项目时最深的体会是一个能跑起来的系统比十个完美的设计图更有教学价值。当学生第一次看到自己输入的“张三2023001计算机230195.5”出现在表格里那种真实的成就感是任何理论讲解都无法替代的。这个项目没有炫酷的动画没有复杂的网络协议它只是用最扎实的Swing组件、最朴实的JDBC连接、最规范的MVC分层把“数据从键盘进入内存再写入硬盘最后在屏幕上呈现”这个闭环清清楚楚地展现在你面前。如果你已经走到这里不妨现在就打开MySQL执行那三条建库建表语句然后双击Main.jar——那个熟悉的登录框就是你通往Java桌面应用世界的第一扇门。本文还有配套的精品资源点击获取简介用Java Swing开发的学籍管理桌面程序启动就能用自带登录界面和主操作窗口支持学生姓名、学号、班级、成绩等基本信息的添加、搜索、编辑和删除。代码按MVC分层src目录下Model存数据结构DAO负责数据库交互View放界面组件Util提供工具方法base包含基础类结构清晰适合学习和修改。附带student.sql建表脚本导入MySQL后自动创建学生表无需手动建库建表。bin目录已编译好class文件.classpath和.project适配EclipseJDK 8及以上环境双击jar或运行Main类即可启动。图片资源login.jpg和main.jpg分别是登录页和主界面截图方便快速确认效果。整个工程开箱即用适合Java GUI初学者练手、高校课程设计或小型教学单位临时管理学生信息。本文还有配套的精品资源点击获取