商城业务:购物车
人生在世如身处荆棘之中,心不动,人不妄动,不动则不伤;如心动则人妄动,伤其身痛其骨,于是体会到世间诸般痛苦。
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、临时购物车
/*** 获取到我们要操作的购物车* @return*/private BoundHashOperations<String, Object, Object> getCartOps() {UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();//1.String cartKey = "";if (userInfoTo.getUserId() != null) {cartKey = CART_PREFIX + userInfoTo.getUserId();} else {cartKey = CART_PREFIX + userInfoTo.getUserKey();}BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);return operations;}
3、登录购物车
@Overridepublic CartItem addToCart(Long skuId, Integer num) {BoundHashOperations<String, Object, Object> cartOps = getCartOps();String res = (String) cartOps.get(skuId.toString());if(StringUtils.isEmpty(res)){CartItem cartItem = new CartItem();// 1.运程查询当前要添加的商品信息CompletableFuture<Void> getSkuInfoTask = CompletableFuture.runAsync(() -> {//2.商品添加到购物车(新商品)R skuInfo = productFeignService.getSkuInfo(skuId);SkuInfoVo data = skuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {});cartItem.setCheck(true);cartItem.setCount(1);cartItem.setImage(data.getSkuDefaultImg());cartItem.setTitle(data.getSkuTitle());cartItem.setPrice(data.getPrice());cartItem.setSkuId(data.getSkuId());},executor);CompletableFuture<Void> getSkuSaleAttr = CompletableFuture.runAsync(() -> {//运程查询sku的组合信息List<String> values = productFeignService.getSkuSaleAttrValues(skuId);cartItem.setSkuAttr(values);}, executor);CompletableFuture<Void> allOf = CompletableFuture.allOf(getSkuInfoTask, getSkuSaleAttr);try {allOf.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}String s = JSON.toJSONString(cartItem);cartOps.put(skuId.toString(),s);return cartItem;}else{//购物车有这个商品CartItem cartItem = JSON.parseObject(res, CartItem.class);cartItem.setCount(cartItem.getCount()+num);cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));return cartItem;}}@Overridepublic CartItem getCartItem(Long skuId) {BoundHashOperations<String, Object, Object> cartOps = getCartOps();String str = (String) cartOps.get(skuId.toString());CartItem cartItem = JSON.parseObject(str, CartItem.class);return cartItem;}
@Overridepublic Cart getCart() {UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();Cart cart = new Cart();if(userInfoTo.getUserId()!=null){//登录String cartKey = CART_PREFIX+userInfoTo.getUserId();//如果临时购物车的数据还没有合并【合并购物车】String tempCartKey= CART_PREFIX + userInfoTo.getUserKey();List<CartItem> tempCartItems = getCartItems(tempCartKey);if(tempCartItems!=null){//合并for (CartItem item : tempCartItems) {addToCart(item.getSkuId(),item.getCount());}}//3.获取登录后的数据List<CartItem> cartItems = getCartItems(cartKey);cart.setItems(cartItems);//清除临时购物车数据clearCart(tempCartKey);}else {//没登陆String cartKey = CART_PREFIX+userInfoTo.getUserKey();//获取临时购物车的所有购物项List<CartItem> cartItems = getCartItems(cartKey);cart.setItems(cartItems);}return cart;}
@Overridepublic void checkItem(Long skuId, Integer check) {BoundHashOperations<String, Object, Object> cartOps = getCartOps();CartItem cartItem = getCartItem(skuId);cartItem.setCheck(check==1?true:false);String s = JSON.toJSONString(cartItem);cartOps.put(skuId.toString(),s);}@Overridepublic void changeItemCount(Long skuId, Integer num) {BoundHashOperations<String, Object, Object> cartOps = getCartOps();CartItem cartItem = getCartItem(skuId);cartItem.setCount(num);String s = JSON.toJSONString(cartItem);cartOps.put(skuId.toString(),s);}@Overridepublic void deleteItem(Long skuId) {BoundHashOperations<String, Object, Object> cartOps = getCartOps();cartOps.delete(skuId.toString());}
人生在世如身处荆棘之中,心不动,人不妄动,不动则不伤;如心动则人妄动,伤其身痛其骨,于是体会到世间诸般痛苦。
相关文章:

商城业务:购物车
人生在世如身处荆棘之中,心不动,人不妄动,不动则不伤;如心动则人妄动,伤其身痛其骨,于是体会到世间诸般痛苦。 1、购物车需求 1)、需求描述: - 用户可以在登录状态下将商品添加到购…...

计算机网络学习笔记(一)
网络是由若干接点和连接这些结点的链路组成。 多个网络通过路由器互联起来构成覆盖范围更大的互联网。 普通用户通过ISP接入因特网。 基于ISP的三层结构因特网 相隔较远的两台主机间通信可能需要经过多个ISP。 有电路交换,报文交换,分组交换三种交换方…...

【单目标优化算法】烟花优化算法(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

微服务项目【秒杀商品展示及商品秒杀】
登录方式调整 第1步:从zmall-common的pom.xml中移除spring-session-data-redis依赖 注意: 1)本次不采用spring-session方式,改用redis直接存储用户登录信息,主要是为了方便之后的jmeter压测; 2)…...

DIDL3_模型选择、复杂度、过欠拟合的相关概念
模型选择、复杂度、过欠拟合的概念模型选择训练误差和泛化误差验证数据集和测试数据集K-则交叉验证(没有足够多数据时使用)过拟合和欠拟合模型容量模型容量的影响估计模型容量控制模型容量数据复杂度处理过拟合的方法(1)ÿ…...
Android 9.0 去除锁屏界面及SystemUI无sim卡拨打紧急电话控件显示功能实现
1.1概述 在9.0的系统rom定制化开发中,关于SystemUI的定制化功能也是比较多的,在SystemUI的锁屏页面和状态栏提示无sim卡拨打紧急电话控件显示等相关提示 的功能中,在有些systemui的定制中是不需要这些功能的,所以需要从systemui中去掉这些功能提示的,这就需要从systemui中…...

AntDB-M设计之内存结构
亚信科技专注通信行业多年,AntDB数据库从诞生开始,就面对通信级的大数据量应用场景挑战,在性能、稳定性、规模化等方面获得了超过10年的通信核心业务系统验证,性能峰值达到每秒百万的通信核心交易量。AntDB-M(AntDB内存…...

互联网舆情监测公司监测哪些内容,TOOM北京舆情监测公司
互联网舆情监测公司是一种提供舆情监测、分析和管理服务的公司,其业务主要涉及互联网舆情监测、数据分析、报告撰写、危机处理等方面。这些公司通过使用各种技术和工具,帮助客户监测他们在互联网上的声誉和品牌形象,并提供相应的建议和解决方…...

一篇文章带你熟练使用Ansible中的playbook
目录 一、Playbook的功能 二、YAML 1、简介 2、特点 3、语法简介 4、YAML 列表 5、YAML的字典 三、playbook执行命令 四、 Playbook的核心组件 五、vim 设定技巧 练习 一、Playbook的功能 playbook 是由一个或多个play组成的列表 Playboot 文件使用YAML来写的 二、…...

HashedWheelTimer
序言这种算法是一种轮询算法的优化升级,能够以只有一个Timer的情况下处理大量的定时任务.Begin结合HashedWheelTimer的思想根据自然时间1分钟为例,来做大批量的定时任务触发首先定一个长度为60的数组,数组中存放的是Set集合,集合里面是任务详情.当有定时任务刚来的时候判断是否…...

OPenCV库移植到ARM开发板子上面配置过程
步骤一 1,环境准备去下载opencv官方的源码。 我这里用的是opencv-4.5.5版本的 2,还需要交叉编译工具一般,你交叉编译的工具板子厂家会提供工具,最好还是用板子厂家提供的交叉编译工具,因为我之前编译试过其他的交叉…...
Jenkins实现CI/CD
Jenkins是一个开源的持续集成和持续交付(CI/CD)解决方案,它可以自动执行构建、测试和部署等任务,从而简化了开发工作流程。本文将详细介绍如何使用Jenkins实现CI/CD。 首先,您需要安装Jenkins并启动它。您可以通过以下…...
如何给img标签里的请求添加自定义header
是这样的需求,有一个web页面,里面图片的上传和预览来自于一个独立的文件服务器,对http的请求需要进行访问权限的设置,就是在请求的header里加一个Authorization的字段。上传好说我用的Axios直接添加一个header就行了,但…...
Linux系统基本概念操作,用户和文件权限管理
常用快捷键和通配符常用快捷键按键作用Ctrld键盘输入结束或退出终端Ctrls暂停当前程序,暂停后按下任意键恢复运行Ctrlz将当前程序放到后台运行,恢复到前台为命令fgCtrla将光标移至输入行头,相当于Home键Ctrle将光标移至输入行末,相…...
数据库中的单表查询和多表查询
一、单表查询素材: 表名:worker-- 表中字段均为中文,比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker (部门号 int(11) NOT NULL,职工号 int(11) NOT NULL,工作时间 date NOT NULL,工资 float(8,2) NOT NULL,政治面貌 varchar(10) …...

全网详解MyBatis-Plus LambdaQueryWrapper的使用说明以及LambdaQueryWrapper和QueryWapper的区别
文章目录1. 文章引言2. 代码演示3. 分析LambdaQueryWrapper3.1 引入LambdaQueryWrapper的原因3.2 LambdaQueryWrapper和QueryWapper的区别4. 重要总结1. 文章引言 今天在公司写代码时,发现同事使用LambdaQueryWrapper来查询数据,而我一直习惯使用QueryW…...

暴力破解(new)
数据来源 本文仅用于信息安全的学习,请遵守相关法律法规,严禁用于非法途径。若观众因此作出任何危害网络安全的行为,后果自负,与本人无关。 01 暴力破解介绍及应用场景 》暴力破解介绍 》暴力破解字典 GitHub - k8gege/Passwor…...

Android12之apex调试
1.问题在调试libtinyalsa.so中添加log后,但是发现push so后,却没有log打印,why?2.分析以下为libtinyalsa.so的位置/system/lib64/libtinyalsa.so /system/lib/libtinyalsa.so /apex/com.android.vndk.v31/lib64/libtinyalsa.so /a…...
Python - 数字(Number)数据类型常用操作
目录数字运算类型转换数学函数数学库math、cmathmath 模块常量math 模块方法随机函数库 randomrandom 模块方法保留小数到指定位数三角函数数字运算 :用于给变量赋值type(x):查看数据所属类型isinstance(x, A_tuple):判断数据是否为预期类型…...

QT(51)-动态链接库-windows
1.qt- 调用win32 DLL 2.qt- 调用MFC DLL 0概述: 01.扩展DLL: 必须有一个DllMain()函数,且调用AfxInitExtensionModule()函数。 CRuntimeClass类-初始化函数CDynLinkLibrary。02.windows定位DLL文件: 1)…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...

Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...
TCP/IP 网络编程 | 服务端 客户端的封装
设计模式 文章目录 设计模式一、socket.h 接口(interface)二、socket.cpp 实现(implementation)三、server.cpp 使用封装(main 函数)四、client.cpp 使用封装(main 函数)五、退出方法…...