YangeIT大约 24 分钟JDKIdeaSwingGui

1. 搭建项目UI页面

1.1 项目UI说明

前言

image
image

常用组件:👇

  • JFrame:窗口,是所有窗口的父类,它是所有窗口的基类。
  • JPanel:面板,是所有面板的父类,它是所有面板的基类。
  • JLabel:标签,用于显示文本或图像。
  • JButton:按钮,用于触发事件。
  • JTextField:文本框,用于输入文本。
  • JPasswordField:密码框,用于输入密码。
  • JComboBox:下拉框,用于选择选项。
  • JList:列表框,用于显示列表项。
  • JTable:表格,用于显示表格数据。
  • JScrollPane:滚动面板,用于包含可滚动的组件。
  • JToolBar:工具栏,用于放置工具按钮。
  • JMenu:菜单,用于创建菜单栏。

说明:👇

  1. JFrame是最外层的容器,可以包含其他组件。其他的组件如JPanel、JLabel、JButton等都是JFrame的子组件。
  2. JPanel是一个容器,可以包含其他组件。JLabel、JButton等组件都是JPanel的子组件。

1.2 搭建主页面

前言

欢迎页面 👇

image
image

代码如下:👇

// 欢迎页面
public class WelcomeUI extends JFrame {
    public WelcomeUI() {
        initialize();
    }

    private void initialize() {
        // 设置窗口标题
        setTitle("黑马医药管理系统");
        // 设置窗口大小
        setSize(500, 400);
        // 设置窗口居中显示
        setLocationRelativeTo(null);
        // 设置窗口关闭时退出程序
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 设置布局
        setLayout(new BorderLayout());

        // 创建主面板,使用网格布局来垂直排列组件
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));// 使用垂直布局
        mainPanel.setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50)); // 设置边距

        // 标题标签
        JLabel titleLabel = new JLabel("欢迎使用黑马医药管理系统", JLabel.CENTER);
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
        titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); // 横向居中
        titleLabel.setMaximumSize(new Dimension(Integer.MAX_VALUE, titleLabel.getPreferredSize().height)); // 设置最大宽度以保持居中
        mainPanel.add(titleLabel);
        mainPanel.add(Box.createVerticalStrut(50)); // 添加垂直间距

        // 登录按钮
        JButton loginButton = new JButton("登录");
        loginButton.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        loginButton.setMaximumSize(new Dimension(180,40));
        loginButton.setAlignmentX(Component.CENTER_ALIGNMENT); // 横向居中
        loginButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //todo 切换到登录界面
                WelcomeUI.this.setVisible(false);
            }
        });
        mainPanel.add(loginButton);
        mainPanel.add(Box.createVerticalStrut(20)); // 添加垂直间距

        // 注册按钮
        JButton registerButton = new JButton("注册");
        registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        registerButton.setMaximumSize(new Dimension(180,40));
        registerButton.setAlignmentX(Component.CENTER_ALIGNMENT); // 横向居中
        registerButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //todo 切换到注册界面
                WelcomeUI.this.setVisible(false);
            }
        });
        mainPanel.add(registerButton);
        mainPanel.add(Box.createVerticalStrut(20)); // 添加垂直间距

        // 退出按钮
        JButton exitButton = new JButton("退出");
        exitButton.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        exitButton.setMaximumSize(new Dimension(180,40));
        exitButton.setAlignmentX(Component.CENTER_ALIGNMENT); // 横向居中
        exitButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0); // 退出程序
            }
        });
        mainPanel.add(exitButton);

        // 将主面板添加到窗口
        add(mainPanel, BorderLayout.CENTER);
    }
}








































 














 























接下来,要点击登录按钮,切换到登录界面,点击注册按钮,切换到注册界面,点击退出按钮,退出程序。

image
image

考虑到2个页面的布局基本一致,所以可以抽取一个公共的页面UserUI页面

登录页面 👇

public class UserUI extends JFrame {
    private String mode; // "login" 或 "register"
    // 登录界面组件
    private JTextField loginUsernameField;
    private JPasswordField loginPasswordField;

    // 注册界面组件
    private JTextField registerUsernameField;
    private JPasswordField registerPasswordField;
    private JPasswordField registerConfirmPasswordField;
    private JTextField nameField; // 新增姓名输入框
    private JTextField phoneField;
    private JTextField codeField;
    private JButton sendCodeButton;

    public UserUI(String mode) {
        this.mode = mode;
        initialize();
    }

