商城业务:购物车

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 商城业务:购物车

人生在世如身处荆棘之中,心不动,人不妄动,不动则不伤;如心动则人妄动,伤其身痛其骨,于是体会到世间诸般痛苦。

1、购物车需求

1)、需求描述:

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

- 放入数据库

- mongodb

- 放入 redis(采用)

登录以后,会将临时购物车的数据全部合并过来,并清空临时购物车;

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

- 放入 localstorage(客户端存储,后台不存)

- cookie - WebSQL

- 放入 redis(采用)

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

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

- 给购物车添加商品

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

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

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

- 选中不选中商品

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

- 提示购物车商品价格变化

2)、数据结构

因此每一个购物项信息,都是一个对象,基本字段包括:

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

Redis 有 5 种不同数据结构,这里选择哪一种比较合适呢?

- 首先不同用户应该有独立的购物车,因此购物车应该以用户的作为 key 来存储,Value 是 用户的所有购物车信息。这样看来基本的`k-v`结构就可以了。

- 但是,我们对购物车中的商品进行增、删、改操作,基本都需要根据商品 id 进行判断, 为了方便后期处理,我们的购物车也应该是`k-v`结构,key 是商品 id,value 才是这个商品的 购物车信息。

综上所述,我们的购物车结构是一个双层 Map:Ma<string,map<string,string>>

- 第一层 Map,Key 是用户 id

- 第二层 Map,Key 是购物车中商品 id,值是购物项数据

3)、流程

参照京东

user-key 是随机生成的 id,不管有没有登录都会有这个 cookie 信息。

两个功能:新增商品到购物车、查询购物车。

新增商品:判断是否登录

- 是:则添加商品到后台 Redis 中,把 user 的唯一标识符作为 key。

- 否:则添加商品到后台 redis 中,使用随机生成的 user-key 作为 key。

查询购物车列表:判断是否登录

- 否:直接根据 user-key 查询 redis 中数据并展示

- 是:已登录,则需要先根据 user-key 查询 redis 是否有数据。

- 有:需要提交到后台添加到 redis,合并数据,而后查询。

- 否:直接去后台查询 redis,而后返回。

2、临时购物车

1. /**
2.      * 获取到我们要操作的购物车
3.      * @return
4.      */
5. private BoundHashOperations<String, Object, Object> getCartOps() {
6. UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
7. //1.
8. String cartKey = "";
9. if (userInfoTo.getUserId() != null) {
10.             cartKey = CART_PREFIX + userInfoTo.getUserId();
11.         } else {
12.             cartKey = CART_PREFIX + userInfoTo.getUserKey();
13.         }
14.         BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
15. return operations;
16.     }

3、登录购物车

1. @Override
2. public CartItem addToCart(Long skuId, Integer num) {
3. 
4.         BoundHashOperations<String, Object, Object> cartOps = getCartOps();
5. String res = (String) cartOps.get(skuId.toString());
6. if(StringUtils.isEmpty(res)){
7. CartItem cartItem = new CartItem();
8. // 1.运程查询当前要添加的商品信息
9.             CompletableFuture<Void> getSkuInfoTask = CompletableFuture.runAsync(() -> {
10. //2.商品添加到购物车(新商品)
11. R skuInfo = productFeignService.getSkuInfo(skuId);
12. SkuInfoVo data = skuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {
13.                 });
14. 
15.                 cartItem.setCheck(true);
16.                 cartItem.setCount(1);
17.                 cartItem.setImage(data.getSkuDefaultImg());
18.                 cartItem.setTitle(data.getSkuTitle());
19.                 cartItem.setPrice(data.getPrice());
20.                 cartItem.setSkuId(data.getSkuId());
21.             },executor);
22. 
23.             CompletableFuture<Void> getSkuSaleAttr = CompletableFuture.runAsync(() -> {
24. //运程查询sku的组合信息
25.                 List<String> values = productFeignService.getSkuSaleAttrValues(skuId);
26.                 cartItem.setSkuAttr(values);
27.             }, executor);
28. 
29.             CompletableFuture<Void> allOf = CompletableFuture.allOf(getSkuInfoTask, getSkuSaleAttr);
30. try {
31.                 allOf.get();
32.             } catch (InterruptedException e) {
33.                 e.printStackTrace();
34.             } catch (ExecutionException e) {
35.                 e.printStackTrace();
36.             }
37. String s = JSON.toJSONString(cartItem);
38. 
39.             cartOps.put(skuId.toString(),s);
40. return cartItem;
41.         }
42. else
43.         {
44. //购物车有这个商品
45. CartItem cartItem = JSON.parseObject(res, CartItem.class);
46.             cartItem.setCount(cartItem.getCount()+num);
47.             cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));
48. 
49. return cartItem;
50. 
51.         }
52. 
53. 
54.     }
55. 
56. @Override
57. public CartItem getCartItem(Long skuId) {
58.         BoundHashOperations<String, Object, Object> cartOps = getCartOps();
59. String str = (String) cartOps.get(skuId.toString());
60. CartItem cartItem = JSON.parseObject(str, CartItem.class);
61. return  cartItem;
62.     }

 

