购物车需求分析与解决方案

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 目标1:说出品优购购物车的实现思路目标2:运用Cookie存储购物车目标3:编写购物车前端代码目标4:运用Redis存储购物车1.购物车需求分析与解决方案1.1需求分析用户在商品详细页点击加入购物车,提交商品SKU编号和购买数量,添加到购物车。

目标1:说出品优购购物车的实现思路
目标2:运用Cookie存储购物车
目标3:编写购物车前端代码
目标4:运用Redis存储购物车

1.购物车需求分析与解决方案

1.1需求分析

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

简单的可以理解为每个商品的属性:颜色/尺码等信息(比如红色M码是一个SKU;红色L码又是一个SKU)。
SKU=Stock Keeping Unit(库存量单位),即库存进出计量的单位,可以是以件,盒,托盘等为单位。SKU是对于大型连锁超市DC(配送中心)物流管理的一个必要的方法。当下已经被引申为产品统一编号的简称,每种产品均对应有唯一的SKU号。
针对电商而言,SKU有另外的注解:
1、SKU是指一款商品,每款都有出现一个SKU,便于电商品牌识别商品。
2、一款商品多色,则是有多个SKU,例:一件衣服,有红色、白色、蓝色,则SKU编码也不相同,如相同则会出现混淆,发错货。

img_225cdb3b862c38a410493394c5b0de9d.png

1.2实现思路

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


img_fef40fb91e9a9f6ffd03a28d0e2200f3.png

京东实现思路: 当用户在未登录的情况下,将此购物车存入cookies , 在用户登陆的情况下,将购物车数据存入redis 。如果用户登陆时,cookies中存在购物车,需要将cookies的购物车合并到redis中存储,清空cookies中的购物车。

1.3购物车实体类

public class Cart implements Serializable{
    private String sellerId;//商家ID
    private String sellerName;//商家名称
    private List<TbOrderItem> orderItemList;//购物车明细
    //getter  and setter  ......
}

这个类是对每个商家的购物车进行的封装

2.Cookie存储购物车

2.1需求分析

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

2.2服务接口层

(1)服务层接口CartService

/**
 * 购物车服务接口 
 * @author Administrator
 */
public interface CartService {
    /**
     * 添加商品到购物车
     * @param cartList
     * @param itemId 商品SKU码
     * @param num 数量
     * @return
     */
    public List<Cart> addGoodsToCartList(List<Cart> cartList,Long itemId,Integer num );
}

2.3服务实现层

实现思路:

        //1.根据商品SKU ID查询SKU商品信息

        //2.获取该商品对应的商家ID        

        //3.根据商家ID判断购物车列表中是否存在该商家的购物车   
    
        //4.如果购物车列表中不存在该商家的购物车

        //4.1 新建购物车对象

        //4.2 将新建的购物车对象添加到购物车列表     

        //5.如果购物车列表中存在该商家的购物车   
    
        // 查询购物车明细列表中是否存在该商品

        //5.1. 如果没有,新增购物车明细 
    
        //5.2. 如果有,在原购物车明细上添加数量,更改金额

购物车服务实现类:

/**
 * 购物车服务实现类
 * @author Administrator
 *
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private TbItemMapper itemMapper;
    
    @Override
    public List<Cart> addGoodsToCartList(List<Cart> cartList, Long itemId, Integer num) {
    
        //1.根据商品SKU ID查询SKU商品信息
        TbItem item = itemMapper.selectByPrimaryKey(itemId);
        if(item==null){
            throw new RuntimeException("商品不存在");
        }
        if(!item.getStatus().equals("1")){
            throw new RuntimeException("商品状态无效");
        }
        
        //2.获取商家ID      
        String sellerId = item.getSellerId();
        
        //3.根据商家ID判断购物车列表中是否存在该商家的购物车       
        Cart cart = searchCartBySellerId(cartList,sellerId);
        
        //4.如果购物车列表中不存在该商家的购物车
        if(cart==null){     
            
            //4.1 新建购物车对象 ,
            cart=new Cart();
            cart.setSellerId(sellerId);
            cart.setSellerName(item.getSeller());                       
            TbOrderItem orderItem = createOrderItem(item,num);
            List orderItemList=new ArrayList();
orderItemList.add(orderItem);
            cart.setOrderItemList(orderItemList);
            
            //4.2将购物车对象添加到购物车列表
            cartList.add(cart);
            
        }else{
            //5.如果购物车列表中存在该商家的购物车           
            // 判断购物车明细列表中是否存在该商品
            TbOrderItem orderItem = searchOrderItemByItemId(cart.getOrderItemList(),itemId);
                        
            if(orderItem==null){
                //5.1. 如果没有,新增购物车明细             
                orderItem=createOrderItem(item,num);
                cart.getOrderItemList().add(orderItem);
            }else{
                //5.2. 如果有,在原购物车明细上添加数量,更改金额
                orderItem.setNum(orderItem.getNum()+num);           
                orderItem.setTotalFee(new BigDecimal(orderItem.getNum()*orderItem.getPrice().doubleValue())  );
                //如果数量操作后小于等于0,则移除
                if(orderItem.getNum()<=0){
                    cart.getOrderItemList().remove(orderItem);//移除购物车明细 
                }
                //如果移除后cart的明细数量为0,则将cart移除
                if(cart.getOrderItemList().size()==0){
                    cartList.remove(cart);
                }
            }           
        }           
        return cartList;
    }
    
    
    /**
     * 根据商家ID查询购物车对象
     * @param cartList
     * @param sellerId
     * @return
     */
    private Cart searchCartBySellerId(List<Cart> cartList, String sellerId){
        for(Cart cart:cartList){
            if(cart.getSellerId().equals(sellerId)){
                return cart;
            }       
        }
        return null;
    }
    
    /**
     * 根据商品明细ID查询
     * @param orderItemList
     * @param itemId
     * @return
     */
    private TbOrderItem searchOrderItemByItemId(List<TbOrderItem> orderItemList ,Long itemId ){
        for(TbOrderItem orderItem :orderItemList){
            if(orderItem.getItemId().longValue()==itemId.longValue()){
                return orderItem;               
            }           
        }
        return null;
    }
    
    /**
     * 创建订单明细
     * @param item
     * @param num
     * @return
     */
    private TbOrderItem createOrderItem(TbItem item,Integer num){
        if(num<=0){
            throw new RuntimeException("数量非法");
        }
        
        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(new BigDecimal(item.getPrice().doubleValue()*num));
        return orderItem;
    }
}