    private void initialize() {
        // 设置窗口标题
        setTitle(mode.equals("login") ? "用户登录" : "用户注册");
        // 设置窗口大小
        setSize(500, mode.equals("login") ? 380 : 580);
        // 设置窗口居中显示
        setLocationRelativeTo(null);
        // 设置窗口关闭时仅隐藏窗口,不退出程序
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        // 创建主面板
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
        mainPanel.setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50));

        // 添加标题
        JLabel titleLabel = new JLabel(mode.equals("login") ? "用户登录" : "用户注册", JLabel.CENTER);
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
        titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        mainPanel.add(titleLabel);
        mainPanel.add(Box.createVerticalStrut(40));

        if (mode.equals("login")) {
            createLoginPanel(mainPanel);
        } else {
            createRegisterPanel(mainPanel);
        }

        add(mainPanel);
    }

    // 创建登录界面
    private void createLoginPanel(JPanel mainPanel) {
        // 创建一个使用GridBagLayout的面板来对齐标签和输入框
        JPanel formPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5); // 设置组件间距

        // 用户名行
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.EAST;
        JLabel loginUsernameLabel = new JLabel("用户名:");
        loginUsernameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        formPanel.add(loginUsernameLabel, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        loginUsernameField = new JTextField(20);
        loginUsernameField.setPreferredSize(new Dimension(200, 30));
        formPanel.add(loginUsernameField, gbc);

        // 密码行
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.anchor = GridBagConstraints.EAST;
        JLabel loginPasswordLabel = new JLabel("密码:");
        loginPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        formPanel.add(loginPasswordLabel, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        loginPasswordField = new JPasswordField(20);
        loginPasswordField.setPreferredSize(new Dimension(200, 30));
        formPanel.add(loginPasswordField, gbc);

        mainPanel.add(formPanel);
        mainPanel.add(Box.createVerticalStrut(30));

        // 按钮行
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 0));
        JButton loginButton = new JButton("登录");
        loginButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        loginButton.setPreferredSize(new Dimension(100, 35));
        loginButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                handleLogin();
            }
        });
        buttonPanel.add(loginButton);

        JButton loginReturnButton = new JButton("返回");
        loginReturnButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        loginReturnButton.setPreferredSize(new Dimension(100, 35));
        loginReturnButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                returnToWelcome();
            }
        });
        buttonPanel.add(loginReturnButton);
        mainPanel.add(buttonPanel);
    }

    // 创建注册界面
    private void createRegisterPanel(JPanel mainPanel) {
        // 创建一个使用GridBagLayout的面板来对齐标签和输入框
        JPanel formPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5); // 设置组件间距

        // 用户名行
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.EAST;
        JLabel registerUsernameLabel = new JLabel("用户名:");
        registerUsernameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        formPanel.add(registerUsernameLabel, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        registerUsernameField = new JTextField(20);
        registerUsernameField.setPreferredSize(new Dimension(200, 30));
        formPanel.add(registerUsernameField, gbc);

        // 密码行
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.anchor = GridBagConstraints.EAST;
        JLabel registerPasswordLabel = new JLabel("密码:");
        registerPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        formPanel.add(registerPasswordLabel, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        registerPasswordField = new JPasswordField(20);
        registerPasswordField.setPreferredSize(new Dimension(200, 30));
        formPanel.add(registerPasswordField, gbc);

        // 确认密码行
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.anchor = GridBagConstraints.EAST;
        JLabel registerConfirmPasswordLabel = new JLabel("确认密码:");
        registerConfirmPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        formPanel.add(registerConfirmPasswordLabel, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        registerConfirmPasswordField = new JPasswordField(20);
        registerConfirmPasswordField.setPreferredSize(new Dimension(200, 30));
        formPanel.add(registerConfirmPasswordField, gbc);

        // 姓名行 - 新增
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.anchor = GridBagConstraints.EAST;
        JLabel nameLabel = new JLabel("姓名:");
        nameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        formPanel.add(nameLabel, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        nameField = new JTextField(20);
        nameField.setPreferredSize(new Dimension(200, 30));
        formPanel.add(nameField, gbc);

        // 手机号行
        gbc.gridx = 0;
        gbc.gridy = 4; // 原来是3,现在因为新增姓名行变成4
        gbc.anchor = GridBagConstraints.EAST;
        JLabel phoneLabel = new JLabel("手机号:");
        phoneLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        formPanel.add(phoneLabel, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        JPanel phoneFieldPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
        phoneField = new JTextField(12); // 减小宽度以适应验证码按钮
        phoneField.setPreferredSize(new Dimension(120, 30));
        sendCodeButton = new JButton("发送验证码");
        sendCodeButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        sendCodeButton.setMaximumSize(new Dimension(90, 30));
        sendCodeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                handleSendCode();
            }
        });
        phoneFieldPanel.add(phoneField);
        phoneFieldPanel.add(sendCodeButton);
        formPanel.add(phoneFieldPanel, gbc);

        // 验证码行
        gbc.gridx = 0;
        gbc.gridy = 5; // 原来是4,现在因为新增姓名行变成5
        gbc.anchor = GridBagConstraints.EAST;
        JLabel codeLabel = new JLabel("验证码:");
        codeLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        formPanel.add(codeLabel, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        codeField = new JTextField(20);
        codeField.setPreferredSize(new Dimension(200, 30));
        formPanel.add(codeField, gbc);

        mainPanel.add(formPanel);
        mainPanel.add(Box.createVerticalStrut(30));

        // 按钮行
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 0));
        JButton registerButton = new JButton("注册");
        registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        registerButton.setPreferredSize(new Dimension(100, 35));
        registerButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                handleRegister();
            }
        });
        buttonPanel.add(registerButton);

        JButton registerReturnButton = new JButton("返回");
        registerReturnButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        registerReturnButton.setPreferredSize(new Dimension(100, 35));
        registerReturnButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                returnToWelcome();
            }
        });
        buttonPanel.add(registerReturnButton);
        mainPanel.add(buttonPanel);
    }

    // 处理登录逻辑
    private void handleLogin() {
        //todo 处理登录逻辑
        System.out.println("登录按钮点击");
        //        直接跳转到主页HomeuI
        TUser user = new TUser();
        user.setUsername(loginUsernameField.getText());
        HomeUI homeUI = new HomeUI(user);
        homeUI.setVisible(true);
        dispose();
    }

    // 处理注册逻辑
    private void handleRegister() {
        // todo 处理注册逻辑
        System.out.println("注册按钮点击");
    }

    // 处理发送验证码
    private void handleSendCode() {
        /// todo 处理发送验证码逻辑
        System.out.println("发送验证码按钮点击");
    }

    // 返回欢迎界面
    private void returnToWelcome() {
        WelcomeUI welcomeUI = new WelcomeUI();
        welcomeUI.setVisible(true);
        dispose(); // 关闭当前窗口
    }
}
























































































































































































































































 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 














