品优购项目记录:day16

今日目标:

(1)理解品优购购物车的实现思路

(2)运用Cookie存储购物车

(3)编写购物车前端代码

(4)运用 Redis 存储购物车

 

目录

1、购物车工程搭建

1.1 需求分析

1.2 工程搭建

2、Cookie存储购物车

2.1 需求分析

2.2 后端-添加商品到购物车

2.3 购物车列表展示

2.4 商品数量加减

2.5 计算总金额和总数量

3、Redis 存储购物车

3.1 需求分析

3.2 后端代码

4、购物车合并

4.1 需求分析

4.2 后端


 

1、购物车工程搭建

 

1.1 需求分析

用户在商品详细页点击加入购物车,提交商品SKU编号和购买数量,添加到购物车。购物车展示页面如下:

 

 

1.2 工程搭建

(1)参考之前的工程进行搭建(分别有:pinyougou-cart-interface、pinyougou-cart-service和pinyougou-cart-web),其中cart-web参考user-web

 

(2)创建购物车组合实体类

package com.pinyougou.pojogroup;

import com.pinyougou.pojo.TbOrderItem;

import java.io.Serializable;
import java.util.List;

/**
 * 购物车组合实体类
 * Author xushuai
 * Description
 */
public class Cart implements Serializable {

    /** 商家ID */
    private String sellerId;
    /** 商家名称 */
    private String sellerName;
    /** 购物车商品明细列表 */
    private List<TbOrderItem> orderItemList;

}

 

 

 

2、Cookie存储购物车

 

2.1 需求分析

使用cookie存储购物车数据。服务层负责逻辑,控制层负责读写cookie 。

 

2.2 后端-添加商品到购物车

(1)服务层接口(cart-interface),新增CartService

package com.pinyougou.cart.service;

import com.pinyougou.pojogroup.Cart;

import java.util.List;

/**
 * 购物车接口
 * Author xushuai
 * Description
 */
public interface CartService {

    /**
     * 添加商品到购物车中
     *
     * @param cartList 购物车列表
     * @param itemId 商品ID
	 * @param num 添加的数量
     * @return java.util.List<com.pinyougou.pojogroup.Cart>
     */
    List<Cart> addGoodsToCartList(List<Cart> cartList, Long itemId, Integer num);
}

(2)服务层实现(cart-service),新增CartServiceImpl

package com.pinyougou.cart.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.cart.service.CartService;
import com.pinyougou.mapper.TbItemMapper;
import com.pinyougou.pojo.TbItem;
import com.pinyougou.pojo.TbOrderItem;
import com.pinyougou.pojogroup.Cart;
import exception.PinyougouException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 购物车实现
 * Author xushuai
 * Description
 */
@Service
@Transactional
public class CartServiceImpl implements CartService {

    @Autowired
    private TbItemMapper itemMapper;


    @Override
    public List<Cart> addGoodsToCartList(List<Cart> cartList, Long itemId, Integer num) {
        /*
         * 1.使用SKUID查询SKU商品对象
         * 2.使用商品对象获取商家信息
         * 3.根据商家ID在购物车列表中查询购物车对象
         * 4.购物车列表中不存在该商家的购物车
         *      4.1 创建新的购物车对象,将新的购物车对象添加到购物车列表
         * 5.购物车列表中存在该商家的购物车
         *      5.1 判断该购物车是否存在该商品的明细
         *          5.1.1 不存在,新增该明细到明细列表
         *          5.1.2 存在,在原有的数量上加上新增的数量,并更改金额
         */
        // 1.查询SKU商品对象
        TbItem item = itemMapper.selectByPrimaryKey(itemId);
        if (item == null) {
            throw new PinyougouException("商品不存在!");
        }
        if (!item.getStatus().equals(TbItem.STATUS_NORMAL)) {
            throw new PinyougouException("商品状态异常");
        }
        // 2.获取商家信息
        String sellerId = item.getSellerId();
        String sellerName = item.getSeller();
        // 3.根据商家ID查询购物车中的对象
        Cart cart = searchCartBySellerId(cartList, sellerId);
        if (cart == null) {// 4.购物车列表中不存在该商家的购物车
            // 创建购物车对象
            cart = new Cart();
            cart.setSellerId(sellerId);
            cart.setSellerName(sellerName);
            List<TbOrderItem> orderItemList = new ArrayList<>();
            // 使用item对象生成购物车明细
            TbOrderItem tbOrderItem = itemToOrderItem(item, num);
            orderItemList.add(tbOrderItem);
            cart.setOrderItemList(orderItemList);

            // 将购物车放入购物车列表
            cartList.add(cart);

        } else {// 5.购物车列表中存在该商家的购物车
            // 5.1 判断该购物车是否存在该商品的明细
            TbOrderItem orderItem = searchOrderItemByItemId(cart.getOrderItemList(), item.getId());
            if (orderItem == null) {// 5.1.1 不存在,新增该明细到明细列表
                orderItem = itemToOrderItem(item, num);
                // 添加到明细列表
                cart.getOrderItemList().add(orderItem);
            } else {// 5.1.2 存在,在原有的数量上加上新增的数量,并更改金额
                // 判断操作后的购物车情况
                if (orderItem.getNum() + num < 1) {// 数量小于1
                    // 移除该明细
                    cart.getOrderItemList().remove(orderItem);
                    if (cart.getOrderItemList().size() == 0) {// 明细列表中无数据
                        // 移除该购物车
                        cartList.remove(cart);
                    }
                }
                // 修改数量
                orderItem.setNum(orderItem.getNum() + num);
                // 修改金额
                orderItem.setTotalFee(BigDecimal.valueOf(orderItem.getPrice().doubleValue() * orderItem.getNum()));
            }
        }

        return cartList;
    }

