购物车
环境搭建
-
修改本地etc文件
cart.mall.com -
拷贝静态资源到nginx
-
将两个HTML页面,拷贝到购物车服务的templates文件夹下,并修改两个html文件中的静态资源引用路径
-
配置网关路由
-
页面效果
购物车需求
需求描述
-
用户可以在登录状态下将商品添加到购物车【登录购物车 / 在线购物车】
-
放入数据库 (购物车读写都是高并发,不适合使用 mysql)
-
MongoDB (并不能带来很高的性能提升)
-
放入 Redis(采用)
登录以后,会将临时购物车的数据全部合并到登录的购物车信息中,并清空临时购物车
-
-
用户可以在未登录状态下将商品添加到购物车【游客购物车 / 离线购物车 / 临时购物车】
-
放入 localstorage (客户端存储,后台不存,虽然后台压力减小,但是无法应用到大数据分析,进行精准分析、推荐)
-
cookie
-
WebSQL
-
放入 Redis (采用)
即使关闭浏览器,下次进入,临时购物车的数据都在
-
-
用户可以使用购物车一起结算下单
-
用户给购物车添加商品
-
用户可以查询自己的购物车
-
用户可以在购物车中修改购买商品的数量
-
用户可以在购物车中删除商品
-
选中 / 不选中商品
-
在购物车中展示商品优惠信息
数据结构
-
购物项
-
每一个购物项信息,都对应一个对象,基本字段包括
{ 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,值是购物项数据
流程
编写购物车和购物项的VO
需要计算的属性,必须重写它的get方法,保证每次获取属性都会进行计算
浏览器有一个cookie;user-key:标识用户身份,一个月后过期;
如果第一次使用jd的购物车功能,都会给一个临时的用户身份
浏览器保存,以后的每次访问都会带上
登录:session有
未登录:按照cookie里带来的user-key来做
第一次:如果没有临时用户,帮忙创建一个临时用户
--> 创建一个拦截器
拦截器
在执行目标方法之前,判断用户的登录状态。并封装传递给controller目标请求
添加配置让拦截器生效
ThreadLocal:同一个线程共享数据(*)
核心原理:是一个Map,以线程为key,同一个线程可以取到相同的数据,不同线程无法共享
效果演示
- 未登录 -- 临时用户
- 查看购物车
- 加入购物车
- redis 中key为 user-key
- 已经登录 -- 登录用户
- 会将临时用户购物车合并进用户购物车
- 购物项增减、勾选、删除