Redis高效反向海淘购物车合并与过期清理实战教程

2026-06-13阅读 0热度 0
其他

开发者在构建反向海淘系统时,会发现购物车模型与本地电商存在显著差异。用户往往同时从淘宝、1688等多个店铺挑选商品,且大量商品设有最低起批量限制。更棘手的是,代购订单通常隔几天才集中提交集运,这就要求购物车数据既要持久化存储,又必须防止存储无限膨胀。我们在Taocarts项目中采用Redis管理购物车,设计出按商家分组的Hash结构,并引入自动过期机制。以下直接展示实现细节。

使用Redis实现反向海淘购物车合并与过期清理

一、购物车的特殊需求

反向海淘场景下的购物车,与常规电商相比,核心差异在于:用户跨店铺下单、商品普遍有最低起批门槛、提交时间高度不确定。因此购物车数据必须持久保存,但又不能无限积累——将过期时间设为7天是平衡存储与用户体验的合理方案。

二、数据结构设计

先定义购物车商品项的数据结构:

// 购物车商品项
@Data
public class CartItem {
    private Long itemId;            // 商品ID
    private String title;
    private String skuProperties;   // 所选规格JSON
    private Integer quantity;
    private BigDecimal price;
    private Long shopId;            // 店铺ID
    private Integer minOrderQty;    // 最低起批量
}
// 购物车整体结构:Hash存储,key=cart:userId,field=shopId,value=该店铺下的商品列表JSON

采用Hash结构,key以用户ID为前缀,field映射店铺ID,value存储该店铺下的商品列表。这样的分组方式便于后续按店铺批量操作。

三、核心操作

核心操作涵盖添加商品、移除商品以及按店铺分组获取购物车。实现代码如下:

@Service
public class CartService {
    @Autowired
    private RedisTemplate redisTemplate;
    private static final String CART_KEY_PREFIX = "cart:";

    // 添加商品到购物车
    public void addItem(Long userId, CartItem item) {
        String key = CART_KEY_PREFIX + userId;
        String shopKey = String.valueOf(item.getShopId());
        // 获取该店铺现有商品列表
        List shopItems = getShopItems(userId, item.getShopId());
        Optional existing = shopItems.stream()
            .filter(i -> i.getItemId().equals(item.getItemId()) 
                && i.getSkuProperties().equals(item.getSkuProperties()))
            .findFirst();
        if (existing.isPresent()) {
            existing.get().setQuantity(existing.get().getQuantity() + item.getQuantity());
        } else {
            shopItems.add(item);
        }
        // 序列化存储
        String json = JSON.toJSONString(shopItems);
        redisTemplate.opsForHash().put(key, shopKey, json);
        // 设置整个购物车的过期时间为7天
        redisTemplate.expire(key, Duration.ofDays(7));
    }

    // 移除商品
    public void removeItem(Long userId, Long shopId, Long itemId, String sku) {
        String key = CART_KEY_PREFIX + userId;
        List shopItems = getShopItems(userId, shopId);
        shopItems.removeIf(i -> i.getItemId().equals(itemId) && i.getSkuProperties().equals(sku));
        if (shopItems.isEmpty()) {
            redisTemplate.opsForHash().delete(key, String.valueOf(shopId));
        } else {
            redisTemplate.opsForHash().put(key, String.valueOf(shopId), JSON.toJSONString(shopItems));
        }
    }

    // 获取购物车所有商品(按店铺分组)
    public Map> getCart(Long userId) {
        String key = CART_KEY_PREFIX + userId;
        Map entries = redisTemplate.opsForHash().entries(key);
        Map> result = new HashMap<>();
        for (Map.Entry entry : entries.entrySet()) {
            Long shopId = Long.valueOf(entry.getKey().toString());
            List items = JSON.parseArray(entry.getValue().toString(), CartItem.class);
            result.put(shopId, items);
        }
        return result;
    }

    private List getShopItems(Long userId, Long shopId) {
        String key = CART_KEY_PREFIX + userId;
        String json = (String) redisTemplate.opsForHash().get(key, String.valueOf(shopId));
        if (json == null) {
            return new ArrayList<>();
        }
        return JSON.parseArray(json, CartItem.class);
    }
}

添加商品时,先检索同店铺内是否已存在相同规格的商品:若存在则累加数量,否则新增条目。每次操作都刷新整个购物车的过期时间,确保活跃用户的购物车不会因长时间未操作而失效。

四、最低起批量校验

结算环节必须对每个店铺内商品的数量进行最低起批量校验。逻辑简洁:遍历所有店铺下的商品,若某件商品数量低于其最低起批量,立即抛出异常。

public void validateMinOrderQty(Long userId) {
    Map> cart = getCart(userId);
    for (Map.Entry> entry : cart.entrySet()) {
        for (CartItem item : entry.getValue()) {
            if (item.getQuantity() < item.getMinOrderQty()) {
                throw new BusinessException(
                    String.format("商品【%s】最少需要购买%d件", item.getTitle(), item.getMinOrderQty()));
            }
        }
    }
}

五、过期清理与主动通知

购物车默认7天自动过期,但用户很可能遗忘。我们在过期前1天通过站内信推送提醒,有效降低流失率。具体利用Redis的key过期事件机制实现。

@Component
public class CartExpirationListener implements KeyExpirationEventListener {
    @Override
    public void onKeyExpired(String key) {
        if (key.startsWith("cart:")) {
            Long userId = Long.valueOf(key.substring(5));
            // 发送站内信提醒
            notificationService.sendCartExpireWarning(userId);
        }
    }
}

注意:Redis的key过期事件默认未开启,需在redis.conf中配置notify-keyspace-events Ex

六、与Taocarts系统的集成

上述购物车逻辑已在Taocarts系统中落地。作为专业代购系统,其购物车模块还支持“代购集运”的批量选择、运费预估等高级功能。搭建反向海淘独立站可直接复用该方案。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策