注意: 上述UI代码,初版大家可以复制老师的,后期我们通过AI帮我们生成,然后在进行修改,这样工作量会少很多,当然里面的逻辑我们自己来实现。

HomeUI页面,这里我们搞个空白页面,后续我们再添加内容。

public class HomeUI extends JFrame {

    public HomeUI(TUser user) {//通过·构造方法传递用户信息
        setTitle("主页");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);
        setLocationRelativeTo(null);

        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout());

        // 添加一个空白面板
        JPanel blankPanel = new JPanel(); // 空白面板
        //添加文字
        JLabel label = new JLabel(user.getNickname()+" 欢迎来到主页");
        label.setFont(new Font("微软雅黑", Font.BOLD, 24));
        blankPanel.add(label);
        mainPanel.add(blankPanel, BorderLayout.CENTER);


        setContentPane(mainPanel);
    }
}









 
 












启动类 👇


/**
 * @Description 项目启动类
 */
public class Application {

    public static void main(String[] args) throws Exception {
        // 设置 FlatLaf 主题 白天模式
        UIManager.setLookAndFeel(new FlatLightLaf());
        //UIManager.setLookAndFeel(new FlatDarkLaf());

        // 启动欢迎界面
        java.awt.EventQueue.invokeLater(() -> new WelcomeUI().setVisible(true));

        System.out.println("项目启动...");

        //testUserMapper();
    }

    private static void testUserMapper() {
        //1. 创建UserDao
        UserDao userDao = new UserDao();
        //2. 调用userDao的方法
        TUser user = userDao.getUserByUsername("zhangsan");
        //3. 输出结果
        System.out.println(user);
    }

}









 
 
 
 
 

















完成上述代码后,点击运行,确保按钮可以正常点击,且正常跳转到对应的页面。

image
image

上述的代码,大家可以复制,后期我们会通过AI帮我们生成,然后在进行修改,这样工作量会少很多,当然里面的逻辑我们自己来实现。

1.3 完成登录和退出逻辑

前言

image
image

从上图可以看到,我们需要实现的功能有:

  1. 登录逻辑
  2. 发送验证码逻辑
  3. 注册逻辑

1.3.1 完成登录逻辑 1️⃣

登录流程图
登录流程图
UserDao userDao = new UserDao();

private void handleLogin() {
    //1.获得组件中用户名和密码
    String username = loginUsernameField.getText().trim();
    String password = new String(loginPasswordField.getPassword()).trim();


    //2.判断用户名和密码是否为空,如果为空,提示用户名和密码不能为空
    if (username.isEmpty() || password.isEmpty()) {
        JOptionPane.showMessageDialog(this, "用户名和密码不能为空", "登录失败", JOptionPane.ERROR_MESSAGE);
        return;
    }
    //3.如果用户名和密码不为空,调用UserDao的getUserByUsername方法,并比较密码,如果密码正确,跳转到用户管理页面,如果密码错误,提示密码错误
    TUser user = userDao.getUserByUsername(username);
    if (user == null) {
        JOptionPane.showMessageDialog(this, "用户不存在", "登录失败", JOptionPane.ERROR_MESSAGE);
        return;
    }

    if (!user.getPassword().equals(password)) {
        JOptionPane.showMessageDialog(this, "密码错误", "登录失败", JOptionPane.ERROR_MESSAGE);
        return;
    }

    //4.登录成功后跳转到主界面
    HomeUI homeUI = new HomeUI();
    homeUI.setVisible(true);
    dispose(); // 关闭当前窗口

}



1.3.2 完成发送验证码逻辑 2️⃣

