品優購項目筆記(十三):購物車解決方案

購物車業務

購物車業務概要分析

在這裏插入圖片描述

購物車對象封裝分析

在這裏插入圖片描述
購物車實體

public class BuyerCart implements Serializable {
    private String sellerId;//商家ID
    private String sellerName;//商家名稱
    private List<OrderItem> orderItemList;//購物車明細

	//..getset
}

購物項實體(在這裏也是訂單項)

public class OrderItem implements Serializable {
    private Long id;

    /**
     * 商品id
     */
    private Long itemId;

    /**
     * SPU_ID
     */
    private Long goodsId;

    /**
     * 訂單id
     */
    private Long orderId;

    /**
     * 商品標題
     */
    private String title;

    /**
     * 商品單價
     */
    private BigDecimal price;

    /**
     * 商品購買數量
     */
    private Integer num;

    /**
     * 商品總金額
     */
    private BigDecimal totalFee;

    /**
     * 商品圖片地址
     */
    private String picPath;

    private String sellerId;

	//...getset
}
    

購物車詳細流程分析

一、添加購物車
在這裏插入圖片描述
二、總體業務流程
在這裏插入圖片描述

跨域訪問問題

當controller中的方法進行簡單地完成之後,進行測試,發現點擊加入購物車按鈕沒有反應
原因:跨域請求被阻止在這裏插入圖片描述
什麼是跨域請求
瀏覽器廠商在開發瀏覽器時,設置了同源策略。
同源策略:要求發送請求的url地址和返回響應的url地址必須保證協議,ip地址,端口號不能夠發生改變,只要有一個發生變化,瀏覽器就會認爲這個響應不安全,會拒絕接收響應數據,這就是跨域請求訪問。

注意:如果前端window.location.href進行跳轉,跳轉到不同服務器頁面,不會觸發跨域訪問問題,只是頁面跳轉,不會有數據返回

解決方案

  1. jsonp:jquery如果發生ajax請求,可以將數據類型設置爲jsonp,原理是jquery在發送數據的同時,會在數據中生產一個令牌,controller接收到數據後,進行處理,返回響應時,將令牌原樣返回,jquery會判斷令牌是否是當初發送的,如果是,則接收響應;反之,拒絕接收。
  2. cors:是w3c支持的解決方法,原理是在響應體設置信息Access-Control-Allow-Origin,如果使用SpringMVC4.2以上版本,可以使用@Cross註解,就相當於設置了響應頭信息

使用cors解決跨域問題

/**
     * 添加商品到購物車
     * @CrossOrigin註解,相當於設置了響應體信息,是w3c支持的一種跨域解決方案
     * origins屬性,設置的地址是返回響應給靜態頁面,靜態頁面所在服務器的地址
     * @param itemId    商品庫存id
     * @param num       購買數量
     * @return
     */
    @RequestMapping("/addGoodsToCartList")
    @CrossOrigin(origins = "http://localhost:8086", allowCredentials = "true")
    public Result addGoodsToCartList(Long itemId, Integer num){
        return new Result(true,"添加成功!");
    }
//添加商品到購物車
	$scope.addToCart=function(){
		//alert('SKUID:'+$scope.sku.id );		
		
		$http.get('http://localhost:8080/cart/addGoodsToCartList.do?itemId='
				+$scope.sku.id+'&num='+$scope.num ,{'withCredentials':true} ).success(
					function(response){
						if(response.success){
							location.href='http://localhost:8080/cart.html';
						}else{
							alert(response.message);
						}					
					}						
				);	
		
	}

購物車的controller方法

一、點擊加入購物車按鈕,將商品添加到購物車

二、返回給前端購物車列表

/**
 * 購物車業務
 */
@RestController
@RequestMapping("/cart")
public class BuyerCartController {

    @Reference
    private CartService cartService;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private HttpServletResponse response;

