源无极

导航

 

一、需求分析

    用户在商品详细页点击加入购物车,提交商品ID和购买数量,

添加到购物车。购物车展示页面如下:

1.准备添加

 

 2.继续添加,购物车效果如下

二、实现思路

购物车数据的存储结构如下:

 

    当用户在未登录的情况下,将此购物车存入cookies , 在用户登陆的情况下,

购物车数据存入redis 如果用户登陆时,cookies中存在购物车,

需要将cookies的购物车合并到redis中存储.

三、实现

(一)先将购物车保存到Cookie中

1.准备工作

1)商品实体

package com.po.entity;
import java.math.BigDecimal;
public class Product {
    private  Integer id;
    //商品ID
    private  String productId;
    //商品名称
    private  String productName;
    //商品图片路径
    private  String productPicPath;
    //商家ID
    private  String sellerId;
    //商家名称
    private  String sellerName;
     //商品价格
    private BigDecimal price;
    //商品标题
    private  String title;
    //商品状态
    private String status;
  //省略set和get
}

 2)购物车明细实体

package com.po.entity;
import java.math.BigDecimal;
import java.util.GregorianCalendar;

//购物车明细
public class OrderItem {
  private Integer id;
    //商品ID
   private String productId;
    //订单ID
    private String orderId;
    //标题
    private String title;
    //商品单价价格
        private BigDecimal price;
    //商品数量
    private Integer num;
    //商品总金额
    private BigDecimal totalFee;
    //图片路径
    private String picPath;
    //商家ID
    private String sellerId;

   //省略set和get
}

 3)

package com.po.entity;
import java.io.Serializable;
import java.util.List;
public class Cart implements Serializable {
    //商家ID
    private String sellerId;
    //商家名称
   private String sellerName;
   //购物车明细列表
   List<OrderItem> orderItemList;
 //省略set和get
 }

 4)商品表

 5)xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.po.dao.ProductMapper">
    <!-- 可根据自己的需求,是否要使用 -->
    <resultMap type="Product" id="LibrarianMap">
        <result column="id" property="id" jdbcType="INTEGER" />
        <result column="product_id" property="productId" jdbcType="VARCHAR" />
        <result column="product_name" property="productName" jdbcType="VARCHAR" />
        <result column="product_pic_path" property="productPicPath" jdbcType="VARCHAR" />
        <result column="seller_id" property="sellerId" jdbcType="VARCHAR" />
        <result column="seller_name" property="sellerName" jdbcType="VARCHAR" />
        <result column="price" property="price" jdbcType="DECIMAL" />
        <result column="title" property="title" jdbcType="VARCHAR" />
        <result column="status" property="status" jdbcType="VARCHAR" />
    </resultMap>
    <select id="findProductById" parameterType="String" resultMap="LibrarianMap">
        select *
        from product
        where product_id = #{productId,jdbcType=VARCHAR}
    </select>

</mapper>

 6)接口

package com.po.service;
import com.po.entity.Cart;
import java.util.List;
public interface CartService {
    //传过来购物车处理之后返回
 List<Cart> addProductToCartList(List<Cart> cartList,String productId,Integer num);
}

 7)购物车实现

