1 基于Swing的Java人事管理系统开发手记
1.1 项目背景与目标
作为一名刚刚掌握了面向对象编程和Java GUI(Swing)知识的开发者,我决定通过一个完整的项目来巩固所学。我选择开发一个人事管理系统,因为它涵盖了从用户界面到数据管理的完整流程,非常适合作为练手项目。
项目核心目标:
- 运用面向对象思想设计系统架构。
- 使用Swing构建直观的图形用户界面。
- 实现人事信息的增、删、改、查(CRUD)核心功能。
- 将理论知识转化为可运行的桌面应用程序。
1.2 技术栈与开发环境
技术选型:
- GUI框架:Java Swing。这是我刚学完的技术,用它来构建桌面界面正合适。
- 数据存储 :为了简化,第一期使用
ArrayList在内存中模拟数据持久化。后续可扩展为文件存储(如序列化对象)或连接数据库(如MySQL)。 - 开发工具:IntelliJ IDEA 。
- JDK版本:Java 8 或以上。
为什么选择Swing?
- 它是Java标准库的一部分,无需额外依赖。
- 组件丰富,足以构建功能完善的桌面应用。
- 学习曲线相对平缓,适合巩固GUI编程基础。
1.3 系统设计与类图规划
在编码之前,我先进行面向对象的设计。核心是识别系统中的实体(类)和它们之间的关系。
1.3.1 核心实体类
-
Employee(员工类)
- 属性:id(工号)、name(姓名)、department(部门)、position(职位)、entryDate(入职日期)、salary(薪资)、phone(电话)。
- 方法:构造方法、getter/setter。
-
User(用户类) - 用于登录验证
- 属性:username(用户名)、password(密码)。
- 方法:构造方法、验证方法。
1.3.2 界面窗体类
- LoginUI(登录窗口) :继承
JFrame,包含用户名、密码输入框和登录按钮。 - EmployeeManagerUI(主管理窗口) :继承
JFrame,包含菜单栏、工具栏、员工信息表格(JTable)和操作按钮。 - EmployeeDialog(员工信息对话框) :继承
JDialog,用于添加或编辑员工信息的表单。
1.3.3 类关系示意图
1.4 开发步骤分解
我将按照以下步骤,边学边做,记录这个项目的完整构建过程。
步骤一:搭建项目结构与创建实体类
- 在IDE中创建新的Java项目。
- 创建
com.wfs.employeeSys.javabean包,在其中定义Employee和User类。

