Skip to content

设计购物车功能的步骤说明

1. 用户状态处理

  • 未登录用户

    • 存储方式:使用浏览器本地存储(localStorageCookie),键为guest_cart,值为商品列表的JSON字符串。
    • 数据迁移:用户登录后,合并本地购物车数据到服务端(通过API发送合并请求)。
  • 已登录用户

    • 存储方式:服务端使用Redis Hash或数据库表存储,键为用户ID(如cart:user123),字段为商品ID,值为商品详情。

2. 数据结构设计

  • 前端本地存储示例(未登录用户):

    json
    [
      {
        "skuId": "1001",
        "quantity": 2,
        "selected": true,
        "price": 199.00,
        "image": "https://example.com/image.jpg",
        "title": "商品名称",
        "addTime": 1620000000000
      }
    ]
  • Redis存储示例(已登录用户):

    bash
    # 用户购物车Hash结构
    HSET cart:user123 1001 '{"quantity":2,"selected":1,"price":199.00}'
  • 数据库表设计(持久化备份):

    sql
    CREATE TABLE cart (
      user_id VARCHAR(36) NOT NULL,
      sku_id VARCHAR(20) NOT NULL,
      quantity INT DEFAULT 1,
      selected TINYINT(1) DEFAULT 1,
      price DECIMAL(10,2),
      created_time BIGINT,
      updated_time BIGINT,
      PRIMARY KEY (user_id, sku_id)
    );

3. 核心功能实现

3.1 添加商品到购物车
  • 请求示例

    http
    POST /api/cart/add
    {
      "skuId": "1001",
      "quantity": 1
    }
  • 逻辑流程

    1. 校验商品状态:调用商品服务验证SKU是否存在、是否上架。
    2. 更新数量
    • 未登录:前端合并本地数据(相同SKU数量累加)。
    • 已登录:Redis HINCRBY原子增加数量。
      bash
      HINCRBY cart:user123 1001 1  # 数量+1
    1. 返回结果:前端提示“添加成功”并更新本地数据或跳转购物车页。
3.2 修改商品数量
  • 请求示例

    http
    POST /api/cart/update
    {
      "skuId": "1001",
      "quantity": 3
    }
  • 逻辑流程

    1. 校验合法性:数量必须≥1且≤库存上限(调用库存服务)。
    2. 更新数据
    • 未登录:遍历本地数组修改对应SKU数量。
    • 已登录:Redis HSET直接覆盖数量。
      bash
      HSET cart:user123 1001 '{"quantity":3,"selected":1}'
    1. 前端响应:重新计算总价并刷新显示。
3.3 删除商品
  • 请求示例

    http
    POST /api/cart/delete
    {
      "skuIds": ["1001", "1002"]
    }
  • 逻辑流程

    1. 批量处理
    • 未登录:过滤本地数组,移除指定SKU。
    • 已登录:Redis HDEL删除字段。
      bash
      HDEL cart:user123 1001 1002
    1. 更新视图:前端移除对应商品DOM节点。
3.4 选中/取消选中商品
  • 请求示例

    http
    POST /api/cart/select
    {
      "skuIds": ["1001"],
      "selected": false
    }
  • 逻辑流程

    1. 更新选中状态
    • 未登录:遍历本地数组修改selected字段。
    • 已登录:读取Redis Hash中的JSON,修改后重新写入。
      bash
      HSET cart:user123 1001 '{"quantity":3,"selected":0}'
    1. 前端计算:重新统计选中商品的总价。

4. 性能优化与扩展

  • 读写分离

    • 读操作优先访问Redis,写操作同步更新数据库(异步队列)。
    java
    // 异步写入数据库的RocketMQ消费者
    @RocketMQMessageListener(topic = "cart_update", consumerGroup = "cart_group")
    public class CartDBConsumer implements RocketMQListener<CartItem> {
        @Override
        public void onMessage(CartItem item) {
            cartMapper.insertOrUpdate(item); // 插入或更新数据库
        }
    }
  • 缓存预热

    • 用户登录时将其数据库中的购物车数据加载到Redis。
    sql
    SELECT * FROM cart WHERE user_id = 'user123';
    -- 结果转换为Redis HSET命令批量执行
  • 分片策略

    • 大商户或高活跃用户单独分片(如cart:user123_shard1)。

5. 安全与容错

  • 输入校验

    • SKU ID格式校验(防止SQL注入)、数量范围校验(≥1且≤99)。
  • 限流防护

    • 接口添加令牌桶限流(如Guava RateLimiter),防止恶意刷接口。
    java
    RateLimiter limiter = RateLimiter.create(100); // 每秒100次请求
    if (limiter.tryAcquire()) {
        processRequest();
    } else {
        throw new RateLimitException();
    }
  • 数据备份

    • 每日定时任务将Redis购物车数据持久化到数据库。

6. 用户体验增强

  • 实时计算总价

    • 前端监听选中状态和数量变化,实时调用API计算优惠和总价。
    javascript
    // 前端示例:计算选中商品总价
    const total = cartItems
      .filter(item => item.selected)
      .reduce((sum, item) => sum + (item.price * item.quantity), 0);
  • 多端同步

    • Web端与App端通过长连接(WebSocket)同步购物车变更。
    javascript
    const ws = new WebSocket('wss://example.com/cart-sync');
    ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      updateLocalCart(data); // 合并本地购物车
    };

7. 架构图

用户请求 → 负载均衡 → 网关(鉴权/限流)

               购物车服务 → Redis(读写购物车数据)
                   ↓                 ↗ 异步
               数据库(持久化) ← 消息队列(RocketMQ)

总结

通过区分登录状态、优化存储结构、实现核心操作逻辑,并结合异步持久化、限流防护、多端同步等策略,可构建一个高效、稳定且用户体验良好的购物车系统。关键点包括:

  • 状态分离:未登录用户依赖本地存储,已登录用户使用Redis+数据库。
  • 原子操作:利用Redis的原子命令保证数据一致性。
  • 性能优先:读写分离、缓存预热、异步处理提升响应速度。
  • 安全兜底:输入校验、限流、备份机制保障系统健壮性。

文章来源于自己总结和网络转载,内容如有任何问题,请大佬斧正!联系我