【Java 实战】通过Redis实现购物车功能

项目场景:

通过Redis实现购物车,包括添加购物车、更新商品数量、删除购物车、结算验证库存等功能。

设计思路

1.数据存储

对于购物车,我们在Redis中需要存储的是用户和商品信息,数据结构类似于Java中Map<String,Map<String,String>>形式,将外层Map的key记为K,内层Map的key和value分别记为HK、HV

使用K来存储用户标识(例如:用户的ID)
使用HK存储商品标识(例如:商品ID)
使用HV存储购物车商品信息(例如:购物车中商品数量、价格、店铺信息等(根据自己业务需求))

Redis 中可以使用boundHashOps方法来实现:BoundHashOperations<String, Object, Object> operations = stringRedisTemplate.boundHashOps(userId);

也可以使用Map<String, object> itemMap = redisTemplate.opsForValue().get(userId);来实现

2.功能结构图

3.功能描述

在添加购物车时需要用户先登录(web界面后台可以通过session获取用户id),这里直接默认传入用户id

添加购物车

添加购物车,需要判断购物车里是否存在该商品,存在则该商品数量增加,不存在需要查询该商品然后将商品加入到购物车,方法:operations.put(key,value);

@Override
public ApiResponse addCart(OperateVo vo) {
    // 用户购物车存储的key
    String key = CART_KEY + vo.getUserId();
    // 获取用户购物车数据
    BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
    // 判断商品是否存在
    String cart = (String) cartMap.get(vo.getSkuId());
    if (StringUtils.isBlank(cart)) {
        // 商品不存在,则添加商品信息
        Item item = itemService.getBySkuId(vo.getSkuId());
        // 添加购物车商品数量
        item.setNum(vo.getNum());
        cartMap.put(vo.getSkuId(), JSON.toJSONString(item));
    } else {
        // 商品存在,则数量增加
        Item item = JSON.parseObject(cart, Item.class);
        item.setNum(item.getNum() + vo.getNum());
        cartMap.put(vo.getSkuId(), JSON.toJSONString(item));
    }
    return ApiResponse.ok();
}

获取购物车信息

通过用户id查询该用户的购物车信息,方法:operations.get(key);

@Override
public ApiResponse showCart(OperateVo vo) {
    CartEntry cartEntry = new CartEntry();
    // 用户购物车存储的key
    String key = CART_KEY + vo.getUserId();
    BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
    // 获取所有的购物车数据
    List<Object> cartList = cartMap.values();
    if (CollectionUtils.isNotEmpty(cartList)) {
        List<Item> items = new ArrayList<>();
        cartList.forEach(item -> {
            String objStr = (String) item;
            Item carItem = JSON.parseObject(objStr, Item.class);
            items.add(carItem);
        });
        cartEntry.setItems(items);
    }
    return ApiResponse.ok(cartEntry);
}

修改商品数量

对购物车中商品的数量进行修改,方法:operations.put(key);

@Override
public ApiResponse updateCartNum(OperateVo vo) {
    // 用户购物车存储的key
    String key = CART_KEY + vo.getUserId();
    BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
    String cart = (String) cartMap.get(vo.getSkuId());
    Item item = JSON.parseObject(cart, Item.class);
    item.setNum(vo.getNum());
    cartMap.put(vo.getSkuId(), JSON.toJSONString(item));
    return ApiResponse.ok();
}

删除购物车

删除购物车中的商品,或者清空用户的购物车,方法分别为:operations.delete(key)、stringRedisTemplate.delete(userId);

@Override
public ApiResponse delCart(OperateVo vo) {
    // 用户购物车存储的key
    String key = CART_KEY + vo.getUserId();
    BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
    cartMap.delete(vo.getSkuId());
    return ApiResponse.ok();
}

结算页面验证购物车商品库存

添加晚购物车后,点击去结算,验证商品库存是否充足

@Override
public ApiResponse checkNumCart(OperateVo vo) {
    CartEntry cartEntry = new CartEntry();
    // 用户购物车存储的key
    String key = CART_KEY + vo.getUserId();
    BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
    if (vo != null) {
        List<Item> items = new ArrayList<>();
        vo.getSkuIds().forEach(id -> {
            String cart = (String) cartMap.get(id);
            Item redisItem = JSON.parseObject(cart, Item.class);
            // 获取商品库存数量
            Item item = itemService.getBySkuId(vo.getSkuId());
            if (item.getNum() < redisItem.getNum()) {
                // 库存不足
                redisItem.setEnough(false);
            }
            items.add(redisItem);
        });
        cartEntry.setItems(items);
    }
    return ApiResponse.ok(cartEntry);
}

代码实现:

好啦,购物车操作的功能到这里已经差不多啦,个人觉得后面购物车下单、拆单及退款处理才是难点😏

接下来,又到了愉快的贴代码环节了,废话不多说,直接上代码:

CartEntry.java

/**
 * 购物车
 *
 * @author:MaodeShu
 * @date:2022-11-12 11:24
 */
