订单服务-提交订单业务立即购买业务

文章目录

  • 1、提交订单 业务
    • 2、在 OrderController 创建 submitOrder 方法
    • 3、 在 OrderServiceImpl 中实现 submitOrder 方法
    • 4、根据id查询sku详情(service-product")
    • 5、查询用户地址保存到订单项中(service-user)
    • 6、删除购物车选中的购物项接口(service-cart)
    • 7、验价验库存
    • 8、创建订单持久化到mysql
    • 9、清空选中的购物车
  • 2、立即购买,不经过购物车
    • 2.1、在 OrderController 创建 buy方法
    • 2.2、在 OrderServiceImpl 中实现 buy 方法
  • 3、订单幂等性校验分析

在这里插入图片描述

1、提交订单 业务

在这里插入图片描述

2、在 OrderController 创建 submitOrder 方法

@RestController
@Tag(name = "订单管理模块", description = "订单管理模块")
@RequestMapping("/api/order/orderInfo")
public class OrderController {@Operation(summary = "提交订单")@PostMapping("/auth/submitOrder")public Result submitOrder(@RequestBody OrderSubmitDto orderSubmitDto) {Long orderId = orderService.submitOrder(orderSubmitDto);return Result.ok(orderId);}
}

3、 在 OrderServiceImpl 中实现 submitOrder 方法

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService {@Resourceprivate CartClient cartClient;@Resourceprivate ProductClient productClient;@Resourceprivate UserClient userClient;@Resourceprivate OrderItemService orderItemService;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Transactional(rollbackFor = Exception.class)@Overridepublic Long submitOrder(OrderSubmitDto orderSubmitDto) {//1、幂等性保证:用户订单确认页提交的相同的请求只处理一次//获取前端提交的tokenList<OrderItem> orderItemList = orderSubmitDto.getOrderItemList();if (CollectionUtils.isEmpty(orderItemList)) {//没有订单项throw new SpzxException(ResultCodeEnum.FAIL,null);}Long token = orderItemList.get(0).getOrderId();//获取redis缓存的token,如果存在删除Boolean delete = stringRedisTemplate.delete("spzx:order:" + token.toString());if (!delete) {//幂等性保证:用户订单确认页提交的相同的请求只处理一次throw new SpzxException(ResultCodeEnum.ORDER_SUBMIT_REPEAT,null);}//2、保证订单中商品价格正确、库存足够//远程调用:service-product 验证前端提交的每个orderItem的价格 和skuId对应的商品当前价格是否一样 和库存是否足够orderItemList.forEach(orderItem -> {Result<ProductSku> skuResult = productClient.getById(orderItem.getSkuId());if (skuResult.getCode() != 200) {throw new SpzxException(ResultCodeEnum.FAIL,null);}ProductSku sku = skuResult.getData();if (sku.getSalePrice().compareTo(orderItem.getSkuPrice()) != 0) {//价格不一致throw new SpzxException(ResultCodeEnum.ORDER_ITEM_PRICE_ERROR,null);}if (sku.getStockNum() < orderItem.getSkuNum()) {//库存不足throw new SpzxException(ResultCodeEnum.ORDER_ITEM_STOCK_ERROR,null);}});Result<UserAddress> userAddressResult = userClient.findUserAddressById(orderSubmitDto.getUserAddressId());if (userAddressResult.getCode() != 200) {//用户收件人地址信息查询失败throw new SpzxException(ResultCodeEnum.FAIL,null);}//3、创建订单持久化OrderInfo orderInfo = new OrderInfo();UserInfo userInfo = SpzxServiceAuthInterceptor.THREAD_LOCAL.get();orderInfo.setUserId(userInfo.getId());orderInfo.setNickName(userInfo.getNickName());//订单号:展示给用户的唯一订单编号String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();orderInfo.setOrderNo(orderNo);orderInfo.setCouponId(0L);//计算订单总金额,并返回总金额BigDecimal totalAmount = orderItemList.stream().map(orderItem -> {return orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuNum()));}).reduce(BigDecimal::add).get();orderInfo.setTotalAmount(totalAmount);orderInfo.setCouponAmount(new BigDecimal("0"));orderInfo.setOriginalTotalAmount(totalAmount);orderInfo.setFreightFee(orderSubmitDto.getFreightFee());//orderInfo.setPayType(0);orderInfo.setOrderStatus(0);//收件人信息UserAddress userAddress = userAddressResult.getData();orderInfo.setReceiverName(userAddress.getName());orderInfo.setReceiverPhone(userAddress.getPhone());orderInfo.setReceiverTagName(userAddress.getTagName());orderInfo.setReceiverProvince(userAddress.getProvinceCode());orderInfo.setReceiverCity(userAddress.getCityCode());orderInfo.setReceiverDistrict(userAddress.getDistrictCode());orderInfo.setReceiverAddress(userAddress.getAddress());orderInfo.setPaymentTime(new Date());orderInfo.setDeliveryTime(new Date());orderInfo.setReceiveTime(new Date());orderInfo.setCancelTime(new Date());orderInfo.setCancelReason("");orderInfo.setRemark(orderSubmitDto.getRemark());this.save(orderInfo);Long orderId = orderInfo.getId();//4、保存订单的所有的订单项列表//订单项关联订单 id 保存orderItemList.forEach(orderItem -> {orderItem.setOrderId(orderId);});orderItemService.saveBatch(orderItemList);//5、删除购物车中已创建订单的购物项//远程调用:service-cart 删除当前用户选中的购物项cartClient.delCheckedCartInfos();//异步:购物车清空无需阻塞订单创建的业务    解耦合:订单创建业务不需要耦合购物车的操作//order服务是生产者发送消息//cart服务是消费者消费消息:根据userId获取他的购物车 再删除选中的购物项//发送订单创建成功的消息到kafka中:购物车需要userId 如果还有其他的业务需要使用订单创建成功的消息,也可以携带其他的数据//userId  幂等性校验使用订单id    order信息/*HashMap<String, Object> params = new HashMap<>();params.put("userId",userInfo.getId());params.put("orderId", orderId);params.put("totalAmount", orderInfo.getTotalAmount());params.put("type", "1");//type表示订单的类型  1、创建订单  2、取消订单   3、更新订单状态//将对象转为json字符串String json = JSON.toJSONString(params);kafkaTemplate.send(SpzxConst.SPZX_ORDER_TOPIC, json);*//*Map<String,Object> params = new HashMap<String,Object>();params.put("userId" , userInfo.getId());params.put("orderId" , orderId);params.put("totalAmount" , orderInfo.getTotalAmount());params.put("type","1");//type表示订单操作的类型  1创建订单  2取消订单  3更新订单状态//将对象转为json字符串String paramsJson = JSON.toJSONString(params);kafkaTemplate.send(SpzxConst.SPZX_ORDER_TOPIC ,paramsJson );*///6、返回订单idreturn orderId;}
}

4、根据id查询sku详情(service-product")

@RestController
@Tag(name = "商品模块")
@RequestMapping(value = "/api/product")
public class ProductController {@Operation(summary = "根据id查询sku商品详情")@GetMapping("getById/{skuId}")public Result getById(@PathVariable("skuId") Long skuId) {ProductSku productSku = productSkuService.getById(skuId);return Result.ok(productSku);}
}@FeignClient(value = "service-product")
public interface ProductClient {//因为远程调用时data存的是 sku对象@GetMapping("/api/product/getById/{skuId}")public Result<ProductSku> getById(@PathVariable("skuId") Long skuId);@PutMapping("/api/product/updateSkuSaleAndStock/{skuId}/{skuNum}")public Result updateSkuSaleAndStock(@PathVariable Long skuId, @PathVariable Integer skuNum);
}

5、查询用户地址保存到订单项中(service-user)

@RestController
@Tag(name = "用户地址管理模块", description = "用户地址管理模块")
@RequestMapping("/api/user/userAddress")
public class UserAddressController {@Operation(summary = "获取地址信息")@GetMapping("/getUserAddress/{id}")public Result findUserAddressById(@PathVariable("id") Long id) {UserAddress userAddress = userAddressService.getById(id);return Result.ok(userAddress);}
}@FeignClient(value = "service-user")
public interface UserClient {@Operation(summary = "获取地址信息")@GetMapping("/api/user/userAddress/getUserAddress/{id}")public Result<UserAddress> findUserAddressById(@PathVariable("id") Long id);
}

6、删除购物车选中的购物项接口(service-cart)

@RestController
@RequestMapping("/api/order/cart")
@Tag(name = "购物车模块")
public class CartController {@Resourceprivate CartService cartService;@Operation(summary = "删除购物车选中购物项")@DeleteMapping("/auth/delCheckedCartInfos")public Result delCheckedCartInfos(){cartService.deleteCheckedCartInfos();return Result.ok();}
}@FeignClient(value = "service-cart")
public interface CartClient {@GetMapping("/api/order/cart/auth/checkedCartInfos")public Result<List<CartInfo>> checkedCartInfos();@DeleteMapping("/api/order/cart/auth/delCheckedCartInfos")public Result<Void> delCheckedCartInfos();
}

7、验价验库存

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService {public Long submitOrder(OrderSubmitDto orderSubmitDto) {List<OrderItem> orderItemList = orderSubmitDto.getOrderItemList();if (CollectionUtils.isEmpty(orderItemList)) {//没有订单项throw new SpzxException(ResultCodeEnum.FAIL,null);}//2、保证订单中商品价格正确、库存足够//远程调用:service-product 验证前端提交的每个orderItem的价格 和skuId对应的商品当前价格是否一样 和库存是否足够orderItemList.forEach(orderItem -> {Result<ProductSku> skuResult = productClient.getById(orderItem.getSkuId());if (skuResult.getCode() != 200) {throw new SpzxException(ResultCodeEnum.FAIL,null);}ProductSku sku = skuResult.getData();if (sku.getSalePrice().compareTo(orderItem.getSkuPrice()) != 0) {//价格不一致throw new SpzxException(ResultCodeEnum.ORDER_ITEM_PRICE_ERROR,null);}if (sku.getStockNum() < orderItem.getSkuNum()) {//库存不足throw new SpzxException(ResultCodeEnum.ORDER_ITEM_STOCK_ERROR,null);}});}
}

8、创建订单持久化到mysql

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService {public Long submitOrder(OrderSubmitDto orderSubmitDto) {Result<UserAddress> userAddressResult = userClient.findUserAddressById(orderSubmitDto.getUserAddressId());if (userAddressResult.getCode() != 200) {//用户收件人地址信息查询失败throw new SpzxException(ResultCodeEnum.FAIL,null);}//3、创建订单持久化OrderInfo orderInfo = new OrderInfo();UserInfo userInfo = SpzxServiceAuthInterceptor.THREAD_LOCAL.get();orderInfo.setUserId(userInfo.getId());orderInfo.setNickName(userInfo.getNickName());//订单号:展示给用户的唯一订单编号String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();orderInfo.setOrderNo(orderNo);orderInfo.setCouponId(0L);//计算订单总金额,并返回总金额BigDecimal totalAmount = orderItemList.stream().map(orderItem -> {return orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuNum()));}).reduce(BigDecimal::add).get();orderInfo.setTotalAmount(totalAmount);orderInfo.setCouponAmount(new BigDecimal("0"));orderInfo.setOriginalTotalAmount(totalAmount);orderInfo.setFreightFee(orderSubmitDto.getFreightFee());//orderInfo.setPayType(0);orderInfo.setOrderStatus(0);//收件人信息UserAddress userAddress = userAddressResult.getData();orderInfo.setReceiverName(userAddress.getName());orderInfo.setReceiverPhone(userAddress.getPhone());orderInfo.setReceiverTagName(userAddress.getTagName());orderInfo.setReceiverProvince(userAddress.getProvinceCode());orderInfo.setReceiverCity(userAddress.getCityCode());orderInfo.setReceiverDistrict(userAddress.getDistrictCode());orderInfo.setReceiverAddress(userAddress.getAddress());orderInfo.setPaymentTime(new Date());orderInfo.setDeliveryTime(new Date());orderInfo.setReceiveTime(new Date());orderInfo.setCancelTime(new Date());orderInfo.setCancelReason("");orderInfo.setRemark(orderSubmitDto.getRemark());this.save(orderInfo);Long orderId = orderInfo.getId();//4、保存订单的所有的订单项列表//订单项关联订单 id 保存orderItemList.forEach(orderItem -> {orderItem.setOrderId(orderId);});orderItemService.saveBatch(orderItemList);
}

9、清空选中的购物车

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService {@Transactional(rollbackFor = Exception.class)@Overridepublic Long submitOrder(OrderSubmitDto orderSubmitDto) {//5、删除购物车中已创建订单的购物项//远程调用:service-cart 删除当前用户选中的购物项cartClient.delCheckedCartInfos();}}

2、立即购买,不经过购物车

在这里插入图片描述

2.1、在 OrderController 创建 buy方法

@RestController
@Tag(name = "订单管理模块", description = "订单管理模块")
@RequestMapping("/api/order/orderInfo")
public class OrderController {@Operation(summary = "立即购买:商品详情页立即购买按钮")@GetMapping("/auth/buy/{skuId}")public Result buy(@PathVariable("skuId") Long skuId) {TradeVo tradeVo = orderService.buy(skuId);return Result.ok(tradeVo);}
}

2.2、在 OrderServiceImpl 中实现 buy 方法

    @Overridepublic TradeVo buy(Long skuId) {Result<ProductSku> skuResult = productClient.getById(skuId);if (skuResult.getCode() != 200) {//商品信息查询失败throw new SpzxException(ResultCodeEnum.FAIL,null);}ProductSku sku = skuResult.getData();Long token = IdUtil.getSnowflake(1,1).nextId();//将token存到redis:redis的大key问题stringRedisTemplate.opsForValue().set("spzx:order:"+token.toString(), "1",  30, TimeUnit.MINUTES);OrderItem orderItem = new OrderItem();orderItem.setOrderId(token);orderItem.setSkuNum(1);orderItem.setSkuPrice(sku.getSalePrice());orderItem.setThumbImg(sku.getThumbImg());orderItem.setSkuId(skuId);orderItem.setSkuName(sku.getSkuName());TradeVo tradeVo = new TradeVo();tradeVo.setTotalAmount(orderItem.getSkuPrice());tradeVo.setOrderItemList(List.of(orderItem));return tradeVo;}

3、订单幂等性校验分析

幂等性如何保证:相同的请求多次提交如果处理的结果一致
解决思路:和防止表单重复提交一样

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

udp发送数据如果超过1个mtu时,抓包所遇到的问题记录说明

最近在测试Syslog udp发送相关功能&#xff0c;测试环境是centos udp头部的数据长度是2个字节&#xff0c;最大传输长度理论上是65535&#xff0c;除去头部这些字节&#xff0c;可以大概的说是64k。 写了一个超过64k的数据(随便用了一个7w字节的buffer)发送demo&#xff0c;打…

USB-SC-09编程电缆使用手册

USB-SC-09编程电缆是通过电脑的USB口仿真成传统串口&#xff08;俗称COM口&#xff09;&#xff0c;从而使用现有的各种编程软件、通信软件和监控软件等&#xff0c;转换盒上的发光二极管指示数据的收发状态&#xff0c;本电缆适用于三菱FX全系列PLC USB-SC-09电缆外观&#xf…

【AIGC评测体系】大模型评测指标集

大模型评测指标集 &#xff08;☆&#xff09;SuperCLUE&#xff08;1&#xff09;SuperCLUE-V&#xff08;中文原生多模态理解测评基准&#xff09;&#xff08;2&#xff09;SuperCLUE-Auto&#xff08;汽车大模型测评基准&#xff09;&#xff08;3&#xff09;AIGVBench-T2…

【python - 数据】

一、序列 序列&#xff08;sequence&#xff09;是一组有顺序的值的集合&#xff0c;是计算机科学中的一个强大且基本的抽象概念。序列并不是特定内置类型或抽象数据表示的实例&#xff0c;而是一个包含不同类型数据间共享行为的集合。也就是说&#xff0c;序列有很多种类&…

Python数据可视化书籍推荐:利用Python进行数据分析

《利用Python进行数据分析》 这本书几乎是数据分析入门必读书了 主要介绍了python 3个库numpy&#xff08;数组&#xff09;&#xff0c;pandas&#xff08;数据分析&#xff09;和matplotlib&#xff08;绘图&#xff09;的学习 阅读本书可以获得一份关于在Python下操作、处…

2024“国培“来也UiBot6.0 RPA数字机器人开发综合应用

前言 (本博客中会有部分课程ppt截屏,如有侵权请及请及时与小北我取得联系~) 国培笔记: 依次读取数组中每个元素 输出调试信息 [ value=[ "vivian", value[0] "老师", "上午好,O(∩_∩)O哈哈~" ], v…

Ozon、美客多补单测评黑科技:打造无懈可击的自养号补单环境

不管哪个跨境平台的风控都会做升级&#xff0c;相对的补单技术也需要进行相应的做升级&#xff0c;风控升级后&#xff0c;自己养号补单需要注意以下技术问题&#xff0c;以确保补单的稳定性和安全性&#xff1a; 一、物理环境 1. 硬件参数伪装&#xff1a;平台已经开始通过I…

在手机上也能开发软件?而且只需要用几句话就可以自动生成一个应用!

随着人工智能技术的飞速发展&#xff0c;软件开发的门槛正在迅速降低。 曾几何时&#xff0c;开发一款软件需要精通编程语言和掌握复杂的开发工具&#xff0c;而如今&#xff0c;只需几句话的描述&#xff0c;便能在手机上轻松开发出功能齐全的软件。 这一切的背后&#xff0…

Steam夏促怎么注册 Steam夏促账号注册教程

随着夏日的炙热渐渐充斥着每一个角落&#xff0c;Steam平台也赶来添热闹&#xff0c;推出了一系列让人眼前一亮的夏季促销活动。如果你也是游戏爱好者&#xff0c;我们肯定不能错过这次的steam夏促。正直本次夏日促销有着很多的游戏迎来史低和新史低&#xff0c;有各种各样的游…

VSCode里python代码不扩展/级联了的解决办法

如图 解决办法&#xff1a;重新下载新的扩展工具 步骤如下 1、在左边工具栏打开Extensions 2、搜索框输入python&#xff0c;选择别的扩展工具&#xff0c;点击Install - 3在扩展工具所在的目录下&#xff0c;新建一个文件&#xff0c;就可以用了

如何通过指纹浏览器使用代理IP?

1.指纹浏览器定义 指纹浏览器是 一种浏览器技术&#xff0c;它根据用户设备的硬件、软件和配置等特征生成唯一标识符&#xff08;称为“指纹”&#xff09;。此指纹用于识别和追踪用户身份&#xff0c;即使用户更改其 IP 地址或清除浏览器数据&#xff08;如缓存和 Cookie&…

PyCharm远程开发

PyCharm远程开发 1- 远程环境说明 每个人的本地电脑环境差别很大。各自在自己电脑上开发功能&#xff0c;测试/运行正常。但是将多个人的代码功能合并&#xff0c;运行服务器上&#xff0c;会出现各种版本兼容性问题。 在实际企业中&#xff0c;一般会有两套环境。第一套是测…

Jenkins教程-13-参数化任务构建

上一小节我们学习了发送html邮件测试报告的方法&#xff0c;本小节我们讲解一下Jenkins参数化任务构建的方法。 很多时候我们需要根据不同的条件去执行构建&#xff0c;如自动化测试中执行test、stg、prod环境的构建&#xff0c;Jenkins是支持参数化构建的。 以下是Jenkins官…

【C++】using namespace std 到底什么意思

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文作为 JohnKi 的学习笔记&#xff0c;引用了部分大佬的案例 &#x1f4e2;未来很长&a…

【C++】多态详解

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 一、多态概念 二、多态的定义及实现 1. 多态的构成条件 2. 虚函数 2.1 什么是虚函数 2.2 虚函数的重写 2.3 虚函数重写的两个…

实战项目——用Java实现图书管理系统

前言 首先既然是管理系统&#xff0c;那咱们就要实现以下这几个功能了--> 分析 1.首先是用户分为两种&#xff0c;一个是管理员&#xff0c;另一个是普通用户&#xff0c;既如此&#xff0c;可以定义一个用户类&#xff08;user&#xff09;&#xff0c;在定义管理员类&am…

哈哈看到这条消息感觉就像是打开了窗户

在这个信息爆炸的时代&#xff0c;每一条动态可能成为我们情绪的小小触发器。今天&#xff0c;当我无意间滑过那条由杜海涛亲自发布的“自曝式”消息时&#xff0c;不禁心头一颤——如果这是我的另一半&#xff0c;哎呀&#xff0c;那画面&#xff0c;简直比烧烤摊还要“热辣”…

多微信运营管理方案

微信作为一款社交通讯软件&#xff0c;已经成为人们日常生活中不可缺少的工具。不仅个人&#xff0c;很多企业都用微信来联系客户、维护客户和营销&#xff0c;这自然而然就会有很多微信账号、手机也多&#xff0c;那管理起来就会带来很多的不便&#xff0c;而多微信私域管理系…

K8s的基本使用和认识

目录 介绍 控制端 Node(节点) 控制端与节点的关系图 基本使用 创建和运行资源 查找和参看资源 修改和删除资源 介绍 控制端 api-server(api)是集群的核心是k8s中最重要的组件,因为它是实现声明式api的关键 kubernetes api-server的核心功能是提供了Kubernetes各类资…

7.6、指针和数组

代码 #include <iostream> using namespace std;int main() {//指针和数组//利用指针访问数组中的元素int arr[10] { 1,2,3,4,5,6,7,8,9,10 };cout << "第一个元素为&#xff1a;" << arr[0] << endl;int * p arr;//arr就是数组首地址co…