Java基础篇09:项目实战

1 基于Swing的Java人事管理系统开发手记

1.1 项目背景与目标

作为一名刚刚掌握了面向对象编程和Java GUI(Swing)知识的开发者,我决定通过一个完整的项目来巩固所学。我选择开发一个人事管理系统,因为它涵盖了从用户界面到数据管理的完整流程,非常适合作为练手项目。

项目核心目标:

  1. 运用面向对象思想设计系统架构。
  2. 使用Swing构建直观的图形用户界面。
  3. 实现人事信息的增、删、改、查(CRUD)核心功能。
  4. 将理论知识转化为可运行的桌面应用程序。

1.2 技术栈与开发环境

技术选型:

  • GUI框架:Java Swing。这是我刚学完的技术,用它来构建桌面界面正合适。
  • 数据存储 :为了简化,第一期使用ArrayList在内存中模拟数据持久化。后续可扩展为文件存储(如序列化对象)或连接数据库(如MySQL)。
  • 开发工具:IntelliJ IDEA 。
  • JDK版本:Java 8 或以上。

为什么选择Swing?

  • 它是Java标准库的一部分,无需额外依赖。
  • 组件丰富,足以构建功能完善的桌面应用。
  • 学习曲线相对平缓,适合巩固GUI编程基础。

1.3 系统设计与类图规划

在编码之前,我先进行面向对象的设计。核心是识别系统中的实体(类)和它们之间的关系。

1.3.1 核心实体类

  1. Employee(员工类)

    • 属性:id(工号)、name(姓名)、department(部门)、position(职位)、entryDate(入职日期)、salary(薪资)、phone(电话)。
    • 方法:构造方法、getter/setter。
  2. User(用户类) - 用于登录验证

    • 属性:username(用户名)、password(密码)。
    • 方法:构造方法、验证方法。

1.3.2 界面窗体类

  1. LoginUI(登录窗口) :继承JFrame,包含用户名、密码输入框和登录按钮。
  2. EmployeeManagerUI(主管理窗口) :继承JFrame,包含菜单栏、工具栏、员工信息表格(JTable)和操作按钮。
  3. EmployeeDialog(员工信息对话框) :继承JDialog,用于添加或编辑员工信息的表单。

1.3.3 类关系示意图

1.4 开发步骤分解

我将按照以下步骤,边学边做,记录这个项目的完整构建过程。

步骤一:搭建项目结构与创建实体类

  1. 在IDE中创建新的Java项目。
  2. 创建com.wfs.employeeSys.javabean包,在其中定义EmployeeUser类。

步骤二:构建登录界面(LoginUI)

  1. 创建com.wfs.employeeSys.UI包。
  2. 设计登录窗口布局。
  3. 为登录按钮添加事件监听器,实现简单的用户名密码验证(可硬编码一个测试账户)。
  4. 验证通过后,关闭登录窗口,打开主管理窗口(EmployeeManagerUI)。

步骤三:构建主管理界面(EmployeeManagerUI)

这是最复杂的部分。

  1. 创建窗体类:继承 JFrame,在构造方法中调用初始化并显示。
  2. 设置窗体属性:位置、大小、关闭操作、布局(BorderLayout)。
  3. 顶部面板:放搜索框、搜索按钮、添加按钮(FlowLayout)。
  4. 表格模型:DefaultTableModel 定义列名,重写 isCellEditable 禁止编辑。
  5. 表格与滚动窗格:JTable + JScrollPane,设置行高。
  6. 填充演示数据:循环 model.addRow 添加 20 条模拟数据。
  7. 右键菜单:JPopupMenu 添加"编辑""删除"项,给表格加鼠标监听器(右键弹出)。
  8. 菜单项事件:获取选中行,弹出提示(实际应实现编辑/删除逻辑)。
  9. 按钮事件:搜索和添加按钮的监听器(暂为空实现)。
  10. 添加组件:顶部面板放 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)。具体步骤如下:

  1. 让窗体类实现监听器接口

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

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

2 石头迷阵

相关推荐
Scott9999HH2 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔2 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社3 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海3 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖4 小时前
JDK 26 新特性详解
java·开发语言
马优晨5 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区7 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大7 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai8 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说8 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json