发送验证码流程图
发送验证码流程图
 private void handleSendCode() {
        String phone = phoneField.getText().trim();
        if (phone.isEmpty()) {
            JOptionPane.showMessageDialog(this, "请输入手机号", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        //使用hutool检查手机号码是否合法
        boolean isphone = PhoneUtil.isPhone(phone);
        if (!isphone) {
            JOptionPane.showMessageDialog(this, "手机号格式不正确", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        //模仿发送验证码成功
        JOptionPane.showMessageDialog(this, "验证码已发送", "提示", JOptionPane.INFORMATION_MESSAGE);

    }

1.3.3 完成注册逻辑 3️⃣

注册流程图
注册流程图
private void handleRegister() {
    // todo 处理注册逻辑
    //1.获得组件中用户名和密码 和确认密码
    String username = registerUsernameField.getText().trim();
    String password = new String(registerPasswordField.getPassword());
    String confirmPassword = new String(registerConfirmPasswordField.getPassword());
    String name = nameField.getText().trim(); // 获取姓名
    String phone = phoneField.getText().trim();
    String code = codeField.getText().trim();
    //2.判断用户名和密码是否为空,如果为空,提示用户名和密码不能为空
    ---
    自己补全
    ---
    //3.判断密码和确认密码是否一致,如果不一致,提示密码不一致
    ---
    自己补全
    ---

    //4.构建User对象
    TUser user = new TUser();
    ---
    自己补全
    ---


    //5.添加用户
    int count=自己补全
    // 判断添加结果
    if (count>0) {
        JOptionPane.showMessageDialog(this, "注册成功", "注册成功", JOptionPane.INFORMATION_MESSAGE);
        // 注册成功后返回欢迎界面
        returnToWelcome();
    } else {
        JOptionPane.showMessageDialog(this, "报错了", "注册失败", JOptionPane.ERROR_MESSAGE);
    }
}

1.4 完成HomeUI设计

前言

各位同学,截止到现在,我们已经完成了登录、注册、发送验证码等功能,接下来,我们需要完成HomeUI的设计。

结合之前的项目介绍,我们HomeUI界面中涉及到用户管理模块,分类管理模块,入库模块,出库模块,报表显示模块,以及退出登录模块。

考虑到我们页面布局工作繁琐,因此这项工作我们交给AI完成,完成后,我们可以进行调整,直到满意为止, 我们主要完成业务逻辑的实现。

接下来我们,来设计HomeUI界面基本布局

+-----------------------------------------------------+
|                  顶部菜单/标题栏           admin  [退出]           |
+-------------------+-------------------------------+
|  左侧导航区        |       右侧主内容区             |
|  [用户管理]        |                               |
|  [分类管理]        |   根据左侧选择显示不同功能界面   |
|  [入库模块]        |   (用户管理面板、入库面板等)   |
|  [出库模块]        |                               |
|  [报表显示]        |                               |
+-------------------+-------------------------------+

大模型提示词:👇 👇

HomeUI.java 开发需求
一、项目环境
• 登录:UserUI.java 登录成功 → 跳转 HomeUI.java;  
• 欢迎页:WelcomeUI.java(登录前展示);  
• 后续扩展:HomeUI 内容区嵌入 CategoryUI.java、MedicineUI.java UserManageUI.java, InboundUI.java, OutboundUI.java, ReportUI.java
• 技术:Java Swing,风格与现有界面一致。  

二、界面设计(苹果风格:简洁、留白、色调统一、控件圆润)

1. 整体布局

分三大部分:头部标题栏、侧边栏菜单、主要内容区域,用 BorderLayout/BoxLayout 组合,分区明确、自适应窗口。  

2. 头部标题栏(顶部一行)
• 左侧:固定文字 “黑马药品管理系统”(苹方/微软雅黑,加粗大字号,深灰/黑色);  
• 右侧:显示 登录用户姓名(从 TUser 对象获取)+ “[退出]”文字;  
• 交互:点击“退出” → 关闭 HomeUI,打开WelcomeUI.java;  
• 样式:浅灰/白色背景,控件间距均匀、适当留白。  

3. 侧边栏菜单(标题栏下左侧)
• 菜单项:垂直排列 分类管理、药品管理、入库管理、出库管理、报表统计、用户管理(可扩展);  
• 样式:矩形按钮(默认浅灰背景,悬停加深,点击激活变色);  
• 尺寸:宽固定(如 180px),高随窗口自适应;  
• 交互:点击菜单 → 右侧内容区切换对应界面(如 CategoryUI)。  

4. 主要内容区域(侧边栏右侧)
• 布局:用 CardLayout 管理面板(切换无闪烁);  
• 占位面板:  
  • CategoryUI:左上角显示“分类管理”;  
  • MedicineUI:左上角显示“药品管理”;
  • InboundUI:左上角显示“入库管理”;
  • OutboundUI:左上角显示“出库管理”;
  • UserManageUI:左上角显示“用户管理”;
  • ReportUI:左上角显示“报表统计”;
• 样式:白色背景,四周留白舒适。  

三、交互与逻辑

1. 用户信息:UserUI 传 TUser 对象(含姓名)到 HomeUI(构造方法传参或 setter),标题栏显示姓名;  
2. 菜单切换:事件监听联动,响应快、无卡顿;  
3. 退出:销毁 HomeUI,打开 Welcome,无残留窗口;  
4. 命名规范:组件名如 headerPanel、sideMenuPanel、contentPanel(便于维护)。  

四、风格一致性

• 色调:浅灰+白色为主,深灰文字,避免花哨;  
• 字体:系统无衬线字体(苹方/微软雅黑/SansSerif),字号层次分明;  
• 与 UserUI、WelcomeUI 背景、按钮、对话框风格统一。  

五、输出要求

1. 提供 HomeUI.java 完整可运行代码(含 import、成员变量、构造方法、界面初始化、事件绑定);  
2. 代码注释清晰(说明区域作用、主要逻辑);  
3. 用户信息传递方案明确(构造方法传参/setter);  
4. 暂不实现 CategoryUI.java、MedicineUI.java UserManageUI.java, InboundUI.java, OutboundUI.java, ReportUI.java 内部逻辑,仅返回占位 JPanel,显示一个文字说明即可。  

目标:符合 JavaSE Swing 规范,界面美观、交互流畅,无缝接入现有项目。



接下来创建一些空的面板,如 MedicineUI.java、InboundUI.java、OutboundUI.java、ReportUI.java、UserManageUI.java

image
image

public class MedicineUI extends JPanel {
    public MedicineUI() {
        super();
        this.setLayout(new BorderLayout());
        this.add(new JLabel("药品管理"), BorderLayout.NORTH);
    }
}

public class CategoryUI extends JPanel {
    public CategoryUI() {
        super();
        this.setLayout(new BorderLayout());
        this.add(new JLabel("分类管理"), BorderLayout.NORTH);
    }
}

public class InboundUI extends JPanel {
    public InboundUI() {
        super();
        this.setLayout(new BorderLayout());
        this.add(new JLabel("入库管理"), BorderLayout.NORTH);
    }
}

public class OutboundUI extends JPanel {
    public OutboundUI() {
        super();
        this.setLayout(new BorderLayout());
        this.add(new JLabel("出库管理"), BorderLayout.NORTH);
    }
}

public class ReportUI extends JPanel {
    public ReportUI() {
        super();
        this.setLayout(new BorderLayout());
        this.add(new JLabel("报表统计"), BorderLayout.NORTH);
    }
}

public class UserManageUI extends JPanel {
    
    public UserManageUI() {
        super();
        this.setLayout(new BorderLayout());
        this.add(new JLabel("用户管理"), BorderLayout.NORTH);
    }

}





利用IDea的tongyi灵码进行辅助编程 👇

image
image

AI生成的代码如下:


public class HomeUI extends JFrame {

    private TUser user;
    private JPanel contentPanel; // 内容面板
    private CardLayout cardLayout; // 卡片布局

    public HomeUI(TUser user) {
        this.user = user;
        initializeComponents();
    }

    private void initializeComponents() {
        setTitle("黑马医药管理系统");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1000, 700);
        setLocationRelativeTo(null);

        // 创建主面板,使用BorderLayout布局
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout());

        // 创建头部面板
        JPanel headerPanel = createHeaderPanel();
        mainPanel.add(headerPanel, BorderLayout.NORTH);

        // 创建中间内容面板(左右分栏)
        JPanel centerPanel = new JPanel();
        centerPanel.setLayout(new BorderLayout());

        // 创建侧边菜单栏
        JPanel sideMenuPanel = createSideMeuPanel();
        centerPnel.add(sideMenuPanel, BorderLayout.WEST);

        // 创建主要内容区域
        contentPanel = createContentPanel();
        centerPanel.add(contentPanel, BorderLayout.CENTER);

        mainPanel.add(centerPanel, BorderLayout.CENTER);

        setContentPane(mainPanel);
    }

    // 创建头部面板
    private JPanel createHeaderPanel() {
        JPanel headerPanel = new JPanel();
        headerPanel.setLayout(new BorderLayout());
        headerPanel.setBackground(Color.LIGHT_GRAY);
        headerPanel.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 15));

        // 左侧标题
        JLabel titleLabel = new JLabel("黑马药品管理系统");
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20));
        titleLabel.setForeground(Color.BLACK);
        headerPanel.add(titleLabel, BorderLayout.WEST);

        // 右侧用户信息和退出按钮
        JPanel userInfoPanel = new JPanel();
        userInfoPanel.setBackground(Color.LIGHT_GAY);

        JLabel userLabel = new JLabel(user.getNicknme());
        userLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        userInfoPanel.add(userLabel);

        JButton logoutButton = new JButton("退出");
        logoutButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
         //设置按钮样式:无边框、无背景(模拟文本)
        logoutButton.setBorderPainted(false); // 不绘制边框
        logoutButton.setContentAreaFilled(false); // 不填充背景


        logoutButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int result = JOptionPane.showConfirmDialog(
                        HomeUI.this,
                        "确定要退出吗?",
                        "确认退出",
                        JOptionPane.YES_NO_OPTION
                );

                if (result == JOptionPane.YES_OPTION) {
                    dispose(); // 销毁当前窗口
                    SwingUtilities.invokLater(() -> {
                        WelcomeUI welcomeUI = new WelcomeUI();
                        welcomeUI.setVisible(true);
                    });
                }
            }
        });
        userInfoPanel.add(logoutButton);

        headerPanel.add(userInfoPanel, BorderLayout.EAST);

        return headerPanel;
    }

    // 创建侧边菜单面板
    private JPanel createSideMenuPanel() {
        JPanel sideMenuPanel = new JPanel();
        sideMenuPanel.setLayout(new BoxLayout(sideMenuPanel, BoxLayout.Y_AXIS));
        sideMenuPanel.setPrefrredSize(new Dimension(180, 0)); // 固定宽度
        sideMenuPanel.setBackground(Color.LIGHT_GRAY);
        sideMenuPanel.setBorder(BorderFactory.creteEmptyBorder(10, 10, 10, 10));

        // 创建菜单按钮数组
        String[] menuItems = {"分类管理", "药品管理", "入库管理", "出库管理", "报表统计", "用户管理"};
        for (String menuItem : menuItems) {
            JButton button = new JButton(menuItem);
            button.setAlignmentX(Component.CENTER_ALIGNMENT); // 居中对齐
            button.setMaximumSize(new Dimension(Integer.MAX_VALUE, 40)); // 设置最大高度
            button.setBackground(Color.WHITE); // 默认背景
            button.setFocuPainted(false); // 移除焦点框

            // 添加悬停效果
            button.addMouseLisener(new java.awt.event.MouseAdapter() {
                @Override
                public void mouseEnered(java.awt.event.MouseEvent evt) {
                    button.setBackground(Color.LIGHT_GRAY); // 悬停时加深
                }

                @Override
                public void mousexited(java.awt.event.MouseEvent evt) {
                    button.setBackground(Color.WHITE); // 离开时恢复
                }
            });

            // 添加点击事件
            button.addActionLstener(e -> showContntPanel(menuItem));

            sideMenuPanel.add(button);
            sideMenuPanel.add(Box.createVerticlStrut(5)); // 添加垂直间距
        }

        return sideMenuPanel;
    }

    // 创建内容面板
    private JPanel createContentPanel() {
        JPanel contentPanel = new JPanel();
        cardLayout = new CardLayout();
        contentPanel.setLayout(cardLayout);

        // 添加各个功能面板
        contentPanel.add(new UserManageUI(), "用户管理");
        contentPanel.add(new CategoryUI(), "分类管理");
        contentPanel.add(new MedicineUI(), "药品管理");
        contentPanel.add(new InboudUI(), "入库管理");
        contentPanel.add(new OutboundUI(), "出库管理");
        contentPanel.add(new ReprtUI(), "报表统计");
       

        return contentPanel;
    }

    // 显示指定的内容面板
    private void showContentPanel(String panelName) {
        cardLayout.show(contentPanel, panelName);
    }
}
运行后效果图
运行后效果图

