电商项目day16(购物车实现)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangwei_620/article/details/85248631

今日目标:

理解购物车的思路

购物车登陆后存储到redis中

一.需求分析

数据结构分析:

       购物车与商家相关联

我们由京东的案列,就是可以看出,不登录,也可以实现购物车的添加,不过天猫不可以,必须登陆后才能进行,添加到购物车

购物车列表中有多个购物车:[

              京东自营(购物车对象){

                      商家id,    sellerId 

                       商家名称:sellerName

                       购物车商品明细列表:

                       [

                                 购物车明细对象(展示商品信息){

                                           荣耀9i

                                            华为p20

                                    }

                       ]

              }

             疆界互联旗舰店:[

             和京东自营存储数据结构相同

             ]

]

上面就是常用的购物车的存储结构

二.实现思路以及解决方案

添加商品到购物车,登陆和未登陆都能实现添加购物车

         未登陆时:

           1.存储到cookie中,这个方法有个弊端,就是只能存4kb

            2.localStorge  储存能达到5kb       是基于html5存储数据对象的

             JSON.stringify();
        JSON.parse();

            3.缓存到redis中作为key-value储存

     登陆后:

           1.缓存到redis中

                      登陆后:用户名    作为redis存储购物车的可以

                     登陆后将购物车列表中的商品提交生成订单后,在清除购物车中的数据

三.未登陆时,购物车功能实现

首先搭建购物车的工程  cart_web    cart_service   cart_interface

工程搭建完毕,分析后端添加购物车的逻辑思路:

非常重要:   

      首先根据商品的id查询   该商家是否存在于购物车中

             1.商家对应的购物车不存在,购物车列表中

                       创建购物车对象,在存入购物车列表中

                        创建购物车对象时,指定该购物车的商家信息,以及构建购物车明细对象和购物车明细列表

                        将购物车的明细对象添加到购物车明细列表中,将购物车明细列表添加到购物车对象,在将

                         购物车对象添加到购物车列表中

            2.商家对应的购物车对象存在于购物车列表中

                       判断该商品是否存在于该购物车商品的明细列表中

                            1.如果该商品不存在购物车明细列表中

                                      则创建购物车明细对象,在添加到购物车明细里列表中

                            2.如果该商品存在购物车明细列表中

                                     修改购物车明细对象的数量和小计金额

首先我们先编写未登陆时,的接口方法

 /**
     * 添加商品到购物车
     */
    public List<Cart> addItemToCartList(List<Cart> cartList, Long itemId, Integer num);

    /**
     * 根据sessionId获得购物车列表
     * @param sessionId
     * @return
     */
    List<Cart> selectCartListFromRedis(String sessionId);

    /**
     * 保存该sessionid 的 cartList 购物车列表
     * @param sessionId
     * @param cartList
     */
    void saveCartListToRedis(String sessionId, List<Cart> cartList);

    /**
     * 合并添加前购物车的数据到登陆后的购物车列表
     * @param cartList_sessionId
     * @param cartList_username
     * @return
     */
    List<Cart> mergeCartList(List<Cart> cartList_sessionId, List<Cart> cartList_username);

    /**
     * 删除之前未登陆的购物车的列表数据
     * @param cartList_sessionId
     */
    void deleteCartList(List<Cart> cartList_sessionId);

service实现的所有的功能,主要是:购物车的添加,以及通过sessionid获取购物车列表,还有就是,未登陆时,购物车列表的数据,在登陆后会跟新到redis数据库中,通过username的作为key值保存,然后删除登陆前购物车的数据

package com.pinyougou.cart.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.cart.service.CartService;
import com.pinyougou.groupentity.Cart;
import com.pinyougou.mapper.TbItemMapper;
import com.pinyougou.pojo.TbItem;
import com.pinyougou.pojo.TbOrderItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;

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