    /**
     * 根据itemId查询购物车明细列表
     *
     * @param orderItemList 购物车明细列表
     * @param itemId        商品ID
     * @return com.pinyougou.pojo.TbOrderItem
     */
    private TbOrderItem searchOrderItemByItemId(List<TbOrderItem> orderItemList, Long itemId) {
        // 遍历购物车明细列表
        for (TbOrderItem orderItem : orderItemList) {
            if (orderItem.getItemId().longValue() == itemId.longValue()) {
                return orderItem;
            }
        }
        return null;
    }

    /**
     * 将item对象转换为OrderItem对象
     *
     * @param item 商品对象
     * @param num  数量
     * @return com.pinyougou.pojo.TbOrderItem
     */
    private TbOrderItem itemToOrderItem(TbItem item, Integer num) {
        TbOrderItem orderItem = new TbOrderItem();
        orderItem.setGoodsId(item.getGoodsId());
        orderItem.setItemId(item.getId());
        orderItem.setNum(num);
        orderItem.setPicPath(item.getImage());
        orderItem.setPrice(item.getPrice());
        orderItem.setSellerId(item.getSellerId());
        orderItem.setTitle(item.getTitle());
        orderItem.setTotalFee(BigDecimal.valueOf(item.getPrice().doubleValue() * num));

        return orderItem;
    }

    /**
     * 根据商家ID查询购物车列表
     *
     * @param cartList 购物车列表
     * @param sellerId 商家ID
     * @return com.pinyougou.pojogroup.Cart
     */
    private Cart searchCartBySellerId(List<Cart> cartList, String sellerId) {
        // 遍历购物车列表
        for (Cart cart : cartList) {
            if (cart.getSellerId().equals(sellerId)) {
                return cart;
            }
        }
        return null;
    }


}

(3)控制层(cart-web),新增CartController

package com.pinyougou.cart.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.pinyougou.cart.service.CartService;
import com.pinyougou.pojogroup.Cart;
import entity.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import util.CookieUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * 购物车控制层
 * Author xushuai
 * Description
 */
@RestController
@RequestMapping("/cart")
public class CartController {

    /** cookieName:cookie名称 */
    private final String CARTLIST_COOKIENAME = "cartList";
    /** cookie_maxAge:cookie存活时间 */
    private final int MAXAGE_COOKIE = 3600 * 60;

    @Reference
    private CartService cartService;

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private HttpServletResponse response;


    /**
     * 添加商品到购物车
     *
     * @param itemId 商品ID
	 * @param num 数量
     * @return entity.Result
     */
    @RequestMapping("/addGoodsToCartList")
    public Result addGoodsToCartList(Long itemId, Integer num) {
        try {
            List<Cart> cartList = findCartList();

            // 添加商品到购物车
            cartList = cartService.addGoodsToCartList(cartList, itemId, num);

            // 将购物车列表转换为json字符串
            String cookieValue = JSON.toJSONString(cartList);
            // 将购物车添加到cookie中
            CookieUtil.setCookie(request, response, CARTLIST_COOKIENAME, cookieValue, MAXAGE_COOKIE, "UTF-8");

            return Result.success("添加商品到购物车成功");
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("添加商品到购物车失败");
        }
    }