    /**
     * 添加商品到購物車
     * @CrossOrigin註解,相當於設置了響應體信息,是w3c支持的一種跨域解決方案
     * origins屬性,設置的地址是返回響應給靜態頁面,靜態頁面所在服務器的地址
     * @param itemId    商品庫存id
     * @param num       購買數量
     * @return
     */
    @RequestMapping("/addGoodsToCartList")
    @CrossOrigin(origins = "http://localhost:8086", allowCredentials = "true")
    public Result addGoodsToCartList(Long itemId, Integer num){
        try {
            //1. 獲取當前登錄用戶名稱
            String username = SecurityContextHolder.getContext().getAuthentication().getName();
            //2. 獲取購物車列表
            List<BuyerCart> cartList = findCartList();
            //3. 將當前商品加入到購物車列表
            cartList = cartService.addItemToCartList(cartList,itemId,num);
            //4. 判斷當前用戶是否登錄, 未登錄用戶名爲"anonymousUser"
            if ("anonymousUser".equals(username)){
                //4.a.如果未登錄, 則將購物車列表存入cookie中
                CookieUtil.setCookie(request, response, Constants.CART_LIST_COOKIE, JSON.toJSONString(cartList), 60 * 60 * 24 * 30, "utf-8");
                //4.b.如果已登錄, 則將購物車列表存入redis中
                cartService.setCartListToRedis(username, cartList);
            }
            return new Result(true,"添加成功!");
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, "添加失敗!");
        }
    }

    /**
     * 獲取購物車列表數據
     * @return
     */
    @RequestMapping("/findCartList")
    public List<BuyerCart> findCartList(){
        //1. 獲取當前登錄用戶名稱
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        //2. 從cookie中獲取購物車列表json格式字符串
        String cookieCartJson = CookieUtil.getCookieValue(request, Constants.CART_LIST_COOKIE, "utf-8");
        //3. 如果購物車列表json串爲空則返回"[]"
        if (cookieCartJson==null || "".equals(cookieCartJson)){
            cookieCartJson = "[]";
        }
        //4. 將購物車列表json轉換爲對象
        List<BuyerCart> cookieCartList = JSON.parseArray(cookieCartJson, BuyerCart.class);
        //5. 判斷用戶是否登錄, 未登錄用戶爲"anonymousUser"
        if (!"anonymousUser".equals(username)){
            //5.a. 未登錄, 返回cookie中的購物車列表對象
            return cookieCartList;
        }else {
            //5.b.1.已登錄, 從redis中獲取購物車列表對象
            List<BuyerCart> redisCartList = cartService.getCartListToRedis(username);
            //5.b.2.判斷cookie中是否存在購物車列表
            if (cookieCartList.size()>0){
                //如果cookie中存在購物車列表則和redis中的購物車列表合併成一個對象
                cartService.mergeCookieCartListAndRedisCartList(cookieCartList,redisCartList);
                //刪除cookie中購物車列表
                CookieUtil.deleteCookie(request,response,Constants.CART_LIST_COOKIE);
                //將合併後的購物車列表存入redis中
                cartService.setCartListToRedis(username,redisCartList);

            }
            //5.b.3.返回購物車列表對象
            return redisCartList;

        }

    }


}

購物車的service方法

package cn.itcast.core.service;