@Data
public class CartEntry {
    List<Item> items;// 商品列表
    BigDecimal totalPrice; // 总结
    int totalNum; // 总数
 }

Item.java

/**
 * 商品信息
 *
 * @author:MaodeShu
 * @date:2022-11-12 11:24
 */
@Data
public class Item extends ItemEntity{
    // 商品是否充足
    private Boolean enough = true;
}

ItemEntity.java

/**
 * 商品实体信息
 *
 * @author:MaodeShu
 * @date:2022-11-12 11:24
 */
@Data
@TableName("item_sku_info")
public class ItemEntity {
    private String productId;// 产品id
    private String productName; // 产品名称
    private String skuId;// 商品skuId
    private String skuName; // 商品skuName
    private String shopId;// 店铺id
    private String shopName;// 店铺名
    private String shopLog; // 店铺logo
    private String coverUrl; // 商品图
    private BigDecimal sellPrice; // 售价
    private Integer num; // 库存
}

OperateVo.java

/**
 * 操作购物车信息
 *
 * @author:MaodeShu
 * @date:2022-11-12 11:24
 */
@Data
public class OperateVo {
    private String userId;// 用户id
    private String skuId; // 商品skuId
    private Integer num;// 数量
    private List<String> skuIds; // 商品skuId列表(选择购物车时使用)
}

CartServiceImpl.java

@Service
public class CartServiceImpl implements CartService {

    private final String CART_KEY = "cart:";

    @Resource
    private RedisTemplate<String, String> stringRedisTemplate;

    @Resource
    private ItemInfoService itemService;

    @Override
    public ApiResponse addCart(OperateVo vo) {
        // 用户购物车存储的key
        String key = CART_KEY + vo.getUserId();
        // 获取用户购物车数据
        BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
        // 判断商品是否存在
        String cart = (String) cartMap.get(vo.getSkuId());
        if (StringUtils.isBlank(cart)) {
            // 商品不存在,则添加商品信息
            Item item = itemService.getBySkuId(vo.getSkuId());
            // 添加购物车商品数量
            item.setNum(vo.getNum());
            cartMap.put(vo.getSkuId(), JSON.toJSONString(item));
        } else {
            // 商品存在,则数量增加
            Item item = JSON.parseObject(cart, Item.class);
            item.setNum(item.getNum() + vo.getNum());
            cartMap.put(vo.getSkuId(), JSON.toJSONString(item));
        }
        return ApiResponse.ok();
    }

    @Override
    public ApiResponse showCart(OperateVo vo) {
        CartEntry cartEntry = new CartEntry();
        // 用户购物车存储的key
        String key = CART_KEY + vo.getUserId();
        BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
        // 获取所有的购物车数据
        List<Object> cartList = cartMap.values();
        if (CollectionUtils.isNotEmpty(cartList)) {
            List<Item> items = new ArrayList<>();
            cartList.forEach(item -> {
                String objStr = (String) item;
                Item carItem = JSON.parseObject(objStr, Item.class);
                items.add(carItem);
            });
            cartEntry.setItems(items);
        }
        return ApiResponse.ok(cartEntry);
    }

    @Override
    public ApiResponse updateCartNum(OperateVo vo) {
        // 用户购物车存储的key
        String key = CART_KEY + vo.getUserId();
        BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
        String cart = (String) cartMap.get(vo.getSkuId());
        Item item = JSON.parseObject(cart, Item.class);
        item.setNum(vo.getNum());
        cartMap.put(vo.getSkuId(), JSON.toJSONString(item));
        return ApiResponse.ok();
    }

    @Override
    public ApiResponse delCart(OperateVo vo) {
        // 用户购物车存储的key
        String key = CART_KEY + vo.getUserId();
        BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
        cartMap.delete(vo.getSkuId());
        return ApiResponse.ok();
    }

    @Override
    public ApiResponse checkNumCart(OperateVo vo) {
        CartEntry cartEntry = new CartEntry();
        // 用户购物车存储的key
        String key = CART_KEY + vo.getUserId();
        BoundHashOperations<String, Object, Object> cartMap = stringRedisTemplate.boundHashOps(key);
        if (vo != null) {
            List<Item> items = new ArrayList<>();
            vo.getSkuIds().forEach(id -> {
                String cart = (String) cartMap.get(id);
                Item redisItem = JSON.parseObject(cart, Item.class);
                // 获取商品库存数量
                Item item = itemService.getBySkuId(vo.getSkuId());
                if (item.getNum() < redisItem.getNum()) {
                    // 库存不足
                    redisItem.setEnough(false);
                }
                items.add(redisItem);
            });
            cartEntry.setItems(items);
        }
        return ApiResponse.ok(cartEntry);
    }
}

总结:

以上就是今天要讲的内容,本文仅仅简单介绍了如何通过Redis实现购物车功能,以上方法亲测有效,希望能给大家一个参考。

创作不易,关注💖、点赞👍、收藏🎉就是对作者最大的鼓励👏,欢迎在下方评论留言🧐

posted on 2022-11-13 20:47  猫的树kireCat  阅读(1021)  评论(0编辑  收藏  举报