品优购项目笔记(十三):购物车解决方案

购物车业务

购物车业务概要分析

在这里插入图片描述

购物车对象封装分析

在这里插入图片描述
购物车实体

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;
    }
}

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