2.4后端控制层

实现思路:
(1)从cookie中取出购物车
(2)向购物车添加商品
(3)将购物车存入cookie

新建CartController.java

@RestController
@RequestMapping("/cart")
public class CartController {

    @Reference
    private CartService cartService;
    
    @Autowired
    private  HttpServletRequest request;
    
    @Autowired
    private  HttpServletResponse response;
    
    
    /**
     * 购物车列表
     * @param request
     * @return
     */
    @RequestMapping("/findCartList")
    public List<Cart> findCartList(){
        String cartListString = util.CookieUtil.getCookieValue(request, "cartList","UTF-8");
        if(cartListString==null || cartListString.equals("")){
            cartListString="[]";
        }
        List<Cart> cartList_cookie = JSON.parseArray(cartListString, Cart.class);
        return cartList_cookie; 
    }
    
    /**
     * 添加商品到购物车
     * @param request
     * @param response
     * @param itemId
     * @param num
     * @return
     */
    @RequestMapping("/addGoodsToCartList")
    public Result addGoodsToCartList(Long itemId,Integer num){
        try {           
            List<Cart> cartList =findCartList();//获取购物车列表
            cartList = cartService.addGoodsToCartList(cartList, itemId, num);   
            util.CookieUtil.setCookie(request, response, "cartList", JSON.toJSONString(cartList),3600*24,"UTF-8");
            return new Result(true, "添加成功");
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, "添加失败");
        }
    }   
}

浏览器测试:

查看购物车:http://localhost:9105/cart/findCartList.do
添加商品到购物车 :
http://localhost:9105/cart/addGoodsToCartList.do?itemId=1369280&num=100

4.Redis存储购物车

4.1需求分析

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

4.2判断当前用户是否登陆

判断当前用户是否登陆,这可以借助于token从redis获取用户信息,如果能查询到用户信息证明当前用户已经登录

4.3远程购物车存取

4.3.1服务接口层

CartService.java定义方法

   /**
     * 从redis中查询购物车
     * @param username
     * @return
     */
    public List<Cart> findCartListFromRedis(String username);
    
    /**
     * 将购物车保存到redis
     * @param username
     * @param cartList
     */
    public void saveCartListToRedis(String username,List<Cart> cartList);

4.3.2服务实现层

CartServiceImpl.java实现方法

@Autowired
    private RedisTemplate redisTemplate;
    @Override
    public List<Cart> findCartListFromRedis(String username) {
        System.out.println("从redis中提取购物车数据....."+username);
        List<Cart> cartList = (List<Cart>) redisTemplate.boundHashOps("cartList").get(username);
        if(cartList==null){
            cartList=new ArrayList();
        }
        return cartList;
    }
    @Override
    public void saveCartListToRedis(String username, List<Cart> cartList) {
        System.out.println("向redis存入购物车数据....."+username);
        redisTemplate.boundHashOps("cartList").put(username, cartList);
    }

4.3.3控制层

修改CartController.java的findCartList方法

/**
 * 购物车列表
 * @param request
 * @return
 */
@RequestMapping("/findCartList")
public List<Cart> findCartList(){
    String userInfo = 根据token获取用户信息;
    if(userInfo){//如果未登录
        //读取本地购物车//
        ..........
        return cartList_cookie;
    }else{//如果已登录                   
        List<Cart> cartList_redis =cartService.findCartListFromRedis(username);//从redis中提取              
        return cartList_redis;
    }           
}

修改addGoodsToCartList方法

/**
 * 添加商品到购物车
 * @param request
 * @param response
 * @param itemId
 * @param num
 * @return
 */
