第一部分:系统分析与设计
系统概述
“我行我素”购物管理系统旨在为小型零售店或线上商店提供一个简单、实用的管理工具,系统核心功能包括:

- 商品管理:添加、修改、删除、查询商品信息(名称、价格、库存、分类等)。
- 购物车管理:用户(模拟顾客)可以浏览商品,将商品加入购物车,并修改数量或移除。
- 订单管理:顾客确认购物车后生成订单,记录订单详情和历史订单。
- 用户管理:简单的用户登录功能(可以扩展为管理员和顾客角色)。
功能模块划分
我们将系统划分为以下几个核心模块:
- 登录模块:验证用户身份。
- 主界面模块:展示系统主要功能入口。
- 商品管理模块:对商品信息进行增删改查。
- 购物车模块:模拟顾客的购物流程。
- 订单管理模块:查看和管理订单信息。
- 数据库连接模块:负责与MySQL数据库交互。
数据库设计
我们需要设计几张核心的数据表来存储信息。
数据库: my_shopping_db
表1: 用户表

CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(50) NOT NULL,
role VARCHAR(20) NOT NULL -- 'admin' or 'customer'
);
表2: 商品表
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INT NOT NULL,
category VARCHAR(50)
);
表3: 订单表
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
order_date DATETIME NOT NULL,
total_amount DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);
表4: 订单详情表
CREATE TABLE order_items (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
price DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
第二部分:项目环境搭建
- JDK 安装: 确保已安装 JDK 8 或更高版本。
- IDE: 推荐使用 IntelliJ IDEA 或 Eclipse。
- 数据库: 安装 MySQL 服务器。
- 数据库连接驱动: 下载 MySQL Connector/J (JDBC驱动)。
- 下载地址: https://dev.mysql.com/downloads/connector/j/
- 将下载的
.jar文件复制到你的项目目录下,并在IDE中将其添加到项目的 Libraries 中。
第三部分:核心代码实现
我们将按照模块化的思想来编写代码。

数据库连接模块 (DBUtil.java)
创建一个工具类来管理数据库连接,避免重复代码。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
private static final String URL = "jdbc:mysql://localhost:3306/my_shopping_db?useSSL=false&serverTimezone=UTC";
private static final String USER = "root"; // 你的数据库用户名
private static final String PASSWORD = "your_password"; // 你的数据库密码
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASSWORD);
}
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
模型类
创建与数据库表对应的Java类。
// User.java
public class User {
private int id;
private String username;
private String password;
private String role;
// Getters and Setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getRole() { return role; }
public void setRole(String role) { this.role = role; }
}
// Product.java
public class Product {
private int id;
private String name;
private double price;
private int stock;
private String category;
// Getters and Setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public int getStock() { return stock; }
public void setStock(int stock) { this.stock = stock; }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
}
// Order.java
public class Order {
private int id;
private int userId;
private java.util.Date orderDate;
private double totalAmount;
// Getters and Setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public int getUserId() { return userId; }
public void setUserId(int userId) { this.userId = userId; }
public java.util.Date getOrderDate() { return orderDate; }
public void setOrderDate(java.util.Date orderDate) { this.orderDate = orderDate; }
public double getTotalAmount() { return totalAmount; }
public void setTotalAmount(double totalAmount) { this.totalAmount = totalAmount; }
}
登录模块 (LoginFrame.java)
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class LoginFrame extends JFrame {
private JTextField usernameField;
private JPasswordField passwordField;
public LoginFrame() {
setTitle("我行我素 - 登录");
setSize(350, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(null);
JLabel userLabel = new JLabel("用户名:");
userLabel.setBounds(50, 50, 80, 25);
add(userLabel);
usernameField = new JTextField();
usernameField.setBounds(130, 50, 150, 25);
add(usernameField);
JLabel passLabel = new JLabel("密码:");
passLabel.setBounds(50, 90, 80, 25);
add(passLabel);
passwordField = new JPasswordField();
passwordField.setBounds(130, 90, 150, 25);
add(passwordField);
JButton loginButton = new JButton("登录");
loginButton.setBounds(130, 130, 100, 30);
add(loginButton);
loginButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String username = usernameField.getText();
String password = new String(passwordField.getPassword());
try (Connection conn = DBUtil.getConnection()) {
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setRole(rs.getString("role"));
JOptionPane.showMessageDialog(LoginFrame.this, "登录成功!");
// 登录成功后打开主界面
new MainFrame(user).setVisible(true);
LoginFrame.this.dispose(); // 关闭登录窗口
} else {
JOptionPane.showMessageDialog(LoginFrame.this, "用户名或密码错误!");
}
} catch (SQLException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(LoginFrame.this, "数据库连接错误!");
}
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new LoginFrame().setVisible(true));
}
}
主界面模块 (MainFrame.java)
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MainFrame extends JFrame {
private User currentUser;
public MainFrame(User user) {
this.currentUser = user;
setTitle("我行我素 - 主界面 (" + currentUser.getUsername() + ")");
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
// 创建菜单栏
JMenuBar menuBar = new JMenuBar();
// 商品管理菜单 (仅管理员可见)
if ("admin".equals(currentUser.getRole())) {
JMenu productMenu = new JMenu("商品管理");
JMenuItem addProductItem = new JMenuItem("添加商品");
JMenuItem viewProductsItem = new JMenuItem("查看商品");
addProductItem.addActionListener(e -> new ProductManagementFrame(this, "add").setVisible(true));
viewProductsItem.addActionListener(e -> new ProductManagementFrame(this, "view").setVisible(true));
productMenu.add(addProductItem);
productMenu.add(viewProductsItem);
menuBar.add(productMenu);
}
// 购物车菜单
JMenu cartMenu = new JMenu("购物车");
JMenuItem viewCartItem = new JMenuItem("查看购物车");
viewCartItem.addActionListener(e -> new ShoppingCartFrame(this, currentUser).setVisible(true));
cartMenu.add(viewCartItem);
menuBar.add(cartMenu);
// 订单菜单
JMenu orderMenu = new JMenu("订单");
JMenuItem viewOrdersItem = new JMenuItem("我的订单");
viewOrdersItem.addActionListener(e -> new OrderFrame(this, currentUser).setVisible(true));
orderMenu.add(viewOrdersItem);
menuBar.add(orderMenu);
add(menuBar, BorderLayout.NORTH);
// 欢迎信息
JLabel welcomeLabel = new JLabel("欢迎使用“我行我素”购物管理系统!", SwingConstants.CENTER);
welcomeLabel.setFont(new Font("宋体", Font.BOLD, 24));
add(welcomeLabel, BorderLayout.CENTER);
}
}
商品管理模块 (ProductManagementFrame.java)
这是一个比较复杂的界面,集成了添加和查看功能。
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
import java.util.Vector;
public class ProductManagementFrame extends JFrame {
private MainFrame parentFrame;
private String mode; // "add" or "view"
private JTable productTable;
private DefaultTableModel tableModel;
public ProductManagementFrame(MainFrame parentFrame, String mode) {
this.parentFrame = parentFrame;
this.mode = mode;
setTitle(mode.equals("add") ? "添加商品" : "商品列表");
setSize(800, 500);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
// 表格模型
tableModel = new DefaultTableModel(new String[]{"ID", "名称", "价格", "库存", "分类"}, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false; // 所有单元格不可编辑
}
};
productTable = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(productTable);
add(scrollPane, BorderLayout.CENTER);
loadProducts();
// 按钮面板
JPanel buttonPanel = new JPanel();
if (mode.equals("add")) {
JButton addButton = new JButton("添加商品");
addButton.addActionListener(e -> showAddProductDialog());
buttonPanel.add(addButton);
}
JButton refreshButton = new JButton("刷新");
refreshButton.addActionListener(e -> loadProducts());
buttonPanel.add(refreshButton);
JButton backButton = new JButton("返回");
backButton.addActionListener(e -> this.dispose());
buttonPanel.add(backButton);
add(buttonPanel, BorderLayout.SOUTH);
}
private void loadProducts() {
tableModel.setRowCount(0);
try (Connection conn = DBUtil.getConnection()) {
String sql = "SELECT * FROM products";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
Vector<Object> row = new Vector<>();
row.add(rs.getInt("id"));
row.add(rs.getString("name"));
row.add(rs.getDouble("price"));
row.add(rs.getInt("stock"));
row.add(rs.getString("category"));
tableModel.addRow(row);
}
} catch (SQLException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, "加载商品失败: " + e.getMessage());
}
}
private void showAddProductDialog() {
JDialog dialog = new JDialog(this, "添加新商品", true);
dialog.setSize(300, 250);
dialog.setLayout(new GridLayout(5, 2, 10, 10));
dialog.setLocationRelativeTo(this);
JTextField nameField = new JTextField();
JTextField priceField = new JTextField();
JTextField stockField = new JTextField();
JTextField categoryField = new JTextField();
dialog.add(new JLabel("商品名称:"));
dialog.add(nameField);
dialog.add(new JLabel("价格:"));
dialog.add(priceField);
dialog.add(new JLabel("库存:"));
dialog.add(stockField);
dialog.add(new JLabel("分类:"));
dialog.add(categoryField);
JButton submitButton = new JButton("提交");
submitButton.addActionListener(e -> {
try {
String name = nameField.getText();
double price = Double.parseDouble(priceField.getText());
int stock = Integer.parseInt(stockField.getText());
String category = categoryField.getText();
if (name.isEmpty()) {
JOptionPane.showMessageDialog(dialog, "商品名称不能为空!");
return;
}
try (Connection conn = DBUtil.getConnection()) {
String sql = "INSERT INTO products (name, price, stock, category) VALUES (?, ?, ?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, name);
pstmt.setDouble(2, price);
pstmt.setInt(3, stock);
pstmt.setString(4, category);
pstmt.executeUpdate();
JOptionPane.showMessageDialog(dialog, "商品添加成功!");
dialog.dispose();
loadProducts(); // 刷新列表
} catch (SQLException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(dialog, "添加失败: " + ex.getMessage());
}
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(dialog, "价格和库存必须是数字!");
}
});
dialog.add(new JLabel()); // 占位
dialog.add(submitButton);
dialog.setVisible(true);
}
}
购物车模块 (ShoppingCartFrame.java)
这个模块模拟了用户购物和下单的完整流程。
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class ShoppingCartFrame extends JFrame {
private MainFrame parentFrame;
private User currentUser;
private JTable cartTable;
private DefaultTableModel cartTableModel;
private List<Product> cartProducts = new ArrayList<>();
private double totalAmount = 0.0;
public ShoppingCartFrame(MainFrame parentFrame, User currentUser) {
this.parentFrame = parentFrame;
this.currentUser = currentUser;
setTitle("我的购物车");
setSize(700, 500);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
// 购物车表格
cartTableModel = new DefaultTableModel(new String[]{"商品ID", "商品名称", "单价", "数量", "小计"}, 0);
cartTable = new JTable(cartTableModel);
JScrollPane scrollPane = new JScrollPane(cartTable);
add(scrollPane, BorderLayout.CENTER);
// 按钮面板
JPanel buttonPanel = new JPanel();
JButton addToCartButton = new JButton("从商品列表添加");
addToCartButton.addActionListener(e -> showProductSelectionDialog());
buttonPanel.add(addToCartButton);
JButton checkoutButton = new JButton("结算");
checkoutButton.addActionListener(e -> checkout());
buttonPanel.add(checkoutButton);
JButton backButton = new JButton("返回");
backButton.addActionListener(e -> this.dispose());
buttonPanel.add(backButton);
add(buttonPanel, BorderLayout.SOUTH);
}
private void showProductSelectionDialog() {
// 这里简化处理,实际应该弹出一个商品列表供选择
// 为了演示,我们直接通过输入框模拟
JDialog dialog = new JDialog(this, "选择商品", true);
dialog.setSize(300, 200);
dialog.setLayout(new GridLayout(3, 2, 10, 10));
dialog.setLocationRelativeTo(this);
JTextField productIdField = new JTextField();
JTextField quantityField = new JTextField();
dialog.add(new JLabel("商品ID:"));
dialog.add(productIdField);
dialog.add(new JLabel("数量:"));
dialog.add(quantityField);
JButton submitButton = new JButton("加入购物车");
submitButton.addActionListener(e -> {
try {
int productId = Integer.parseInt(productIdField.getText());
int quantity = Integer.parseInt(quantityField.getText());
Product product = getProductById(productId);
if (product != null && product.getStock() >= quantity) {
addToCart(product, quantity);
dialog.dispose();
updateCartTable();
} else {
JOptionPane.showMessageDialog(dialog, "商品不存在或库存不足!");
}
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(dialog, "请输入有效的数字!");
}
});
dialog.add(new JLabel()); // 占位
dialog.add(submitButton);
dialog.setVisible(true);
}
private Product getProductById(int id) {
try (Connection conn = DBUtil.getConnection()) {
String sql = "SELECT * FROM products WHERE id = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
Product p = new Product();
p.setId(rs.getInt("id"));
p.setName(rs.getString("name"));
p.setPrice(rs.getDouble("price"));
p.setStock(rs.getInt("stock"));
return p;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
private void addToCart(Product product, int quantity) {
// 检查购物车是否已有该商品
for (Product p : cartProducts) {
if (p.getId() == product.getId()) {
// 简单起见,不允许重复添加,直接更新数量
// 实际应用中应该合并数量
return;
}
}
Product cartProduct = new Product();
cartProduct.setId(product.getId());
cartProduct.setName(product.getName());
cartProduct.setPrice(product.getPrice());
// 注意:这里应该创建一个包含数量的购物车项类,但为了简化,我们只存product
cartProducts.add(product);
totalAmount += product.getPrice() * quantity;
}
private void updateCartTable() {
cartTableModel.setRowCount(0);
totalAmount = 0.0;
// 这里简化了,实际应该从cartProducts中读取并计算
// 为了演示,我们假设已经添加了商品
try (Connection conn = DBUtil.getConnection()) {
String sql = "SELECT * FROM products WHERE id IN (1, 2)"; // 模拟已添加的商品
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
Vector<Object> row = new Vector<>();
int quantity = 1; // 模拟数量为1
row.add(rs.getInt("id"));
row.add(rs.getString("name"));
row.add(rs.getDouble("price"));
row.add(quantity);
row.add(rs.getDouble("price") * quantity);
cartTableModel.addRow(row);
totalAmount += rs.getDouble("price") * quantity;
}
} catch (SQLException e) {
e.printStackTrace();
}
// 更新总计
cartTableModel.addRow(new Object[]{"", "", "", "总计:", totalAmount});
}
private void checkout() {
if (cartProducts.isEmpty()) {
JOptionPane.showMessageDialog(this, "购物车为空,无法结算!");
return;
}
try (Connection conn = DBUtil.getConnection()) {
conn.setAutoCommit(false); // 开启事务
// 1. 创建订单
String orderSql = "INSERT INTO orders (user_id, order_date, total_amount) VALUES (?, NOW(), ?)";
PreparedStatement orderPstmt = conn.prepareStatement(orderSql, Statement.RETURN_GENERATED_KEYS);
orderPstmt.setInt(1, currentUser.getId());
orderPstmt.setDouble(2, totalAmount);
orderPstmt.executeUpdate();
ResultSet rs = orderPstmt.getGeneratedKeys();
int orderId = 0;
if (rs.next()) {
orderId = rs.getInt(1);
}
// 2. 创建订单详情并更新库存
for (Product p : cartProducts) {
String itemSql = "INSERT INTO order_items (order_id, product_id, quantity, price) VALUES (?, ?, ?, ?)";
PreparedStatement itemPstmt = conn.prepareStatement(itemSql);
itemPstmt.setInt(1, orderId);
itemPstmt.setInt(2, p.getId());
itemPstmt.setInt(3, 1); // 假设数量为1
itemPstmt.setDouble(4, p.getPrice());
itemPstmt.executeUpdate();
// 更新库存
String stockSql = "UPDATE products SET stock = stock - 1 WHERE id = ?";
PreparedStatement stockPstmt = conn.prepareStatement(stockSql);
stockPstmt.setInt(1, p.getId());
stockPstmt.executeUpdate();
}
conn.commit(); // 提交事务
JOptionPane.showMessageDialog(this, "订单创建成功!订单号: " + orderId);
cartProducts.clear();
updateCartTable();
this.dispose();
} catch (SQLException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, "结算失败: " + e.getMessage());
}
}
}
订单模块 (OrderFrame.java)
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.sql.*;
import java.util.Vector;
public class OrderFrame extends JFrame {
private MainFrame parentFrame;
private User currentUser;
public OrderFrame(MainFrame parentFrame, User currentUser) {
this.parentFrame = parentFrame;
this.currentUser = currentUser;
setTitle("我的订单");
setSize(800, 500);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
DefaultTableModel tableModel = new DefaultTableModel(new String[]{"订单ID", "下单日期", "总金额"}, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
JTable orderTable = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(orderTable);
add(scrollPane, BorderLayout.CENTER);
JButton refreshButton = new JButton("刷新");
refreshButton.addActionListener(e -> loadOrders(tableModel));
add(refreshButton, BorderLayout.SOUTH);
loadOrders(tableModel);
}
private void loadOrders(DefaultTableModel model) {
model.setRowCount(0);
try (Connection conn = DBUtil.getConnection()) {
String sql = "SELECT id, order_date, total_amount FROM orders WHERE user_id = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, currentUser.getId());
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Vector<Object> row = new Vector<>();
row.add(rs.getInt("id"));
row.add(rs.getTimestamp("order_date"));
row.add(rs.getDouble("total_amount"));
model.addRow(row);
}
} catch (SQLException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, "加载订单失败: " + e.getMessage());
}
}
}
第四部分:总结与展望
我们已经成功构建了一个功能相对完整的“我行我素”购物管理系统,这个项目涵盖了:
- GUI开发:使用Swing创建了多个交互界面。
- 数据库交互:通过JDBC实现了数据的增删改查。
- 业务逻辑:模拟了从商品浏览、加入购物车到下单的完整购物流程。
- 面向对象:使用了类和对象来组织代码,提高了可维护性。
如何运行
- 准备数据库:按照上面的SQL脚本创建
my_shopping_db数据库和相应的表。 - 初始化数据:向
users表中插入至少一个管理员用户(用户名admin,密码password)。 - 配置连接:修改
DBUtil.java中的URL、USER和PASSWORD为你的实际数据库配置。 - 编译运行:在IDE中运行
LoginFrame.java的main方法。
未来可以扩展的方向
- 角色权限细化:实现真正的管理员和顾客角色,顾客不能进入商品管理界面。
- 更完善的UI:使用更美观的布局管理器(如
GridBagLayout)和组件,美化界面。 - 商品选择优化:在“加入购物车”时,弹出一个带JList或JTable的商品列表,而不是手动输入ID。
- 购物车功能增强:允许在购物车中修改商品数量或删除商品,并实时计算总价。
- 异常处理:增加更健壮的异常处理机制,如数据库连接失败时的重试逻辑。
- 打包部署:将项目打包成可执行的
.jar文件,方便分发。 - 多线程:对于耗时操作(如大数据查询),可以使用SwingWorker来避免界面卡顿。
这个项目是一个很好的起点,通过不断迭代和完善,它可以成长为一个非常实用的应用程序。
