游乐游手机版
首页/AI教程/文章详情

基于Redis的反向海淘购物车合并与过期清理方案

时间:2026-06-13 14:50
针对反向海淘购物车商品跨店铺、有最低起批量且提交时间不固定的特点,采用Redis的Hash结构按商家分组存储购物车数据,支持7天自动过期,并在过期前1天发送站内信提醒,同时实现最低起批量校验,兼顾持久化与控制数据膨胀。

在技术开发者的实战视角下,反向海淘购物车的设计逻辑与普通电商有着显著差异。用户常常跨淘宝、1688等多个店铺挑选商品,许多商品还设有最低起批量;更棘手的是,用户往往隔几天才提交代购集运请求,这就要求购物车数据既实现持久化,又不能无限膨胀。我们在Taocarts系统中采用Redis存储购物车数据,设计了按商家分组的存储结构,并支持自动过期清理。以下直接展示实现方案。

使用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的键过期事件来实现。

@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的键过期事件默认并未开启,需在 redis.conf 配置文件中设置 notify-keyspace-events Ex 才能启用该功能。

六、与Taocarts系统的集成应用

上述购物车逻辑已在Taocarts系统中得到完整实现。作为专业的代购系统,该购物车模块还额外支持“代购集运”的批量选择、运费预估等高级功能。对于搭建反向海淘独立站的开发者而言,可以直接复用这套成熟方案。

来源:https://developer.aliyun.com/article/1741111
上一篇反向海淘运费计算引擎实现多渠道体积重补差逻辑 下一篇两步检测法:判定品牌内容是否被AI回答直接引用或概括引用
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
RAG四标融合企业知识资产体系四库协同GEO优化实践
AI教程 · 2026-07-01

RAG四标融合企业知识资产体系四库协同GEO优化实践

生成式AI正在彻底改写信息检索的底层逻辑。传统SEO依赖关键词堆砌和外链建设的策略,在大模型的内容采信规则下已经基本失效。取而代之的,是生成式引擎优化(GEO)。它不再关注外链数量,而是重点衡量你的知识是否结构化、证据链是否坚实、信源是否可靠——这些维度才是RAG(检索增强生成)架构真正看重的核心指

一个普通上班人分享WorkBuddy使用心得与真实体验
AI教程 · 2026-07-01

一个普通上班人分享WorkBuddy使用心得与真实体验

前言 最近我开始使用WorkBuddy——这是腾讯推出的一款AI办公工作台。差不多用了一周时间,趁印象还新鲜,把真实的使用感受记录下来,给还在犹豫的朋友做个参考。不吹不黑,只说实际体验。 初印象:不只是聊天机器人 之前用过不少AI工具,大多数就是个对话框,你问它答,答完就结束了。WorkBuddy不

AI幻觉变真功能实战教程:App Inventor 2视频录制拓展一周开发实录
AI教程 · 2026-07-01

AI幻觉变真功能实战教程:App Inventor 2视频录制拓展一周开发实录

先讲一个颇具戏剧性的开端。 这件事的开端颇显荒诞——有用户前来咨询,称AI Pro版的介绍中提到我们有一款“视频录制拓展”。团队全体成员都感到困惑,翻遍产品列表,发现根本不存在该组件。AI那种“一本正经胡说八道”的能力,这次确实让我们陷入尴尬。 按常理,此事到此便可结束——一句“抱歉,暂时没有这个拓

别再混淆OLAP和SQL-on-Hadoop两者查询本质不同
AI教程 · 2026-07-01

别再混淆OLAP和SQL-on-Hadoop两者查询本质不同

OLAP和SQL-on-Hadoop虽都使用SQL查询数据,但本质不同。SQL-on-Hadoop负责海量数据批量计算与ETL,查询速度秒级至分钟级;OLAP通过预聚合实现毫秒级多维分析,适合BI报表。两者在数据平台分工协作,前者是后厨加工,后者是前台快速服务。

GEO优化深度解析:AI偏好FAQ还是长文内容?
AI教程 · 2026-07-01

GEO优化深度解析:AI偏好FAQ还是长文内容?

在GEO优化中,AI对内容形式无统一偏好:FAQ在简单查询中引用率41%,长文在复杂查询中达58%。内容应基于用户意图选择形式,FAQ适配简单事实类问题,长文建立主题权威,两者互补而非替代。