至此,我们已经完成了主界面,接下来我们需要完成各个功能页面。

1.5 完成用户管理页面

前言

接下来,我们完成用户管理页面,如下的空白页面👇

image
image

用户管理页面,大致如下👇

image
image

提示词👇

UserManageUI.java 开发需求文档

一、项目环境

• 所属模块:HomeUI.java 内容区嵌入的子界面(通过侧边栏“用户管理”菜单切换显示);  
• 技术:Java Swing,风格与现有界面(UserUI、WelcomeUI、HomeUI)一致;  
• 数据依赖:需加载用户数据(模拟从数据库查询,包含序号、用户名、昵称、手机号码、角色、创建时间等字段)。  

二、界面设计(苹果风格:简洁、留白、色调统一、控件圆润)

1. 整体布局
采用 BorderLayout + FlowLayout + 边距控制,分区明确:  
• 顶部:检索区(左:检索框+检索按钮;右:添加按钮);  
• 中部:表格区(占满剩余空间,带滚动条);  
• 整体背景白色,四周留白舒适(如 EmptyBorder(10, 10, 10, 10))。  

2. 检索与操作区(顶部第一行)
• 左侧:检索组件  
  • 检索输入框:宽度约 200px,提示文字“请输入用户名/昵称”,无边框(或浅灰细边框),圆角(6px);  
  • 检索按钮:文字“检索”,浅灰背景(默认)、悬停加深、点击激活变色,圆角矩形,与输入框间距 8px。
  • 重置按钮:文字“重置”,浅灰背景(默认)、悬停加深、点击激活变色,圆角矩形,与输入框间距 8px。 
