購物車列表的存儲實現

需求分析

在這裏插入圖片描述
當我們點擊加入購物車的時候,將商品加入到我們的購物車,頁面傳遞到後臺的信息是商品的id和數量,我們根據id和數量將商品放進購物車,購物車數據存儲到cookie或者是服務器端
購物車列表在cookie的存儲指的是我們在不登錄的情況下也能將商品添加到購物車,這時購物車中的商品信息存儲在瀏覽器端的cookie,用戶清除瀏覽器緩存或者cookie過期後,購物車中就不存在商品信息
在這裏插入圖片描述
創建購物車的單個商家對象Cart,List Cart構成了購物車,Cart對象存儲的是像京東自營、xx專賣店所包含商品的數據

public class Cart implements Serializable {

    private String sellerId;//商家id
    private String sellerName;//商家名稱
    private List<TbOrderItem> orderItemList;//購物車明細

    public Cart() {
    }

    public Cart(String sellerId, String sellerName, List<TbOrderItem> orderItemList) {
        this.sellerId = sellerId;
        this.sellerName = sellerName;
        this.orderItemList = orderItemList;
    }

    public String getSellerId() {
        return sellerId;
    }

    public void setSellerId(String sellerId) {
        this.sellerId = sellerId;
    }

    public String getSellerName() {
        return sellerName;
    }

    public void setSellerName(String sellerName) {
        this.sellerName = sellerName;
    }

    public List<TbOrderItem> getOrderItemList() {
        return orderItemList;
    }

    public void setOrderItemList(List<TbOrderItem> orderItemList) {
        this.orderItemList = orderItemList;
    }
}

存儲實現

注意
Long類型數據的比較通過longValue()方法在進行比較,而long類型可以通過==比較

/*
添加商品到購物車
cartList 老的購物車
 */
@Override
public List<Cart> addCart(List<Cart> cartList, Long itemId, Integer num) {
    TbItem item = itemMapper.selectByPrimaryKey(itemId);
    //做安全校驗
    if (item==null){
        throw new RuntimeException("該商品不存在");
    }
    if (!item.getStatus().equals("1")){
        throw new RuntimeException("該商品暫不支持添加購物車");
    }
    String sellerId = item.getSellerId();
    Cart cart = searchItemInCartList(cartList, sellerId);
    if (cart!=null){//購物車中已經存在該商家
        List<TbOrderItem> orderItems = cart.getOrderItemList();//獲取用戶在這個商家中的商品明細
        //判斷新商品在不在購物車的商品明細裏
        TbOrderItem orderItem = searchItemInOrderOtemList(orderItems, itemId);
        if (orderItem!=null){//如果該商品已經在購物車中,改變數量和總價
            orderItem.setNum(orderItem.getNum()+num);
            orderItem.setTotalFee(new BigDecimal(orderItem.getPrice().doubleValue()*orderItem.getNum()));
            //移除商品數量減到0的商品明細
            if (orderItem.getNum()<=0){
                orderItems.remove(orderItem);
            }
            if (orderItems.size()==0){//如果商家在購物車列表的商品數量爲0,就移除該商家
                cartList.remove(orderItems);
            }
        }
        else{//如果該商品不在購物車中,添加該商品信息到新建的商品明細中
            TbOrderItem newOrderItem = createOrderItem(item, num);
            orderItems.add(newOrderItem);
        }

    }
    else{//購物車中不存在該商家,創建該商家的購物明細
        TbOrderItem orderItem = createOrderItem(item, num);
        List<TbOrderItem> items = new ArrayList<>();//創建集合用來保存商品信息
        items.add(orderItem);
        Cart newCart = new Cart(item.getSellerId(),item.getSeller(),items);
        cartList.add(newCart);
    }
    return cartList;
}
/*
檢測商家商品明細是否存在於購物車列表
 */