package com.po.service;
import com.po.dao.ProductMapper;
import com.po.entity.Cart;
import com.po.entity.OrderItem;
import com.po.entity.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private ProductMapper productMapper;

    @Override
    public List<Cart> addProductToCartList(List<Cart> cartList, String productId, Integer num) {
        /*
        说明:前端添加商品到购物车时传过来添加商品前的购物车对象
             然后还有将要被添加的商品ID以及商品数量(注意:商品详情页面
             只有一家商品其中的一个商品)
         1.先去数据库查找到productId对应的商品对象Product
         2.根据Product获得商家ID(sellerId)和商家名称
         3.遍历购物车列表cartList有没有商家ID(sellerId)
          1)如果不存在cart,创建购物车对象cart,购物车明细OrderItem
          将商品添加到购物车明细列表中orderItemList
          2)如果存在cart,查看orderItemList中是否有该商品
           i)有:修改改商品数量和金额
           ii)没有:将该商品添加到orderItemList中
           iii)判断一下商品数量为0的时候。
         */
        //1.先去数据库查找到productId对应的商品对象Product
        Product product = productMapper.findProductById(productId);   if (product==null){
            throw  new RuntimeException("商品不存在");
        }
        if(!"1".equals(product.getStatus())){
            throw  new RuntimeException("商品状态不正常");
        }
        // 2.根据Product获得商家ID(sellerId)和商家名称
        String sellerId = product.getSellerId();
        // 3.遍历购物车列表cartList有没有商家ID(sellerId)
        Cart cart = checkCart(cartList, sellerId);

        if(cart==null){//  1)如果不存在cart,创建购物车对象cart,购物车明细OrderItem
            cart =new Cart();
            cart.setSellerId(sellerId);
            cart.setSellerName(product.getSellerName());
            //准备商家对于的购物车明细列表
            OrderItem orderItem = createOrderItem(product, num);
            List<OrderItem> orderItemList = new ArrayList<>();
            orderItemList.add(orderItem);
            cart.setOrderItemList(orderItemList);
            //将该商家的商品添加到购物车列表
            cartList.add(cart);
        }else {//2)如果存在cart,查看orderItemList中是否有该商品
            OrderItem orderItem = checkOrderItem(cart.getOrderItemList(), productId);
            if(orderItem!=null){//i)有:修改改商品数量和金额
                //该商品添加过数量以现在传过来的为准
                orderItem.setNum(num);
                orderItem.setTotalFee(new BigDecimal(product.getPrice().doubleValue()*num));
                if(orderItem.getNum()<=0){//如果发现数量小于等于0将该商品明细移除
                 cart.getOrderItemList().remove(orderItem);
                }
            }else {//没有:将该商品添加到orderItemList中
                OrderItem orderItem1 = createOrderItem(product, num);
                //添加到购物车该商家对于的明细列表
                cart.getOrderItemList().add(orderItem1);
            }
            //检查该商家的商品明细都没有时将该商家的购物车对象移除
            if(cart.getOrderItemList().size()<=0){
                cartList.remove(cart);
            }

        }    return cartList;
    }
    //检查某商家在购物车里面的商品明细是否存在
    private OrderItem checkOrderItem(List<OrderItem> orderItems,String productId){
        for (OrderItem orderItem:orderItems){
            if(orderItem.getProductId().equals(productId)){
               return  orderItem;
            }
        }
        return null;
    }

    //创建购物车商品明细
    private OrderItem createOrderItem(Product product,Integer num){
        OrderItem orderItem = new OrderItem();
        orderItem.setNum(num);
        orderItem.setPicPath(product.getProductPicPath());
        orderItem.setPrice(product.getPrice());
        orderItem.setProductId(product.getProductId());
        orderItem.setSellerId(product.getSellerId());
        orderItem.setTitle(product.getTitle());
        orderItem.setTotalFee(new BigDecimal(product.getPrice().doubleValue()*num));
        return orderItem;
    }

    //检查购物车是否有该商家
    private Cart checkCart(List<Cart> cartList,String sellerId ){
        if(cartList!=null) {
            for (Cart cart : cartList) {
                if (cart.getSellerId().equals(sellerId)) {
                    return cart;
                }
            }
        }
        return null;
    }
}

 8)controller