• 右侧:添加按钮  
  • 文字“添加用户”,样式同检索按钮(统一按钮风格),与左侧检索组件间距 16px。  
• 布局:用 FlowLayout 横向排列,居中对齐,整体区域背景白色,高度约 50px(含内边距)。  

3. 表格区(第二行)
• 表格组件:JTable + JScrollPane(带垂直滚动条,无水平滚动条,列宽自适应内容);  
• 表头字段(按顺序):  
  序号 用户名 昵称 手机号码 角色 创建时间 操作
• 操作列:每行包含“编辑”和“删除”两个按钮(文字按钮,样式同检索按钮,间距 2,列宽固定约 100px,按钮高度和列一致);  
• 表格样式:  
  • 表头:浅灰背景,深灰文字,加粗,居中对齐;  
  • 内容行:白色背景,深灰文字,居中对齐(序号、手机号、创建时间),用户名/昵称/角色左对齐;  
  • 行高:紧凑适中,隔行浅灰背景(斑马纹,提升可读性);  
  • 边框:表格外框浅灰细边框,单元格间无分隔线(或极浅灰分隔线,符合苹果简洁风格);
  • 列宽:序号 20px,其他 100px,剩余的宽度自适应内容(如手机号、创建时间)。
• 按钮:所有的按钮通过一个方法 createButton() 统一初始化样式(如圆角、背景色、字体、边距等),避免重复代码。

