商品管理系统

该项目是一个基于Java的桌面应用程序,用于管理商品信息,主要包括增删改查四个功能。通过图形用户界面与用户进行交互,并且使用JSON文件来保存和读取商品数据。

GitHub仓库:https://github.com/TshiauHuan/Goods_Manage_System

项目结构

项目包含以下主要部分:

  1. 商品类(Goods.java)

  2. 商品实现类(Product.java)

  3. 商品服务接口(GoodsService.java)

  4. 商品服务实现类(GoodsServiceImpl.java)

  5. 主类(Main.java)

最终效果:

  1. 用户界面

  1. 相关业务弹窗

  1. 警告弹窗

项目流程

项目工作流程

  1. 加载数据:启动程序时,从goods.json文件中加载商品数据,并初始化商品列表。

  2. 显示界面:创建一个图形用户界面,包含商品表格和操作按钮。

  3. 添加商品:点击“添加商品”按钮,弹出对话框输入商品信息,确认后将商品添加到商品列表并更新表格显示。

  4. 删除商品:选择表格中的商品,点击“删除商品”按钮,删除该商品并更新表格显示。

  5. 修改商品:选择表格中的商品,点击“修改商品”按钮,弹出对话框修改商品信息,确认后更新商品列表和表格显示。

  6. 查询商品:输入商品编号或名称,点击“查询”按钮,在表格中显示匹配的商品。

  7. 显示所有商品:点击“显示所有商品”按钮,在表格中显示所有商品。

  8. 保存数据:每次进行添加、删除、修改操作时,都会将最新的商品数据保存到goods.json文件中。

1. 商品类(Goods.java

商品类是一个抽象类,包含商品的基本属性:编号、名称、价格和数量。我们将这些属性封装在这个类中,以便在具体实现类中继承和使用。

public abstract class Goods {
    private String id;
    private String name;
    private double price;
    private int quantity;
​
    // 构造函数和getter/setter方法
}

2. 商品实现类(Product.java

在这个系统中,Product 类是具体的商品类,它继承了抽象的 Goods 类,用来表示商品的具体实例。在代码中,Product 类用于创建具体的商品对象,并且这些对象被添加到 GoodsServiceImpl 的商品列表中。下面是如何在各个部分中使用 Product 类的具体示例。

2.1在Product 类中

Product 类继承了 Goods 类,没有额外的属性或方法,仅仅是对 Goods 类的具体化。

public class Product extends Goods {
    public Product(String id, String name, double price, int quantity) {
        super(id, name, price, quantity);  // 调用父类构造函数
    }
}

2.2 Main 类中的使用

Main 类中,使用 Product 类来创建具体的商品对象,并通过 GoodsService 接口将它们添加到系统中。

2.3 GoodsServiceImpl 类中的使用

GoodsServiceImpl 类中使用 Product 类来处理商品的增删改查操作。

3. 商品服务接口(GoodsService.java

这个接口定义了商品管理的基本操作:添加商品、删除商品、修改商品、查询商品和获取所有商品列表。接口为这些操作提供了一种标准,具体实现将在实现类中完成。

public interface GoodsService {
    void addGoods(Goods goods);
    void deleteGoods(String id);
    void updateGoods(Goods goods);
    Goods queryGoods(String identifier);
    List<Goods> getAllGoods();
}

4. 商品服务实现类(GoodsServiceImpl.java

这个类实现了商品服务接口中的所有方法,负责处理具体的商品管理逻辑。同时,它还包含正则表达式,用于验证商品编号和名称的格式。

public class GoodsServiceImpl implements GoodsService {
    private List<Goods> goodsList;
​
    public GoodsServiceImpl() {
        this.goodsList = new ArrayList<>();
    }
​
    @Override
    public void addGoods(Goods goods) {
        if (isValidId(goods.getId()) && isValidName(goods.getName())) {
            goodsList.add(goods);
        }
    }
​
    // 其他方法...
​
    private boolean isValidId(String id) {
        return Pattern.matches("[a-zA-Z0-9]+", id);
    }
​
    private boolean isValidName(String name) {
        return Pattern.matches("[\\u4e00-\\u9fa5a-zA-Z0-9 ]+", name);
    }
}

5. 主类 (Main.java)

主类是程序的入口,创建图形用户界面,并处理用户的各种操作(添加、删除、修改、查询商品)。还负责从文件中加载商品数据和将数据保存到文件中。

1. 导入包和库

首先,导入需要的Java标准库、Swing库、Gson库等。

package GoodsManageSystem;
​
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

2. 全局变量和对象

然后定义全局变量和对象,包括商品服务对象和表格模型。

public class Main {
    private static GoodsService goodsService = new GoodsServiceImpl();
    private static final String DATA_FILE = "goods.json";
    private static DefaultTableModel tableModel;
  • goodsService:商品服务对象,用于管理商品。

  • DATA_FILE:数据文件名,用于保存和加载商品数据。

  • tableModel:表格模型,用于管理表格中的数据。

3. 主方法 (main)

public static void main(String[] args) {
    loadGoodsData();
​
    JFrame frame = new JFrame("商品管理系统");
    frame.setSize(600, 400);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new BorderLayout());
    frame.setLocationRelativeTo(null);
  • loadGoodsData():加载商品数据。

  • 创建窗口 frame,设置大小、关闭操作、布局和位置。

4. 创建表格和滚动面板

    String[] columnNames = {"商品编号", "商品名称", "数量", "价格"};
    tableModel = new DefaultTableModel(columnNames, 0);
    JTable table = new JTable(tableModel);
​
    JScrollPane scrollPane = new JScrollPane(table);
  • columnNames:定义表格的列名。

  • tableModel:初始化表格模型。

  • table:创建表格组件,并将表格模型关联到表格。

  • scrollPane:创建滚动面板,将表格添加到滚动面板中。

5. 创建按钮和查询面板

    JButton addButton = new JButton("添加商品");
    JButton deleteButton = new JButton("删除商品");
    JButton updateButton = new JButton("修改商品");
    JButton listButton = new JButton("显示所有商品");
​
    Dimension buttonSize = new Dimension(150, 25);
    addButton.setPreferredSize(buttonSize);
    deleteButton.setPreferredSize(buttonSize);
    updateButton.setPreferredSize(buttonSize);
    listButton.setPreferredSize(buttonSize);
  • 创建各个按钮,并设置其大小。

6. 创建查询面板

    JPanel queryPanel = new JPanel(new FlowLayout());
    JLabel queryLabel = new JLabel("输入商品编号或名称以查询:");
    JTextField queryField = new JTextField(20);
    JButton queryButton = new JButton("查询");
​
    queryPanel.add(queryLabel);
    queryPanel.add(queryField);
    queryPanel.add(queryButton);
  • queryPanel:查询面板,用于放置查询相关的组件。

  • queryLabel:查询标签。

  • queryField:查询文本框。

  • queryButton:查询按钮。

7. 创建按钮面板

    JPanel buttonPanel = new JPanel(new GridLayout(5, 1));
    buttonPanel.add(addButton);
    buttonPanel.add(deleteButton);
    buttonPanel.add(updateButton);
    buttonPanel.add(queryButton);
    buttonPanel.add(listButton);
  • buttonPanel:按钮面板,采用网格布局,将各个按钮添加到面板中。

8. 将组件添加到主窗口

    frame.add(queryPanel, BorderLayout.NORTH);
    frame.add(scrollPane, BorderLayout.CENTER);
    frame.add(buttonPanel, BorderLayout.EAST);
​
    frame.setVisible(true);
    showAllGoodsInTable();
}
  • 将查询面板、滚动面板和按钮面板添加到主窗口中。

  • 显示主窗口。

  • showAllGoodsInTable():显示所有商品在表格中。

9. 各种操作的方法

添加商品
private static void showAddProductDialog() {
    JDialog dialog = new JDialog();
    dialog.setTitle("添加商品");
    dialog.setSize(300, 300);
    dialog.setLayout(new GridLayout(5, 2));
    dialog.setLocationRelativeTo(null);
​
    JLabel idLabel = new JLabel("商品编号:");
    JTextField idField = new JTextField();
    JLabel nameLabel = new JLabel("商品名称:");
    JTextField nameField = new JTextField();
    JLabel priceLabel = new JLabel("价格:");
    JTextField priceField = new JTextField();
    JLabel quantityLabel = new JLabel("数量:");
    JTextField quantityField = new JTextField();
​
    JButton confirmButton = new JButton("确定");
    JButton cancelButton = new JButton("取消");
​
    dialog.add(idLabel);
    dialog.add(idField);
    dialog.add(nameLabel);
    dialog.add(nameField);
    dialog.add(priceLabel);
    dialog.add(priceField);
    dialog.add(quantityLabel);
    dialog.add(quantityField);
    dialog.add(confirmButton);
    dialog.add(cancelButton);
​
    confirmButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            String id = idField.getText();
            String name = nameField.getText();
            String priceText = priceField.getText();
            String quantityText = quantityField.getText();
​
            if (id.isEmpty() || name.isEmpty() || priceText.isEmpty() || quantityText.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "所有字段均为必填项。");
                return;
            }
​
            if (!goodsService.isValidId(id)) {
                JOptionPane.showMessageDialog(dialog, "商品编号格式不正确,请输入字母或数字。");
                return;
            }
​
            if (!goodsService.isValidName(name)) {
                JOptionPane.showMessageDialog(dialog, "商品名称格式不正确,只能包含字符(中文、英文)、数字和空格。");
                return;
            }
​
            try {
                double price = Double.parseDouble(priceText);
                int quantity = Integer.parseInt(quantityText);
​
                if (goodsService.queryGoods(id) == null) {
                    Product product = new Product(id, name, price, quantity);
                    goodsService.addGoods(product);
                    showAllGoodsInTable();
                    saveGoodsData();
                    dialog.dispose();
                } else {
                    JOptionPane.showMessageDialog(dialog, "商品编号已存在,请使用唯一的商品编号。");
                }
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(dialog, "价格和数量必须为数字。");
            }
        }
    });
​
    cancelButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            dialog.dispose();
        }
    });