1. @Override
2. public Cart getCart() {
3. UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
4. Cart cart = new Cart();
5. if(userInfoTo.getUserId()!=null){
6. //登录
7. String cartKey = CART_PREFIX+userInfoTo.getUserId();
8. //如果临时购物车的数据还没有合并【合并购物车】
9.            String tempCartKey= CART_PREFIX + userInfoTo.getUserKey();
10.             List<CartItem> tempCartItems = getCartItems(tempCartKey);
11. if(tempCartItems!=null){
12. //合并
13. for (CartItem item : tempCartItems) {
14.                     addToCart(item.getSkuId(),item.getCount());
15.                 }
16.             }
17. //3.获取登录后的数据
18.             List<CartItem> cartItems = getCartItems(cartKey);
19.             cart.setItems(cartItems);
20. //清除临时购物车数据
21.             clearCart(tempCartKey);
22. 
23.         }else {
24. //没登陆
25. String cartKey = CART_PREFIX+userInfoTo.getUserKey();
26. //获取临时购物车的所有购物项
27.             List<CartItem> cartItems = getCartItems(cartKey);
28.             cart.setItems(cartItems);
29. 
30. 
31.         }
32. return cart;
33.     }
1. 
2. @Override
3. public void checkItem(Long skuId, Integer check) {
4.         BoundHashOperations<String, Object, Object> cartOps = getCartOps();
5. 
6. CartItem cartItem = getCartItem(skuId);
7.         cartItem.setCheck(check==1?true:false);
8. String s = JSON.toJSONString(cartItem);
9.         cartOps.put(skuId.toString(),s);
10. 
11.     }
12. 
13. @Override
14. public void changeItemCount(Long skuId, Integer num) {
15.         BoundHashOperations<String, Object, Object> cartOps = getCartOps();
16. CartItem cartItem = getCartItem(skuId);
17.         cartItem.setCount(num);
18. String s = JSON.toJSONString(cartItem);
19.         cartOps.put(skuId.toString(),s);
20. 
21.     }
22. 
23. @Override
24. public void deleteItem(Long skuId) {
25.         BoundHashOperations<String, Object, Object> cartOps = getCartOps();
26.         cartOps.delete(skuId.toString());
27.     }

人生在世如身处荆棘之中,心不动,人不妄动,不动则不伤;如心动则人妄动,伤其身痛其骨,于是体会到世间诸般痛苦。


相关实践学习
基于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
相关文章
|
3月前
|
存储 SQL NoSQL
商城业务---购物车
这篇文章讨论了商城业务中购物车功能的实现,包括用户登录状态下和未登录状态下购物车的处理方式。文章详细描述了购物车的基本需求、流程分析、判断用户登录状态的拦截器实现、临时购物车和登录购物车的数据操作,以及添加商品到购物车的过程。此外,还提到了可能遇到的问题和解决方案,以及在Redis中存储商品信息的不同数据结构选择。最后,文章展示了未登录和登录状态下购物车的使用效果和Redis中数据的存储情况。
商城业务---购物车
|
3月前
|
缓存 监控 算法
京东购物车如何提升30%性能
【8月更文挑战第27天】以下是一些提升京东购物车性能的方法:1. 减少网络请求次数,采用异步请求;2. 使用本地和服务器端缓存;3. 优化购物车算法,如商品归堆和实时计算;4. 前端优化,如图片压缩和延迟加载;5. 后端架构优化,包括数据库和服务器资源优化;6. 建立性能监控系统并持续优化。这些措施可显著提升用户体验。
|
6月前
|
API 开发者
淘宝店铺订单接口丨淘宝店铺订单交易接口技术文档
淘宝店铺订单接口丨淘宝店铺订单交易接口技术文档
|
6月前
|
JavaScript
基础购物车
基础购物车
38 1
|
SQL JSON 前端开发
加入购物车【项目 商城】
加入购物车【项目 商城】
49 0
|
SQL 前端开发
创建订单【项目 商城】
创建订单【项目 商城】
57 0
美多商城商品部分(三)
美多商城商品部分(三)
|
小程序 UED
拼团/秒杀商城模式小程序/APP开发
拼团秒杀商城模式小程序的开发为用户提供了一个热门商品的抢购平台,增加了购物的乐趣和互动性。本文将重点介绍拼团秒杀商城模式小程序的功能特点和开发优势,展示其在打造热门商品的抢购平台方面的独特魅力。
|
前端开发 JavaScript
商城业务:商品详情
商城业务:商品详情
|
存储 移动开发 缓存
电商开发系列 - 购物车如何设计?
购物车,是购物平台(网上商城)必备的功能,像京东、淘宝、当当都有这样的功能,那购物车是怎么实现的,做过商城的小伙伴应该知道,未做过商城的小伙伴可能就不知道,为了让初入商城开发的小伙伴了解这块怎么做,从程序开发的角度来讨论一下这个场景
355 0