使用Java代码实现的智能购物商城系统,包含商品浏览、购物车管理和智能推荐功能。推荐算法采用基于用户的协同过滤算法,通过分析用户行为数据为用户推荐个性化商品。
shopping/
├── database.sql # 数据库脚本
├── src/
│ └── com/smartshop/
│ ├── db/
│ │ └── DatabaseConnection.java # 数据库连接工具类
│ ├── model/
│ │ ├── Product.java # 商品模型
│ │ ├── User.java # 用户模型
│ │ └── CartItem.java # 购物车项模型
│ ├── dao/
│ │ ├── ProductDAO.java # 商品数据访问对象
│ │ └── CartDAO.java # 购物车数据访问对象
│ ├── recommendation/
│ │ └── CollaborativeFiltering.java # 协同过滤推荐算法
│ └── ui/
│ └── ShoppingMallGUI.java # 购物商城图形界面
└── README.md # 项目说明文档
-- 创建数据库
CREATE DATABASE IF NOT EXISTS smartshop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE smartshop;
-- 用户表
CREATE TABLE IF NOT EXISTS users (
user_id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
email VARCHAR(100),
phone VARCHAR(20),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 商品表
CREATE TABLE IF NOT EXISTS products (
product_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(200) NOT NULL,
description TEXT,
category VARCHAR(100),
price DECIMAL(10, 2) NOT NULL,
stock INT DEFAULT 0,
image_url VARCHAR(500),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 购物车表
CREATE TABLE IF NOT EXISTS cart (
cart_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT DEFAULT 1,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id),
FOREIGN KEY (product_id) REFERENCES products(product_id),
UNIQUE KEY (user_id, product_id)
);
-- 订单表
CREATE TABLE IF NOT EXISTS orders (
order_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
total_amount DECIMAL(10, 2) NOT NULL,
status VARCHAR(20) DEFAULT 'pending',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id)
);
-- 订单详情表
CREATE TABLE IF NOT EXISTS order_items (
item_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(order_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
-- 用户行为表(用于推荐算法)
CREATE TABLE IF NOT EXISTS user_behavior (
behavior_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
product_id INT NOT NULL,
behavior_type VARCHAR(20) NOT NULL COMMENT 'view, purchase, cart',
rating INT DEFAULT 0 COMMENT '0-5分评分',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
-- 插入示例商品数据
INSERT INTO products (name, description, category, price, stock) VALUES
('智能手机', '最新款智能手机,高性能处理器', '电子产品', 3999.00, 100),
('笔记本电脑', '轻薄本,15.6英寸屏幕', '电子产品', 5999.00, 50),
('无线耳机', '蓝牙5.0,降噪功能', '电子产品', 299.00, 200),
('智能手表', '健康监测,运动追踪', '电子产品', 1299.00, 80),
('平板电脑', '10英寸高清屏幕', '电子产品', 2499.00, 60),
('机械键盘', 'RGB背光,青轴', '电子产品', 499.00, 150),
('游戏鼠标', '16000DPI,可编程按键', '电子产品', 399.00, 120),
('显示器', '27英寸2K分辨率', '电子产品', 1899.00, 40),
('移动电源', '20000mAh,快充', '电子产品', 199.00, 300),
('路由器', 'WiFi6,千兆网口', '电子产品', 699.00, 70);
-- 插入示例用户数据
INSERT INTO users (username, password, email, phone) VALUES
('user1', 'password1', 'user1@example.com', '13800000001'),
('user2', 'password2', 'user2@example.com', '13800000002'),
('user3', 'password3', 'user3@example.com', '13800000003');
-- 插入示例用户行为数据(用于推荐算法)
INSERT INTO user_behavior (user_id, product_id, behavior_type, rating) VALUES
(1, 1, 'view', 4),
(1, 2, 'purchase', 5),
(1, 3, 'view', 3),
(1, 4, 'view', 4),
(2, 1, 'view', 5),
(2, 2, 'view', 3),
(2, 5, 'purchase', 4),
(2, 6, 'view', 4),
(3, 1, 'purchase', 5),
(3, 3, 'view', 4),
(3, 7, 'purchase', 4),
(3, 8, 'view', 3);
package com.smartshop.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* 数据库连接工具类
*/
public class DatabaseConnection {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/smartshop?useSSL=false&serverTimezone=UTC&characterEncoding=utf8";
private static final String USERNAME = "root";
private static final String PASSWORD = "root123";
private static Connection connection = null;
/**
* 获取数据库连接
*/
public static Connection getConnection() {
try {
if (connection == null || connection.isClosed()) {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
return connection;
} catch (ClassNotFoundException e) {
System.err.println("数据库驱动加载失败: " + e.getMessage());
return null;
} catch (SQLException e) {
System.err.println("数据库连接失败: " + e.getMessage());
return null;
}
}
/**
* 关闭数据库连接
*/
public static void closeConnection() {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
System.err.println("关闭数据库连接失败: " + e.getMessage());
}
}
}
/**
* 测试数据库连接
*/
public static boolean testConnection() {
try {
Connection conn = getConnection();
if (conn != null && !conn.isClosed()) {
System.out.println("数据库连接成功!");
return true;
}
return false;
} catch (SQLException e) {
System.err.println("数据库连接测试失败: " + e.getMessage());
return false;
}
}
}
package com.smartshop.model;
/**
* 商品模型类
*/
public class Product {
private int productId;
private String name;
private String description;
private String category;
private double price;
private int stock;
private String imageUrl;
public Product() {
}
public Product(int productId, String name, String description, String category, double price, int stock, String imageUrl) {
this.productId = productId;
this.name = name;
this.description = description;
this.category = category;
this.price = price;
this.stock = stock;
this.imageUrl = imageUrl;
}
// Getters and Setters
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
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 getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
@Override
public String toString() {
return "Product{" +
"productId=" + productId +
", name='" + name + '\'' +
", description='" + description + '\'' +
", category='" + category + '\'' +
", price=" + price +
", stock=" + stock +
", imageUrl='" + imageUrl + '\'' +
'}';
}
}
package com.smartshop.model;
/**
* 用户模型类
*/
public class User {
private int userId;
private String username;
private String password;
private String email;
private String phone;
public User() {
}
public User(int userId, String username, String password, String email, String phone) {
this.userId = userId;
this.username = username;
this.password = password;
this.email = email;
this.phone = phone;
}
// Getters and Setters
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
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 getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", username='" + username + '\'' +
", email='" + email + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
package com.smartshop.model;
/**
* 购物车项模型类
*/
public class CartItem {
private int cartId;
private int userId;
private int productId;
private String productName;
private double price;
private int quantity;
public CartItem() {
}
public CartItem(int cartId, int userId, int productId, String productName, double price, int quantity) {
this.cartId = cartId;
this.userId = userId;
this.productId = productId;
this.productName = productName;
this.price = price;
this.quantity = quantity;
}
// Getters and Setters
public int getCartId() {
return cartId;
}
public void setCartId(int cartId) {
this.cartId = cartId;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
/**
* 计算小计
*/
public double getSubtotal() {
return price * quantity;
}
@Override
public String toString() {
return "CartItem{" +
"cartId=" + cartId +
", userId=" + userId +
", productId=" + productId +
", productName='" + productName + '\'' +
", price=" + price +
", quantity=" + quantity +
'}';
}
}
package com.smartshop.dao;
import com.smartshop.db.DatabaseConnection;
import com.smartshop.model.Product;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 商品数据访问对象类
*/
public class ProductDAO {
/**
* 获取所有商品
*/
public List getAllProducts() {
List products = new ArrayList<>();
String sql = "SELECT * FROM products";
try (Connection conn = DatabaseConnection.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
Product product = new Product();
product.setProductId(rs.getInt("product_id"));
product.setName(rs.getString("name"));
product.setDescription(rs.getString("description"));
product.setCategory(rs.getString("category"));
product.setPrice(rs.getDouble("price"));
product.setStock(rs.getInt("stock"));
product.setImageUrl(rs.getString("image_url"));
products.add(product);
}
} catch (SQLException e) {
System.err.println("获取商品列表失败: " + e.getMessage());
}
return products;
}
/**
* 根据ID获取商品
*/
public Product getProductById(int productId) {
String sql = "SELECT * FROM products WHERE product_id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, productId);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
Product product = new Product();
product.setProductId(rs.getInt("product_id"));
product.setName(rs.getString("name"));
product.setDescription(rs.getString("description"));
product.setCategory(rs.getString("category"));
product.setPrice(rs.getDouble("price"));
product.setStock(rs.getInt("stock"));
product.setImageUrl(rs.getString("image_url"));
return product;
}
} catch (SQLException e) {
System.err.println("获取商品失败: " + e.getMessage());
}
return null;
}
/**
* 根据分类获取商品
*/
public List getProductsByCategory(String category) {
List products = new ArrayList<>();
String sql = "SELECT * FROM products WHERE category = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, category);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Product product = new Product();
product.setProductId(rs.getInt("product_id"));
product.setName(rs.getString("name"));
product.setDescription(rs.getString("description"));
product.setCategory(rs.getString("category"));
product.setPrice(rs.getDouble("price"));
product.setStock(rs.getInt("stock"));
product.setImageUrl(rs.getString("image_url"));
products.add(product);
}
} catch (SQLException e) {
System.err.println("获取分类商品失败: " + e.getMessage());
}
return products;
}
/**
* 搜索商品
*/
public List searchProducts(String keyword) {
List products = new ArrayList<>();
String sql = "SELECT * FROM products WHERE name LIKE ? OR description LIKE ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
String searchPattern = "%" + keyword + "%";
pstmt.setString(1, searchPattern);
pstmt.setString(2, searchPattern);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Product product = new Product();
product.setProductId(rs.getInt("product_id"));
product.setName(rs.getString("name"));
product.setDescription(rs.getString("description"));
product.setCategory(rs.getString("category"));
product.setPrice(rs.getDouble("price"));
product.setStock(rs.getInt("stock"));
product.setImageUrl(rs.getString("image_url"));
products.add(product);
}
} catch (SQLException e) {
System.err.println("搜索商品失败: " + e.getMessage());
}
return products;
}
/**
* 更新商品库存
*/
public boolean updateStock(int productId, int quantity) {
String sql = "UPDATE products SET stock = stock - ? WHERE product_id = ? AND stock >= ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, quantity);
pstmt.setInt(2, productId);
pstmt.setInt(3, quantity);
int affectedRows = pstmt.executeUpdate();
return affectedRows > 0;
} catch (SQLException e) {
System.err.println("更新库存失败: " + e.getMessage());
return false;
}
}
/**
* 获取所有分类
*/
public List getAllCategories() {
List categories = new ArrayList<>();
String sql = "SELECT DISTINCT category FROM products";
try (Connection conn = DatabaseConnection.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
categories.add(rs.getString("category"));
}
} catch (SQLException e) {
System.err.println("获取分类列表失败: " + e.getMessage());
}
return categories;
}
}
package com.smartshop.dao;
import com.smartshop.db.DatabaseConnection;
import com.smartshop.model.CartItem;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 购物车数据访问对象类
*/
public class CartDAO {
/**
* 添加商品到购物车
*/
public boolean addToCart(int userId, int productId, int quantity) {
// 先检查购物车中是否已存在该商品
String checkSql = "SELECT quantity FROM cart WHERE user_id = ? AND product_id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement checkPstmt = conn.prepareStatement(checkSql)) {
checkPstmt.setInt(1, userId);
checkPstmt.setInt(2, productId);
ResultSet rs = checkPstmt.executeQuery();
if (rs.next()) {
// 已存在,更新数量
int currentQuantity = rs.getInt("quantity");
String updateSql = "UPDATE cart SET quantity = ? WHERE user_id = ? AND product_id = ?";
try (PreparedStatement updatePstmt = conn.prepareStatement(updateSql)) {
updatePstmt.setInt(1, currentQuantity + quantity);
updatePstmt.setInt(2, userId);
updatePstmt.setInt(3, productId);
return updatePstmt.executeUpdate() > 0;
}
} else {
// 不存在,插入新记录
String insertSql = "INSERT INTO cart (user_id, product_id, quantity) VALUES (?, ?, ?)";
try (PreparedStatement insertPstmt = conn.prepareStatement(insertSql)) {
insertPstmt.setInt(1, userId);
insertPstmt.setInt(2, productId);
insertPstmt.setInt(3, quantity);
return insertPstmt.executeUpdate() > 0;
}
}
} catch (SQLException e) {
System.err.println("添加到购物车失败: " + e.getMessage());
return false;
}
}
/**
* 获取用户购物车中的所有商品
*/
public List getCartItems(int userId) {
List cartItems = new ArrayList<>();
String sql = "SELECT c.*, p.name as product_name, p.price " +
"FROM cart c " +
"JOIN products p ON c.product_id = p.product_id " +
"WHERE c.user_id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
CartItem item = new CartItem();
item.setCartId(rs.getInt("cart_id"));
item.setUserId(rs.getInt("user_id"));
item.setProductId(rs.getInt("product_id"));
item.setProductName(rs.getString("product_name"));
item.setPrice(rs.getDouble("price"));
item.setQuantity(rs.getInt("quantity"));
cartItems.add(item);
}
} catch (SQLException e) {
System.err.println("获取购物车商品失败: " + e.getMessage());
}
return cartItems;
}
/**
* 更新购物车中的商品数量
*/
public boolean updateCartItem(int userId, int productId, int quantity) {
String sql = "UPDATE cart SET quantity = ? WHERE user_id = ? AND product_id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, quantity);
pstmt.setInt(2, userId);
pstmt.setInt(3, productId);
return pstmt.executeUpdate() > 0;
} catch (SQLException e) {
System.err.println("更新购物车商品失败: " + e.getMessage());
return false;
}
}
/**
* 从购物车中删除商品
*/
public boolean removeFromCart(int userId, int productId) {
String sql = "DELETE FROM cart WHERE user_id = ? AND product_id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
pstmt.setInt(2, productId);
return pstmt.executeUpdate() > 0;
} catch (SQLException e) {
System.err.println("从购物车删除商品失败: " + e.getMessage());
return false;
}
}
/**
* 清空购物车
*/
public boolean clearCart(int userId) {
String sql = "DELETE FROM cart WHERE user_id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
return pstmt.executeUpdate() > 0;
} catch (SQLException e) {
System.err.println("清空购物车失败: " + e.getMessage());
return false;
}
}
/**
* 计算购物车总金额
*/
public double getCartTotal(int userId) {
String sql = "SELECT SUM(c.quantity * p.price) as total " +
"FROM cart c " +
"JOIN products p ON c.product_id = p.product_id " +
"WHERE c.user_id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
return rs.getDouble("total");
}
} catch (SQLException e) {
System.err.println("计算购物车总金额失败: " + e.getMessage());
}
return 0.0;
}
/**
* 获取购物车商品数量
*/
public int getCartItemCount(int userId) {
String sql = "SELECT SUM(quantity) as count FROM cart WHERE user_id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
return rs.getInt("count");
}
} catch (SQLException e) {
System.err.println("获取购物车商品数量失败: " + e.getMessage());
}
return 0;
}
}
package com.smartshop.recommendation;
import com.smartshop.db.DatabaseConnection;
import com.smartshop.model.Product;
import java.sql.*;
import java.util.*;
/**
* 协同过滤推荐算法
* 基于用户的协同过滤算法
*/
public class CollaborativeFiltering {
/**
* 为用户推荐商品
* @param userId 用户ID
* @param topN 推荐商品数量
* @return 推荐商品列表
*/
public List recommendProducts(int userId, int topN) {
// 1. 找到与目标用户相似的用户
Map similarUsers = findSimilarUsers(userId);
// 2. 获取相似用户喜欢的商品
Map productScores = new HashMap<>();
for (Map.Entry entry : similarUsers.entrySet()) {
int similarUserId = entry.getKey();
double similarity = entry.getValue();
// 获取该用户购买或浏览过的商品
List userProducts = getUserProducts(similarUserId);
for (RecommendedProduct product : userProducts) {
// 如果目标用户还没有购买过这个商品,则计算推荐分数
if (!hasUserPurchasedProduct(userId, product.getProductId())) {
double score = product.getRating() * similarity;
productScores.merge(product.getProductId(), score, Double::sum);
}
}
}
// 3. 按分数排序并返回topN个商品
List> sortedProducts = new ArrayList<>(productScores.entrySet());
sortedProducts.sort((a, b) -> Double.compare(b.getValue(), a.getValue()));
List recommendedProducts = new ArrayList<>();
for (int i = 0; i < Math.min(topN, sortedProducts.size()); i++) {
int productId = sortedProducts.get(i).getKey();
Product product = getProductById(productId);
if (product != null) {
recommendedProducts.add(product);
}
}
return recommendedProducts;
}
/**
* 找到与目标用户相似的用户
* 使用余弦相似度计算用户相似性
*/
private Map findSimilarUsers(int userId) {
Map similarUsers = new HashMap<>();
// 获取所有用户
List allUsers = getAllUsers();
// 获取目标用户的评分向量
Map targetUserRatings = getUserRatings(userId);
for (int otherUserId : allUsers) {
if (otherUserId != userId) {
// 获取其他用户的评分向量
Map otherUserRatings = getUserRatings(otherUserId);
// 计算余弦相似度
double similarity = calculateCosineSimilarity(targetUserRatings, otherUserRatings);
if (similarity > 0) {
similarUsers.put(otherUserId, similarity);
}
}
}
// 按相似度排序
List> sortedUsers = new ArrayList<>(similarUsers.entrySet());
sortedUsers.sort((a, b) -> Double.compare(b.getValue(), a.getValue()));
// 只返回最相似的5个用户
Map result = new LinkedHashMap<>();
for (int i = 0; i < Math.min(5, sortedUsers.size()); i++) {
result.put(sortedUsers.get(i).getKey(), sortedUsers.get(i).getValue());
}
return result;
}
/**
* 计算两个用户之间的余弦相似度
*/
private double calculateCosineSimilarity(Map user1Ratings, Map user2Ratings) {
Set commonProducts = new HashSet<>(user1Ratings.keySet());
commonProducts.retainAll(user2Ratings.keySet());
if (commonProducts.isEmpty()) {
return 0.0;
}
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (int productId : commonProducts) {
double rating1 = user1Ratings.get(productId);
double rating2 = user2Ratings.get(productId);
dotProduct += rating1 * rating2;
norm1 += rating1 * rating1;
norm2 += rating2 * rating2;
}
if (norm1 == 0 || norm2 == 0) {
return 0.0;
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
/**
* 获取用户的评分向量
*/
private Map getUserRatings(int userId) {
Map ratings = new HashMap<>();
String sql = "SELECT product_id, rating FROM user_behavior WHERE user_id = ? AND rating > 0";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int productId = rs.getInt("product_id");
double rating = rs.getDouble("rating");
ratings.put(productId, rating);
}
} catch (SQLException e) {
System.err.println("获取用户评分失败: " + e.getMessage());
}
return ratings;
}
/**
* 获取用户购买或浏览过的商品
*/
private List getUserProducts(int userId) {
List products = new ArrayList<>();
String sql = "SELECT product_id, AVG(rating) as avg_rating FROM user_behavior " +
"WHERE user_id = ? AND rating > 0 GROUP BY product_id";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
RecommendedProduct product = new RecommendedProduct();
product.setProductId(rs.getInt("product_id"));
product.setRating(rs.getDouble("avg_rating"));
products.add(product);
}
} catch (SQLException e) {
System.err.println("获取用户商品失败: " + e.getMessage());
}
return products;
}
/**
* 检查用户是否已经购买过某个商品
*/
private boolean hasUserPurchasedProduct(int userId, int productId) {
String sql = "SELECT COUNT(*) FROM user_behavior WHERE user_id = ? AND product_id = ? AND behavior_type = 'purchase'";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
pstmt.setInt(2, productId);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
return rs.getInt(1) > 0;
}
} catch (SQLException e) {
System.err.println("检查用户购买记录失败: " + e.getMessage());
}
return false;
}
/**
* 获取所有用户ID
*/
private List getAllUsers() {
List users = new ArrayList<>();
String sql = "SELECT DISTINCT user_id FROM users";
try (Connection conn = DatabaseConnection.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
users.add(rs.getInt("user_id"));
}
} catch (SQLException e) {
System.err.println("获取用户列表失败: " + e.getMessage());
}
return users;
}
/**
* 根据商品ID获取商品信息
*/
private Product getProductById(int productId) {
String sql = "SELECT * FROM products WHERE product_id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, productId);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
Product product = new Product();
product.setProductId(rs.getInt("product_id"));
product.setName(rs.getString("name"));
product.setDescription(rs.getString("description"));
product.setCategory(rs.getString("category"));
product.setPrice(rs.getDouble("price"));
product.setStock(rs.getInt("stock"));
product.setImageUrl(rs.getString("image_url"));
return product;
}
} catch (SQLException e) {
System.err.println("获取商品信息失败: " + e.getMessage());
}
return null;
}
/**
* 记录用户行为(用于推荐算法)
*/
public void recordUserBehavior(int userId, int productId, String behaviorType, int rating) {
String sql = "INSERT INTO user_behavior (user_id, product_id, behavior_type, rating) VALUES (?, ?, ?, ?)";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
pstmt.setInt(2, productId);
pstmt.setString(3, behaviorType);
pstmt.setInt(4, rating);
pstmt.executeUpdate();
} catch (SQLException e) {
System.err.println("记录用户行为失败: " + e.getMessage());
}
}
/**
* 内部类:推荐商品
*/
private static class RecommendedProduct {
private int productId;
private double rating;
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public double getRating() {
return rating;
}
public void setRating(double rating) {
this.rating = rating;
}
}
}
package com.smartshop.ui;
import com.smartshop.dao.CartDAO;
import com.smartshop.dao.ProductDAO;
import com.smartshop.model.CartItem;
import com.smartshop.model.Product;
import com.smartshop.recommendation.CollaborativeFiltering;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
/**
* 智能购物商城图形界面
*/
public class ShoppingMallGUI extends JFrame {
private static final int CURRENT_USER_ID = 1; // 当前用户ID
private ProductDAO productDAO;
private CartDAO cartDAO;
private CollaborativeFiltering collaborativeFiltering;
private JTabbedPane tabbedPane;
private JPanel productsPanel;
private JPanel cartPanel;
private JPanel recommendationsPanel;
private DefaultListModel cartModel;
private JList cartList;
private JLabel totalLabel;
// 设置全局中文字体
private static final Font CHINESE_FONT = new Font("Microsoft YaHei", Font.PLAIN, 14);
private static final Font CHINESE_FONT_BOLD = new Font("Microsoft YaHei", Font.BOLD, 14);
private static final Font CHINESE_FONT_LARGE = new Font("Microsoft YaHei", Font.BOLD, 24);
private static final Font CHINESE_FONT_TITLE = new Font("Microsoft YaHei", Font.BOLD, 20);
public ShoppingMallGUI() {
productDAO = new ProductDAO();
cartDAO = new CartDAO();
collaborativeFiltering = new CollaborativeFiltering();
// 设置全局字体
setGlobalFont();
// 测试数据库连接
if (!com.smartshop.db.DatabaseConnection.testConnection()) {
JOptionPane.showMessageDialog(this, "数据库连接失败,请检查数据库配置!",
"错误", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
initializeUI();
loadProducts();
loadRecommendations();
loadCart();
}
/**
* 设置全局中文字体
*/
private void setGlobalFont() {
// 设置UIManager的全局字体
UIManager.put("Label.font", CHINESE_FONT);
UIManager.put("Button.font", CHINESE_FONT);
UIManager.put("TextField.font", CHINESE_FONT);
UIManager.put("TextArea.font", CHINESE_FONT);
UIManager.put("Panel.font", CHINESE_FONT);
UIManager.put("TabbedPane.font", CHINESE_FONT_BOLD);
UIManager.put("List.font", CHINESE_FONT);
UIManager.put("Table.font", CHINESE_FONT);
UIManager.put("TableHeader.font", CHINESE_FONT_BOLD);
UIManager.put("MenuItem.font", CHINESE_FONT);
UIManager.put("CheckBox.font", CHINESE_FONT);
UIManager.put("RadioButton.font", CHINESE_FONT);
UIManager.put("ComboBox.font", CHINESE_FONT);
UIManager.put("Spinner.font", CHINESE_FONT);
UIManager.put("FormattedTextField.font", CHINESE_FONT);
UIManager.put("OptionPane.font", CHINESE_FONT);
UIManager.put("OptionPane.buttonFont", CHINESE_FONT_BOLD);
UIManager.put("Tree.font", CHINESE_FONT);
}
/**
* 初始化用户界面
*/
private void initializeUI() {
setTitle("智能购物商城");
setSize(1200, 800);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
// 创建主面板
JPanel mainPanel = new JPanel(new BorderLayout());
// 创建工具栏
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
JLabel titleLabel = new JLabel("智能购物商城", JLabel.CENTER);
titleLabel.setFont(CHINESE_FONT_LARGE);
titleLabel.setBorder(new EmptyBorder(10, 20, 10, 20));
JButton refreshButton = new JButton("刷新");
refreshButton.setFont(CHINESE_FONT);
refreshButton.addActionListener(e -> {
loadProducts();
loadRecommendations();
loadCart();
});
toolBar.add(titleLabel);
toolBar.add(Box.createHorizontalGlue());
toolBar.add(refreshButton);
// 创建选项卡面板
tabbedPane = new JTabbedPane();
tabbedPane.setFont(CHINESE_FONT_BOLD);
// 商品浏览选项卡
productsPanel = new JPanel(new BorderLayout());
tabbedPane.addTab("商品浏览", productsPanel);
// 购物车选项卡
cartPanel = new JPanel(new BorderLayout());
tabbedPane.addTab("购物车", cartPanel);
// 推荐商品选项卡
recommendationsPanel = new JPanel(new BorderLayout());
tabbedPane.addTab("推荐商品", recommendationsPanel);
mainPanel.add(toolBar, BorderLayout.NORTH);
mainPanel.add(tabbedPane, BorderLayout.CENTER);
add(mainPanel);
}
/**
* 加载商品列表
*/
private void loadProducts() {
productsPanel.removeAll();
// 创建搜索面板
JPanel searchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
searchPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
JTextField searchField = new JTextField(30);
searchField.setFont(CHINESE_FONT);
JButton searchButton = new JButton("搜索");
searchButton.setFont(CHINESE_FONT);
searchButton.addActionListener(e -> {
String keyword = searchField.getText().trim();
if (!keyword.isEmpty()) {
displayProducts(productDAO.searchProducts(keyword));
} else {
displayProducts(productDAO.getAllProducts());
}
});
JButton allButton = new JButton("显示全部");
allButton.setFont(CHINESE_FONT);
allButton.addActionListener(e -> {
searchField.setText("");
displayProducts(productDAO.getAllProducts());
});
JLabel searchLabel = new JLabel("搜索关键词:");
searchLabel.setFont(CHINESE_FONT);
searchPanel.add(searchLabel);
searchPanel.add(searchField);
searchPanel.add(searchButton);
searchPanel.add(allButton);
productsPanel.add(searchPanel, BorderLayout.NORTH);
// 创建商品显示面板
JPanel displayPanel = new JPanel(new BorderLayout());
productsPanel.add(displayPanel, BorderLayout.CENTER);
// 显示所有商品
displayProducts(productDAO.getAllProducts());
productsPanel.revalidate();
productsPanel.repaint();
}
/**
* 显示商品列表
*/
private void displayProducts(List products) {
// 从BorderLayout的CENTER组件中获取容器
Component centerComponent = ((BorderLayout) productsPanel.getLayout()).getLayoutComponent(BorderLayout.CENTER);
JPanel productsContainer;
if (centerComponent == null) {
productsContainer = new JPanel(new BorderLayout());
productsPanel.add(productsContainer, BorderLayout.CENTER);
} else {
productsContainer = (JPanel) centerComponent;
}
productsContainer.removeAll();
if (products == null || products.isEmpty()) {
JLabel emptyLabel = new JLabel("暂无商品", JLabel.CENTER);
emptyLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 16));
productsContainer.add(emptyLabel, BorderLayout.CENTER);
} else {
JPanel gridPanel = new JPanel(new GridLayout(0, 3, 15, 15));
gridPanel.setBorder(new EmptyBorder(15, 15, 15, 15));
for (Product product : products) {
JPanel productPanel = createProductPanel(product);
gridPanel.add(productPanel);
}
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
productsContainer.add(scrollPane, BorderLayout.CENTER);
}
productsContainer.revalidate();
productsContainer.repaint();
}
/**
* 创建商品面板
*/
private JPanel createProductPanel(Product product) {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(new LineBorder(new Color(200, 200, 200), 1));
panel.setBackground(Color.WHITE);
// 商品名称
JLabel nameLabel = new JLabel(product.getName(), JLabel.CENTER);
nameLabel.setFont(CHINESE_FONT_BOLD);
nameLabel.setBorder(new EmptyBorder(10, 5, 5, 5));
// 商品描述
JTextArea descArea = new JTextArea(product.getDescription());
descArea.setEditable(false);
descArea.setLineWrap(true);
descArea.setWrapStyleWord(true);
descArea.setFont(CHINESE_FONT);
descArea.setBorder(new EmptyBorder(5, 10, 5, 10));
descArea.setBackground(Color.WHITE);
// 商品价格
JLabel priceLabel = new JLabel(String.format("¥%.2f", product.getPrice()), JLabel.CENTER);
priceLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 18));
priceLabel.setForeground(new Color(255, 51, 51));
priceLabel.setBorder(new EmptyBorder(5, 5, 5, 5));
// 商品库存
JLabel stockLabel = new JLabel("库存: " + product.getStock(), JLabel.CENTER);
stockLabel.setFont(CHINESE_FONT);
stockLabel.setBorder(new EmptyBorder(5, 5, 10, 5));
// 添加到购物车按钮
JButton addToCartButton = new JButton("加入购物车");
addToCartButton.setFont(CHINESE_FONT);
addToCartButton.setBackground(new Color(51, 122, 183));
addToCartButton.setForeground(Color.WHITE);
addToCartButton.addActionListener(e -> addToCart(product));
// 按钮面板
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
buttonPanel.add(addToCartButton);
buttonPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
// 信息面板
JPanel infoPanel = new JPanel(new BorderLayout());
infoPanel.add(nameLabel, BorderLayout.NORTH);
infoPanel.add(descArea, BorderLayout.CENTER);
infoPanel.add(priceLabel, BorderLayout.SOUTH);
panel.add(infoPanel, BorderLayout.NORTH);
panel.add(stockLabel, BorderLayout.CENTER);
panel.add(buttonPanel, BorderLayout.SOUTH);
return panel;
}
/**
* 加载购物车
*/
private void loadCart() {
cartPanel.removeAll();
// 创建购物车列表
cartModel = new DefaultListModel<>();
cartList = new JList<>(cartModel);
cartList.setFont(CHINESE_FONT);
cartList.setCellRenderer(new CartItemRenderer());
// 创建操作面板
JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
actionPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
JButton removeButton = new JButton("移除选中");
removeButton.setFont(CHINESE_FONT);
removeButton.addActionListener(e -> removeFromCart());
JButton clearButton = new JButton("清空购物车");
clearButton.setFont(CHINESE_FONT);
clearButton.addActionListener(e -> clearCart());
totalLabel = new JLabel("总计: ¥0.00");
totalLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 16));
totalLabel.setForeground(new Color(255, 51, 51));
actionPanel.add(removeButton);
actionPanel.add(clearButton);
actionPanel.add(Box.createHorizontalStrut(20));
actionPanel.add(totalLabel);
cartPanel.add(actionPanel, BorderLayout.NORTH);
cartPanel.add(new JScrollPane(cartList), BorderLayout.CENTER);
// 更新购物车显示
updateCartDisplay();
cartPanel.revalidate();
cartPanel.repaint();
}
/**
* 更新购物车显示
*/
private void updateCartDisplay() {
cartModel.clear();
List cartItems = cartDAO.getCartItems(CURRENT_USER_ID);
for (CartItem item : cartItems) {
cartModel.addElement(item);
}
double total = cartDAO.getCartTotal(CURRENT_USER_ID);
totalLabel.setText(String.format("总计: ¥%.2f", total));
}
/**
* 添加商品到购物车
*/
private void addToCart(Product product) {
if (product.getStock() <= 0) {
JOptionPane.showMessageDialog(this, "商品库存不足!", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
boolean success = cartDAO.addToCart(CURRENT_USER_ID, product.getProductId(), 1);
if (success) {
// 记录用户行为
collaborativeFiltering.recordUserBehavior(CURRENT_USER_ID, product.getProductId(), "cart", 3);
JOptionPane.showMessageDialog(this, "商品已添加到购物车!", "成功", JOptionPane.INFORMATION_MESSAGE);
updateCartDisplay();
} else {
JOptionPane.showMessageDialog(this, "添加失败", "错误", JOptionPane.ERROR_MESSAGE);
}
}
/**
* 从购物车移除商品
*/
private void removeFromCart() {
CartItem selectedItem = cartList.getSelectedValue();
if (selectedItem == null) {
JOptionPane.showMessageDialog(this, "请先选择要移除的商品", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
int confirm = JOptionPane.showConfirmDialog(this,
"确定要移除选中的商品吗?", "确认", JOptionPane.YES_NO_OPTION);
if (confirm == JOptionPane.YES_OPTION) {
boolean success = cartDAO.removeFromCart(CURRENT_USER_ID, selectedItem.getProductId());
if (success) {
updateCartDisplay();
} else {
JOptionPane.showMessageDialog(this, "移除失败", "错误", JOptionPane.ERROR_MESSAGE);
}
}
}
/**
* 清空购物车
*/
private void clearCart() {
int confirm = JOptionPane.showConfirmDialog(this,
"确定要清空购物车吗?", "确认", JOptionPane.YES_NO_OPTION);
if (confirm == JOptionPane.YES_OPTION) {
boolean success = cartDAO.clearCart(CURRENT_USER_ID);
if (success) {
updateCartDisplay();
} else {
JOptionPane.showMessageDialog(this, "清空失败", "错误", JOptionPane.ERROR_MESSAGE);
}
}
}
/**
* 加载推荐商品
*/
private void loadRecommendations() {
recommendationsPanel.removeAll();
JLabel titleLabel = new JLabel("为您推荐", JLabel.CENTER);
titleLabel.setFont(CHINESE_FONT_TITLE);
titleLabel.setBorder(new EmptyBorder(15, 15, 15, 15));
recommendationsPanel.add(titleLabel, BorderLayout.NORTH);
// 获取推荐商品
List recommendedProducts = collaborativeFiltering.recommendProducts(CURRENT_USER_ID, 6);
JPanel gridPanel = new JPanel(new GridLayout(0, 3, 15, 15));
gridPanel.setBorder(new EmptyBorder(15, 15, 15, 15));
if (recommendedProducts.isEmpty()) {
JLabel emptyLabel = new JLabel("暂无推荐商品,请先浏览商品并添加到购物车", JLabel.CENTER);
emptyLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 16));
gridPanel.add(emptyLabel);
} else {
for (Product product : recommendedProducts) {
JPanel productPanel = createProductPanel(product);
gridPanel.add(productPanel);
}
}
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
recommendationsPanel.add(scrollPane, BorderLayout.CENTER);
recommendationsPanel.revalidate();
recommendationsPanel.repaint();
}
/**
* 购物车项目渲染器
*/
private static class CartItemRenderer extends JPanel implements ListCellRenderer {
@Override
public Component getListCellRendererComponent(JList extends CartItem> list, CartItem value,
int index, boolean isSelected, boolean cellHasFocus) {
setLayout(new BorderLayout());
setBorder(new EmptyBorder(10, 10, 10, 10));
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
removeAll();
// 商品信息
JPanel infoPanel = new JPanel(new GridLayout(3, 1));
JLabel nameLabel = new JLabel(value.getProductName());
nameLabel.setFont(CHINESE_FONT_BOLD);
JLabel priceLabel = new JLabel(String.format("价格: ¥%.2f", value.getPrice()));
priceLabel.setFont(CHINESE_FONT);
JLabel quantityLabel = new JLabel("数量: " + value.getQuantity());
quantityLabel.setFont(CHINESE_FONT);
infoPanel.add(nameLabel);
infoPanel.add(priceLabel);
infoPanel.add(quantityLabel);
// 小计
JLabel subtotalLabel = new JLabel(String.format("小计: ¥%.2f", value.getSubtotal()));
subtotalLabel.setFont(CHINESE_FONT_BOLD);
subtotalLabel.setForeground(new Color(255, 51, 51));
add(infoPanel, BorderLayout.WEST);
add(subtotalLabel, BorderLayout.EAST);
return this;
}
}
/**
* 主方法
*/
public static void main(String[] args) {
// 设置系统外观
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
// 在事件分发线程中创建和显示GUI
SwingUtilities.invokeLater(() -> {
ShoppingMallGUI gui = new ShoppingMallGUI();
gui.setVisible(true);
});
}
}
确保已安装MySQL 8.0并启动服务
或者把上述建库建表语句复制到database.sql文件中,然后执行database.sql脚本创建数据库和表:
mysql -u root -p < database.sql
或在MySQL命令行中执行:
source database.sql;
需要下载MySQL Connector驱动包,并添加到项目的classpath中,或者放在项目目录下。
下载地址: https://dev.mysql.com/downloads/connector/j/
下载后,将mysql-connector-j-9.6.0.jar文件放在项目目录下,或者添加到项目的classpath中。
或者从本网站下载:mysql-connector-j-9.6.0.jar
假设MySQL驱动包为mysql-connector-j-9.6.0.jar,编译命令如下:
cd C:\Users\Administrator\shopping
javac -cp "mysql-connector-j-9.6.0.jar" -d build src/com/smartshop/**/*.java
或者使用如下语句逐个编译java文件,注意空格:
javac -encoding UTF-8 -cp ".;mysql-connector-j-9.6.0.jar" com\smartshop\ui\ShoppingMallGUI.java
java -cp "build;mysql-connector-j-9.6.0.jar" com.smartshop.ui.ShoppingMallGUI
或
java -cp ".;mysql-connector-j-9.6.0.jar" com.smartshop.ui.ShoppingMallGUI
本项目采用基于用户的协同过滤算法:
使用余弦相似度计算用户之间的相似性: