购物车 ​
1. 表结构分析 ​
当前项目购物车是没有表的,需要把购物车存储到Redis中,那么使用什么样的数据结构来存储购物车呢?
购物车不入MySQL数据库,所以没有表
购物车实现的方案:
存入MySQL
优点:不会丢失数据
缺点:速度慢,每一次操作购物车都需要读写数据库,IO操作频繁,对MySQL压力比较大
存入Redis
优点:速度快,并发能力强
缺点:可能丢失数据
Redis什么时候会丢失数据呢?
java// 服务器突然down机,RDB会丢失数据,AOF(出了always)之外,都会丢数据 // 如何解决:集群-------> Redis有几种集群模式:主从模式、哨兵模式、集群模式 // 内存淘汰(当前Redis内存不足的时候,再次需要存入新的数据的时候,会触发内存淘汰策略) // 如何解决: // a, 内存淘汰策略配置为 no-evication // b, 对于Redis中的一些可以设置过期时间的 key,应该尽量的主动设置过期时间,等到过期时间到了之后,主动淘汰这部分数据先存入Redis,采用一些策略同步到MySQL
优点:可靠性高,并发能力也强
缺点:可能会出现MySQL和Redis数据不同步的问题
在用户没登录的时候存入cookie,在用户登录之后,把数据存入MySQL
存入Redis,考虑使用Hash数据结构存储用户的购物车。
shell
key:用户id
field:商品id
value:CartInfoDTO
2. 业务功能 ​
2.1 添加购物车 ​

通过上图可知,在添加购物车的业务中,需要完成的接口如下
图中第一步。
功能描述:就是把商品添加到购物车,不用考虑是临时用户还是已经登录的用户
java
@RequestMapping("cart/add/{skuId}/{skuNum}")
public Result addCart(@PathVariable Long skuId, @PathVariable Integer skuNum, HttpServletRequest request) {
// 获取用户id
String userId = AuthContext.getUserId(request);
if (StringUtils.isBlank(userId)) {
userId = AuthContext.getUserTempId(request);
}
// 添加商品到购物车
cartService.addToCart(skuId,userId,skuNum);
return Result.ok();
}添加商品到购物车
java
public void addToCart(Long skuId, String userId, Integer skuNum) {
// 这里可以使用我们定义好的前后缀常量构造购物车的key:RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX(user:userId:cart)
// 获取用户购物车
// 查看用户购物车中是否包含该商品
// 如果包含,更新数量(根据skuId,获取购物车中的CartInfoDTO, 修改数量)
// 如果不包含,添加商品到购物车(根据skuId调用商品服务(skuName, skuPrice, defaultImg) + skuNum ——> CartInfoDTO)
}2.2 展示购物车列表 ​

查看用户的购物车列表
java
@GetMapping("/cart")
public Result cartList(HttpServletRequest request) {
// 获取用户Id
String userId = AuthContext.getUserId(request);
// 获取临时用户Id
String userTempId = AuthContext.getUserTempId(request);
// 调用购物车服务,获取用户的购物车列表
// 如果userId不为空且userTempId也不为空,那么意味着要合并购物车,并删除用户临时用户的购物车
List<CartInfoDTO> cartInfoList = cartService.getCartList(userId, userTempId);
return Result.ok(cartInfoList);
}合并购物车思路:注意在获取用户购物车数据时,使用和添加购物车时的key相同
java
public List<CartInfoDTO> getCartList(String userId, String userTempId) {
// 1. 如果userId为空,那么表示用户未登录,直接返回用户userTempId的临时购物车列表
// 2. 如果userId不为空,那么表示用户已经登录
// 3. 查询出已经登录的购物车、查询出未登录的购物车
// 4. 如果未登录的购物车为空,那么直接返回已经登录的购物车
// 5. 如果未登录的购物车不为空,那么需要合并 未登录和已登录的购物车,得到合并之后的购物车
// 合并需要注意 同一个商品的数量和状态(合并之后的数据,放到用户登录之后的购物车)
// 6. 把合并之后的购物车的商品进行排序,按照添加购物车的时间排序
// 7. 更新用户userId的购物车
// 8. 删除用户临时Id userTempId的购物车
// 9. 返回合并之后的购物车
}2.3 选中状态变更 ​


请求:PUT /cart/check/5/0
参数 5: 表示商品的skuId
参数 0: 表示商品在购物车中的状态,1表示选中,0表示未选中,默认为1
java
@PutMapping("cart/check/{skuId}/{isChecked}")
public Result checkCart(@PathVariable Long skuId, @PathVariable Integer isChecked,
HttpServletRequest request)
{
// TODO
// 修改指定用户购物车中指定商品的 isChecked状态
return Result.ok();
}2.4 删除购物车 ​
2.4.1 删除对应的商品 ​


请求: DELETE /cart/38
java
@DeleteMapping("/cart/{skuId}")
public Result deleteCart(@PathVariable("skuId") Long skuId, HttpServletRequest request) {
//注意在获取用户购物车数据时,使用和添加购物车时的key相同
// TODO
// 删除指定用户购物车中指定的商品
return Result.ok();
}2.4.2 删除已选中的商品 ​


请求: DELETE /cart/checked
java
@DeleteMapping("/cart/checked")
public Result deleteChecked(HttpServletRequest request) {
// 注意在获取用户购物车数据时,使用和添加购物车时的key相同
// 根据userId先获取购物车数据
// TODO
// 遍历购物车中的购物车商品数据,删除用户购物车中所有已经被选中的商品
return Result.ok();
}