@Service
@Transactional
public class CartServiceImpl implements CartService {
    @Autowired
    private TbItemMapper itemMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 添加商品到购物车
     * @param cartList
     * @param itemId
     * @param num
     * @return
     *  首先根据商品的id查询   该商家是否存在于购物车中
                 1.商家对应的购物车不存在,购物车列表中
                           创建购物车对象,在存入购物车列表中
                            创建购物车对象时,指定该购物车的商家信息,以及构建购物车明细对象和购物车明细列表
                            将购物车的明细对象添加到购物车明细列表中,将购物车明细列表添加到购物车对象,在将
                             购物车对象添加到购物车列表中
                2.商家对应的购物车对象存在于购物车列表中
                           判断该商品是否存在于该购物车商品的明细列表中
                                1.如果该商品不存在购物车明细列表中
                                          则创建购物车明细对象,在添加到购物车明细里列表中
                                2.如果该商品存在购物车明细列表中
                                         修改购物车明细对象的数量和小计金额
     */
    @Override
    public List<Cart> addItemToCartList(List<Cart> cartList, Long itemId, Integer num) {
        //首先根据商品的id查询   该商家是否存在于购物车中
        TbItem item = itemMapper.selectByPrimaryKey(itemId);
        //优化操作,添加购物车的时候,刚好该商品下架了

        if(item==null){
            throw new RuntimeException("商品不存在");
        }

        //如果商品的状态不为1则无效
        if (!item.getStatus().equals("1")){
            throw  new RuntimeException("商品无效");
        }
        String sellerId = item.getSellerId();
        //在购物车列表中基于商品id 查询购物车对象
        Cart cart = searchCartBySellerId(cartList,sellerId);
        //判断购物车是否在空
        if (cart==null){//购物车为空
            //创建购物车对象,
            cart = new Cart();
            //指定该购物车的商家信息,以及构建购物车明细对象和购物车明细列表
            cart.setSellerId(sellerId);
            cart.setSellerName(item.getSeller());
            //以及构建购物车明细对象和购物车明细列表
            List<TbOrderItem> orderItemList = new ArrayList<>();
            //构建商品明细对象
            TbOrderItem orderItem = createOrderItem(item,num);
            //购物车的明细对象添加到购物车明细列表中
            orderItemList.add(orderItem);
            //购物车明细列表添加到购物车对象
            cart.setOrderItemList(orderItemList);
            //购物车对象添加到购物车列表中
            cartList.add(cart);
        }else{//该商品的存在
            //先通过购物车获取当前购物车的商品明细对象
            List<TbOrderItem> orderItemList = cart.getOrderItemList();
            //判断该商品是否存在于该购物车商品的明细列表中
            TbOrderItem orderItem = searchOrderIdByItemId(orderItemList,itemId);
            if (orderItem==null){//在商品列表中不存在
                //如果该商品不存在购物车明细列表中
                //则创建购物车明细对象,在添加到购物车明细里列表中
                orderItem = createOrderItem(item,num);
                //在添加到购物车明细里列表中
                orderItemList.add(orderItem);
            }else{//存在于商品列表中
                //修改购物车明细对象的数量和小计金额
                orderItem.setNum(orderItem.getNum()+num);
                //小计金额
                orderItem.setTotalFee(new BigDecimal(orderItem.getPrice().doubleValue()*orderItem.getNum()));

                //如果商品数量小于1 则删除该商品
                if(orderItem.getNum()<1){
                    orderItemList.remove(orderItem);
                }
                //如果购物车商品明细列表中没有商品了, 则直接从购物车里列表中移除
                if (orderItemList.size()<=0){
                    cartList.remove(cart);
                }
            }
        }
        return cartList;
    }



    //判断该商品是否存在于该购物车商品的明细列表中
    private TbOrderItem searchOrderIdByItemId(List<TbOrderItem> orderItems, Long itemId) {
        for (TbOrderItem orderItem : orderItems) {
            if(orderItem.getItemId().longValue()==itemId.longValue()){//存在商品列表中
                return orderItem;
            }
        }
        return null;
    }

    //创建商品的明细对象
    private TbOrderItem createOrderItem(TbItem item, Integer num) {
        //优化操作
        //创建商品的数量如果为负数
        if(num<1){
            throw new RuntimeException("新添加商品到购物车,商品数量不能小于1");
        }
        /*
          `item_id` bigint(20) NOT NULL COMMENT '商品id',
          `goods_id` bigint(20) DEFAULT NULL COMMENT 'SPU_ID',
          `title` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品标题',
          `price` decimal(20,2) DEFAULT NULL COMMENT '商品单价',
          `num` int(10) DEFAULT NULL COMMENT '商品购买数量',
          `total_fee` decimal(20,2) DEFAULT NULL COMMENT '商品总金额',
          `pic_path` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品图片地址',
          `seller_id` varchar(100) COLLATE utf8_bin DEFAULT NULL,
         */
        TbOrderItem orderItem = new TbOrderItem();
        orderItem.setItemId(item.getId());
        orderItem.setGoodsId(item.getGoodsId());
        orderItem.setTitle(item.getTitle());
        orderItem.setPrice(item.getPrice());
        orderItem.setNum(num);
        orderItem.setTotalFee(new BigDecimal(item.getPrice().doubleValue()*num));
        orderItem.setPicPath(item.getImage());
        orderItem.setSellerId(item.getSellerId());
        return orderItem;
    }

