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 石头迷阵

相关推荐
海兰8 小时前
【第21篇-续】graph-Stream-Node改造为适配openAI模型示例
java·人工智能·spring boot·spring·spring ai
vKd0Ff21L8 小时前
如何在Dev-C++中设置TDM-GCC为默认编译器第九十一篇
java·jvm·c++
武子康8 小时前
Java-221 RocketMQ 消息存储核心原理:CommitLog、ConsumerQueue、IndexFile 与消息过滤机制
java·大数据·分布式·消息队列·rabbitmq·rocketmq·java-rocketmq
北风toto8 小时前
为什么 IntelliJ IDEA Community 无法开发 Vue?——附解决方案
java·vue.js·intellij-idea
programhelp_8 小时前
Google 2026 New Grad SDE VO 三轮面试详解 | 含Behavioral、Coding、Design
java·服务器·数据库
froginwe118 小时前
Vue.js 监听属性
开发语言
c++逐梦人8 小时前
五种IO模型与⾮阻塞IO
开发语言·网络
翎沣8 小时前
C++面向对象三大特性
开发语言·c++
驭渊的小故事8 小时前
java中的进程的详细解析
java·开发语言