​
    dialog.setVisible(true);
}
  • 该方法会弹出对话框,输入商品信息,并进行验证和添加操作。

修改商品
private static void showUpdateProductDialog(String id) {
    Goods goods = goodsService.queryGoods(id);
    if (goods == null) {
        JOptionPane.showMessageDialog(null, "商品不存在。");
        return;
    }
​
    JDialog dialog = new JDialog();
    dialog.setTitle("修改商品");
    dialog.setSize(300, 300);
    dialog.setLayout(new GridLayout(5, 2));
    dialog.setLocationRelativeTo(null);
​
    JLabel idLabel = new JLabel("商品编号:");
    JTextField idField = new JTextField(goods.getId());
    JLabel nameLabel = new JLabel("商品名称:");
    JTextField nameField = new JTextField(goods.getName());
    JLabel priceLabel = new JLabel("价格:");
    JTextField priceField = new JTextField(String.valueOf(goods.getPrice()));
    JLabel quantityLabel = new JLabel("数量:");
    JTextField quantityField = new JTextField(String.valueOf(goods.getQuantity()));
​
    JButton confirmButton = new JButton("确定");
    JButton cancelButton = new JButton("取消");
​
    dialog.add(idLabel);
    dialog.add(idField);
    dialog.add(nameLabel);
    dialog.add(nameField);
    dialog.add(priceLabel);
    dialog.add(priceField);
    dialog.add(quantityLabel);
    dialog.add(quantityField);
    dialog.add(confirmButton);
    dialog.add(cancelButton);
​
    confirmButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            String newId = idField.getText();
            String newName = nameField.getText();
            String priceText = priceField.getText();
            String quantityText = quantityField.getText();
​
            if (newId.isEmpty() || newName.isEmpty() || priceText.isEmpty() || quantityText.isEmpty()) {
                JOptionPane.showMessageDialog(dialog
​
, "所有字段均为必填项。");
                return;
            }
​
            if (!goodsService.isValidId(newId)) {
                JOptionPane.showMessageDialog(dialog, "商品编号格式不正确,请输入字母或数字。");
                return;
            }
​
            if (!goodsService.isValidName(newName)) {
                JOptionPane.showMessageDialog(dialog, "商品名称格式不正确,只能包含字符(中文、英文)、数字和空格。");
                return;
            }
​
            try {
                double price = Double.parseDouble(priceText);
                int quantity = Integer.parseInt(quantityText);
​
                goods.setId(newId);
                goods.setName(newName);
                goods.setPrice(price);
                goods.setQuantity(quantity);
​
                goodsService.updateGoods(goods);
                showAllGoodsInTable();
                saveGoodsData();
                dialog.dispose();
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(dialog, "价格和数量必须为数字。");
            }
        }
    });
​
    cancelButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            dialog.dispose();
        }
    });
​
    dialog.setVisible(true);
}
  • 该方法弹出对话框,允许修改商品信息,并进行验证和修改操作。