package com.po.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.po.entity.Cart;
import com.po.entity.CartForm;
import com.po.service.CartService;
import com.po.utils.CookieUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.NamedParameterBatchUpdateUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/cart")
public class CartController {
   @Autowired
    private  CartService cartService;
//查询购物列表 @RequestMapping(
"/cartList") public List<Cart> findCartList(HttpServletRequest request){ String cartList = CookieUtil.getCookieValue(request,"cartList" , "utf-8"); if(cartList==null||"".equals(cartList)){ cartList="[]"; } List<Cart> carts = JSON.parseArray(cartList, Cart.class); return carts; } //添加购物车 @RequestMapping(path = "/addCart/{product_id}/{num}",method = RequestMethod.GET) public String addProductToCart(HttpServletRequest request, HttpServletResponse response, @PathVariable("product_id") String productId, @PathVariable("num") Integer num){ try { List<Cart> cartList =findCartList(request);//获取购物车列表 cartList = cartService.addProductToCartList(cartList,productId,num); CookieUtil.setCookie(request, response, "cartList", JSON.toJSONString(cartList),3600*24,"UTF-8"); return "添加成功"; }catch (Exception e){ e.printStackTrace(); return "添加失败"; } } }

 补充:(set个getCookie都需要设置utf-8)

 /**
     * 得到Cookie的值,
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
             e.printStackTrace();
        }
        return retValue;
    }

 

 /**
     * 设置Cookie的值,并使其在指定时间内生效
     * 
     * @param cookieMaxage cookie生效的最大秒数
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else {
                cookieValue = URLEncoder.encode(cookieValue, encodeString);
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {// 设置域名的cookie
                String domainName = getDomainName(request);
                System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                    cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
             e.printStackTrace();
        }
    }

 

 

2.测试:

1)添加第一个商家商品

 

 2)查看购物车列表

 

3)添加第二个商家的商品

  4)查看

 

5 )给第二个商家添加商品

 

 6)添加这个商品

 

 7)查看

 

 8)删除时看效果

 

 9)苹果购物车被清空

 

(二)登入时购物车保存到redis中

 1.接口添加的方法如下

public interface CartService {
    //传过来购物车处理之后返回
    List<Cart> addProductToCartList(List<Cart> cartList,String productId,Integer num);
    //从redis发现购物车
    List<Cart> findProductListFromRedis(String username);
    //将购物车保存到redis
    void addProductToRedis(String username,List<Cart> cartList);
    //合并redis和cookie的购物车
    List<Cart> mergeCart(List<Cart> cartListRdis,List<Cart> cartListCookie);
    //删除redi中的购物车
    String deleteCartRdis(String username);
}

 2. 将购物车保存到redis以及从redis获取购物车注意保存的是字符JSON.toJSONString(cartList)

@Override
    public List<Cart> findProductListFromRedis(String username) {
         System.out.println("从redis获取数据。。");
        String cartListr= (String) redisTemplate.boundHashOps("cartList").get(username);
        List<Cart> carts = JSON.parseArray(cartListr, Cart.class);
        if(carts==null){
            carts =new ArrayList<Cart>();
        }
        return carts;
    }

    @Override
    public void addProductToRedis(String username, List<Cart> cartList) {
        System.out.println("将购物车存储到redis中。。");
        redisTemplate.boundHashOps("cartList").put(username,JSON.toJSONString(cartList));
    }

 3.合并购物车(重点

 @Override
    public List<Cart> mergeCart(List<Cart> cartListRdis, List<Cart> cartListCookie) {
        //key=sellerId
         Map<String, Cart> collectRs = cartListRdis.stream().collect(Collectors.toMap(Cart::getSellerId, 
                 cartListRdi -> cartListRdi));
        if(cartListCookie==null){//cookie为空直接返回
           return cartListRdis;
        }else {//该商家的商品不是第一次添加到redis中的购物车里面
            for (Cart cartc:cartListCookie){
                if(collectRs.containsKey(cartc.getSellerId())){
                    for(OrderItem orderItem:cartc.getOrderItemList()){
                        cartListRdis = this.addProductToCartList(cartListRdis, orderItem.getProductId(),
                                orderItem.getNum());
                    }
                }else {//该商家的商品第一次添加到redis中的购物车里面
                    cartListRdis.add(cartc);
                }
            }
        }
        return cartListRdis;
    }

 4.删除redis

 @Override
    public String deleteCartRdis(String username) {
         redisTemplate.boundHashOps("cartList").delete(username);
         return "删除购物车成功";
    }

 5.查看购物车(controller修改如下)

 @RequestMapping(path="/cartList",method = RequestMethod.GET)
    public List<Cart> findCartList(HttpServletRequest request,HttpServletResponse response) {
        String cartListc = CookieUtil.getCookieValue(request, "cartList", "utf-8");
        if (cartListc == null || "".equals(cartListc)) {
            cartListc = "[]";
        }
        String username = request.getParameter("username");
        List<Cart> cartLists =null;
        List<Cart>  cartListRc = JSON.parseArray(cartListc, Cart.class);
       if ( request.getParameter("username")!=null) {//如果用户登入了应该将cookie合并到redis再给用户看
            //从redis拿出
            List<Cart> cartListRedis = cartService.findProductListFromRedis(username);
             System.out.println("从redis中拿出:"+cartListRedis.toString());
            cartLists= cartService.mergeCart(cartListRedis, cartListRc);
            //合并完添加到redis
            cartService.addProductToRedis(username,cartLists);
           //合并完删除cookie
           CookieUtil.deleteCookie(request,response,"cartList");
        }else {
           cartLists=cartListRc;
       }
        return cartLists;
    }

 6.添加商品

  //添加购物车
    @RequestMapping(path = "/addCart/{product_id}/{num}", method = RequestMethod.GET)
    public String addProductToCart(HttpServletRequest request, HttpServletResponse response,
                                   @PathVariable("product_id") String productId, @PathVariable("num") Integer num) {
        try {
            String username = request.getParameter("username");
            //cartList是合并之后的也可能是只是从cookis中拿的
            List<Cart> cartList = findCartList(request,response);
            //处理好购物车准备存
            List<Cart> carts = cartService.addProductToCartList(cartList, productId, num);
            if (username!=null) {//保存到redis
                cartService.addProductToRedis(username,carts);
            } else {//保存到cookis
                CookieUtil.setCookie(request, response, "cartList", JSON.toJSONString(carts), 3600 * 24, "UTF-8");
            }
            return "添加成功";
        } catch (Exception e) {
            e.printStackTrace();
            return "添加失败";
        }

    }

 7.删除redis中的商品

 @RequestMapping(path="/delete")
    public String deleteCartFromRedis(HttpServletRequest request,HttpServletResponse response) {
        String username = request.getParameter("username");
       return cartService.deleteCartRdis(username);
    }

 8.测试:(cookie和redis中都没有值

1)不登入情况下添加一个商品

 2).不登入查看(此时从cookie中拿到值

 

 3).登入查看(此时完成合并,同时将购物车存到了redis)

 

 4).此时不登入再查看cookie中的购物车已经被清空了

 

 5)不登入添加第二个商品

 

6)此时cookie中有购物车

 

 7)redis有之前的购物车(登入完成合并

 

 

 

 

  7)登入情况下添加第二个商家的第二个商品

 8)登入时查看

 

9)添数量为0的删除效果

 

 10)数量为0被删除

 

 

 

 

 

posted on 2020-05-17 20:46  源无极  阅读(190)  评论(0)    收藏  举报