private Cart searchItemInCartList(List<Cart> cartList,String sellerId){
    for (Cart cart : cartList) {
        if (cart.getSellerId().equals(sellerId)) {//購物車中已經存在該商家
            return cart;
        }
    }
    return null;
}
/*
判斷商品是否存在於商家商品明細中
 */
private TbOrderItem searchItemInOrderOtemList(List<TbOrderItem> itemList,Long itemId){
    for (TbOrderItem orderItem : itemList) {
        if (orderItem.getItemId().longValue()==itemId.longValue()) {//如果該商品已經在購物車中
            return orderItem;
        }
    }
    return null;
}
/*
新建商品明細中的單個商品信息
 */
private TbOrderItem createOrderItem(TbItem item,Integer num){
    TbOrderItem orderItem = new TbOrderItem();
    orderItem.setGoodsId(item.getGoodsId());
    orderItem.setItemId(item.getId());
    orderItem.setTitle(item.getTitle());
    orderItem.setNum(num);
    orderItem.setPrice(item.getPrice());
    orderItem.setTotalFee(new BigDecimal(orderItem.getPrice().doubleValue()*num));
    orderItem.setPicPath(item.getImage());
    return orderItem;
}

未登錄保存在cookie中

在後端對cookie進行操作
注意
複雜對象是不能進行編碼的,可以先轉換成字符串,字符串是可編碼的,這樣就可以避免中文亂碼

@Reference
private CartService cartService;

@Autowired
private HttpServletRequest request;

@Autowired
private HttpServletResponse response;
@RequestMapping("/add")
public Result addCart(Long itemId,Integer num){
    try {
        List<Cart> cartList = findCartList();
        List<Cart> carts = cartService.addCart(cartList, itemId, num);
        //存入cookie
        //複雜對象不支持編碼,轉成字符串,字符串是可編碼的,防止對象中中文亂碼
        String cartsJson = JSON.toJSONString(carts);
        CookieUtil.setCookie(request,response,"cartList",cartsJson,3600*24,"utf-8");
        return new Result(true,"加入購物車成功!");
    } catch (Exception e) {
        e.printStackTrace();
        return new Result(false,"加入購物車失敗!");
    }

}

CookieUtil是我們自己封裝的工具類

優化(登錄存儲在redis,未登錄保存在cookie)

判斷當前用戶是否登陸,如果未登錄採用Cookie存儲,如果登錄則採用Redis存儲。登錄後要進行Cookie購物車與Redis購物車的合併操作,並清除Cookie購物車。
修改spring-security.xml配置文件
之前我們是直接放行有關購物車操作的請求,這樣的話spring-security就不會驗證是否登錄,也自然就沒有登錄相關信息
現在我們需要,spring-security裏有登錄相關信息,不登錄也能執行有關購物車的操作,登錄也可以操作
解決辦法就是,修改攔截的權限
在這裏插入圖片描述
刪除<http pattern="/cart/*.do" security="none"></http>
access=“IS_AUTHENTICATED_ANONYMOUSLY” 用於設置資源可以在不登陸時訪問。
此配置與 security="none"的區別在於當用戶未登陸時獲取登陸人賬號的值爲anonymousUser,而security="none"的話,無論是否登陸都不能獲取登錄人賬號的值。

否則:"/cart/*.do" security="none"表示不攔截,繞過spring security,此時SecurityContextHolder.getContext()上下文爲空。

service層代碼同上,修改controller代碼如下

@Reference
private CartService cartService;

@Autowired
private HttpServletRequest request;

@Autowired
private HttpServletResponse response;