删除商品
private static void deleteSelectedProduct() {
    int selectedRow = tableModel.getSelectedRow();
    if (selectedRow >= 0) {
        String id = (String) tableModel.getValueAt(selectedRow, 0);
        goodsService.deleteGoods(id);
        showAllGoodsInTable();
        saveGoodsData();
    } else {
        JOptionPane.showMessageDialog(null, "请先选择一个商品。");
    }
}
  • 该方法删除选中的商品,并更新表格和数据文件。

显示所有商品
private static void showAllGoodsInTable() {
    tableModel.setRowCount(0); // 清空表格
    List<Goods> goodsList = goodsService.getAllGoods();
    for (Goods goods : goodsList) {
        Object[] row = {goods.getId(), goods.getName(), goods.getQuantity(), goods.getPrice()};
        tableModel.addRow(row);
    }
}
  • 该方法将所有商品显示在表格中。

查询商品
private static void searchProductByIdOrName(String identifier) {
    Goods goods = goodsService.queryGoods(identifier);
    tableModel.setRowCount(0); // 清空表格
    if (goods != null) {
        Object[] row = {goods.getId(), goods.getName(), goods.getQuantity(), goods.getPrice()};
        tableModel.addRow(row);
    } else {
        JOptionPane.showMessageDialog(null, "未找到匹配的商品。");
    }
}
  • 该方法根据商品编号或名称查询商品,并显示结果。