步骤二:构建登录界面(LoginUI)
- 创建
com.wfs.employeeSys.UI包。 - 设计登录窗口布局。
- 为登录按钮添加事件监听器,实现简单的用户名密码验证(可硬编码一个测试账户)。
- 验证通过后,关闭登录窗口,打开主管理窗口(EmployeeManagerUI)。
步骤三:构建主管理界面(EmployeeManagerUI)
这是最复杂的部分。
- 创建窗体类:继承 JFrame,在构造方法中调用初始化并显示。
- 设置窗体属性:位置、大小、关闭操作、布局(BorderLayout)。
- 顶部面板:放搜索框、搜索按钮、添加按钮(FlowLayout)。
- 表格模型:DefaultTableModel 定义列名,重写 isCellEditable 禁止编辑。
- 表格与滚动窗格:JTable + JScrollPane,设置行高。
- 填充演示数据:循环 model.addRow 添加 20 条模拟数据。
- 右键菜单:JPopupMenu 添加"编辑""删除"项,给表格加鼠标监听器(右键弹出)。
- 菜单项事件:获取选中行,弹出提示(实际应实现编辑/删除逻辑)。
- 按钮事件:搜索和添加按钮的监听器(暂为空实现)。
- 添加组件:顶部面板放 NORTH,滚动窗格放 CENTER。
1.5 关键代码片段示例
1.5.1 实体类
java
// Employee类:用于主界面展示
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private int id;
private String name;
private String sex;
private int age;
private String phone;
private String position;
private String entryDate;
private double salary;
private String department;
}
// User类:用于注册登录
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String loginName; // 登录名
private String password; // 密码
}
1.5.2 LoginUI界面
java
package com.wfs.employeeSys.UI;
import com.wfs.employeeSys.javabean.User;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
public class LoginUI extends JFrame implements ActionListener {
private JTextField usernameField; // 用户名输入框
private JPasswordField passwordField; // 密码输入框
private JButton loginButton; // 登录按钮
private JButton registerButton; // 注册按钮
private static ArrayList<User> users = new ArrayList<>();
static {
users.add(new User("Wufsh", "123456"));
users.add(new User("WangSi", "123456"));
users.add(new User("LiuChi", "123456"));
}
public LoginUI() {
super("登录界面");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 400);
this.setLocationRelativeTo(null); // 居中显示
createAndShowGUI();
}
private void createAndShowGUI() {
// 创建主窗口
// 创建面板
JPanel panel = new JPanel();
panel.setLayout(null);
panel.setBackground(new Color(240, 240, 240));
// 设置字体和颜色
Font customFont = new Font("楷体", Font.BOLD, 18);
Color primaryColor = new Color(66, 135, 245);
Color secondaryColor = new Color(204, 204, 204); // 更浅的颜色用于注册按钮
// 标题
JLabel titleLabel = new JLabel("人事管理系统");
titleLabel.setBounds(50, 30, 300, 30);
titleLabel.setFont(new Font("楷体", Font.BOLD, 24));
panel.add(titleLabel);
// 用户名标签
JLabel usernameLabel = new JLabel("用户名:");
usernameLabel.setBounds(50, 100, 150, 30);
usernameLabel.setFont(customFont);
panel.add(usernameLabel);
// 用户名输入框
usernameField = new JTextField();
usernameField.setBounds(160, 100, 190, 30);
usernameField.setFont(customFont);
panel.add(usernameField);
// 密码标签
JLabel passwordLabel = new JLabel("密 码:");
passwordLabel.setBounds(50, 150, 150, 30);
passwordLabel.setFont(customFont);
panel.add(passwordLabel);
// 密码输入框
passwordField = new JPasswordField();
passwordField.setBounds(160, 150, 190, 30);
passwordField.setFont(customFont);
panel.add(passwordField);
// 登录按钮
loginButton = new JButton("登 录");
loginButton.setBounds(50, 200, 150, 30);
loginButton.setFont(customFont);
loginButton.setBackground(primaryColor);
loginButton.setForeground(Color.WHITE);
panel.add(loginButton);
loginButton.addActionListener(this);
// 注册按钮
registerButton = new JButton("注 册");
registerButton.setBounds(200, 200, 150, 30);
registerButton.setFont(customFont);
registerButton.setBackground(secondaryColor);
registerButton.setForeground(Color.BLACK);
panel.add(registerButton);
registerButton.addActionListener(this);
// 添加面板到窗口
this.add(panel);
this.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
// 这里可能是登录按钮点击过来的,也可能是注册按钮点击过来的。
// 判断到底是登录还是注册按钮点击的。
JButton btn = (JButton) e.getSource();
if (btn == loginButton) {
// 独立功能独立成方法;
login();
}else {
System.out.println("注册过来的");
}
}
private void login() {
// 1、获取用户输入的用户名和密码
String userName = usernameField.getText();
String password = new String(passwordField.getPassword());
// 2、遍历集合,判断用户输入的用户名和密码是否和集合中的对象匹配。 匹配成功,则登录成功。
// 3、根据登录名称去查询用户对象返回。查询到用户对象,说明登录名称正确了。
User user = getUserByLoginName(userName);
if (user != null) {
// 4、判断密码是否正确。
if (user.getPassword().equals(password)) {
// 登录成功
System.out.println("登录成功!");
// 跳转到员工管理界面
new EmployeeManagerUI();
this.dispose(); // 关闭当前登录界面
}else {
// 密码错误
JOptionPane.showMessageDialog(this, "密码错误!");
}
}else {
JOptionPane.showMessageDialog(this, "登录名称不存在!");
}
}
private User getUserByLoginName(String loginName) {
for (int i = 0; i < users.size(); i++) {
User user = users.get(i);
if (user.getLoginName().equals(loginName)) {
return user;
}
}
return null; // 没有查询到用户对象,说明登录名称不正确。
}
}
1.5.3 EmployeeManagerUI界面
java
package com.wfs.employeeSys.UI;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class EmployeeManagerUI extends JFrame {
private JFrame frame;
private JTable table;
private DefaultTableModel model;
private JTextField textFieldSearch;
public EmployeeManagerUI() {
frame = this;
initialize();
frame.setVisible(true);
}
private void initialize() {
frame.setBounds(100, 100, 800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
// 输入框和搜索按钮
JPanel topPanel = new JPanel();
topPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
textFieldSearch = new JTextField(20);
JButton btnSearch = new JButton("搜索");
JButton btnAdd = new JButton("添加");
topPanel.add(textFieldSearch);
topPanel.add(btnSearch);
topPanel.add(btnAdd);
// 创建表格模型
model = new DefaultTableModel(
new Object[][]{},
new String[]{"ID", "姓名", "职位", "部门"}
) {
@Override
public boolean isCellEditable(int row, int column) {
return false; // 设置所有单元格为不可编辑
}
};
table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
table.setRowHeight(30);
// 添加数据到表格
for (int i = 0; i < 20; i++) {
model.addRow(new Object[]{i + 1, "员工" + (i + 1), "职位" + (i + 1), "部门" + (i + 1)});
}
// 右键菜单
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem editItem = new JMenuItem("编辑");
JMenuItem deleteItem = new JMenuItem("删除");
popupMenu.add(editItem);
popupMenu.add(deleteItem);
table.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) { // 明确检查是否为鼠标右键
int row = table.rowAtPoint(e.getPoint());
if (row >= 0) {
table.setRowSelectionInterval(row, row);
popupMenu.show(table, e.getX(), e.getY());
}
}
}
});
// 绑定事件到菜单项
editItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = table.getSelectedRow();
if (selectedRow >= 0) {
int id = (Integer) model.getValueAt(selectedRow, 0); // 假设ID在第一列
JOptionPane.showMessageDialog(frame, "删除 ID: " + id);
// 这里可以添加编辑逻辑,比如打开一个新的对话框让用户修改数据
}
}
});
deleteItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = table.getSelectedRow();
if (selectedRow >= 0) {
int id = (Integer) model.getValueAt(selectedRow, 0); // 假设ID在第一列
JOptionPane.showMessageDialog(frame, "删除 ID: " + id);
// 这里可以添加删除逻辑,比如从模型中移除该行
}
}
});
// 搜索按钮监听器
btnSearch.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String searchValue = textFieldSearch.getText();
// 这里可以添加搜索逻辑
}
});
// 添加按钮监听器
btnAdd.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 这里可以添加添加新员工的逻辑
}
});
frame.getContentPane().add(topPanel, BorderLayout.NORTH);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
}
}
6. 注意事项(自己踩的坑)
6.1 loginUI事件触发器的实现方式
LoginUI 中事件触发器的实现采用了 类自身实现监听器接口 的方式(即 implements ActionListener)。具体步骤如下:
-
让窗体类实现监听器接口

-
重写接口中的事件处理方法

-
为事件源(按钮)注册监听器