    /**
     * 获取购物车列表
     *
     * @return java.util.List<com.pinyougou.pojogroup.Cart>
     */
    @RequestMapping("/findCartList")
    public List<Cart> findCartList() {
        // 从cookie中获取购物车列表
        String cartListJson = CookieUtil.getCookieValue(request, CARTLIST_COOKIENAME, "UTF-8");
        List<Cart> cartList = JSON.parseArray(cartListJson, Cart.class);
        return cartList;
    }


}

 

 

 

2.3 购物车列表展示

(1)前端:编写cartService.js

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

(2)前端:编写cartController.js

//购物车控制层 
app.controller('cartController', function ($scope, cartService) {
    //查询购物车列表
    $scope.findCartList = function () {
        cartService.findCartList().success(
            function (response) {
                $scope.cartList = response;
            }
        );
    }
});

(3)页面引入JS文件和基础指令,并初始化执行查询购物车列表方法

(4)页面绑定变量

(5)添加商品到购物车

(6)查看购物车

 

 

 

2.4 商品数量加减

(1)前端:在cartService.js中新增方法

    //添加商品到购物车
    this.addGoodsToCartList = function (itemId, num) {
        return $http.get('cart/addGoodsToCartList.do?itemId=' + itemId + '&num=' + num);
    }

(2)前端:在cartController.js中新增方法

    //添加商品到购物车
    $scope.addGoodsToCartList = function (itemId, num) {
        cartService.addGoodsToCartList(itemId, num).success(
            function (response) {
                if (response.success) {
                    $scope.findCartList();//刷新列表
                } else {
                    alert(response.message);//弹出错误提示
                }
            }
        );
    }

(3)前端:页面 加减号 绑定单击事件

 

 

2.5 计算总金额和总数量

(1)前端:在cartService.js中新增方法

    // 合计金额
    this.sum = function (cartList) {
        // 返回结果集
        var totalValue = {totalNum: 0, totalMoney: 0};
        // 遍历购物车列表
        for (var i = 0; i < cartList.length; i++) {
            var cart = cartList[i];
            for (var j = 0; j < cart.orderItemList.length; j++) {
                // 累加数量
                totalValue.totalNum += cart.orderItemList[j].num;
                // 累加金额
                totalValue.totalMoney += cart.orderItemList[j].totalFee;
            }
        }
        return totalValue;
    }

(2)前端:在cartController.js中的findCartList中新增逻辑

(3)页面绑定变量

 

 

 

 

 

3、Redis 存储购物车

 

3.1 需求分析

判断当前用户是否登陆,如果未登录采用Cookie存储,如果登录则采用Redis存储。登录后要进行Cookie购物车与Redis购物车的合并操作,并清除Cookie购物车。

 

3.2 后端代码

(1)后端:修改放行cart/*.do的配置,将其配置为匿名角色访问权限

(2)后端:服务层接口(cart-interface),在CartService中新增方法

    /**
     * 从redis中获取购物车列表
     *
     * @param
     * @return java.util.List<com.pinyougou.pojogroup.Cart>
     */
    List<Cart> findCartListFromRedis(String username);

    /**
     * 将购物车列表保存到redis中
     *
     * @param username 当前登录用户名
     * @param cartList 购物车列表
     */
    void saveCartListToRedis(String username, List<Cart> cartList);

(3)后端:服务层实现(cart-service),在CartServiceImpl中新增实现

    @Override
    public List<Cart> findCartListFromRedis(String username) {
        System.out.println("从redis中获取当前用户的购物车");
        // 从购物车中获取
        List<Cart> cartList = (List<Cart>) redisTemplate.boundHashOps(REDIS_CARTLIST_KEY).get(username);
        if (cartList == null) {
            cartList = new ArrayList<>();
        }
        return cartList;
    }

    @Override
    public void saveCartListToRedis(String username, List<Cart> cartList) {
        System.out.println("将购物车存入redis中");
        // 将购物车保存到redis
        redisTemplate.boundHashOps(REDIS_CARTLIST_KEY).put(username, cartList);
    }