@Autowired
private RedisTemplate redisTemplate;
@RequestMapping("/addGoodsToCart")
public Result addCart(Long itemId,Integer num){

    try {
        List<Cart> cartList = findCartList();
        List<Cart> carts = cartService.addCart(cartList, itemId, num);
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        if ("anonymousUser".equals(username)){//沒有登錄,將信息存入cookie
            //存入cookie
            //複雜對象不支持編碼,轉成字符串,字符串是可編碼的,防止對象中中文亂碼
            String cartsJson = JSON.toJSONString(carts);
            CookieUtil.setCookie(request,response,"cartList",cartsJson,3600*24,"utf-8");
            System.out.println(">>>>>save cartList to cookie" );
        }
        else{//已登錄,存入redis
            redisTemplate.boundHashOps("cartList").put(username,carts);
            System.out.println(">>>>>save cartList to Redis" );
        }

        return new Result(true,"加入購物車成功!");
    } catch (Exception e) {
        e.printStackTrace();
        return new Result(false,"加入購物車失敗!");
    }

}
/*
獲取到原來的購物車對象
 */
@RequestMapping("/findCartList")
public List<Cart> findCartList(){
    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    if ("anonymousUser".equals(username)) {//沒有登錄,從cookie取出信息
        String cartListStr = CookieUtil.getCookieValue(request, "cartList","utf-8");
        if (cartListStr==null || cartListStr.equals("")){
            cartListStr = "[]";
        }
        List<Cart> cartList = JSON.parseArray(cartListStr, Cart.class);
        System.out.println(">>>>>get cartList from Cookie" );
        return cartList;
    }else{//已登錄,從redis中取出信息
        List<Cart> cartList = (List<Cart>) redisTemplate.boundHashOps("cartList").get(username);
        if (cartList==null){
            cartList = new ArrayList<>();
        }
        System.out.println(">>>>>get cartList from Redis" );
        return cartList;
    }

}
@RequestMapping("/test")
public List<Cart> testCartList(){
    String cartListStr = CookieUtil.getCookieValue(request, "cartList","utf-8");
    if (cartListStr==null || cartListStr.equals("")){
        cartListStr = "[]";
    }
    List<Cart> cartList = JSON.parseArray(cartListStr, Cart.class);
    return cartList;
}

這樣我們就做到了,未登錄時,購物車信息存儲在本地瀏覽器的cookie中,已登錄時購物車信息存儲在redis服務器中

購物車的合併(將cookie中的購物車信息同步到redis中)

service層新添合併方法,會調用之前的添加方法

/**
* 將cookieList合併到redisList
* @param redisList
* @param cookieList
* @return
*/
@Override
public List<Cart> joinCartList(List<Cart> redisList, List<Cart> cookieList) {
   for (Cart cart : cookieList) {
       List<TbOrderItem> orderItemList = cart.getOrderItemList();
       for (TbOrderItem orderItem : orderItemList) {
           addCart(redisList,orderItem.getItemId(),orderItem.getNum());
       }
   }
   return redisList;
}

修改controller層的獲取方法

@RequestMapping("/findCartList")
public List<Cart> findCartList(){
    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    // 從cookie中獲取購物車列表,如果考慮將cookie同步到redis的情況
    // 那麼,不管登錄與否,都需要獲取本地cookie數據
    String cartListStr = CookieUtil.getCookieValue(request, "cartList","utf-8");
    if (cartListStr==null || cartListStr.equals("")){
        cartListStr = "[]";
    }
    List<Cart> cookieList = JSON.parseArray(cartListStr, Cart.class);
    //沒有登錄,從cookie取出信息
    if ("anonymousUser".equals(username)) {
        System.out.println(">>>>>get cartList from Cookie" );
        return cookieList;
    }
    //已登錄
    else{
        List<Cart> redisList = (List<Cart>) redisTemplate.boundHashOps("cartList").get(username);
        if (redisList==null){
            redisList = new ArrayList<>();
        }
        if (cookieList.size()>0){//如果cookie的購物車裏有數據就進行合併,沒有就直接返回redis中的數據
            //合併購物車
            redisList = cartService.joinCartList(redisList, cookieList);
            // 將合併後的數據重新存回redis
            redisTemplate.boundHashOps("cartList").put(username,redisList);
            // 合併完成後,刪除本地的cookie
            CookieUtil.deleteCookie(request, response, "cartList");
            System.out.println(">>>>>import cookie to redis");
        }
        return redisList;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章