尚品汇总结七:商品详情模块(面试专用)

news2024/10/7 8:24:50

一、业务介绍

     订单业务在整个电商平台中处于核心位置,也是比较复杂的一块业务。是把“物”变为“钱”的一个中转站。

      整个订单模块一共分四部分组成:

  1. 结算页面

在购物车列表页面中,有一个结算的按钮,用户一点击这个按钮时,跳转到结算页,结算页展示了用户在购物车中选中的商品数据(商品清单),还要展示用户所有的收货人信息,让用户选择。

为了防止 用户提交订单之后 使用浏览器的回退功能,不刷新的情况下,重复的提交订单,在结算页生成的时候,咱们在结算页中放了个流水号(订单号)。

这个流水号 是后台采用 UUID生成的,把流水号存redis一份,结算页存一份。

  1. 下单

用户在结算页点击 提交订单按钮,开始进行下单(订单信息保存),

  1. 要去校验流水号,把结算页的流水号和redis中的流水号比较,如果相同可以下单,如果不同不能下单。
  2. 校验库存,调用库存接口,进行库存量的查询,如果没货了,给提示,库存不足。
  3. 校验商品价格,防止下单这会 商品的价格有变化。调用商品服务查询商品的最新价格,和之前的价格比较。
  4. 向订单表和订单明细表中 添加数据。
  5. 删除redis中的流水号,这样只有下过一次单了,redis的流水号就没了,即使用户通过浏览器回退到结算,结算页还有流水号,但是redis中的没了,比较就不通过。
  6. 保存订单之后,使用rabbitMQ发送一个延时消息,进行过期订单的关闭工作。
  1. 对接支付服务

下单成功,给用户跳转到支付页面,让用户选择支付方式,进行支付。

当支付成功之后,支付服务使用RabbitMQ通知订单服务,订单要修改订单的状态,从未支付改为  已支付。

  1. 对接库存管理系统

下单的时候 要校验库存,支付成功后,订单服务使用rabbitMQ通知库存服务,要通知库存去打包,当库存锁定库存 扣减库存,扣减成功之后,库存服务使用rabbitMQ通知订单服务,订单要修改状态,从已支付改为待发货。后续 当库存打包完成,发货了,订单还要修改状态,从待发货改为 已发货,给用户展示物流信息。

二、结算页

 入口:购物车点击计算按钮

 分析

   分析页面需要的数据:

  1. 得到用户信息
  2. 购物车中选择的商品列表
  3. 收货人信息

 

三、下单

1、数据结构

orderInfo :订单表

orderDetail :订单明细

id

主键。自动生成

consignee

收货人名称。页面获取

consignee_tel

收货人电话。页面获取

deliveryAddress

收货地址。页面获取

total_amount

总金额。计算

order_status

订单状态,用于显示给用户查看。设定初始值。

userId

用户Id。从拦截器已放到请求属性中。

payment_way

支付方式(网上支付、货到付款)。页面获取

orderComment

订单状态。页面获取

out_trade_no

第三方支付编号。按规则生成

create_time

创建时间。设当前时间             

expire_time

默认当前时间+1天

process_status

订单进度状态,程序控制、 后台管理查看。设定初始值,

tracking_no

物流编号,初始为空,发货后补充

parent_order_id

拆单时产生,默认为空

id

主键,自动生成

order_id

订单编号,主表保存后给从表

sku_id

商品id 页面传递

sku_name

商品名称,后台添加

img_url

图片路径,后台添加

order_price

商品单价,从页面中获取,并验价。

sku_num

商品个数,从页面中获取

2、分析下单:

  1. 保存单据前要做校验:验库存、验证价格。
  2. 保存单据: orderInfo orderDetail。
  3. 保存以后把购物车中的商品删除。
  4. 重定向到支付页面。

3、如何解决用户利用浏览器刷新和回退重复提交订单?

在进入结算页面是我们生产了一个流水号,然后保存到结算页面的隐藏元素中一份,Redis中存一份,每次用户提交订单时都检查reids中流水号与页面提交的是否相符,如果相等可以提交,当订单保存以后把后台的流水号删除掉。那么第二次用户用同一个页面提交的话流水号就会匹配失败,无法重复保存订单。

3.1 修改结算页增加流水号的生成

实现类

@Override

  public String getTradeNo(String userId) {

    // 定义key

    String tradeNoKey = "user:" + userId + ":tradeCode";

    // 定义一个流水号

    String tradeNo = UUID.randomUUID().toString().replace("-", "");

    redisTemplate.opsForValue().set(tradeNoKey, tradeNo);

    return tradeNo;

}

  

  @Override

  public boolean checkTradeCode(String userId, String tradeCodeNo) {

    // 定义key

    String tradeNoKey = "user:" + userId + ":tradeCode";

    String redisTradeNo = (String) redisTemplate.opsForValue().get(tradeNoKey);

    return tradeCodeNo.equals(redisTradeNo);

}

  //删除流水号

  @Override

  public void deleteTradeNo(String userId) {

    // 定义key

    String tradeNoKey = "user:" + userId + ":tradeCode";

    // 删除数据

    redisTemplate.delete(tradeNoKey);

}

