Java Swing+MySQL人事管理系统实战:基于Druid与DAO的分层设计
发布时间:2026/9/14 3:04:32来源:尧图网络
简介这是一套以 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层拿到Listmodel再填充到JTable或JComboBoxmodel只是纯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) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;注意几个细节。第一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配置逐项说明driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/epms?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse usernameroot password你的密码 initialSize5 minIdle5 maxActive20 maxWait60000driverClassName在MySQL 8.0下必须是com.mysql.cj.jdbc.Driver旧版的com.mysql.jdbc.Driver虽然能跑但会打印Deprecation警告。url里的serverTimezone必须显式指定否则8.0驱动会拿本机时区去匹配数据库时区报出的错误信息长到让人误以为是连接失败。useSSLfalse是因为本地学习环境没有证书配置开着反而会多一次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弹窗提示结果。这里有一个关键坑——耗时查询不应该阻塞EDTEvent 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继承AbstractTableModelpublic class EmployeeTableModel extends AbstractTableModel { private ListEmployee data; private String[] columns {工号, 姓名, 部门, 岗位, 入职日期, 工资}; public void setData(ListEmployee 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 11”这种写法虽然能避免多余AND报错但课程设计里更推荐用List收集条件片段再拼接StringBuilder sql new StringBuilder(SELECT * FROM employee WHERE 11); ListObject 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写法不对改成characterEncodingutf8删除GBK相关设置Public Key Retrieval is not allowedMySQL 8.0的sha256_password插件导致url追加allowPublicKeyRetrievaltrueThe server time zone value Öйú时区未配置url增加serverTimezoneAsia/Shanghaijava.lang.ClassNotFoundException: com.mysql.jdbc.Driver驱动jar没引入或类名写错确认lib里有mysql-connector-java类名用com.mysql.cj.jdbc.DriverAccess denied for user rootlocalhost密码错误或root仅允许localhost访问在mysql命令行执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 新密码时区报错里出现乱码“Öйú”是因为旧驱动把Asia/Shanghai按本地编码解析后显示成乱码不用管它直接按第2列改配置即可。5.2 Druid监控页面的隐藏能力Druid不只是连接池它自带一个StatViewServlet能查看活动连接数、SQL执行次数、慢查询列表。在桌面应用里没有Web容器但可以通过DruidDataSource的日志输出看到监控统计。在druid.properties里加一行filtersstat,slf4j程序启动后在IDEA控制台观察日志能看到每条SQL的执行时间。这个能力在调优列表查询时很有用如果打开首页时要查员工表还要查部门表才能渲染下拉框两条SQL的执行时间会被分别打印哪条慢一目了然。5.3 打包成可分发JAR的关键步骤课程设计提交时最好提供一个双击就能跑的jar包而不是让老师去IDEA里找main类。Swing应用的打包要点是把druid.properties放到resource目录并确保打进了jarmysql-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.jarClass-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”这类模块化警告。跑通后的自测路径是登录、查看列表、新增一条员工数据、修改它的部门、退出重启后确认数据还在这套操作做完即可交付。本文还有配套的精品资源点击获取
网站建设高端定制企业官网