@RequestMapping("/addGoodsToCartList")
public Result addGoodsToCartList(Long itemId,Integer num){
    String userInfo = 根据token获取用户信息;

    try {           
        List<Cart> cartList =findCartList();//获取购物车列表
        cartList = cartService.addGoodsToCartList(cartList, itemId, num);
        if(xxx){ //如果是未登录,保存到cookie
            CookieUtil.setCookie(request, response, "cartList", JSON.toJSONString(cartList),3600*24 ,"UTF-8");
            System.out.println("向cookie存入数据");
        }else{//如果是已登录,保存到redis
            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, "添加失败");
    }
}

4.4购物车合并

4.4.1服务接口层

CartService.java定义方法

/**
     * 合并购物车
     * @param cartList1
     * @param cartList2
     * @return
     */
    public List<Cart> mergeCartList(List<Cart> cartList1,List<Cart> cartList2);

4.4.2服务实现层

CartServiceImpl.java实现方法

public List<Cart> mergeCartList(List<Cart> cartList1, List<Cart> cartList2) {
        System.out.println("合并购物车");
        for(Cart cart: cartList2){
            for(TbOrderItem orderItem:cart.getOrderItemList()){
                cartList1= addGoodsToCartList(cartList1,orderItem.getItemId(),orderItem.getNum());      
            }           
        }       
        return cartList1;
    }

4.4.3控制层

CartController类的findCartList方法

@RequestMapping("/findCartList")
    public List<Cart> findCartList(){
        String username = SecurityContextHolder.getContext().getAuthentication().getName(); 
        String cartListString  = util.CookieUtil.getCookieValue(request, "cartList", "UTF-8");
        if(cartListString==null || cartListString.equals("")){
            cartListString="[]";
        }
        List<Cart> cartList_cookie = JSON.parseArray(cartListString, Cart.class);
        if(username.equals("anonymousUser")){//如果未登录            
            return cartList_cookie;         
        }else{
            List<Cart> cartList_redis =cartService.findCartListFromRedis(username);//从redis中提取  
            if(cartList_cookie.size()>0){//如果本地存在购物车
                //合并购物车
                cartList_redis=cartService.mergeCartList(cartList_redis, cartList_cookie);  
                //清除本地cookie的数据
                util.CookieUtil.deleteCookie(request, response, "cartList");
                //将合并后的数据存入redis 
                cartService.saveCartListToRedis(username, cartList_redis); 
            }           
            return cartList_redis;          
        }   
    }
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
6月前
|
搜索推荐 测试技术
对淘宝购物车进行测试用例设计
对淘宝购物车进行测试用例设计
292 0
|
5月前
|
人工智能 5G 区块链
创新产品的需求分析:未来的图书会是什么样子?
创新产品的需求分析:未来的图书会是什么样子?
|
12月前
|
存储 文件存储
4. 通讯录实现的需求分析和架构设计
4. 通讯录实现的需求分析和架构设计
155 0
|
6月前
|
安全
短剧系统开发详细指南/步骤流程/功能需求/案例源码
Short film system development refers to the system developed for the production and display of short films. A short drama usually refers to a film completed in a relatively short period of time, usually between a few minutes and half an hour, and is an independent form of film and television work. I
|
6月前
|
设计模式 监控 架构师
如何在项目中考虑非功能需求
软件非功能需求包括性能、可靠性、安全性、易用性、可维护性、可移植性、兼容性、可重用性、可扩展性和可观察性。质量属性分为开发期和运行期,如易理解性、可扩展性、可测试性等是开发期质量,性能、安全性、易用性等是运行期质量。评估方法有ATAM(架构评估技术)、ADMEMS矩阵方法、SAAM(软件架构分析法)和CBAM(成本效益分析法)。ATAM包括建立评估小组、获取架构信息、风险承担者观点和形成最终报告四个阶段。
260 0
|
6月前
|
前端开发 Java
springboot项目中外卖用户下单业务功能之需求分析+数据模型+功能开发(详细步骤)
springboot项目中外卖用户下单业务功能之需求分析+数据模型+功能开发(详细步骤)
91 0
交易所系统开发规则案例丨需求分析丨功能设计丨详细步骤丨源码逻辑
Before developing a digital currency exchange system, a detailed requirement analysis is required. Firstly, it is necessary to clarify the types of digital currencies and trading varieties that the system needs to support. Secondly, it is necessary to determine the user roles and permission manageme
|
存储 NoSQL Redis
82分布式电商项目 - 购物车需求分析
82分布式电商项目 - 购物车需求分析
61 1
|
存储 缓存 BI
一种经典的客户关系管理系统(CRM)订单模型的设计与实现
一种经典的客户关系管理系统(CRM)订单模型的设计与实现
|
存储 JSON NoSQL
购物车系统设计
在用户选购商品时,下单前,暂存用户想购买的商品。 购物车对数据可靠性要求不高,性能也无特别要求,在整个电商系统是相对容易设计和实现的一个子系统。
646 0