3.2 OrderController中的submitOrder方法中

/**
 *
提交订单
 * @param
orderInfo
 
* @param request
 
* @return
 
*/

@PostMapping("auth/submitOrder")
public Result submitOrder(@RequestBody OrderInfo orderInfo, HttpServletRequest request) {
   
// 获取到用户Id
   
String userId = AuthContextHolder.getUserId(request);
    orderInfo.setUserId(Long.parseLong(userId));
   
// 获取前台页面的流水号
   
String tradeNo = request.getParameter("tradeNo");
   
// 调用服务层的比较方法
    
boolean flag = orderService.checkTradeCode(userId, tradeNo);
   
if (!flag) {
       
// 比较失败!
       
return Result.fail().message("不能重复提交订单!");
    }
   
//  删除流水号
   
orderService.deleteTradeNo(userId);
   
// 验证库存:
   
List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
   
for (OrderDetail orderDetail : orderDetailList) {
       
// 验证库存:
       
boolean result = orderService.checkStock(orderDetail.getSkuId(), orderDetail.getSkuNum());
       
if (!result) {
           
return Result.fail().message(orderDetail.getSkuName() + "库存不足!");
        }
       
// 验证价格:
       
BigDecimal skuPrice = productFeignClient.getSkuPrice(orderDetail.getSkuId());
       
if (orderDetail.getOrderPrice().compareTo(skuPrice) != 0) {
           
// 重新查询价格!
           
cartFeignClient.loadCartCache(userId);
           
return Result.fail().message(orderDetail.getSkuName() + "价格有变动!");
        }
    }
   
// 验证通过,保存订单!
   
Long orderId = orderService.saveOrderInfo(orderInfo);
   
return Result.ok(orderId);
}

4、验库存

通过restful接口查询商品是否有库存

    一般电商系统的商品库存,都不由电商系统本身来管理,由另外一套仓库管理系统,或者进销存系统来管理,电商系统通过第三方接口调用该系统。

    由于库管系统可能是异构的系统,所以不在微服务体系之内。只支持restful风格的webservice调用和消息队列的调用。

详见《库存管理系统手册》

根据手册中的接口文档,编写调用代码。

查询库存接口

四、业务流程和话术

1、订单业务流程图

    

 

2、业务话术(自己总结)

     当用户点击结算的时候,这块我们用网关全局过滤器先判断用户是否登录,如果用户没有登录,则跳转到登陆页面,让用户去登录,登录成功之后,跳转到订单结算页面(这块在跳转到登录页面的时候,把之前的请求地址保存下来,作为参数进行跳转,在登录成功之后,查看是否有请求参数,如果有就跳转到对应的url,如果值为null,跳转到首页);如果用户登录了,则跳转到订单结算页面;

当跳转到订单结算页面的时候,首先对收货人地址进行管理,其次选择支付方式,一期的时候只提供了支付宝支付(微信、支付宝),确认订单信息,然后提交数据到后台,生成对应的订单表、订单详情表和订单物流表(当订单生成的时候,我们要调用对应的库存系统针对订单的商品数量进行验库存,还要进行验价格)。当订单创建成功之后,自动跳转到成功页面(将订单数据和到期时间传递过去)。

这块我们设置的订单的有效时间为24小时(这个时间可以自己定,只要合理就行),因为我们利用延时队列实现定时消息发送,消费者到时间后监听到消息,进行订单校验,如果订单是未支付状态,把订单状态修改为关闭订单。

3、常见面试问题:

  1. 订单表结构(存了什么信息)?

谁负责订单的开发,谁创建订单表。

订单表:

     人+流程+金额+时间

 收货人信息(收货人电话、地址、名称)、用户的id、总金额、订单状态、订单交易编号(全局唯一不重复,采用字符串+时间戳+随机数)、物流单编号、创建时间、失效时间。

订单明细表:

  商品有关的数据

Sku的id,数量、购买的价格、默认图片

  1. 订单业务流程是什么样的?(订单你是怎么做的?)

看上面的文字描述,把文字描述 变成你的话 面试的时候 说出来了。

  1. 订单有效期是多久,怎么取消订单?

有效期 只要合理就行   30分钟、45分、2小时  24小时

 10秒钟,365一天  这种的就是不合理了。

