一、需求分析
用户在商品详细页点击加入购物车,提交商品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被删除


浙公网安备 33010602011771号