数据加载和保存
private static void loadGoodsData() {
    try (FileReader reader = new FileReader(DATA_FILE)) {
        Gson gson = new Gson();
        Type type = new TypeToken<List<Product>>() {}.getType();
        List<Product> goodsList = gson.fromJson(reader, type);
        for (Product product : goodsList) {
            goodsService.addGoods(product);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
​
private static void saveGoodsData() {
    try (FileWriter writer = new FileWriter(DATA_FILE)) {
        Gson gson = new Gson();
        List<Goods> goodsList = goodsService.getAllGoods();
        gson.toJson(goodsList, writer);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • loadGoodsData():从文件加载商品数据。

  • saveGoodsData():将商品数据保存到文件。


可能会有的问题

1. 如何将数据保存到JSON文件中

在这个项目中,我们使用了Gson库将数据保存到JSON文件中。具体来说,通过调用Gson的toJson方法将商品数据列表序列化为JSON格式,并使用FileWriter将其写入到文件中。下面是详细的步骤:

1.1 引入Gson库

导入Gson的本质就是引入jar包。

教程见: https://blog.csdn.net/2302_80067378/article/details/137665364

Gson.jar的资源在文件夹中

1.2 准备数据

首先需要把商品数据保存在一个列表中,这个列表存储了所有的商品对象。

    private List<Goods> goodsList;

1.3 加载数据

在程序启动时,我们会尝试从一个名为 goods.json 的文件中读取数据,并将这些数据加载到我们的商品列表中。我们使用了Gson库来实现JSON与Java对象之间的转换。

    private static void loadGoodsData() {

        try (FileReader reader = new FileReader(DATA_FILE)) {

            Gson gson = new Gson();

            Type type = new TypeToken<List<Product>>() {}.getType();

            List<Product> goodsList = gson.fromJson(reader, type);

            for (Product product : goodsList) {

                goodsService.addGoods(product);

            }

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

1.4 保存数据

当用户添加、删除或更新商品时,我们需要将最新的商品列表保存到 goods.json 文件中。同样,我们使用Gson库将商品列表转换成JSON格式并写入文件。

    private static void saveGoodsData() {

        try (FileWriter writer = new FileWriter(DATA_FILE)) {

            Gson gson = new Gson();

            List<Goods> goodsList = goodsService.getAllGoods();

            gson.toJson(goodsList, writer);

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

2. 用户界面是如何编写的?又是如何与这些业务进行交互的?

2.1 窗体的编写

Main.java中,窗体的主要部分是JFrame和一些Swing组件,如JButtonJTableJPanel等。这些组件被组合在一起形成一个图形用户界面。

2.1.1 初始化窗体

使用 JFrame 创建主窗口。窗口的大小设定为600x400像素,布局管理器设置为 BorderLayout,并将窗口位置设置在屏幕中央

JFrame frame = new JFrame("商品管理系统");
frame.setSize(600, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setLocationRelativeTo(null);
2.1.2 创建表格模型和表格

使用 JTable 创建一个表格来显示商品信息。表格的数据由 DefaultTableModel 管理,表格模型包含商品的编号、名称、数量和价格。

String[] columnNames = {"商品编号", "商品名称", "数量", "价格"};
tableModel = new DefaultTableModel(columnNames, 0);
JTable table = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(table);
2.1.3 创建按钮和按钮面板

创建添加、删除、修改和显示所有商品的按钮,并将这些按钮放在一个垂直布局的面板中。

   JButton addButton = new JButton("添加商品");
   JButton deleteButton = new JButton("删除商品");
   JButton updateButton = new JButton("修改商品");
   JButton listButton = new JButton("显示所有商品");
​
   JPanel buttonPanel = new JPanel(new GridLayout(5, 1));
   buttonPanel.add(addButton);
   buttonPanel.add(deleteButton);
   buttonPanel.add(updateButton);
   buttonPanel.add(listButton);
2.1.4 创建查询面板

创建一个查询面板,包括一个标签、一个文本输入框和一个查询按钮。

   JPanel queryPanel = new JPanel(new FlowLayout());
   JLabel queryLabel = new JLabel("输入商品编号或名称以查询:");
   JTextField queryField = new JTextField(20);
   JButton queryButton = new JButton("查询");
​
   queryPanel.add(queryLabel);
   queryPanel.add(queryField);
   queryPanel.add(queryButton);
2.1.5 添加组件到主窗口

将表格的滚动面板添加到主窗口的中央区域,将按钮面板添加到东侧区域,将查询面板添加到北侧区域。

frame.add(queryPanel, BorderLayout.NORTH);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(buttonPanel, BorderLayout.EAST);

2.2 窗体与业务逻辑的交互

窗体通过事件监听器与业务逻辑进行交互。以下是几个关键操作的交互方式:

2.2.1 创建业务逻辑对象

创建 GoodsService 接口的实现类 GoodsServiceImpl 的实例,来管理所有商品的增删改查操作。

private static GoodsService goodsService = new GoodsServiceImpl();
2.2.2 按钮的事件监听器

每个按钮都添加了 ActionListener,当用户点击按钮时,会执行相应的操作。例如,点击“添加商品”按钮时,会打开一个对话框让用户输入商品信息,然后调用业务逻辑的 addGoods 方法添加商品。

   addButton.addActionListener(new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent e) {
           showAddProductDialog();
       }
   });
​
   deleteButton.addActionListener(new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent e) {
           int selectedRow = table.getSelectedRow();
           if (selectedRow != -1) {
               String id = (String) tableModel.getValueAt(selectedRow, 0);
               goodsService.deleteGoods(id);
               tableModel.removeRow(selectedRow);
               saveGoodsData();
           } else {
               JOptionPane.showMessageDialog(frame, "请选择要删除的商品。");
           }
       }
   });
​
   updateButton.addActionListener(new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent e) {
           int selectedRow = table.getSelectedRow();
           if (selectedRow != -1) {
               String id = (String) tableModel.getValueAt(selectedRow, 0);
               showUpdateProductDialog(id);
           } else {
               JOptionPane.showMessageDialog(frame, "请选择要修改的商品。");
           }
       }
   });
​
   queryButton.addActionListener(new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent e) {
           String name = queryField.getText();
           Goods goods = goodsService.queryGoods(name);
           if (goods != null) {
               showGoodsInTable(goods);
           } else {
               JOptionPane.showMessageDialog(frame, "未找到商品。");
           }
       }
   });
​
   listButton.addActionListener(new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent e) {
           showAllGoodsInTable();
       }
   });
2.2.3 对话框与业务逻辑的交互

当用户在对话框中输入商品信息并点击确认按钮时,收集输入的数据,创建一个 Product 对象,并调用 goodsService.addGoods(goods) 方法添加商品。

   confirmButton.addActionListener(new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent e) {
           String id = idField.getText();
           String name = nameField.getText();
           double price = Double.parseDouble(priceField.getText());
           int quantity = Integer.parseInt(quantityField.getText());
​
           Goods goods = new Product(id, name, price, quantity);
           goodsService.addGoods(goods);
           saveGoodsData();
           showAllGoodsInTable();
           dialog.dispose();
       }
   });

总结

该任务总体难度较高,在实现过程中借助了AI工具辅助编写代码。

最终能够正常运行,基本实现目标效果。但效果有些不尽人意,同时存在着一些BUG,后续需要改进。

一个老鼠人