三、交互与逻辑

1. 数据加载
• 定义独立方法 loadUserData():模拟从数据源(如 UserDao)加载用户数据,返回 List<TUser>(包含序号、用户名、昵称、手机号、角色、创建时间等字段),TUser实体类在cn.yangeit.entity包下;  
• 页面初始化时自动调用 loadUserData() 加载数据并刷新表格;  
• 检索按钮点击时,根据输入框关键词过滤数据,调用 loadUserData(keyword) 重新加载并刷新表格(关键词可为空,即加载全部)。  

2. 表格初始化
• 定义独立方法 initTable():创建 DefaultTableModel(指定表头字段,操作列设为非 editable),关联 JTable,并设置表格样式(行高、对齐方式、斑马纹等);  
• 数据加载后,将 List<TUser> 转换为表格行数据,通过 tableModel.setDataVector() 更新表格内容。  

3. 按钮交互

• 检索按钮:绑定 ActionListener,获取输入框文本,调用 loadUserData(keyword) 刷新表格;  
• 添加用户按钮:绑定 ActionListener,点击后打开添加用户对话框(显示用户名username,名字nickname, 手机号码telphone,密码password),点击保存后,触发saveuser方法;  
• 编辑/删除按钮:操作列的每行按钮绑定 ActionListener,点击编辑按钮时获取当前行数据(如用户名,用户id,用户密码,用户昵称,手机号码),弹出对应的编辑对话框(确认和取消按钮 在最下方),确认后执行逻辑saveUser(当前先留空,仅打印日志)。  
• 点击删除按钮时获取当前行数据(如用户名,用户id),弹出确认对话框(如“确定删除用户XXX?”),确认后执行逻辑deleteById(用户id)(当前先留空,仅打印日志)
• 要让 JTable正确显示操作列的按钮(水平布局,编辑在左,删除在右),必须通过 自定义 TableCellRenderer和 TableCellEditor​ 实现,操作列背景颜色和其他列一致,且删除按钮红色,编辑按钮蓝色

4. 组件命名规范
• 检索输入框:searchField;  
• 检索按钮:searchBtn;  
• 添加按钮:addBtn;  
• 表格:userTable;  
• 表格模型:tableModel;  
• 滚动面板:scrollPane。  

四、风格一致性

• 色调:浅灰+白色为主(背景、按钮默认色),深灰文字(表头、内容),按钮悬停/激活色为深一点的浅灰(如 #E0E0E0 → #D0D0D0);  
• 字体:系统无衬线字体(苹方/微软雅黑/SansSerif),表头字号 13px(加粗),内容字号 12px;  
• 与现有界面统一:按钮样式、对话框风格、背景色与 HomeUI 侧边栏按钮、UserUI 输入框保持一致。  

五、输出要求

1. 提供 UserManageUI.java 完整可运行代码(含 import、成员变量、构造方法、界面初始化、事件绑定);  
2. 代码注释清晰:说明各区域作用(如“检索区”“表格区”)、主要方法逻辑(如 loadUserData() 数据加载流程);  
3. 独立方法定义:  
   • initTable():初始化表格模型和样式;  
   • loadUserData():无参,加载全部用户数据;  
   • loadUserData(String keyword):带参,根据关键词过滤加载数据;  
   • saveUser():保存用户数据(仅打印日志)  
   • deleteById():删除用户数据(仅打印日志)
4. 暂不实现业务逻辑(如实际数据查询、改密/删除后端交互),仅模拟数据(如 List<TUser> 硬编码 5-10 条测试数据)和前端交互(按钮点击日志打印);  
5. 表格操作列按钮可点击,点击时打印当前行数据(如“点击删除用户:张三”)。  

目标:符合 JavaSE Swing 开发规范,界面美观(苹果风格)、交互流畅,数据与界面分离,便于后续扩展业务逻辑。

将UserManageUI.java拖拽到右侧的tongyi灵码对话框中,输入上述提示词,点击确定 👇

image
image

代码审查后,点击接受修改 👇

然后调整错误地方,点击运行,观察运行效果 👇

image
image

如果有错,爆红, 等待修改后,再运行,直至运行成功 👇

image
image

接下来测试添加,删除,编辑按钮,是否正常输出日志 👇

image
image

1.6 完成用户列表数据

前言

上面我们完成了用户管理页面的界面,接下来我们需要完成用户列表数据,👇

image
image

首先,在UserMapper中增加一个getAllUsersWithoutPassword获取所有用户的sql语句(不包含密码)

@Select("select id, username, nickname, role, telphone, create_time, update_time from t_user")
List<User> getAllUsersWithoutPassword();

接着,在UserDao中增加一个listUser方法,调用UserMapper的getAllUsersWithoutPassword方法(复制已有的方法,改改方法名 ),返回用户列表

public List<TUser> listUser() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<TUser> list =userMapper.getAllUsersWithoutPassword();
    sqlSession.commit();
    sqlSession.close();
    return list;
}

