Description or Example
# Bug修复
## postHandle的空指针异常
> 这是因为没有初始化isExistsTempUser这个属性导致的空指针异常, 因此, 需要初始化为false
# 核心源码
```java
@GetMapping("/cart.html")
public ModelAndView cartIndex(ModelAndView mv) {
// 获取用户的购物车
CartVO cartVO = cartService.getCart();
// 把用户的购物车放在请求域里面
mv.addObject("cart", cartVO);
mv.setViewName("cartList");
return mv;
}
```
```java
@Override
public CartVO getCart() {
// 获取对hash的操作对象
BoundHashOperations<String, Object, Object> hashHandle = getHashHandle();
// 首先我们需要判断, 是否登陆过, 如果没有登陆过, 则没有购物车合并之说
UserBO userBO = CartInterceptor.USER_INFO_ID.get();
Long userId = userBO.getUserId();
String userKey = userBO.getUserKey();
CartVO cartVO = new CartVO(); // 创建一个购物车对象
if (userId == null) { // 尚未登录, 未登录, 直接将整个购物车查询出来
return cartVO.setCartItemVOS(getAllCartItems(hashHandle)).setReduce(new BigDecimal(0));
}else { // 已经登录了, 需要判断离线购物车是否存在购物项, 如果存在需要合并
// 首先获取离线购物车操作
BoundHashOperations<String, Object, Object> offLineHashHandle = getHashHandle(false, true);
if (offLineHashHandle.size() > 0L) { // 离线购物车有东西, 需要合并
List<CartItemVO> offLineCartItems = getAllCartItems(offLineHashHandle);
this.addCartItems(hashHandle, offLineCartItems);
// 合并完了之后, 需要清空购物车
this.flushOffLineCart(userKey);
}
// 无论是否需要合并, 最后都需要获取在线购物车的数据
return cartVO.setCartItemVOS(getAllCartItems(hashHandle)).setReduce(new BigDecimal(0L));
}
}
/**
* 直接删除离线购物车
* @param userKey
*/
private void flushOffLineCart(String userKey) {
redisTemplate.delete(CART_PREFIX + userKey);
}
/**
* 批量添加购物项
* @param hashHandle
* @param offLineCartItems
*/
private void addCartItems(BoundHashOperations<String, Object, Object> hashHandle, List<CartItemVO> offLineCartItems) {
for (CartItemVO offLineCartItem : offLineCartItems) {
String cartKey = offLineCartItem.getSkuId().toString(); // 获取对应的key
Object cartItemJson = hashHandle.get(cartKey);
if (cartItemJson != null) { // 该购物项存在了, 需要做累加
CartItemVO cartItemVO = JSON.parseObject((String) cartItemJson, CartItemVO.class);
hashHandle.put(cartItemVO.getSkuId().toString(), JSON.toJSONString(cartItemVO.setCount(cartItemVO.getCount() + offLineCartItem.getCount())));
}else { // 否则不存在, 直接添加
hashHandle.put(offLineCartItem.getSkuId().toString(), JSON.toJSONString(offLineCartItem));
}
}
}
/**
* 获取所有的购物项并且赋值
* @param hashHandle
* @param cartVO
*/
private List<CartItemVO> getAllCartItems(BoundHashOperations<String, Object, Object> hashHandle) {
List<Object> cartItems = hashHandle.values(); // 获取所有的购物项
if (cartItems != null && !cartItems.isEmpty()) {
return cartItems.stream()
.map(cartItem -> JSON.parseObject((String) cartItem, CartItemVO.class))
.collect(Collectors.toList());
}
return null;
}
/**
* 该方法主要是给用户最优选择, 如果登陆了选择在线购物车, 否则离线
* @return
*/
private BoundHashOperations<String, Object, Object> getHashHandle() {
// 判断是否登录, 如果登录了使用在线购物车, 否则使用离线购物车
return CartInterceptor.USER_INFO_ID.get().getUserId() != null ?
getHashHandle(true, false) : getHashHandle(false, true);
}
private BoundHashOperations<String, Object, Object> getHashHandle(boolean isOnline, boolean isOffline) {
if (isOnline && isOffline || !isOnline && !isOffline) { // 如果在线和离线同时选, 抛异常
throw new RuntimeException("只能获取在线购物车或离线购物车的单一操作, 不能同时获取");
}
UserBO userBO = CartInterceptor.USER_INFO_ID.get();
Long userId = userBO.getUserId();
String userKey = userBO.getUserKey();
if (isOnline) {
return redisTemplate.boundHashOps(CART_PREFIX + userId);
}
return redisTemplate.boundHashOps(CART_PREFIX + userKey);
}
```
# 知识点
## 利用直接添加购物项有什么问题(之前的方法)?
> 最大的问题是远程调用微服务, 因为主要目的是让离线购物车的数据合并到在线, 相关的数据已知, 不需要从结果的一部分推断结果, 效率很差, 因此, 不能直接调用
> 而且, 不要忘记清空离线购物车