(4)后端:控制层修改findCartList和addGoodsToCartList方法

    /**
     * 添加商品到购物车
     *
     * @param itemId 商品ID
	 * @param num 数量
     * @return entity.Result
     */
    @RequestMapping("/addGoodsToCartList")
    public Result addGoodsToCartList(Long itemId, Integer num) {
        // 获取当前登录用户名
        String loginUser = SecurityContextHolder.getContext().getAuthentication().getName();

        try {
            List<Cart> cartList = findCartList();
            // 添加商品到购物车
            cartList = cartService.addGoodsToCartList(cartList, itemId, num);

            // 判断是否存入redis
            if (loginUser == ROLE_ANONYMOUSUSER) {// 未登录
                // 将购物车列表转换为json字符串
                String cookieValue = JSON.toJSONString(cartList);
                // 将购物车添加到cookie中
                CookieUtil.setCookie(request, response, CARTLIST_COOKIENAME, cookieValue, MAXAGE_COOKIE, "UTF-8");
            } else {// 已登录
                // 存入redis
                cartService.saveCartListToRedis(loginUser, cartList);
            }

            return Result.success("添加商品到购物车成功");
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("添加商品到购物车失败");
        }
    }

    /**
     * 获取购物车列表
     *
     * @return java.util.List<com.pinyougou.pojogroup.Cart>
     */
    @RequestMapping("/findCartList")
    public List<Cart> findCartList() {
        // 获取当前登录用户名
        String loginUser = SecurityContextHolder.getContext().getAuthentication().getName();
        // 判断是否为匿名权限
        if (loginUser.equals(ROLE_ANONYMOUSUSER)) {// 为匿名权限,未登录状态
            // 从cookie中获取购物车列表
            String cartListJson = CookieUtil.getCookieValue(request, CARTLIST_COOKIENAME, "UTF-8");
            if (cartListJson == null || cartListJson.equals("")) {
                cartListJson = "[]";
            }
            List<Cart> cartList_cookie = JSON.parseArray(cartListJson, Cart.class);
            return cartList_cookie;
        } else {// 不是匿名权限,登录状态
            // 从redis中获取购物车列表
            List<Cart> cartList_redis = cartService.findCartListFromRedis(loginUser);
            return cartList_redis;
        }
    }

(5)单点登录对接购物车

 

 

 

4、购物车合并

 

4.1 需求分析

当登录成功时,将cookie购物车中的购物车列表和redis中的购物车列表进行合并

 

 

4.2 后端

(1)服务层接口(cart-interface),新增方法

    /**
     * 合并购物车
     *
     * @param cartList1 购物车1
	 * @param cartList2 购物车2
     * @return java.util.List<com.pinyougou.pojogroup.Cart>
     */
    List<Cart> mergeCartList(List<Cart> cartList1, List<Cart> cartList2);

(2)服务层实现(cart-service),新增实现

    @Override
    public List<Cart> mergeCartList(List<Cart> cartList1, List<Cart> cartList2) {
        // 遍历任意购物车
        for (Cart cart : cartList1) {
            // 遍历购物车明细列表
            for (TbOrderItem orderItem : cart.getOrderItemList()) {
                // 进行合并操作
                cartList2 = addGoodsToCartList(cartList2, orderItem.getItemId(), orderItem.getNum());
            }
        }
        return cartList2;
    }

(3)控制层,修改findCartList方法中的逻辑

    /**
     * 获取购物车列表
     *
     * @return java.util.List<com.pinyougou.pojogroup.Cart>
     */
    @RequestMapping("/findCartList")
    public List<Cart> findCartList() {
        // 获取当前登录用户名
        String loginUser = SecurityContextHolder.getContext().getAuthentication().getName();
        // 从cookie中获取购物车列表
        String cartListJson = CookieUtil.getCookieValue(request, CARTLIST_COOKIENAME, "UTF-8");
        if (cartListJson == null || cartListJson.equals("")) {
            cartListJson = "[]";
        }
        List<Cart> cartList_cookie = JSON.parseArray(cartListJson, Cart.class);
        // 判断是否为匿名权限
        if (loginUser.equals(ROLE_ANONYMOUSUSER)) {// 为匿名权限,未登录状态

            return cartList_cookie;
        } else {// 不是匿名权限,登录状态
            // 从redis中获取购物车列表
            List<Cart> cartList_redis = cartService.findCartListFromRedis(loginUser);
            // cookie购物车中存在数据
            if (cartList_cookie.size() > 0) {
                // 进行购物车合并
                cartList_redis = cartService.mergeCartList(cartList_cookie, cartList_redis);
                // 清除cookie中的购物车数据
                CookieUtil.deleteCookie(request, response, CARTLIST_COOKIENAME);
                // 将合并后的购物车数据存入reids
                cartService.saveCartListToRedis(loginUser, cartList_redis);
            }

            return cartList_redis;
        }
    }

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值