最后,在UserManageUI中的数据加载方法中,调用UserDao的listUser方法,返回用户列表

  UserDao userDao = new UserDao();

    /**
     * 获取模拟数据
     * @return 用户列表
     */
    private List<TUser> getMockData() {

        List<TUser> users = userDao.listUser();

        return users;
    }

重启运行,观察运行效果如下图 👇

image
image

1.7 完成用户增加

前言

接下来我们来完成用户增加功能,👇,当然这项功能是管理员才有权限的👇

增加用户对话框
增加用户对话框

我们先分析一下,流程,如下图:👇

新增用户流程图
新增用户流程图

在UserManageUI中,找到添加用户确认框的方法,如下图 👇

image
image

接下来参考流程图,完成代码,如下图 👇

  private boolean saveUser(String username, String nickname, String tel, String password) {

        //2.判断用户名和密码是否为空,如果为空,提示用户名和密码不能为空
        if (username.isEmpty() || password.isEmpty() ||nickname.isEmpty() || tel.isEmpty()) {
            JOptionPane.showMessageDialog(this, "请填写所有字段", "注册失败", JOptionPane.ERROR_MESSAGE);
            return false;
        }

//        System.out.println("保存用户: " + username + ", 昵称: " + nickname + ", 手机: " + tel);
        //1.通过用户名查询用户,如果存在,弹出提示框,用户已存在,结束
        TUser user = userDao.getUserByUsername(username);
        if (user != null) {
            JOptionPane.showMessageDialog(this, "用户已存在!", "错误", JOptionPane.ERROR_MESSAGE);
            return false;
        }
        //2.判断手机是否合法
        if (!PhoneUtil.isPhone(tel)) {
            JOptionPane.showMessageDialog(this, "手机号格式不正确!", "错误", JOptionPane.ERROR_MESSAGE);
            return false;
        }


        //3.如果用户名不存在,构建用户对象,赋值属性
        user = new TUser();
        user.setUsername(username);
        user.setNickname(nickname);
        user.setTelphone(tel);
        user.setPassword(password);
        user.setRole("user");
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());

        //4.调用数据库保存用户
        userDao.addUser(user);


        return true;
    }
image
image

1.8 完成用户编辑

前言

点击编辑按钮,弹出编辑对话框,如下图 👇

image
image

在UserManageUI中,找到编辑用户确认框的方法,如下图 👇

image
image

接下来开始编码:👇

首先,在UserMapper.java中增加一个updateById方法,用于更新用户信息,如下 👇


    //修改用户昵称,手机号码,密码
@Update("update t_user set nickname = #{nickname}, telphone = #{telphone}, password = #{password} where id = #{id}")
int updateById(TUser user);

接着,在UserDao中增加一个updateUserById方法,调用UserMapper的updateById方法,如下 👇

public int updateUserById(TUser user) {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    int count=userMapper.updateById(user);
    sqlSession.commit();
    sqlSession.close();
    return count;
}

最后,在UserManageUI中,找到编辑用户确认框的方法,并改造saveUser方法 👇

private boolean saveUser(String type, String username, String nickname, String tel, String password) {
        System.out.println("用户: " + username + ", 昵称: " + nickname + ", 手机: " + tel);


        if (type.equals("save")) {
            //1.判断用户名和密码是否为空,如果为空,提示用户名和密码不能为空
            if (username.isEmpty() || password.isEmpty() || nickname.isEmpty() || tel.isEmpty()) {
                JOptionPane.showMessageDialog(this, "请填写所有字段", "注册失败", JOptionPane.ERROR_MESSAGE);
                return false;
            }
            //2.判断手机是否合法
            if (!PhoneUtil.isPhone(tel)) {
                JOptionPane.showMessageDialog(this, "手机号格式不正确!", "错误", JOptionPane.ERROR_MESSAGE);
                return false;
            }
            //1.通过用户名查询用户,如果存在,弹出提示框,用户已存在,结束
            TUser user = userDao.getUserByUsername(username);
            if (user != null) {
                JOptionPane.showMessageDialog(this, "用户已存在!", "错误", JOptionPane.ERROR_MESSAGE);
                return false;
            }


            //3.如果用户名不存在,构建用户对象,赋值属性
            user = new TUser();
            user.setUsername(username);
            user.setNickname(nickname);
            user.setTelphone(tel);
            user.setPassword(password);
            user.setRole("user");
            user.setCreateTime(LocalDateTime.now());
            user.setUpdateTime(LocalDateTime.now());
            //4.调用数据库保存用户
            userDao.addUser(user);
            return true;
        } else {
            TUser user = userDao.getUserByUsername(username);
            if (!password.isEmpty()) {
                user.setPassword(password);
            }
            user.setTelphone(tel);
            user.setNickname(nickname);
            user.setPassword(password);
            user.setUpdateTime(LocalDateTime.now());
            userDao.updateUserById(user);
            return true;
        }
    }




































 
 
 
 
 
 
 
 
 
 


1.9 完成用户删除

前言

点击删除按钮,调用deleteUserByUsername 删除用户,大家自行完成!

注意:只有role为admin的用户才有权限删除用户

image
image