    //根据商品的id查询是否存在购物车对象
    private Cart searchCartBySellerId(List<Cart> cartList, String sellerId) {
        for (Cart cart : cartList) {
            if (cart.getSellerId().equals(sellerId)){
                return cart;
            }
        }
        return null;
    }
    //通过sessionid获得购物车列表
    @Override
    public List<Cart> selectCartListFromRedis(String sessionId) {
        //从redis中获取
        List<Cart> cartList = (List<Cart>) redisTemplate.boundValueOps(sessionId).get();
        //判断cartList是否为空,因为你要返回一个list列表,如果为空,前台就不能通过fastJson解析了
        if (cartList==null){
            //为空我们可以直接从新创建一个新的arrayList
            cartList = new ArrayList<>();
        }
        return cartList;
    }
    //保存购物车列表到redis中
    @Override
    public void saveCartListToRedis(String sessionId, List<Cart> cartList) {
        redisTemplate.boundValueOps(sessionId).set(cartList,7L, TimeUnit.DAYS);
    }
    //合并登陆前购物车的数据到登陆后的购物车数据中
    @Override
    public List<Cart> mergeCartList(List<Cart> cartList_sessionId, List<Cart> cartList_username) {
        //注意我们只需要构建我们需要添加的数据,因为我们在上面已经做过判断,我们只需要,拼装数据即可
        for (Cart cart : cartList_sessionId) {
            //获取购车列表
            List<TbOrderItem> itemList = cart.getOrderItemList();
            for (TbOrderItem orderItem : itemList) {
                //获取num和ItemId的值
                Integer num = orderItem.getNum();
                Long itemId = orderItem.getItemId();
                //购物车列表我们直接用登陆的就可以了
                cartList_username=   addItemToCartList(cartList_username,itemId,num);
            }
        }
        return cartList_username;
    }
    //删除登陆前购物车的数据
    @Override
    public void deleteCartList(List<Cart> cartList_sessionId) {
        redisTemplate.delete(cartList_sessionId);
    }
}

controller层:

思路分析:我们主要做两件事    1.购物车列表数据的展示     2.添加商品到购物车列表中   还有一个非常重要就是获取sessionid的方法,我们浏览器的存在的cookie是一次会话,我们想要用户的商品存储一周,我们必须后台进行,重新创建cookie,设置为一周过期,通过一个工具类

CookieUtil来获取和存储

@RestController
@RequestMapping("/cart")
public class CartController {
    @Autowired
    private HttpSession session;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private HttpServletResponse response;
    @Reference
    private CartService cartService;
    /**
     * 获得sessionid的方法
     */
    private String getSessionId(){

        //先尝试从"cartCookie"中获得sessionId信息
        String sessionId = CookieUtil.getCookieValue(request, "cartList", "utf-8");
        if (sessionId==null){
            //在从浏览器中获取sessionid
             sessionId = session.getId();
             //将浏览器获取的sessionId保存一周
            CookieUtil.setCookie(request,response,"cartList",sessionId,3600*24*7,"utf-8");
        }
        return sessionId;
    }
    /**
     * 展示购物车列表数据
     */
    @RequestMapping("/findCartList")
    public List<Cart> findCartList(){
        //获取登陆人用户名
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        //未登陆时,基于sessionid从redis中获取购物车数据列表
        String sessionId = getSessionId();
        //从redis中获取
        List<Cart>  cartList_sessionId =  cartService.selectCartListFromRedis(sessionId);
        if ("anonymousUser".equals(username)){//未登陆
            System.out.println("selectCartListFromRedis by sessionId....");
            return cartList_sessionId;
        }else{//已登录
            System.out.println("selectCartListFromRedis by username....");
            List<Cart>  cartList_username =  cartService.selectCartListFromRedis(username);
            //用户登录前,如果已经添加商品到购物车列表中。
            if(cartList_sessionId!=null&&cartList_sessionId.size()>0){//说明添加前已经存在商品了
                //登陆后,将登陆前的购物车列表数据合并到登陆后的购物车列表中
             cartList_username = cartService.mergeCartList(cartList_sessionId,cartList_username);
             //将合并后的结果从新放到缓存中
                cartService.saveCartListToRedis(username,cartList_username);
                //清除合并前的购物车列表数据
                cartService.deleteCartList(cartList_sessionId);
            }
            return cartList_username;
        }

    }

