购物车
购物车
一、购物车需求
1、需求描述
- 用户可以在登录状态下将商品添加到购物车【用户购物车/在线购物车】
- 放入数据库
- mongodb
- 放入 redis(采用)
登录以后, 会将临时购物车的数据全部合并过来, 并清空临时购物车;
- 用户可以在未登录状态下将商品添加到购物车【游客购物车/离线购物车/临时购物车】
- 放入 localstorage(客户端存储, 后台不存)
- cookie
- WebSQL
- 放入 redis(采用)
浏览器即使关闭, 下次进入, 临时购物车数据都在
- 用户可以使用购物车一起结算下单
- 给购物车添加商品
- 用户可以查询自己的购物车
- 用户可以在购物车中修改购买商品的数量。
- 用户可以在购物车中删除商品。
- 选中不选中商品
- 在购物车中展示商品优惠信息
- 提示购物车商品价格变化
2、数据结构
因此每一个购物项信息, 都是一个对象, 基本字段包括:
{
skuId: 2131241,
check: true,
title: "Apple iphone.....",
defaultImage: "...",
price: 4999,
count: 1,
totalPrice: 4999,
skuSaleVO: {...}
}
另外, 购物车中不止一条数据, 因此最终会是对象的数组。 即:
[
{...},{...},{...}
]
-
数据存储方式
购物车是一个读多写多的场景,因此放入数据库并不合适,但购物车又是需要持久化,因此这里我们选用redis存储购物车数据。 -
数据存储结构
一个购物车是由多个购物项组成的,但是我们用List进行存储并不合适,因为使用List查找某个购物项时需要挨个遍历每个购物项,会造成大量时间损耗,为保证查找速度,我们使用hash进行存储 -
首先不同用户应该有独立的购物车, 因此购物车应该以用户的作为 key 来存储, Value 是用户的所有购物车信息。 这样看来基本的k-v结构就可以了。
-
但是, 我们对购物车中的商品进行增、 删、 改操作, 基本都需要根据商品 id 进行判断,为了方便后期处理, 我们的购物车也应该是k-v结构, key 是商品 id, value 才是这个商品的购物车信息。
综上所述, 我们的购物车结构是一个双层 Map: Map<String,Map<String,String>>
-
第一层 Map, Key 是用户 id
-
第二层 Map, Key 是购物车中商品 id, 值是购物项数据
3、流程
参照京东
user-key 是随机生成的 id, 不管有没有登录都会有这个 cookie 信息。
两个功能: 新增商品到购物车、 查询购物车。
新增商品: 判断是否登录
- 是: 则添加商品到后台 Redis 中, 把 user 的唯一标识符作为 key。
- 否: 则添加商品到后台 redis 中, 使用随机生成的 user-key 作为 key。
查询购物车列表: 判断是否登录
- 否: 直接根据 user-key 查询 redis 中数据并展示
- 是: 已登录, 则需要先根据 user-key 查询 redis 是否有数据。
- 有: 需要提交到后台添加到 redis, 合并数据, 而后查询。
- 否: 直接去后台查询 redis, 而后返回
二、临时购物车
/**
* 获取到我们要操作的购物车
* @return
*/
private BoundHashOperations<String, Object, Object> getCartOps() {
UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
String cartKey = "";
if (userInfoTo.getUserId() != null) {
//gulimall:cart:1
cartKey = CART_PREFIX + userInfoTo.getUserId();
} else {
cartKey = CART_PREFIX + userInfoTo.getUserKey();
} B
oundHashOperations<String, Object, Object> operations =
redisTemplate.boundHashOps(cartKey);
return operations;
}
三、登录购物车
@Override
public Cart getCart() throws ExecutionException, InterruptedException {
Cart cart = new Cart();
UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
if(userInfoTo.getUserId()!=null){
//1、 登录
String cartKey =CART_PREFIX+ userInfoTo.getUserId();
//2、 如果临时购物车的数据还没有进行合并【合并购物车】
String tempCartKey = CART_PREFIX + userInfoTo.getUserKey();
List<CartItem> tempCartItems = getCartItems(tempCartKey);
if(tempCartItems!=null){
//临时购物车有数据, 需要合并
for (CartItem item : tempCartItems) {
addToCart(item.getSkuId(),item.getCount());
} //
清除临时购物车的数据
clearCart(tempCartKey);
} //
3、 获取登录后的购物车的数据【包含合并过来的临时购物车的数据, 和登录后的购
物车的数据】
List<CartItem> cartItems = getCartItems(cartKey);
cart.setItems(cartItems);
}else{
//2、 没登录
String cartKey =CART_PREFIX+ userInfoTo.getUserKey();
//获取临时购物车的所有购物项
List<CartItem> cartItems = getCartItems(cartKey);
cart.setItems(cartItems);
} r
eturn cart;
}