分布式高级篇(七) - 商城业务 - 购物车

1,296 阅读3分钟

购物车

环境搭建

  • 修改本地etc文件

    cart.mall.com
    

    image-20210202091824760

  • 拷贝静态资源到nginx

    image-20210202093854707

  • 将两个HTML页面,拷贝到购物车服务的templates文件夹下,并修改两个html文件中的静态资源引用路径

    image-20210202094315588

    image-20210202094445426

  • 配置网关路由

    image-20210202100620321

  • 页面效果

    image-20210202102813795

购物车需求

需求描述

  • 用户可以在登录状态下将商品添加到购物车【登录购物车 / 在线购物车】

    • 放入数据库 (购物车读写都是高并发,不适合使用 mysql)

    • MongoDB (并不能带来很高的性能提升)

    • 放入 Redis(采用)

      登录以后,会将临时购物车的数据全部合并到登录的购物车信息中,并清空临时购物车

  • 用户可以在未登录状态下将商品添加到购物车【游客购物车 / 离线购物车 / 临时购物车】

    • 放入 localstorage (客户端存储,后台不存,虽然后台压力减小,但是无法应用到大数据分析,进行精准分析、推荐)

    • cookie

    • WebSQL

    • 放入 Redis (采用)

      即使关闭浏览器,下次进入,临时购物车的数据都在

  • 用户可以使用购物车一起结算下单

  • 用户给购物车添加商品

  • 用户可以查询自己的购物车

  • 用户可以在购物车中修改购买商品的数量

  • 用户可以在购物车中删除商品

  • 选中 / 不选中商品

  • 在购物车中展示商品优惠信息

数据结构

  • 购物项

    image-20210202105052199

  • 每一个购物项信息,都对应一个对象,基本字段包括

    {
    	skuId:123321,  //商品id
    	check:true,    //是否被选中
    	title:"Apple iphone...",
    	defaultImage: "xxx",
    	price:5998.00
    	count:1,
    	totalPrice:13678.00
    	skuSaleVo:{}  //销售属性的值
    }
    

    另外购物车中不止一条数据,因此最终会是对象的数组,即:

    [
    	{
    	skuId:123321,  //商品id
    	check:true,    //是否被选中
    	title:"Apple iphone...",
    	defaultImage: "xxx",
    	price:5998.00
    	count:1,
    	totalPrice:13678.00
    	skuSaleVo:{}  //销售属性的值
    	},
    	{
    	skuId:111222,  //商品id
    	check:true,    //是否被选中
    	title:"Apple iphone...",
    	defaultImage: "xxx",
    	price:3398.00
    	count:10,
    	totalPrice:44678.00
    	skuSaleVo:{}  //销售属性的值
     }
    ]
    
  • Redis 有五种不同数据结构,这里选择哪一种比较合适呢?Map<String,List>>

    • 首先不同用户应该有独立的购物车,因此购物车应该以用户id作为 key 来存储,Value是用户的所有购物车信息。这样看来基本的 k-v 结构就可以了
    • 但是,我们对购物车中的商品进行增、删、改操作,基本都需要根据商品id进行判断,为了后期方便处理,我们购物车也应该是 k-v 结构,key是商品id,value 才是这个商品的购物车信息
    • 总上所述,我们购物车结构是一个双层 Map:Map<String,Map<String,CartItemInfo>>
      • 第一层 Map,key 是用户 id
      • 第二层 Map,key是购物车中商品 id,值是购物项数据

    image-20210202111245926

流程

编写购物车和购物项的VO

需要计算的属性,必须重写它的get方法,保证每次获取属性都会进行计算

image-20210202113359902

浏览器有一个cookie;user-key:标识用户身份,一个月后过期;
如果第一次使用jd的购物车功能,都会给一个临时的用户身份
浏览器保存,以后的每次访问都会带上
登录:session有
未登录:按照cookie里带来的user-key来做
第一次:如果没有临时用户,帮忙创建一个临时用户
  --> 创建一个拦截器
拦截器
在执行目标方法之前,判断用户的登录状态。并封装传递给controller目标请求

添加配置让拦截器生效

image-20210202143646638

ThreadLocal:同一个线程共享数据(*)

核心原理:是一个Map,以线程为key,同一个线程可以取到相同的数据,不同线程无法共享

image-20210202140832369

效果演示

  • 未登录 -- 临时用户
    • 查看购物车
    • 加入购物车
    • redis 中key为 user-key
  • 已经登录 -- 登录用户
    • 会将临时用户购物车合并进用户购物车
    • 购物项增减、勾选、删除