Java Swing与MySQL构建人事管理系统实战项目源码
简介:本项目是一个基于Java Swing和MySQL实现的人事管理系统,适用于课程设计与Java初学者实践。系统采用Swing构建桌面端用户界面,使用MySQL存储员工信息,并通过JDBC实现数据库连接。项目采用MVC架构设计,包含DAO层与业务逻辑层,实现员工信息的增删改查功能。附带运行视频,便于理解和学习Java桌面应用开发流程,涵盖GUI编程、数据库操作与模块化开发等核心知识点。 
1. Java Swing图形界面开发
Java Swing是Java平台上用于构建跨平台桌面应用程序的重要工具包,它提供了丰富的图形界面组件和灵活的事件处理机制。Swing库基于AWT(Abstract Window Toolkit),但在功能和可定制性上更加强大。通过Swing,开发者可以构建出结构清晰、交互性强的用户界面,为后续人事管理系统的人机交互设计奠定基础。
本章将从Swing的核心组件入手,如按钮(JButton)、文本框(JTextField)、标签(JLabel)等,介绍它们的创建与使用方式。同时,将详细讲解Swing中的布局管理器(如FlowLayout、BorderLayout、GridLayout等),帮助开发者实现界面的自适应排布。
此外,事件处理机制是Swing程序响应用户操作的关键。我们将通过示例代码演示如何绑定按钮点击事件,并讲解ActionListener、MouseListener等监听器接口的使用方法。通过本章的学习,读者将掌握Java Swing界面开发的基本流程与核心技能。
2. MySQL数据库设计与操作
在现代信息系统开发中,数据库是承载数据存储与管理的核心。MySQL作为一款开源、高效、稳定的数据库管理系统,广泛应用于各类中大型项目中,尤其适合与Java技术栈结合使用的人事管理系统。本章将从数据库基础出发,深入讲解人事管理系统中关键数据表的设计、SQL语句的高效编写、以及数据库的优化与管理策略。通过本章内容,读者将掌握从零构建一个结构合理、性能稳定的人事管理系统数据库架构的全过程。
2.1 MySQL数据库基础
MySQL是一种关系型数据库管理系统(RDBMS),它以结构化的方式组织数据,并通过SQL语言进行操作。理解数据库的基础概念是进行后续开发与设计的前提。
2.1.1 数据库的基本概念
数据库由多个数据表组成,每个数据表存储特定类型的数据记录。在数据库中,以下几个核心概念尤为重要:
- 数据库(Database) :是数据的集合,包含多个表和相关对象。
- 表(Table) :由行(记录)和列(字段)组成,用于存储具体的数据。
- 字段(Column) :表中的一列,代表某一类数据。
- 记录(Row) :表中的一行,表示一个具体的数据项。
- 主键(Primary Key) :唯一标识表中每一行的字段,通常用于建立表之间的关联。
- 外键(Foreign Key) :用于建立多个表之间的关联关系,保证数据的完整性。
以下是一个简单的数据库结构示意图,展示了人事管理系统中各表之间的关系:
erDiagram
DEPARTMENT ||--o{ EMPLOYEE : "1:N"
ROLE ||--o{ EMPLOYEE : "1:N"
EMPLOYEE {
int id
string name
int department_id
int role_id
}
DEPARTMENT {
int id
string name
}
ROLE {
int id
string name
}
该图展示了人事管理系统中常见的三个表: EMPLOYEE 、 DEPARTMENT 和 ROLE ,它们之间通过外键建立联系。
2.1.2 表、字段与数据类型的选择
在设计数据库表时,合理的字段选择和数据类型定义至关重要,直接影响到系统的性能和可扩展性。
1. 表的设计原则
- 规范化设计 :减少数据冗余,提高数据一致性。
- 命名规范 :表名使用小写,多个单词用下划线分隔(如
employee_info)。 - 主键设计 :优先使用自增整数作为主键。
2. 字段类型选择
| 字段名 | 数据类型 | 说明 |
|---|---|---|
id |
INT |
主键,自增 |
name |
VARCHAR(100) |
员工姓名,长度限制100 |
email |
VARCHAR(255) |
邮箱地址,长度较长 |
hire_date |
DATE |
入职日期 |
department_id |
INT |
外键,关联部门表 |
role_id |
INT |
外键,关联角色表 |
3. 创建员工信息表的SQL语句
CREATE TABLE employee (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
hire_date DATE,
department_id INT,
role_id INT,
FOREIGN KEY (department_id) REFERENCES department(id),
FOREIGN KEY (role_id) REFERENCES role(id)
);
逐行分析与说明:
id INT AUTO_INCREMENT PRIMARY KEY:定义主键并设置为自增;name VARCHAR(100) NOT NULL:姓名字段,最大长度100,不能为空;email VARCHAR(255) UNIQUE:邮箱字段,最大长度255,并设置为唯一;hire_date DATE:入职日期字段;department_id INT和role_id INT:外键字段;FOREIGN KEY:设置外键约束,保证数据完整性。
2.2 人事管理系统数据库设计
人事管理系统通常需要管理员工、部门、角色与权限等信息。因此,数据库设计需围绕这些核心实体展开。
2.2.1 员工信息表设计
员工信息表是系统中最核心的表之一,存储员工的基本信息。
示例表结构:
CREATE TABLE employee (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
gender ENUM('男', '女') NOT NULL,
birth_date DATE,
phone VARCHAR(20),
email VARCHAR(255) UNIQUE,
hire_date DATE NOT NULL,
department_id INT,
role_id INT,
salary DECIMAL(10, 2),
status ENUM('在职', '离职') DEFAULT '在职',
FOREIGN KEY (department_id) REFERENCES department(id),
FOREIGN KEY (role_id) REFERENCES role(id)
);
字段说明:
gender ENUM('男', '女'):枚举类型,限制性别输入;status ENUM('在职', '离职') DEFAULT '在职':员工状态,默认为“在职”;salary DECIMAL(10, 2):薪资字段,保留两位小数;phone VARCHAR(20):电话字段,允许国际号码格式。
2.2.2 部门信息表设计
部门信息表用于管理组织结构。
CREATE TABLE department (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL UNIQUE,
description TEXT,
manager_id INT,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
字段说明:
manager_id INT:指向员工表,表示部门负责人;create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP:自动记录创建时间。
2.2.3 角色与权限表设计
角色与权限表用于管理系统权限分配。
CREATE TABLE role (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
description TEXT
);
CREATE TABLE permission (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
description TEXT
);
CREATE TABLE role_permission (
role_id INT,
permission_id INT,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES role(id),
FOREIGN KEY (permission_id) REFERENCES permission(id)
);
结构说明:
role表:存储角色信息;permission表:存储权限信息;role_permission表:多对多关联表,实现角色与权限的绑定。
2.3 SQL语句的编写与执行
SQL是操作数据库的核心工具。编写高效、安全的SQL语句对于系统的稳定运行至关重要。
2.3.1 查询语句的编写技巧
示例:查询所有在职员工及其所属部门名称
SELECT e.id, e.name, e.email, d.name AS department_name
FROM employee e
JOIN department d ON e.department_id = d.id
WHERE e.status = '在职';
逻辑分析:
- 使用
JOIN连接员工表与部门表; - 使用别名
e和d提高可读性; - 使用
WHERE筛选在职员工; - 使用
AS给字段起别名,方便程序处理。
查询优化技巧:
- 使用索引提升查询速度;
- 避免使用
SELECT *,只选择需要的字段; - 合理使用分页查询(LIMIT/OFFSET)。
2.3.2 数据的插入、更新与删除
插入数据:
INSERT INTO employee (name, gender, birth_date, phone, email, hire_date, department_id, role_id, salary)
VALUES ('张三', '男', '1990-01-01', '13800000000', 'zhangsan@example.com', '2020-05-01', 1, 2, 8000.00);
更新数据:
UPDATE employee
SET salary = 8500.00
WHERE id = 1;
删除数据(物理删除):
DELETE FROM employee
WHERE id = 1;
软删除实现(推荐):
建议在表中添加 is_deleted 字段,避免直接删除数据。
ALTER TABLE employee ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE;
UPDATE employee
SET is_deleted = TRUE
WHERE id = 1;
2.4 数据库的优化与管理
随着数据量的增长,数据库性能问题逐渐显现。合理的优化与管理策略是保障系统高效运行的关键。
2.4.1 索引的使用与优化
索引是加速查询的关键工具,但不合理的索引也会增加写入开销。
示例:在员工表的 email 字段添加唯一索引
ALTER TABLE employee ADD UNIQUE INDEX idx_email (email);
索引使用建议:
- 经常作为查询条件的字段应建立索引;
- 避免对频繁更新的字段建立索引;
- 使用复合索引来优化多条件查询。
查询索引信息:
SHOW INDEX FROM employee;
2.4.2 数据库的备份与恢复策略
定期备份数据库是防止数据丢失的重要手段。
备份命令:
mysqldump -u root -p dbname > backup.sql
恢复命令:
mysql -u root -p dbname < backup.sql
自动化备份脚本示例(Linux):
#!/bin/bash
DATE=$(date +"%Y%m%d")
BACKUP_DIR="/backup/mysql"
DB_NAME="hr_system"
USER="root"
PASSWORD="your_password"
mysqldump -u $USER -p$PASSWORD $DB_NAME > $BACKUP_DIR/$DB_NAME-$DATE.sql
脚本说明:
- 使用
date命令生成备份文件名; - 通过
mysqldump执行备份; - 可设置定时任务(如crontab)定期执行备份。
通过本章内容的学习,读者应已掌握MySQL数据库的基础知识、人事管理系统数据库的设计方法、SQL语句的编写技巧以及数据库优化与管理的基本策略。这些内容将为后续Java与数据库交互、DAO层设计及MVC架构实现打下坚实基础。
3. JDBC数据库连接实现
Java Database Connectivity(JDBC)是Java平台中用于与数据库进行交互的核心API。它提供了一套标准接口,使得Java程序能够与各种关系型数据库建立连接、执行SQL语句并处理结果集。在人事管理系统的开发中,JDBC扮演着连接业务逻辑与数据库之间桥梁的关键角色。本章将从JDBC的基本概念入手,逐步深入讲解如何实现Java与MySQL数据库的连接,以及连接池的使用和异常处理策略,帮助开发者构建稳定、高效的数据库访问层。
3.1 JDBC基础概念
JDBC是Java语言中用于数据库访问的标准接口,它屏蔽了底层数据库的差异,使得开发者可以使用统一的方式与不同数据库进行交互。理解JDBC的基本概念是实现数据库连接的前提。
3.1.1 JDBC驱动类型与连接方式
JDBC驱动是实现JDBC接口的类库,用于与特定数据库通信。根据实现方式的不同,JDBC驱动可以分为以下四类:
| 驱动类型 | 名称 | 特点 | 使用场景 |
|---|---|---|---|
| Type 1 | JDBC-ODBC Bridge | 使用ODBC作为中介,兼容性差 | 旧系统或测试环境 |
| Type 2 | Native-API | 使用数据库本地API,性能较好但依赖本地库 | 某些Oracle环境 |
| Type 3 | Net-Protocol | 通过中间件服务器与数据库通信 | 企业级分布式系统 |
| Type 4 | Native-Protocol | 完全用Java实现,直接与数据库通信 | 最常用,推荐使用 |
MySQL常用的JDBC驱动为Type 4类型,其驱动类名为 com.mysql.cj.jdbc.Driver ,连接URL格式如下:
jdbc:mysql://host:port/database?parameter=value
例如:
String url = "jdbc:mysql://localhost:3306/hr_system?useSSL=false&serverTimezone=UTC";
3.1.2 Connection、Statement与ResultSet对象的使用
JDBC中三个核心接口 Connection 、 Statement 和 ResultSet 构成了数据库访问的基本流程。
Connection对象
Connection 代表与数据库的连接。通过 DriverManager.getConnection() 方法建立连接:
Connection conn = DriverManager.getConnection(url, username, password);
Statement对象
Statement 用于执行静态SQL语句:
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
ResultSet对象
ResultSet 表示查询结果集,通过遍历结果集获取数据:
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println("ID: " + id + ", Name: " + name);
}
完整示例代码
import java.sql.*;
public class JdbcExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/hr_system?useSSL=false&serverTimezone=UTC";
String user = "root";
String password = "password";
try (Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM employees")) {
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println("ID: " + id + ", Name: " + name);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
逻辑分析与参数说明
try-with-resources:自动关闭资源,避免内存泄漏。Connection:建立与MySQL数据库的连接。Statement:执行SQL语句。ResultSet:处理查询结果。SQLException:捕捉数据库访问过程中的异常。
3.2 Java与MySQL数据库的连接
Java与MySQL数据库的连接是JDBC操作的基础。本节将详细介绍如何配置连接字符串以及使用 DriverManager 建立连接。
3.2.1 配置JDBC连接字符串
连接字符串是JDBC连接的核心参数,其格式如下:
jdbc:mysql://<host>:<port>/<database>?<parameters>
常见参数包括:
| 参数 | 说明 | 示例 |
|---|---|---|
| useSSL | 是否使用SSL连接 | useSSL=false |
| serverTimezone | 设置服务器时区 | serverTimezone=UTC |
| autoReconnect | 是否自动重连 | autoReconnect=true |
| characterEncoding | 字符编码 | characterEncoding=utf8 |
| useUnicode | 是否使用Unicode | useUnicode=true |
完整示例:
String url = "jdbc:mysql://localhost:3306/hr_system?useSSL=false&serverTimezone=UTC&characterEncoding=utf8&useUnicode=true";
3.2.2 使用DriverManager建立连接
DriverManager 类负责管理JDBC驱动并建立连接。以下是建立连接的步骤:
- 加载驱动类:
Class.forName("com.mysql.cj.jdbc.Driver");
- 建立连接:
Connection conn = DriverManager.getConnection(url, user, password);
示例代码
import java.sql.*;
public class MySqlConnection {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/hr_system?useSSL=false&serverTimezone=UTC";
String user = "root";
String password = "password";
try {
// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立连接
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println("连接成功!");
// 关闭连接
conn.close();
} catch (ClassNotFoundException e) {
System.err.println("找不到驱动类");
} catch (SQLException e) {
System.err.println("数据库连接失败");
e.printStackTrace();
}
}
}
逻辑分析与参数说明
Class.forName():显式加载驱动类,确保JVM能够识别MySQL驱动。DriverManager.getConnection():根据URL、用户名和密码建立连接。conn.close():关闭连接,释放资源。- 异常处理:区分驱动类未找到和连接失败两种情况,分别处理。
3.3 数据库连接池的使用
频繁地建立和关闭数据库连接会带来性能损耗。为提高系统效率,通常使用 数据库连接池 来管理连接资源。
3.3.1 C3P0连接池的配置
C3P0是一个开源的JDBC连接池,使用简单且配置灵活。以下是使用C3P0的基本配置方式。
Maven依赖
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
配置C3P0连接池
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P0DataSource {
private static ComboPooledDataSource dataSource;
static {
dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
} catch (PropertyVetoException e) {
e.printStackTrace();
}
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/hr_system?useSSL=false&serverTimezone=UTC");
dataSource.setUser("root");
dataSource.setPassword("password");
// 连接池参数
dataSource.setInitialPoolSize(5);
dataSource.setMinPoolSize(5);
dataSource.setMaxPoolSize(20);
dataSource.setMaxStatements(50);
dataSource.setAcquireIncrement(5);
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
逻辑分析与参数说明
ComboPooledDataSource:C3P0的核心数据源类。setDriverClass():设置数据库驱动类名。setJdbcUrl():设置数据库连接字符串。setUser()、setPassword():数据库用户名和密码。setInitialPoolSize():初始连接数。setMinPoolSize():最小连接数。setMaxPoolSize():最大连接数。setMaxStatements():最大缓存的SQL语句数。setAcquireIncrement():每次增加的连接数。
3.3.2 连接池的使用与管理
使用连接池获取连接并执行SQL语句的示例:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class C3P0Test {
public static void main(String[] args) {
try (Connection conn = C3P0DataSource.getConnection();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM employees");
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println("ID: " + rs.getInt("id") + ", Name: " + rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
连接池的优势
- 性能提升 :避免频繁创建和销毁连接。
- 资源管理 :限制最大连接数,防止资源耗尽。
- 连接复用 :连接在使用后放回池中,供其他请求复用。
3.4 数据访问异常处理
数据库操作中可能会出现各种异常,如连接失败、SQL语法错误、权限不足等。合理处理这些异常是保证系统健壮性的关键。
3.4.1 SQL异常的捕获与处理
JDBC中的异常主要由 SQLException 类表示。开发者应使用try-catch块捕获并处理这些异常。
示例代码
try (Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM employees")) {
while (rs.next()) {
System.out.println("Name: " + rs.getString("name"));
}
} catch (SQLException e) {
System.err.println("SQL异常发生");
System.err.println("错误代码: " + e.getErrorCode());
System.err.println("SQL状态: " + e.getSQLState());
e.printStackTrace();
}
参数说明
getErrorCode():返回数据库厂商定义的错误代码。getSQLState():返回标准化的SQL状态码。printStackTrace():打印异常堆栈信息,用于调试。
3.4.2 数据库连接失败的解决方案
连接失败是常见的问题,可能原因包括:
- 驱动类未加载 :检查是否添加了正确的JDBC驱动。
- URL配置错误 :检查主机、端口、数据库名是否正确。
- 网络问题 :确认数据库服务是否启动,网络是否通顺。
- 权限不足 :确认用户是否有权限访问数据库。
解决方案流程图(mermaid)
graph TD
A[数据库连接失败] --> B{驱动类是否加载?}
B -->|是| C{URL是否正确?}
B -->|否| D[检查Maven依赖或jar包]
C -->|是| E{网络是否正常?}
C -->|否| F[修正URL参数]
E -->|是| G{用户权限是否正确?}
E -->|否| H[检查数据库服务与网络]
G -->|是| I[其他错误]
G -->|否| J[检查MySQL用户权限配置]
常见错误处理建议
- ClassNotFoundException :未找到驱动类,需检查
Class.forName()或依赖配置。 - CommunicationsException :数据库无法连接,检查MySQL服务是否启动。
- AccessDeniedException :用户名或密码错误,或权限不足。
- SQLSyntaxErrorException :SQL语句语法错误,需检查语句拼写与表结构。
4. DAO模式数据访问层设计
在Java企业级开发中,数据访问层(Data Access Layer)的设计至关重要。DAO(Data Access Object)模式作为经典的分层设计模式之一,广泛应用于Java项目中,尤其是在与数据库交互频繁的系统中。通过DAO模式,我们可以实现数据访问逻辑与业务逻辑的分离,提升系统的可维护性、可扩展性以及代码的重用率。本章将深入探讨DAO模式的基本结构、在人事管理系统中的应用方式,并通过具体接口与方法的实现来展示其设计与优化策略。
4.1 DAO模式概述
4.1.1 数据访问对象模式的结构
DAO模式是一种设计模式,其核心思想是将数据库访问逻辑封装在一个独立的接口或类中,使业务层无需直接处理底层的数据库操作。其典型结构包括以下几个部分:
- DAO接口 :定义了对数据的增删改查操作方法。
- DAO实现类 :实现DAO接口中的方法,具体负责与数据库交互。
- 数据模型类(Entity) :映射数据库表的Java对象,用于封装数据。
- 工厂类或服务类 :用于创建DAO实例,实现解耦。
如下是一个典型的DAO结构示意图(使用Mermaid绘制):
classDiagram
class DAOFactory {
+getEmployeeDAO(): EmployeeDAO
+getDepartmentDAO(): DepartmentDAO
}
interface EmployeeDAO {
+Employee findById(int id)
+List~Employee~ findAll()
+void save(Employee employee)
+void update(Employee employee)
+void delete(int id)
}
class EmployeeDAOImpl {
-Connection connection
+Employee findById(int id)
+List~Employee~ findAll()
+void save(Employee employee)
+void update(Employee employee)
+void delete(int id)
}
class Employee {
-int id
-String name
-int departmentId
...
}
DAOFactory --> EmployeeDAO
DAOFactory --> EmployeeDAOImpl
EmployeeDAO <|-- EmployeeDAOImpl
EmployeeDAOImpl --> Employee
通过上述结构图可以看出,DAO模式通过接口与实现的分离,使得业务逻辑层无需关心底层数据库的实现细节,仅需调用DAO接口即可完成数据操作。
4.1.2 DAO模式在项目中的优势
DAO模式之所以在Java项目中被广泛采用,主要有以下几个优势:
| 优势 | 说明 |
|---|---|
| 解耦 | 业务逻辑层与数据访问层完全分离,降低耦合度 |
| 可维护性 | 数据访问逻辑集中,便于维护和修改 |
| 可扩展性 | 支持多种数据库实现,只需更换DAO实现类即可 |
| 代码复用 | DAO接口可以在多个业务模块中复用 |
| 易于测试 | 通过MockDAO实现,可以方便地进行单元测试 |
例如,在人事管理系统中,如果需要将数据库从MySQL迁移到PostgreSQL,只需更换DAO实现类即可,而无需修改业务层代码,大大提升了系统的可移植性。
4.2 员工信息DAO设计
4.2.1 EmployeeDAO接口设计
在人事管理系统中,员工信息是核心数据之一。为了规范数据访问操作,我们首先定义一个 EmployeeDAO 接口,声明常见的CRUD操作方法。接口设计如下:
public interface EmployeeDAO {
Employee findById(int id);
List<Employee> findAll();
void save(Employee employee);
void update(Employee employee);
void delete(int id);
}
代码逻辑分析:
findById(int id):根据员工ID查询员工信息。findAll():获取所有员工信息。save(Employee employee):保存新员工记录。update(Employee employee):更新已有员工信息。delete(int id):根据ID删除员工记录。
通过接口定义,业务层可以统一调用这些方法,而无需关心具体的数据库操作逻辑。
4.2.2 数据库操作方法实现
接下来,我们实现 EmployeeDAO 接口的具体操作类 EmployeeDAOImpl ,该类负责与数据库进行交互:
public class EmployeeDAOImpl implements EmployeeDAO {
private Connection connection;
public EmployeeDAOImpl(Connection connection) {
this.connection = connection;
}
@Override
public Employee findById(int id) {
String sql = "SELECT * FROM employees WHERE id = ?";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setInt(1, id);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
return new Employee(
rs.getInt("id"),
rs.getString("name"),
rs.getInt("department_id")
);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public List<Employee> findAll() {
List<Employee> employees = new ArrayList<>();
String sql = "SELECT * FROM employees";
try (Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
employees.add(new Employee(
rs.getInt("id"),
rs.getString("name"),
rs.getInt("department_id")
));
}
} catch (SQLException e) {
e.printStackTrace();
}
return employees;
}
// 其他save、update、delete方法实现略...
}
参数说明与执行逻辑分析:
connection:构造函数注入数据库连接,保证DAO实例可以访问数据库。findById方法中:- 使用预编译SQL语句防止SQL注入。
- 使用
ResultSet读取查询结果并封装为Employee对象。 findAll方法中:- 使用
Statement执行全表查询。 - 遍历
ResultSet将每一行数据转换为Employee对象并存入集合。
4.3 部门信息DAO设计
4.3.1 DepartmentDAO接口设计
部门信息是员工信息的重要关联对象,因此也需要设计对应的DAO接口:
public interface DepartmentDAO {
Department findById(int id);
List<Department> findAll();
void save(Department department);
void update(Department department);
void delete(int id);
}
该接口定义与 EmployeeDAO 类似,同样遵循CRUD操作规范。
4.3.2 数据库操作方法实现
对应实现类 DepartmentDAOImpl 如下(以 findById 为例):
public class DepartmentDAOImpl implements DepartmentDAO {
private Connection connection;
public DepartmentDAOImpl(Connection connection) {
this.connection = connection;
}
@Override
public Department findById(int id) {
String sql = "SELECT * FROM departments WHERE id = ?";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setInt(1, id);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
return new Department(
rs.getInt("id"),
rs.getString("name")
);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
// 其他方法略...
}
逻辑分析:
- 与员工DAO类似,使用预编译语句提升安全性。
- 查询结果封装为
Department对象,供业务层调用。
4.4 DAO模式的扩展与优化
4.4.1 泛型DAO的设计思路
为了减少重复代码,提高代码复用率,可以设计一个 泛型DAO接口 ,支持所有实体类的通用操作:
public interface GenericDAO<T> {
T findById(int id);
List<T> findAll();
void save(T entity);
void update(T entity);
void delete(int id);
}
对应的泛型实现类 GenericDAOImpl :
public class GenericDAOImpl<T> implements GenericDAO<T> {
private final Class<T> entityClass;
private final Connection connection;
public GenericDAOImpl(Class<T> entityClass, Connection connection) {
this.entityClass = entityClass;
this.connection = connection;
}
@Override
public T findById(int id) {
// 通过反射或ORM框架实现
return null;
}
// 其他方法略...
}
这种方式适用于使用反射或ORM框架(如Hibernate)的项目,可以极大提升开发效率。
4.4.2 使用Spring管理DAO层
在实际企业级项目中,通常会使用 Spring框架 来管理DAO层,实现依赖注入和自动装配。通过Spring,我们可以:
- 自动注入
DataSource - 使用
@Repository注解DAO实现类 - 使用
@Transactional管理事务
示例代码如下:
@Repository
public class EmployeeDAOImpl implements EmployeeDAO {
private final JdbcTemplate jdbcTemplate;
@Autowired
public EmployeeDAOImpl(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public Employee findById(int id) {
String sql = "SELECT * FROM employees WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new EmployeeRowMapper(), id);
}
}
参数说明:
@Repository:标记该类为Spring的DAO组件,便于扫描和注入。JdbcTemplate:Spring提供的简化JDBC操作的工具类。EmployeeRowMapper:自定义映射类,将结果集转换为Java对象。
通过Spring管理DAO层,不仅简化了数据库操作,还增强了系统的可测试性与可维护性。
本章通过详细设计与代码实现,展示了DAO模式在Java项目中的核心作用。通过DAO接口与实现的分离,系统结构更清晰,数据访问层更具可扩展性与可维护性。同时,我们还探讨了泛型DAO的设计思路以及如何结合Spring框架优化DAO层的实现,为人事管理系统的构建提供了坚实的数据访问基础。
5. MVC架构在Java项目中的应用
MVC(Model-View-Controller)架构是软件工程中非常常见且经典的分层架构模式,广泛应用于桌面应用、Web应用以及移动端开发中。它通过将应用程序划分为三个核心部分——模型(Model)、视图(View)和控制器(Controller)——实现了逻辑分离,提升了代码的可维护性、可扩展性与可测试性。在人事管理系统中,采用MVC架构可以有效组织代码结构,提高开发效率,并为后期的功能扩展与维护提供良好的基础。
本章将围绕MVC架构的核心概念,结合Java Swing开发与DAO数据访问层的实现,深入探讨MVC在人事管理系统中的具体应用。我们将从MVC的基本原理出发,逐步讲解模型层的设计与实现、视图层的界面布局与交互、以及控制器层的事件响应机制,并通过实际代码示例展示如何在Java项目中落地MVC架构。
5.1 MVC架构的基本原理
MVC是一种分层设计模式,旨在将用户界面逻辑、业务逻辑与数据处理逻辑分离。这种分离使得各个组件之间的耦合度降低,便于维护和扩展。
5.1.1 MVC三要素的职责划分
| 组件 | 职责描述 |
|---|---|
| Model(模型) | 负责数据的获取、存储与管理,处理业务逻辑,不依赖于视图或控制器。 |
| View(视图) | 负责用户界面的展示,响应用户操作并通知控制器,不处理业务逻辑。 |
| Controller(控制器) | 负责接收用户输入,协调模型与视图之间的交互,更新模型数据并刷新视图。 |
5.1.2 MVC的工作流程
通过以下Mermaid流程图,我们可以清晰地看到MVC中各组件之间的交互流程:
sequenceDiagram
participant User
participant View
participant Controller
participant Model
User->>View: 用户操作界面
View->>Controller: 传递用户操作事件
Controller->>Model: 调用业务逻辑
Model->>Model: 处理数据
Model-->>Controller: 返回处理结果
Controller-->>View: 更新视图
View-->>User: 展示新界面
在实际开发中,例如在员工信息管理界面中,用户点击“查询”按钮后,视图将该事件传递给控制器,控制器调用模型执行数据库查询操作,模型返回查询结果后,控制器再将数据传递给视图进行展示。
5.1.3 MVC的优势与应用场景
| 优势 | 描述 |
|---|---|
| 高内聚、低耦合 | 各组件之间职责明确,相互依赖度低,便于独立开发与测试。 |
| 易于维护与扩展 | 由于结构清晰,新增功能或修改逻辑时不易影响其他部分。 |
| 支持多视图共享模型 | 模型可以被多个视图复用,提升代码复用率。 |
| 提升开发效率 | 多人协作开发时,前端与后端可以并行开发,提升整体开发效率。 |
MVC广泛应用于Web开发(如Spring MVC)、桌面应用(如Java Swing)和移动开发(如Android开发)中。在Java Swing项目中,合理应用MVC架构可以显著提升项目的可读性和可维护性。
5.2 模型层(Model)的设计与实现
模型层是MVC架构的核心部分,负责处理业务逻辑和数据操作。在人事管理系统中,模型层主要包括员工信息实体类、数据访问对象(DAO)以及业务逻辑类。
5.2.1 实体类的设计
以员工信息为例,我们设计一个 Employee 类来封装员工的基本信息:
public class Employee {
private int id;
private String name;
private String department;
private double salary;
private String position;
// 构造方法、getter和setter方法省略
}
代码分析:
id:员工唯一标识。name:员工姓名。department:所属部门。salary:工资。position:职位。
该实体类与数据库中的 employee 表相对应,用于在模型层中传递数据。
5.2.2 数据访问对象(DAO)的集成
在第4章中我们已经实现了 EmployeeDAO ,该类封装了与数据库的交互逻辑。在模型层中,我们通过调用DAO实现数据的增删改查。
public class EmployeeService {
private EmployeeDAO employeeDAO = new EmployeeDAO();
public List<Employee> getAllEmployees() {
return employeeDAO.findAll();
}
public boolean addEmployee(Employee employee) {
return employeeDAO.insert(employee) > 0;
}
public boolean updateEmployee(Employee employee) {
return employeeDAO.update(employee) > 0;
}
public boolean deleteEmployee(int id) {
return employeeDAO.deleteById(id) > 0;
}
}
代码分析:
EmployeeDAO:通过DAO类与数据库进行交互。EmployeeService:业务逻辑类,封装了员工信息的增删改查操作。- 各方法调用DAO的对应方法实现数据库操作,并返回操作结果。
5.2.3 业务逻辑的封装与复用
除了基本的CRUD操作,模型层还可以封装更复杂的业务逻辑,例如根据部门统计员工人数、计算部门平均工资等。
public double calculateAverageSalaryByDepartment(String department) {
List<Employee> employees = employeeDAO.findByDepartment(department);
if (employees.isEmpty()) return 0.0;
double total = employees.stream().mapToDouble(Employee::getSalary).sum();
return total / employees.size();
}
代码分析:
- 通过
employeeDAO.findByDepartment获取指定部门的员工列表。 - 使用Java 8的Stream API计算平均工资。
- 返回计算结果。
5.3 视图层(View)的设计与实现
视图层负责用户界面的展示和用户交互。在Java Swing项目中,我们使用Swing组件构建图形界面,并遵循MVC原则,将界面交互事件交给控制器处理。
5.3.1 员工信息管理界面设计
我们以一个员工信息管理界面为例,使用Swing组件构建界面:
public class EmployeeView extends JFrame {
private JTextField idField;
private JTextField nameField;
private JComboBox<String> departmentComboBox;
private JTextField salaryField;
private JButton addButton;
private JButton updateButton;
private JButton deleteButton;
private JTable employeeTable;
public EmployeeView() {
// 初始化组件
setTitle("员工信息管理系统");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
// 表单输入区域
JPanel formPanel = new JPanel(new GridLayout(5, 2));
formPanel.add(new JLabel("员工ID:"));
idField = new JTextField();
formPanel.add(idField);
formPanel.add(new JLabel("姓名:"));
nameField = new JTextField();
formPanel.add(nameField);
formPanel.add(new JLabel("部门:"));
departmentComboBox = new JComboBox<>(new String[]{"人事部", "技术部", "市场部"});
formPanel.add(departmentComboBox);
formPanel.add(new JLabel("工资:"));
salaryField = new JTextField();
formPanel.add(salaryField);
// 操作按钮
JPanel buttonPanel = new JPanel(new FlowLayout());
addButton = new JButton("新增");
updateButton = new JButton("修改");
deleteButton = new JButton("删除");
buttonPanel.add(addButton);
buttonPanel.add(updateButton);
buttonPanel.add(deleteButton);
// 数据表格
String[] columnNames = {"ID", "姓名", "部门", "工资"};
employeeTable = new JTable(new DefaultTableModel(columnNames, 0));
JScrollPane scrollPane = new JScrollPane(employeeTable);
// 添加组件
add(formPanel, BorderLayout.NORTH);
add(buttonPanel, BorderLayout.CENTER);
add(scrollPane, BorderLayout.SOUTH);
}
// Getter方法供Controller使用
public JTextField getIdField() { return idField; }
public JTextField getNameField() { return nameField; }
public JComboBox<String> getDepartmentComboBox() { return departmentComboBox; }
public JTextField getSalaryField() { return salaryField; }
public JButton getAddButton() { return addButton; }
public JButton getUpdateButton() { return updateButton; }
public JButton getDeleteButton() { return deleteButton; }
public JTable getEmployeeTable() { return employeeTable; }
}
代码分析:
- 使用Swing组件构建表单输入区域、按钮操作区和数据展示表格。
- 提供Getter方法供控制器访问界面元素。
- 使用
JTable展示员工信息列表,方便用户查看。
5.3.2 表格数据绑定
通过 DefaultTableModel 可以实现表格数据的动态绑定:
public void refreshTable(List<Employee> employees) {
DefaultTableModel model = (DefaultTableModel) employeeTable.getModel();
model.setRowCount(0); // 清空表格
for (Employee emp : employees) {
Object[] row = {emp.getId(), emp.getName(), emp.getDepartment(), emp.getSalary()};
model.addRow(row);
}
}
代码分析:
refreshTable方法接收员工列表,动态更新表格内容。- 每次调用前先清空原有数据,避免重复显示。
- 使用
DefaultTableModel.addRow()逐行添加数据。
5.4 控制器层(Controller)的设计与实现
控制器层是连接模型层和视图层的桥梁,负责处理用户输入、调用业务逻辑并更新视图。
5.4.1 控制器类的设计
我们创建一个 EmployeeController 类来处理用户操作:
public class EmployeeController {
private EmployeeView view;
private EmployeeService service;
public EmployeeController(EmployeeView view, EmployeeService service) {
this.view = view;
this.service = service;
// 注册按钮事件
view.getAddButton().addActionListener(e -> addEmployee());
view.getUpdateButton().addActionListener(e -> updateEmployee());
view.getDeleteButton().addActionListener(e -> deleteEmployee());
// 初始化加载数据
refreshTable();
}
private void refreshTable() {
List<Employee> employees = service.getAllEmployees();
view.refreshTable(employees);
}
private void addEmployee() {
Employee emp = new Employee();
emp.setId(Integer.parseInt(view.getIdField().getText()));
emp.setName(view.getNameField().getText());
emp.setDepartment((String) view.getDepartmentComboBox().getSelectedItem());
emp.setSalary(Double.parseDouble(view.getSalaryField().getText()));
if (service.addEmployee(emp)) {
refreshTable();
JOptionPane.showMessageDialog(view, "新增成功!");
} else {
JOptionPane.showMessageDialog(view, "新增失败!");
}
}
private void updateEmployee() {
// 类似于addEmployee,此处略
}
private void deleteEmployee() {
int id = Integer.parseInt(view.getIdField().getText());
if (service.deleteEmployee(id)) {
refreshTable();
JOptionPane.showMessageDialog(view, "删除成功!");
} else {
JOptionPane.showMessageDialog(view, "删除失败!");
}
}
}
代码分析:
EmployeeController接收视图和模型实例,注册按钮点击事件。- 调用
service执行业务逻辑,如新增、修改、删除员工。 - 操作成功后刷新表格并弹出提示信息。
5.4.2 事件驱动机制的实现
Java Swing中的事件驱动机制是控制器实现的核心。通过 ActionListener 监听按钮点击事件,控制器可以响应用户操作并执行相应的逻辑。
view.getAddButton().addActionListener(e -> addEmployee());
代码分析:
- 为“新增”按钮添加事件监听器。
- 点击按钮时触发
addEmployee()方法。 - 类似地,为“修改”和“删除”按钮注册监听器。
5.5 MVC架构的整合与应用
将模型、视图、控制器整合到主程序中:
public class MainApp {
public static void main(String[] args) {
EmployeeView view = new EmployeeView();
EmployeeService service = new EmployeeService();
new EmployeeController(view, service);
view.setVisible(true);
}
}
代码分析:
- 创建视图、服务和控制器实例。
- 控制器绑定视图和模型。
- 显示界面并启动事件循环。
5.6 MVC架构在项目中的优势体现
在人事管理系统中,MVC架构带来了以下明显优势:
- 模块清晰 :各层职责明确,便于团队协作与维护。
- 可扩展性强 :新增功能时只需在对应层进行扩展,不影响其他部分。
- 易于测试 :模型层可独立测试业务逻辑,无需依赖界面。
- 代码复用高 :模型和控制器可被多个视图复用,提高开发效率。
通过本章的深入讲解与代码示例,我们已经掌握了如何在Java项目中应用MVC架构,为人事管理系统的开发奠定了坚实基础。下一章我们将围绕员工信息的增删改查功能进行详细实现。
6. 员工信息增删改查功能实现
在人事管理系统中,员工信息的增删改查(CRUD)功能是最核心的模块之一,它直接决定了系统的可用性和数据管理的效率。本章将围绕员工信息的查询、新增、修改和删除四个核心操作展开,详细分析每个功能的实现逻辑、技术选型、代码结构以及优化策略。通过本章的学习,开发者将能够掌握如何在Java Swing应用中集成数据库操作,构建一个完整且稳定的员工信息管理模块。
6.1 员工信息的查询功能
查询功能是人事管理系统中最常用的操作之一,负责从数据库中获取员工信息并展示给用户。为了提升用户体验,查询功能应支持多种查询条件,并能对结果进行分页展示。
6.1.1 查询条件的设置与执行
在实现查询功能时,首先需要设计灵活的查询条件设置界面,通常包括按姓名、部门、职位等字段进行筛选。这些条件可以通过Swing中的 JTextField 、 JComboBox 组件进行输入。
// 查询条件输入示例
public class EmployeeSearchPanel extends JPanel {
private JTextField nameField;
private JComboBox<String> departmentComboBox;
public EmployeeSearchPanel() {
nameField = new JTextField(20);
departmentComboBox = new JComboBox<>(new String[]{"全部", "技术部", "市场部", "行政部"});
this.add(new JLabel("姓名:"));
this.add(nameField);
this.add(new JLabel("部门:"));
this.add(departmentComboBox);
}
public String getSearchName() {
return nameField.getText().trim();
}
public String getSelectedDepartment() {
return (String) departmentComboBox.getSelectedItem();
}
}
代码逻辑分析:
nameField用于输入姓名关键字。departmentComboBox下拉框提供部门筛选。getSearchName()和getSelectedDepartment()方法用于获取用户输入的查询条件。- 该面板可嵌入到主界面中,作为查询条件输入组件。
参数说明:
- JTextField(20) :设置文本框长度为20个字符。
- JComboBox<>(String[]) :构造一个字符串数组的下拉框。
6.1.2 查询结果的展示与分页
查询结果通常以表格形式展示,使用 JTable 配合 TableModel 实现。为了提升性能,查询结果应支持分页加载,避免一次性加载过多数据。
查询结果表格展示
// 查询结果表格模型
public class EmployeeTableModel extends AbstractTableModel {
private List<Employee> employees;
private String[] columnNames = {"ID", "姓名", "性别", "部门", "职位", "电话", "邮箱"};
public EmployeeTableModel(List<Employee> employees) {
this.employees = employees;
}
@Override
public int getRowCount() {
return employees.size();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public String getColumnName(int column) {
return columnNames[column];
}
@Override
public Object getValueAt(int row, int column) {
Employee emp = employees.get(row);
switch (column) {
case 0: return emp.getId();
case 1: return emp.getName();
case 2: return emp.getGender();
case 3: return emp.getDepartment();
case 4: return emp.getPosition();
case 5: return emp.getPhone();
case 6: return emp.getEmail();
default: return null;
}
}
}
代码逻辑分析:
AbstractTableModel是Swing中表格模型的抽象类,继承后需实现getRowCount()、getColumnCount()、getValueAt()等方法。employees存储查询结果数据。columnNames定义表格列标题。getValueAt()根据行号和列号获取对应字段值。
分页功能实现
分页功能可通过SQL语句的 LIMIT 和 OFFSET 实现。例如:
SELECT * FROM employee WHERE name LIKE '%张%' LIMIT 10 OFFSET 20;
对应的Java代码:
public List<Employee> searchEmployees(String name, String department, int page, int pageSize) {
List<Employee> list = new ArrayList<>();
String sql = "SELECT * FROM employee WHERE 1=1";
if (!name.isEmpty()) {
sql += " AND name LIKE ?";
}
if (!department.equals("全部")) {
sql += " AND department = ?";
}
sql += " LIMIT ? OFFSET ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
int paramIndex = 1;
if (!name.isEmpty()) {
ps.setString(paramIndex++, "%" + name + "%");
}
if (!department.equals("全部")) {
ps.setString(paramIndex++, department);
}
ps.setInt(paramIndex++, pageSize);
ps.setInt(paramIndex++, (page - 1) * pageSize);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Employee emp = new Employee();
emp.setId(rs.getInt("id"));
emp.setName(rs.getString("name"));
emp.setGender(rs.getString("gender"));
emp.setDepartment(rs.getString("department"));
emp.setPosition(rs.getString("position"));
emp.setPhone(rs.getString("phone"));
emp.setEmail(rs.getString("email"));
list.add(emp);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
代码逻辑分析:
- 使用
PreparedStatement防止SQL注入。 LIMIT ? OFFSET ?实现分页查询。- 动态拼接SQL语句,根据输入条件调整查询条件。
ResultSet遍历后封装为Employee对象并添加到列表中。
参数说明:
- page :当前页码。
- pageSize :每页显示条数。
- LIMIT ? OFFSET ? :控制每页的数据范围。
查询功能流程图
graph TD
A[用户输入查询条件] --> B{条件是否为空?}
B -- 是 --> C[执行无条件查询]
B -- 否 --> D[执行条件查询]
C --> E[调用DAO查询方法]
D --> E
E --> F[获取查询结果]
F --> G{结果是否为空?}
G -- 是 --> H[提示无数据]
G -- 否 --> I[更新表格模型]
6.2 员工信息的新增功能
新增功能是人事管理系统中不可或缺的一部分,负责将员工信息写入数据库。该功能应包括输入校验、数据格式处理以及插入操作。
6.2.1 输入校验与数据格式处理
在新增员工信息前,必须对输入数据进行校验,确保数据的完整性与合法性。例如,姓名不能为空、电话格式正确、邮箱符合正则表达式等。
public boolean validateEmployee(Employee employee) {
if (employee.getName() == null || employee.getName().trim().isEmpty()) {
JOptionPane.showMessageDialog(null, "姓名不能为空");
return false;
}
if (!employee.getPhone().matches("\\d{11}")) {
JOptionPane.showMessageDialog(null, "电话号码格式不正确");
return false;
}
if (!employee.getEmail().matches("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$")) {
JOptionPane.showMessageDialog(null, "邮箱格式不正确");
return false;
}
return true;
}
代码逻辑分析:
- 使用正则表达式校验电话和邮箱格式。
- 若校验失败,弹出提示框并返回
false。 - 所有校验通过后返回
true。
6.2.2 数据插入数据库的实现
插入操作通过JDBC完成,将校验通过的数据插入到数据库中。
public boolean addEmployee(Employee employee) {
String sql = "INSERT INTO employee (name, gender, department, position, phone, email) VALUES (?, ?, ?, ?, ?, ?)";
try (Connection conn = DBUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, employee.getName());
ps.setString(2, employee.getGender());
ps.setString(3, employee.getDepartment());
ps.setString(4, employee.getPosition());
ps.setString(5, employee.getPhone());
ps.setString(6, employee.getEmail());
int rows = ps.executeUpdate();
return rows > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
代码逻辑分析:
- 使用
PreparedStatement插入数据,防止SQL注入。 executeUpdate()执行插入语句,返回受影响的行数。- 若插入成功,返回
true,否则返回false。
参数说明:
- executeUpdate() :执行更新操作(INSERT、UPDATE、DELETE)。
- rows > 0 :判断是否插入成功。
6.3 员工信息的修改功能
修改功能用于更新已有的员工信息,需先加载数据到界面供用户编辑,再将修改后的数据提交到数据库。
6.3.1 数据的加载与编辑
修改功能需要先从数据库加载员工信息,并将其显示在表单中。
public Employee getEmployeeById(int id) {
String sql = "SELECT * FROM employee WHERE id = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
Employee emp = new Employee();
emp.setId(rs.getInt("id"));
emp.setName(rs.getString("name"));
emp.setGender(rs.getString("gender"));
emp.setDepartment(rs.getString("department"));
emp.setPosition(rs.getString("position"));
emp.setPhone(rs.getString("phone"));
emp.setEmail(rs.getString("email"));
return emp;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
代码逻辑分析:
- 使用
PreparedStatement按ID查询员工信息。 ResultSet读取结果集并封装为Employee对象。- 若未找到记录,返回
null。
6.3.2 修改后数据的提交与更新
修改完成后,将更新后的数据提交到数据库。
public boolean updateEmployee(Employee employee) {
String sql = "UPDATE employee SET name=?, gender=?, department=?, position=?, phone=?, email=? WHERE id=?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, employee.getName());
ps.setString(2, employee.getGender());
ps.setString(3, employee.getDepartment());
ps.setString(4, employee.getPosition());
ps.setString(5, employee.getPhone());
ps.setString(6, employee.getEmail());
ps.setInt(7, employee.getId());
int rows = ps.executeUpdate();
return rows > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
代码逻辑分析:
- 使用
PreparedStatement执行UPDATE语句。 WHERE id=?保证更新的是指定员工。- 若更新成功,返回
true。
6.4 员工信息的删除功能
删除功能负责从数据库中移除员工信息。为了数据安全,系统应提供删除确认机制,并支持软删除与物理删除两种方式。
6.4.1 删除确认机制
删除操作前,应弹出确认对话框,防止误删。
int confirm = JOptionPane.showConfirmDialog(null, "确定要删除该员工信息吗?", "删除确认", JOptionPane.YES_NO_OPTION);
if (confirm == JOptionPane.YES_OPTION) {
deleteEmployeeById(employeeId);
}
代码逻辑分析:
JOptionPane.showConfirmDialog()弹出确认框。- 若用户选择“是”,调用删除方法。
6.4.2 数据的软删除与物理删除
物理删除
public boolean deleteEmployeeById(int id) {
String sql = "DELETE FROM employee WHERE id = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id);
int rows = ps.executeUpdate();
return rows > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
软删除(推荐做法)
软删除通过添加 is_deleted 字段标记删除状态。
ALTER TABLE employee ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE;
public boolean softDeleteEmployee(int id) {
String sql = "UPDATE employee SET is_deleted = TRUE WHERE id = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id);
int rows = ps.executeUpdate();
return rows > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
代码逻辑分析:
- 物理删除使用
DELETE语句直接删除记录。 - 软删除使用
UPDATE语句将is_deleted字段设为TRUE。 - 查询时应添加
WHERE is_deleted = FALSE过滤已删除数据。
本章总结:
本章详细讲解了员工信息增删改查功能的实现流程,涵盖了界面设计、数据校验、SQL语句编写、DAO操作等多个方面。通过具体代码示例和流程图,展示了如何在Java Swing应用中实现完整的CRUD操作,并对删除功能进行了软删除与物理删除的对比分析,为系统的数据安全与性能优化提供了参考方案。
7. Java桌面应用程序开发流程
7.1 项目开发流程概述
7.1.1 需求分析与功能规划
在开发Java桌面应用程序之前,首先需要明确项目的目标和用户需求。以人事管理系统为例,核心功能包括员工信息管理、部门管理、权限控制等。需求分析阶段应明确以下几点:
- 用户角色(如管理员、普通员工)
- 各角色的操作权限
- 系统主界面布局与功能模块划分
- 数据库结构与交互逻辑
功能规划通常使用任务分解表进行梳理,如下所示:
| 功能模块 | 子功能 | 功能描述 |
|---|---|---|
| 员工管理 | 增删改查 | 管理员工基本信息 |
| 部门管理 | 增删改查 | 管理部门信息 |
| 权限管理 | 角色分配、权限设置 | 控制用户访问权限 |
| 登录认证 | 用户登录 | 身份验证与权限加载 |
| 系统设置 | 数据库连接配置 | 修改数据库连接参数 |
7.1.2 技术选型与架构设计
Java桌面应用开发通常采用Swing作为GUI框架,结合MVC架构进行模块化设计。技术选型如下:
- 前端 :Java Swing + MVC架构
- 后端 :JDBC + DAO模式
- 数据库 :MySQL
- 连接池 :C3P0
- 日志 :Log4j 或 JDK Logging
- 构建工具 :Maven 或 Gradle(推荐使用Maven)
架构设计如下图所示,采用典型的三层架构:
graph TD
A[Swing View] --> B[Controller]
B --> C[Service Layer]
C --> D[DAO Layer]
D --> E[MySQL Database]
7.2 项目结构组织
7.2.1 包结构的划分与命名规范
为了便于维护和扩展,项目应采用清晰的包结构。推荐的包命名规范如下:
com.example.hrms
├── controller // 控制器类
├── view // Swing界面组件
├── model // 数据模型类(如Employee、Department)
├── dao // 数据访问对象
├── service // 业务逻辑处理
├── util // 工具类(如数据库连接工具)
├── config // 配置类
├── test // 测试类
命名建议:
- 类名采用大驼峰命名法(如
EmployeeService) - 方法名采用小驼峰命名法(如
getEmployeeById) - 常量使用全大写命名(如
MAX_RETRY_COUNT)
7.2.2 模块化开发与依赖管理
模块化开发是Java项目中推荐的开发模式。可以使用Maven进行依赖管理,确保各模块之间解耦。例如,在 pom.xml 中定义模块依赖:
<modules>
<module>hrms-model</module>
<module>hrms-dao</module>
<module>hrms-service</module>
<module>hrms-view</module>
</modules>
每个模块职责明确,便于测试与部署。
7.3 系统的部署与运行
7.3.1 可执行Jar文件的生成
使用Maven构建项目时,可以通过 maven-jar-plugin 插件生成可执行Jar文件。配置示例如下:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.example.hrms.MainApp</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
执行命令生成Jar文件:
mvn clean package
生成的Jar文件位于 target/ 目录下,可以直接运行:
java -jar hrms-app.jar
7.3.2 系统运行环境配置
为确保系统顺利运行,需配置以下环境:
- JRE环境 :确保目标机器安装JRE 1.8或以上版本
- 数据库连接配置 :在
config/db.properties文件中配置数据库连接参数:
db.url=jdbc:mysql://localhost:3306/hrms
db.user=root
db.password=123456
- 日志输出路径 :Log4j配置日志输出路径,便于排查问题
7.4 调试与测试方法
7.4.1 单元测试与集成测试
使用JUnit进行单元测试,验证DAO与Service层逻辑是否正确。例如:
@Test
public void testGetEmployeeById() {
EmployeeDAO dao = new EmployeeDAO();
Employee emp = dao.getEmployeeById(1);
assertNotNull(emp);
assertEquals("张三", emp.getName());
}
集成测试则需模拟真实数据库连接,验证各层之间的交互是否正常。
7.4.2 系统调试技巧与日志记录
在Swing界面中添加日志输出面板,可以实时查看程序运行状态。推荐使用Log4j配置日志级别:
log4j.rootLogger=DEBUG, console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
调试时可通过以下方式输出关键变量:
import org.apache.log4j.Logger;
private static final Logger logger = Logger.getLogger(EmployeeController.class);
public void loadEmployeeData() {
logger.info("开始加载员工数据...");
try {
List<Employee> employees = employeeService.getAllEmployees();
logger.debug("查询到 " + employees.size() + " 条员工记录");
} catch (Exception e) {
logger.error("加载员工数据失败", e);
}
}
通过日志记录,可以快速定位界面操作、数据库连接、数据处理等各环节的异常情况,提升调试效率。
简介:本项目是一个基于Java Swing和MySQL实现的人事管理系统,适用于课程设计与Java初学者实践。系统采用Swing构建桌面端用户界面,使用MySQL存储员工信息,并通过JDBC实现数据库连接。项目采用MVC架构设计,包含DAO层与业务逻辑层,实现员工信息的增删改查功能。附带运行视频,便于理解和学习Java桌面应用开发流程,涵盖GUI编程、数据库操作与模块化开发等核心知识点。
更多推荐


所有评论(0)