咱们使用的是 rabbitMQ的延时消息。下订单时候 发送 了一个消息,这个消息时间不到不能被消费,只有时间到了,消费者才能去消费这个消息,进行订单的关闭,关闭之前需要判断 订单是否支付,只有没支付的订单才能关闭。

  1. 怎么防止订单重复提交?
  1. 用户通过浏览器回退功能,回退到结算页,并且没有刷新页面的情况下,再次提交订单。 解决是通过 生成结算的时候  生成流水号,这个流水号存redis一份,在结算页也存了一份,当提交订单的时候,结算页中的流水号会传给提交订单接口,拿到页面传过的流水号和redis的流水号比较,相同,可以提交订单,不同不能提交订单。当订单提交完成后,删除redis的流水号,redis流水号没了,再回退提交,比较流水号就会不通过。
  2. 用户通过浏览器回退功能,回退到结算页,刷新页面了,重新请求了一次结算页,结算页会重新查询购物车中选中的商品数据。当用户下单成功后,可以去删除购物车中所有选中的商品。
  1. 订单超卖问题怎么解决的?

这个商品在库存中就一个了,有多个人同时下单,这种问题 你们怎么解决的?

咱们做的:

   这个问题没解决,都可以下单成功。

  为了多卖货,减少库存积压,增加流动资金

用户都可以下单成功 也都可以付钱成功,没货了,再去进。

拼多多:2天内发货。

下单的时候  就去做库存扣减,防止超卖:

  1. 防止并发的情况 库存扣减变成负数。

加锁了

 使用分布式锁。

数据库层面的锁。

悲观锁:

 Select 库存量 from 库存表 where skuid=? for update;

Update 更新 去减库存。

事务的提交或者回滚的时候 锁释放。

乐观锁

表中加一个version字段

Select 库存量,version from 库存表 where skuid =?

  Update 库存表 set (库存量-1,version+1) where skuid =? And version=之前查出的值。

  1. 订单状态都有什么

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/842283.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单细胞测序基础知识

构建文库 上机测序 根据不同的荧光检测不同的碱基 质量控制&#xff08;质控QC&#xff09; 去除低质量的序列 表达定量 统计reads数&#xff0c;进而得到表达矩阵 标准化 让所有样本处在同一起跑线上 主成分分析PCA 图中每个点都代表一个样本&#xff0c;不同颜色…

【Linux】网络套接字知识点补足

目录 1 地址转换函数 1.1 字符串转in_addr的函数: 1.2 in_addr转字符串的函数: 1.3 关于inet_ntoa 2 TCP协议通讯流程 1 地址转换函数 本节只介绍基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP 地址但是我们通常用点分十进制的字符串…

[BabysqliV3.0]phar反序列化

