本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本项目是一个基于Java Swing和MySQL实现的人事管理系统,适用于课程设计与Java初学者实践。系统采用Swing构建桌面端用户界面,使用MySQL存储员工信息,并通过JDBC实现数据库连接。项目采用MVC架构设计,包含DAO层与业务逻辑层,实现员工信息的增删改查功能。附带运行视频,便于理解和学习Java桌面应用开发流程,涵盖GUI编程、数据库操作与模块化开发等核心知识点。
Swing_mysql

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驱动并建立连接。以下是建立连接的步骤:

  1. 加载驱动类:
Class.forName("com.mysql.cj.jdbc.Driver");
  1. 建立连接:
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);
    }
}

通过日志记录,可以快速定位界面操作、数据库连接、数据处理等各环节的异常情况,提升调试效率。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本项目是一个基于Java Swing和MySQL实现的人事管理系统,适用于课程设计与Java初学者实践。系统采用Swing构建桌面端用户界面,使用MySQL存储员工信息,并通过JDBC实现数据库连接。项目采用MVC架构设计,包含DAO层与业务逻辑层,实现员工信息的增删改查功能。附带运行视频,便于理解和学习Java桌面应用开发流程,涵盖GUI编程、数据库操作与模块化开发等核心知识点。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

更多推荐