    /**
     * 添加商品到购物车
     */
    @RequestMapping("/addItemToCartList")
    public Result addItemToCartList(Long itemId, Integer num){
        try {

            //获取登陆人用户名
            String username = SecurityContextHolder.getContext().getAuthentication().getName();
            System.out.println(username);
            //获取sessionId
            String sessionId = getSessionId();
            //1.查询购物车列表
            List<Cart> cartList = findCartList();
            if ("anonymousUser".equals(username)){//未登陆
                System.out.println("saveCartListToRedis by sessionId.....");
                //2.添加商品到购物车
                cartList =  cartService.addItemToCartList(cartList,itemId, num);
                //3.保存购物车列表到redis中
                cartService.saveCartListToRedis(sessionId,cartList);
            }else{//已登录
                System.out.println("saveCartListToRedis by username.....");
                cartService.saveCartListToRedis(username,cartList);

            }

            return new Result(true,"添加购物车成功");
        } catch (RuntimeException e) {
            e.printStackTrace();
            return new Result(false,e.getMessage());
        }
        catch (Exception e) {
            e.printStackTrace();
            return new Result(false,"添加购物车失败");
        }
    }

}

前台实现:

service层:

//服务层
app.service('cartService',function($http){
	    	
	//查找购物车列表数据
	this.findCartList=function(){
		return $http.get('cart/findCartList.do');
	}

	//查找购物车列表数据
	this.addItemToCartList=function (itemId,num) {
		return $http.get('cart/addItemToCartList.do?itemId='+itemId+'&num='+num)
    }

});

controller层:

 //控制层 
app.controller('cartController' ,function($scope,$controller   ,cartService){
	
	$controller('baseController',{$scope:$scope});//继承
	
    //读取列表数据绑定到表单中  
	$scope.findCartList=function(){
        cartService.findCartList().success(
			function(response){
				$scope.cartList=response;
				sum();
			}			
		);
	}

	//添加商品到购物车
	$scope.addItemToCartList=function (itemId,num) {
		cartService.addItemToCartList(itemId,num).success(function (response) {
			if (response.success){
				//添加购物车工程
                $scope.findCartList();
			}else{
				//添加购物车失败
				alert(response.message)
			}
        })
    }
	//统计商品的数量和总计
	sum=function () {
		//总数量 和总金额
		$scope.totalNum = 0;
		$scope.totalMoney=0.00;
		//遍历购物车列表
		for (var i = 0;i<$scope.cartList.length;i++){
			//获取购物车对象
			var cart = $scope.cartList[i];
			var orderItemList = cart.orderItemList;//获取商品明细列表
			//遍历商品购物车明细列表
			for(var j = 0;j<orderItemList.length;j++){
				$scope.totalNum = orderItemList[i].num;
				$scope.totalMoney= orderItemList[i].totalFee;
			}
		}
    }

});	

1.页面的设置:

注意:如果我们未登陆,则要添加购物车,我们需要获取用户名:则通过一个spring-security.xml的配置

//之前增加的放行,删掉,否则所有访问cart下的访问都不进入到springSecurity中
<http pattern="/cart/*.do" security="none"></http>
//但是我们需要购物车可以不登录也能增加到购物车中的操作,IS_AUTHENTICATED_ANONYMOUSLY和上面的配置区别在于,可以匿名访问springSecurity(加在入口点引用中,注意拦截规则小范围的在上面)
<intercept-url pattern="/cart/*.do" access="IS_AUTHENTICATED_ANONYMOUSLY"/> 
//在此拦截器上<intercept-url pattern="/**" access="ROLE_USER"/> 

2.页面跳转的问题

思路分析:我们设置一个login.html页面这个页面就做一件事,就是用于转发跳转到cart.html页面,因为我们在spring-sceurity.xml中没有放行,所以会先进入cas登陆界面,我们登陆后,会转发到cart.html页面

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>跳转页面</title>
    <script type="text/javascript">
        location.href="cart.html";
    </script>
</head>
<body>

</body>
</html>

猜你喜欢

转载自blog.csdn.net/wangwei_620/article/details/85248631
今日推荐