文章目录 [BabysqliV3.0]phar反序列化 [BabysqliV3.0]phar反序列化 开始以为是sql注入 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ST1jvadM-1691302941344)(https://raw.githubusercontent.com/leekosss/photoBed/master/202308032140269.png)…

CentOS 7中,配置了Oracle jdk,但是使用java -version验证时,出现的版本是OpenJDK,如何解决?

1.首先&#xff0c;检查已安装的jdk版本 sudo yum list installed | grep java2.移除、卸载圈红的系统自带的openjdk sudo yum remove java-1.7.0-openjdk.x86_64 sudo yum remove java-1.7.0-openjdk-headless.x86_64 sudo yum remove java-1.8.0-openjdk.x86_64 sudo yum r…

java.util.NoSuchElementException: No value present-报错(已解决)

阿丹&#xff1a; 今天在spring-boot整合MongoDB的过程中出现了下面的错误&#xff0c;是因为追求新技术、更优雅产生的。 记录一下。 错误截图如下&#xff1a; 错误位置代码如下&#xff1a; 主要问题&#xff08;问题原因&#xff09;&#xff1a; 因为之前升级了我的jdk的…

Java基础——注解

1 概述 注解用于对Java中类、方法、成员变量做标记&#xff0c;然后进行特殊处理&#xff0c;至于到底做何种处理由业务需求来决定。 例如&#xff0c;JUnit框架中&#xff0c;标记了注解Test的方法就可以被当做测试方法进程执行 2 自定义注解 public interface 注解名称 {p…

GLTF在线场景编辑工具

推荐&#xff1a;使用 NSDT场景编辑器助你快速搭建可二次编辑的3D应用场景 以下是Babylon.js Sandbox的主要功能和特点&#xff1a; 1、创建和编辑场景&#xff1a;Babylon.js Sandbox允许用户在一个交互式的3D环境中创建和编辑glTF场景。您可以添加不同类型的物体、调整其位置…

重型并串式液压机械臂建模与simscape仿真

一、建模 Hydraulic manipulator Figure 1 shows different constituting parts of the manipulator considered, with every part labeled using numbers from 1 to 10. For each part, a CAD model is provided. Each file is named in accordance with the corresponding la…

基于YOLOv7的密集场景行人检测识别分析系统

密集场景下YOLO系列模型的精度如何&#xff1f;本文的主要目的就是想要基于密集场景基于YOLOv7模型开发构建人流计数系统&#xff0c;简单看下效果图&#xff1a; 这里实验部分使用到的数据集为VSCrowd数据集。 实例数据如下所示&#xff1a; 下载到本地解压缩后如下所示&…

K8s operator从0到1实战

Operator基础知识 Kubernetes Operator是一种用于管理和扩展Kubernetes应用程序的模式和工具。它们是一种自定义的Kubernetes控制器&#xff0c;可以根据特定的应用程序需求和业务逻辑扩展Kubernetes功能。 Kubernetes Operator基于Kubernetes的控制器模式&#xff0c;通过自…

cocos creator 的input.on 不生效

序&#xff1a; 1、执行input.on的时候发现不生效 2、一直按控制台也打印不出来console.log 3、先收藏这篇&#xff0c;因为到时候cocos要开发serveApi的时候&#xff0c;你得选一款趁手的后端开发并且&#xff0c;对习惯用ts写脚本的你来说&#xff0c;node是入门最快&#xf…

npm install报错 -> npm ERR! Unexpected token ‘.‘ 报错解决办法。

问题原因&#xff1a; 用nvm1.1.7的版本安装了16.x以上的node, 然后再下载依赖的时候就报错了&#xff1b;总结一下就是nvm版本太低了&#xff0c;他的里面没有集成高版本node导致的。 解决办法&#xff1a; 把nvm切换到新版本就行了。 1. 卸载掉当前所有的node nvm unins…

今天开始学习如何正式调查

本节要讲解三个内容 样本容量 调查方式 调查问卷的回收 在正式调查之前需要确定样本容量 就说要准备调查多少人确定好样本容量之后又要考虑设计的调查问卷 是以什么样的方式发出去 问卷的回收又要注意什么问题 要讲的主要内容 先看样本容量 样本容量确定的基本原…

【Paper Reading】CenterNet:Keypoint Triplets for Object Detection

背景 首先是借鉴Corner Net 表述了一下基于Anchor方法的不足&#xff1a; anchor的大小/比例需要人工来确认anchor并没有完全和gt的bbox对齐&#xff0c;不利于分类任务。 但是CornerNet也有自己的缺点 CornerNet 只预测了top-left和bottom-right 两个点&#xff0c;并没有…

S系列数字源表为何如此受欢迎?

为什么选择S系列数字源表? 性能强大-作为电压源和或电流源&#xff0c;并同步测量电流和或电压&#xff0c;支持四象限工作。可以限定电压或电流输出大小&#xff0c;预防器件损坏。覆盖3pA-3A的电流范围100μV-300V的电压范围&#xff0c;全量程测量精度0.03%。 灵活多样-支…

【高频面试题】微服务篇

文章目录 Spring Cloud1.Spring Cloud 5大组件有哪些&#xff1f;2.服务注册和发现是什么意思&#xff1f;Spring Cloud 如何实现服务注册发现&#xff1f;3.负载均衡如何实现的 ?4.什么是服务雪崩&#xff0c;怎么解决这个问题&#xff1f;5.微服务是怎么监控的 业务相关6.项…

arcgis--数据库构建网络数据集

1、打开arcmap软件&#xff0c;导入数据&#xff0c;如下&#xff1a; 该数据已经过处理&#xff0c;各交点处均被打断&#xff0c;并进行了拓扑检查。 2、在文件夹下新建文件数据库&#xff0c;名称为路网&#xff0c;在数据库下新建要素类&#xff0c;并导入道路shp文件&…

Matlab修改文本编码格式为UTF-8

一、修改文本编码格式 Matlab默认使用GBK编码格式&#xff0c;当代码中有中文注释时&#xff0c;注释显示乱码。 修改配置文件(安装目录下的bin目录有个lcdata.xml)&#xff0c;如下&#xff1a; 1. 删除 2. 修改 < encoding name”UTF-8”> < encoding_alias nam…

文件的管理

一、目录文件的管理 1、创建 2、编辑 3、查看内容 4、删除 二、普通文件的管理 1、创建 2、编辑 3、查看 1&#xff09;整个文档内容的查看 2&#xff09;文档列内容处理后查看 面试重点&#xff0c;年年考 3&#xff09;搜索文件内容查看&#xff0c;列出有关键字的一行 4、…

谷粒商城第十天-分组新增级联显示商品分类分组修改级联回显商品分类

目录 一、总述 二、前端实现 三、后端实现 四、总结 一、总述 本次就是一个小的优化。 就是分组新增或者是修改的时候&#xff0c;直接显示商品分类的id可读性不高&#xff0c;新增的时候需要填写对商品分类的id&#xff0c;修改的时候&#xff0c;就只是给你一个商品分类…