news 2026/9/14 3:04:13

Java Swing+MySQL人事管理系统实战:基于Druid与DAO的分层设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java Swing+MySQL人事管理系统实战:基于Druid与DAO的分层设计

简介:这是一套以 Java、Swing 与 MySQL 为核心的企业人事管理系统项目源码,适合正在完成 Java 期末大作业或课程设计的本科、高职学生参考使用。项目按照数据访问层、视图层与模型层进行模块划分,内置 Druid 数据库连接池配置,附带 SQL 初始化脚本与 README 说明文档,能够本地编译并直接运行;整体评价达到 98 分,难度适中,功能上可覆盖员工信息维护、部门管理、考勤与薪资核算等典型人事业务场景,既能用于学习框架分层思路,也能作为答辩演示项目。压缩包共 96 个文件,大小约 6.34MB,以 Java 源码、PNG 运行截图、SQL 脚本和 jar 依赖包为主,同时包含 XML 配置、properties 配置与项目工程文件,便于快速导入 IDE 查看界面效果、数据库表结构及核心代码。内容还配有操作截图和初始数据,可以直观理解前端界面与后台数据的联动过程;目前已有 199 人学习/下载,适合需要拿完整项目做课程设计或在此基础上做二次功能开发的 Java 初学者。

1. Swing加MySQL做人事系统,为什么课程设计选这个组合

在Spring Boot和Vue铺天盖地的时代,用Java Swing做桌面人事管理系统看起来有点复古,但它恰恰是期末大作业和课程设计里性价比最高的组合。这个epms项目用到的技术栈很收敛:Swing负责界面、JDBC加Druid连接池负责数据库访问、MySQL 8.0做存储,加上一个清晰的DAO分层,没有Spring的自动装配,也没有MyBatis的XML映射,所有对象都是自己new、自己关连接,反而能把Java基础里最该考察的东西全部覆盖到。

这套项目本地编译就能跑,结构里能看到dao、view、model、test四个核心目录,sql目录下是epms.sql建表脚本,resources里是druid.properties连接池配置。对Java刚学完集合和JDBC、正在做课设的人来说,它演示了一个完整系统的组织方式:界面和逻辑分开、SQL不散落在按钮事件里、数据库连接统一从连接池取。对已经工作的人也有参考价值,Swing的JTable渲染、Druid参数调优、结果集映射这几个点,放到现在依然能扒出不少细节。

2. 项目结构与数据模型:从epms.sql到每个Java包的职责

拿到压缩包先别急着运行,把目录结构读一遍比跑通更有价值。zip里除了12张截图和README,核心代码集中在src下的com目录,默认包名是epms体系。常见分层方式是:model放实体类,对应数据库表;dao放数据访问接口和实现,里面只有SQL和结果集处理;view放Swing窗口;test放不依赖GUI的入口测试类。

2.1 包结构拆解与依赖关系

依赖关系是单向的:view层调用dao层拿到List<model>,再填充到JTable或JComboBox;model只是纯POJO,不持有任何连接对象;druid.properties只被一个工具类读取,全局只有一个DataSource实例。这样做的好处是,如果老师要求把Swing换成JavaFX,只要保留dao和model,重写view层即可。

lib目录下放着mysql-connector-java和druid的jar包。注意IDEA里引入外部jar的方式是File > Project Structure > Libraries,而不是直接把jar拖到src目录。项目里能看到EPMS.iml和workspace.xml,说明作者用的是IntelliJ IDEA,导入时直接Open这个iml文件就能把依赖结构带进来。

2.2 核心表结构与字段设计思路

epms.sql是建库建表脚本,执行时建议用Navicat或MySQL Workbench。一个典型的企业人事系统至少会拆出这几张表:登录用户表、部门表、员工表、考勤表、工资变动表。用员工表为主体举一组建表示例,这和包里sql的规模接近:

CREATE TABLE employee ( emp_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '员工编号', emp_no VARCHAR(20) UNIQUE NOT NULL COMMENT '工号', emp_name VARCHAR(50) NOT NULL COMMENT '姓名', dept_id INT NOT NULL COMMENT '所属部门', position VARCHAR(50) COMMENT '岗位', hire_date DATE COMMENT '入职日期', salary DECIMAL(10,2) DEFAULT 0 COMMENT '基本工资', status TINYINT DEFAULT 1 COMMENT '1在职 0离职', CONSTRAINT fk_dept FOREIGN KEY (dept_id) REFERENCES dept(dept_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

注意几个细节。第一,emp_no设置UNIQUE约束,避免界面层重复校验;第二,外键约束在MySQL里默认是开启的,导出sql时如果报外键关联错误,先按依赖顺序建表,先建dept再建employee;第三,salary用DECIMAL(10,2)而不是DOUBLE,因为浮点类型在金额累加时会出现精度漂移,这是课程设计答辩时老师最爱问的点。

2.3 表字段类型选择与字符集陷阱

MySQL 8.0默认字符集已是utf8mb4,但如果建库时用了老版本导出的sql,很可能表里还是utf8。字段里只要出现员工姓名,utf8和utf8mb4在绝大多数汉字场景下没区别,可一旦有人把emoji写进备注字段,utf8就直接报错。稳妥做法是建库时显式指定:

CREATE DATABASE epms DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

数据量不大时,有人觉得外键和索引多余,但人事系统的查询场景是“按部门筛人”“按工号精确查”,这种查询走主键索引和UNIQUE索引的性能差异在几千条数据上虽然感知不到,可索引设计本身就是评分点之一。建议在dept_id上补一个普通索引INDEX idx_dept(dept_id),外键约束在InnoDB下会自动创建,但单独查部门的场景下这个索引的收益更直接。

3. 登录流程与DAO层:Druid连接池的参数到底怎么配

登录是这套系统里最值得逐行读的模块,因为它把Swing事件监听、PreparedStatement防注入、MD5加密、连接池获取四个知识点串在了一起。压缩包里的druid.properties是整套配置的入口,配置不对最典型的报错是“Cannot create PoolableConnectionFactory”或者时区异常。

3.1 druid.properties配置逐项说明

driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/epms?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username=root password=你的密码 initialSize=5 minIdle=5 maxActive=20 maxWait=60000

driverClassName在MySQL 8.0下必须是com.mysql.cj.jdbc.Driver,旧版的com.mysql.jdbc.Driver虽然能跑但会打印Deprecation警告。url里的serverTimezone必须显式指定,否则8.0驱动会拿本机时区去匹配数据库时区,报出的错误信息长到让人误以为是连接失败。useSSL=false是因为本地学习环境没有证书配置,开着反而会多一次SSL握手。

initialSize是启动时预创建的连接数,minIdle是池里最少保活的空闲连接,maxActive是峰值并发上限。桌面系统同时在线操作的人通常不超过几十个,maxActive给到20足够。如果把这个配置搬到生产环境,maxWait建议从60000下调到10000,否则连接池打满后请求会卡住一分钟才失败。

3.2 DAO层登录验证如何组织

登录不该在按钮事件里直接写连接对象,而是通过一个LoginDao把“连接获取、SQL执行、结果判断”封装起来:

public class LoginDao { private DruidDataSource dataSource; public LoginDao(DruidDataSource dataSource) { this.dataSource = dataSource; } public boolean checkLogin(String username, String password) { String sql = "SELECT COUNT(*) FROM sys_user WHERE username=? AND password=?"; try (Connection conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { return rs.getInt(1) > 0; } } } catch (SQLException e) { e.printStackTrace(); } return false; } }

这段代码用try-with-resources保证连接自动归还给连接池,注意归还不是关闭物理连接,Druid的Connection在调用close()时是放回池里,所以不用手动再调dataSource.getConnection()去管理生命周期。PreparedStatement的setString把用户名和密码当参数绑定,杜绝了拼接字符串带来的SQL注入风险。

如果项目的登录表密码存的是MD5,那校验时要先对输入做同样的加密再比对:

String md5Input = DigestUtils.md5Hex(password + salt);

salt是盐值,课程设计里经常省略,但如果答辩被问到“密码怎么防脱库”,能答出加盐哈希比硬编码一个固定盐值好得多。注意MD5本身不可逆、但可暴力碰撞,生产系统至少要换SHA-256加随机盐,这一步可以作为项目优化方向在报告里写一笔。

3.3 登录按钮的Swing事件处理

view层登录窗口的核心逻辑:按钮被点击后,在事件线程里执行DAO查询,然后用JOptionPane弹窗提示结果。这里有一个关键坑——耗时查询不应该阻塞EDT(Event Dispatch Thread),但课程设计里数据量小,直接同步调用不会让界面卡死,反而是老师在检查时更容易挑刺的是弹窗后没有清空密码框。

JButton loginBtn = new JButton("登录"); loginBtn.addActionListener(e -> { String name = nameField.getText().trim(); String pwd = new String(pwdField.getPassword()); if (name.isEmpty() || pwd.isEmpty()) { JOptionPane.showMessageDialog(frame, "用户名和密码不能为空"); return; } boolean ok = loginDao.checkLogin(name, pwd); if (ok) { frame.dispose(); new MainFrame().setVisible(true); } else { JOptionPane.showMessageDialog(frame, "用户名或密码错误"); pwdField.setText(""); } });

这里用pwdField.getPassword()而不是getText(),是因为Swing的JPasswordField建议用字符数组获取输入,字符串对象在常量池里驻留时间更短,减少密码被内存转储的风险。这一处细节能明显看出代码是认真写过的,评审分高并不意外。

4. 员工管理模块实战:JTable刷新、DAO增删改查与事务边界

员工管理是系统的主界面,涉及的功能点最全:列表查询、按条件筛选、新增员工、编辑、离职标记。这一步把model、view、dao三个包串成了完整链条,也是课程设计报告里“业务流程分析”部分的主要素材。

4.1 员工列表查询与JTable数据填充

列表页常规做法是MainFrame里放一个JTable,数据源自EmployeeDao的listAll()。为了解耦,会把Employee实体包一层EmployeeTableModel,继承AbstractTableModel:

public class EmployeeTableModel extends AbstractTableModel { private List<Employee> data; private String[] columns = {"工号", "姓名", "部门", "岗位", "入职日期", "工资"}; public void setData(List<Employee> data) { this.data = data; fireTableDataChanged(); } @Override public int getRowCount() { return data == null ? 0 : data.size(); } @Override public int getColumnCount() { return columns.length; } @Override public Object getValueAt(int rowIndex, int columnIndex) { Employee e = data.get(rowIndex); switch (columnIndex) { case 0: return e.getEmpNo(); case 1: return e.getEmpName(); case 4: return new SimpleDateFormat("yyyy-MM-dd").format(e.getHireDate()); default: return ""; } } }

注意getValueAt的第4列返回格式化后的日期字符串,而实体里存的是java.util.Date,类型转换要在展示层做,不要把格式化逻辑塞进setHireDate方法里。DAO查询时用rs.getDate("hire_date")拿java.sql.Date,可以直接赋给实体,JDBC驱动会自动完成日期类型转换。

查询按钮里的常见写法是拼一个动态SQL:只有工号为空时才不拼接工号条件。这里最容易出的坑是SQL条件拼接时有几个空格的问题,比如“WHERE 1=1”这种写法虽然能避免多余AND报错,但课程设计里更推荐用List收集条件片段再拼接:

StringBuilder sql = new StringBuilder("SELECT * FROM employee WHERE 1=1"); List<Object> params = new ArrayList<>(); if (empNo != null && !empNo.isEmpty()) { sql.append(" AND emp_no = ?"); params.add(empNo); }

逻辑是先构建片段集合,再统一用Object[]传入PreparedStatement,这样参数顺序不会乱。如果项目里已经用了Druid,这条查询直接复用dataSource.getConnection()即可,不用自己管理DriverManager注册。

4.2 新增员工的入参校验与SQL参数绑定

新增员工弹窗一般用一个JDialog,包含工号、姓名、部门下拉框、日期选择器、工资输入框。点击保存时先做前端校验,再调EmployeeDao.insert():

public boolean insert(Employee emp) throws SQLException { String sql = "INSERT INTO employee(emp_no, emp_name, dept_id, position, hire_date, salary) VALUES (?,?,?,?,?,?)"; boolean saved = false; Connection conn = null; PreparedStatement ps = null; try { conn = dataSource.getConnection(); conn.setAutoCommit(false); ps = conn.prepareStatement(sql); ps.setString(1, emp.getEmpNo()); ps.setString(2, emp.getEmpName()); ps.setInt(3, emp.getDeptId()); ps.setString(4, emp.getPosition()); ps.setDate(5, new java.sql.Date(emp.getHireDate().getTime())); ps.setBigDecimal(6, emp.getSalary()); saved = ps.executeUpdate() > 0; conn.commit(); } catch (SQLException ex) { if (conn != null) conn.rollback(); throw ex; } finally { if (ps != null) ps.close(); if (conn != null) conn.close(); } return saved; }

open打开的连接,close是还给连接池。但这里既然手动管理了,就必须在finally里释放ps和conn,否则连接池的连接会被耗尽,运行几个小时后界面操作突然变卡。

工资字段用setBigDecimal而不是setDouble,对应建表时的DECIMAL类型,这样查询出来的BigDecimal再放回实体,前端显示时格式化两位小数,精度问题全程不会出现。入职日期先用SimpleDateFormat把界面上的"yyyy-MM-dd"字符串转成java.util.Date,再转java.sql.Date,注意SimpleDateFormat.parse会抛出ParseException,要try-catch并在界面提示“日期格式应为yyyy-MM-dd”,而不是让程序崩掉。

4.3 数据刷新机制:列表查完要重新加载

新增或编辑后,主列表必须刷新。最直接的方案是保存按钮成功的回调里重新执行listAll()并调用model.setData(list),而不是直接操作JTable的行。如果项目用了MVC分层,这里建议加一个简单的观察者模式,MainFrame实现一个RefreshListener接口,由EmployeeEditDialog在保存后触发刷新,避免主窗体持有一个全局的dialog引用。

public interface RefreshListener { void onDataChanged(); }

编辑和新增共用一个JDialog,靠visible参数区分:新增时清空所有字段、工号可编辑;编辑时先根据选中行回填Employee对象、工号锁定防止改主键。回填时getValueAt拿到的是Object,要强转回Employee,这里用前面的EmployeeTableModel的getRowValue(row)封装一下更安全。

4.4 事务边界在哪:删除和修改尽量带上事务

删除员工放在一个事务里做的好处是:如果后续还要删除该员工在考勤表里的记录,两条删除语句要么一起成功要么一起回滚。常见做法是写一个TransactionDao,接收Connection对象,在service层控制提交和回滚。但在课程设计里不必引入Spring的@Transactional,手动setAutoCommit(false)就够了,因为这已经是评审答辩能接受的事务粒度。

参数上要注意,deleteById的入参是emp_id还是emp_no要跟主键对齐。界面上选中一行后,表格里显示的是工号,但传给DAO的应该是rowId,这个id可以从Employee模型里取出,不要重新用工号去查一次。

5. 部署排错与打包进阶:时区、Druid监控和Swing应用发布

到了可以运行并且列表、增删改查都能走的阶段,剩下的就是那些在不同电脑上复制项目时才会遇到的环境问题,以及怎样把最终产物交给老师检查。

5.1 常见报错比对表

报错现象大概率原因处理方式
Unknown initial character set index '255'连接字符串里characterEncoding写法不对改成characterEncoding=utf8,删除GBK相关设置
Public Key Retrieval is not allowedMySQL 8.0的sha256_password插件导致url追加allowPublicKeyRetrieval=true
The server time zone value 'Öйú'时区未配置url增加serverTimezone=Asia/Shanghai
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver驱动jar没引入或类名写错确认lib里有mysql-connector-java,类名用com.mysql.cj.jdbc.Driver
Access denied for user 'root'@'localhost'密码错误或root仅允许localhost访问在mysql命令行执行ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '新密码'

时区报错里出现乱码“Öйú”,是因为旧驱动把Asia/Shanghai按本地编码解析后显示成乱码,不用管它,直接按第2列改配置即可。

5.2 Druid监控页面的隐藏能力

Druid不只是连接池,它自带一个StatViewServlet能查看活动连接数、SQL执行次数、慢查询列表。在桌面应用里没有Web容器,但可以通过DruidDataSource的日志输出看到监控统计。在druid.properties里加一行:

filters=stat,slf4j

程序启动后,在IDEA控制台观察日志,能看到每条SQL的执行时间。这个能力在调优列表查询时很有用:如果打开首页时要查员工表还要查部门表才能渲染下拉框,两条SQL的执行时间会被分别打印,哪条慢一目了然。

5.3 打包成可分发JAR的关键步骤

课程设计提交时,最好提供一个双击就能跑的jar包,而不是让老师去IDEA里找main类。Swing应用的打包要点是:把druid.properties放到resource目录并确保打进了jar;mysql-connector和druid的jar要放到jar包外的lib文件夹,并在MANIFEST.MF里声明Class-Path。

jar cvfm EPMS.jar MANIFEST.MF -C out .

MANIFEST.MF里写成:

Main-Class: com.epms.LoginFrame Class-Path: lib/mysql-connector-java-8.0.30.jar lib/druid-1.2.8.jar

Class-Path是相对路径,所以lib目录必须和EPMS.jar放在同一级文件夹里。如果不想用命令行,IDEA的Artifacts > Jar > from modules with dependencies也能生成带依赖的jar,只是依赖会被解包打进jar里,体积从几百KB膨胀到几十MB,但省去了配MANIFEST的麻烦。

5.4 从10张截图反查验收项

压缩包里带12张运行截图,编号从1到12,覆盖了登录、主界面、员工列表、考勤表和增删改查弹窗。把它们当作验收清单对照自己的机器:图片里出现的中文标题和提示语,在代码里搜索对应字符串,能快速确认哪些功能是完整实现的。最后再确认一遍README里的运行环境说明,如果写明JDK版本是8,就用8去跑,避免在JDK 17下遇到“illegal reflective access”这类模块化警告。跑通后的自测路径是登录、查看列表、新增一条员工数据、修改它的部门、退出重启后确认数据还在,这套操作做完即可交付。

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

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

Redisson 如何用 RFencedLock 获取围栏令牌保护外部资源

Redisson 如何用 RFencedLock 获取围栏令牌保护外部资源 【免费下载链接】redisson Redisson: Valkey & Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, Sor…

作者头像 李华
网站建设 2026/9/14 3:03:00

HTML5 PC静态模板:高性能单页网站搭建与优化指南

简介&#xff1a;这是一份专为PC端设计的产品介绍类单页静态网页模板&#xff0c;面向网页设计初学者、中小企业市场人员及个人开发者&#xff0c;解决快速搭建专业级产品展示页面的需求。模板基于HTML5标准开发&#xff0c;纯静态实现&#xff0c;无需后端支持&#xff0c;兼顾…

作者头像 李华
网站建设 2026/9/14 3:02:29

为什么七大数学难题,卡在了同一个地方?

为什么七大数学难题&#xff0c;卡在了同一个地方&#xff1f;你站在一个漆黑的房间里&#xff0c;手里只有一支手电筒。你照向墙壁&#xff0c;看到墙上有一个影子。你研究了很久&#xff0c;写下了关于这个影子的所有规律&#xff0c;写了几百篇论文&#xff0c;拿了好几个奖…

作者头像 李华
网站建设 2026/9/14 3:01:49

Megatron-LM 中基于 FP8 精度的 Llama-3-8B 分布式训练实战指南

Megatron-LM 中基于 FP8 精度的 Llama-3-8B 分布式训练实战指南 【免费下载链接】Megatron-LM Ongoing research training transformer models at scale 项目地址: https://gitcode.com/GitHub_Trending/me/Megatron-LM 本篇技术指南以 examples/llama/README.md 为核心…

作者头像 李华
网站建设 2026/9/14 3:01:41

微网虚拟电厂MILP调度:EV与需求响应协同建模

简介&#xff1a;本资源聚焦含多种需求响应与电动汽车参与的微网虚拟电厂日前优化调度问题&#xff0c;面向电力系统、能源互联网方向的研究生、科研人员及工程技术人员&#xff0c;解决分布式资源协同建模与经济性调度策略设计难题。压缩包共6个文件&#xff08;2.57MB&#x…

作者头像 李华
网站建设 2026/9/14 3:00:39

HTML5静态单页模板:零部署PC产品页实战指南

简介&#xff1a;这是一份专为产品展示场景设计的HTML5单页静态网页模板&#xff0c;面向网页设计初学者、中小企业市场人员及无需后端开发的快速建站需求者&#xff0c;解决产品介绍页面快速搭建、视觉统一与跨屏适配问题。压缩包共146个文件&#xff0c;含3个结构清晰的HTML主…

作者头像 李华