import cn.itcast.core.dao.item.ItemDao;
import cn.itcast.core.pojo.entity.BuyerCart;
import cn.itcast.core.pojo.item.Item;
import cn.itcast.core.pojo.order.OrderItem;
import cn.itcast.core.util.Constants;
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private ItemDao itemDao;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List<BuyerCart> addItemToCartList(List<BuyerCart> cartList, Long itemId, Integer num) {
        //1. 根據商品SKU ID查詢SKU商品信息
        Item item = itemDao.selectByPrimaryKey(itemId);
        //2. 判斷商品是否存在不存在, 拋異常
        if (item == null){
            throw new RuntimeException("該商品不存在!");
        }
        //3. 判斷商品狀態是否爲1已審覈, 狀態不對拋異常
        if (!"1".equals(item.getStatus())){
            throw new RuntimeException("該商品未審覈!");
        }
        //4.獲取當前商品的商家ID
        String sellerId = item.getSellerId();
        //5.根據商家ID查詢購物車列表中是否存在該商家的購物車
        BuyerCart buyerCart = findBuyerCartBySellerId(cartList, sellerId);
        //6.判斷如果購物車列表中不存在該商家的購物車
        if (buyerCart == null) {
            //6.a.1 新建購物車對象
            buyerCart = new BuyerCart();
            //設置新創建的購物車對象的賣家id
            buyerCart.setSellerId(sellerId);
            //設置新創建的購物車對象的賣家名稱
            buyerCart.setSellerName(item.getSeller());
            //創建購物項集合
            List<OrderItem> orderItemList = new ArrayList<>();
            //創建購物項
            OrderItem orderItem = createOrderItem(item, num);
            //將購物項添加到購物項集合
            orderItemList.add(orderItem);
            //將購物項集合添加到購物車
            buyerCart.setOrderItemList(orderItemList);
            //6.a.2 將新建的購物車對象添加到購物車列表
            cartList.add(buyerCart);
        }else {
            //6.b.1如果購物車列表中存在該商家的購物車 (查詢購物車明細列表中是否存在該商品)
            List<OrderItem> orderItemList = buyerCart.getOrderItemList();
            OrderItem orderItem = findOrderItemByItemId(orderItemList, itemId);
            //6.b.2判斷購物車明細是否爲空
            if (orderItem == null){
                //6.b.3爲空,新增購物車明細
                orderItem= createOrderItem(item, num);
                //將新增購物項加入到購物項集合
                orderItemList.add(orderItem);
            }else {
                //6.b.4不爲空,在原購物車明細上添加數量,更改金額
                orderItem.setNum(orderItem.getNum() + num);
                //設置總價格
                orderItem.setTotalFee(orderItem.getPrice().multiply(new BigDecimal(orderItem.getNum())));
            }
            //6.b.5如果購物車明細中數量操作後小於等於0,則移除
            if (orderItem.getNum() <= 0){
                orderItemList.remove(orderItem);
            }
            //6.b.6如果購物車中購物車明細列表爲空,則移除
            if (orderItemList.size() <= 0){
                cartList.remove(buyerCart);
            }
        }
        //7. 返回購物車列表對象
        return cartList;
    }

    /**
     * 判斷當前購物項中是否存在這個商品
     * @param orderItemList
     * @param itemId
     * @return
     */
    private OrderItem findOrderItemByItemId(List<OrderItem> orderItemList, Long itemId){
        if (orderItemList != null){
            for (OrderItem orderItem : orderItemList) {
                if (orderItem.getItemId().equals(itemId)){
                    return orderItem;
                }
            }
        }
        return null;
    }

    /**
     * 創建購物項對象
     * @param item
     * @param num
     * @return
     */
    private OrderItem createOrderItem(Item item, Integer num){
        if (num <= 0){
            throw new RuntimeException("購買數量非法!");
        }
        OrderItem orderItem = new OrderItem();
        orderItem.setNum(num);
        orderItem.setGoodsId(item.getGoodsId());
        orderItem.setItemId(item.getId());
        orderItem.setPicPath(item.getImage());
        orderItem.setPrice(item.getPrice());
        orderItem.setSellerId(item.getSellerId());
        orderItem.setTitle(item.getTitle());
        orderItem.setTotalFee(item.getPrice().multiply(new BigDecimal(num)));
        return orderItem;
    }

    /**
     * 判斷購物車中,是否有該商家的購物車
     * @param cartList
     * @param sellerId
     * @return
     */
    private BuyerCart findBuyerCartBySellerId(List<BuyerCart> cartList, String sellerId){
        if (cartList != null){
            for (BuyerCart buyerCart : cartList) {
                if (buyerCart.getSellerId().equals(sellerId)){
                    return buyerCart;
                }
            }
        }
        return null;
    }

    @Override
    public void setCartListToRedis(String username, List<BuyerCart> cartList) {
        redisTemplate.boundHashOps(Constants.CART_LIST_REDIS).put(username,cartList);
    }

    @Override
    public List<BuyerCart> getCartListToRedis(String username) {
        List<BuyerCart> cartList = (List<BuyerCart>)redisTemplate.boundHashOps(Constants.CART_LIST_REDIS).get(username);
        if (cartList == null){
            cartList = new ArrayList<>();
        }
        return cartList;
    }

    @Override
    public List<BuyerCart> mergeCookieCartListAndRedisCartList(List<BuyerCart> cookieCartList, List<BuyerCart> redisCartList) {
        if (cookieCartList != null){
            //遍歷cookie購物車集合
            for (BuyerCart cookieCart : cookieCartList) {
                //遍歷cookie購物車中的購物項集合
                for (OrderItem cookieOrderItem : cookieCart.getOrderItemList()) {
                    //將cookie中的購物項加入到redis的購物車集合中
                    redisCartList = addItemToCartList(redisCartList,cookieOrderItem.getItemId(),cookieOrderItem.getNum());
                }
            }
        }

        return redisCartList;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章