## 第15章-支付成功后续业务&取消关闭订单业务 **学习目标:** - 完成支付成功后续业务处理 - 订单状态修改 - 对接库存系统扣减库存 - 订单拆单 - 完成订单关闭后续业务处理 - 修改订单状态 - 关闭本地交易记录 - 关闭支付宝交易记录 # 1、支付成功处理 ## 1.1 更改订单状态 订单支付成功后,我们已经更改了订单支付记录状态,接下来我还有**更改订单状态**,因为他们是不同的微服务模块,所以我们采用**消息队列**的方式,保证**数据最终一致性**; ### 1.1.1 在MqConst常量类添加变量 ```java /** * 订单支付 */ public static final String EXCHANGE_DIRECT_PAYMENT_PAY = "exchange.direct.payment.pay"; public static final String ROUTING_PAYMENT_PAY = "payment.pay"; //队列 public static final String QUEUE_PAYMENT_PAY = "queue.payment.pay"; /** * 减库存 */ public static final String EXCHANGE_DIRECT_WARE_STOCK = "exchange.direct.ware.stock"; public static final String ROUTING_WARE_STOCK = "ware.stock"; //队列 public static final String QUEUE_WARE_STOCK = "queue.ware.stock"; /** * 减库存成功,更新订单状态 */ public static final String EXCHANGE_DIRECT_WARE_ORDER = "exchange.direct.ware.order"; public static final String ROUTING_WARE_ORDER = "ware.order"; //队列 public static final String QUEUE_WARE_ORDER = "queue.ware.order"; ``` ### 1.1.2 在service-payment 中添加依赖和配置 ```xml com.atguigu.gmall rabbit-util 1.0 ``` ### 1.1.3 支付成功发送消息 `service-payment`模块com.atguigu.gmall.payment.service.impl.PaymentInfoServiceImpl#paySuccess方法 ```java @Autowired private RabbitService rabbitService; /** * 修改本地交易记录状态 * * @param outTradeNo 订单编号 * @param paymentType 支付方式 * @param paramsMap 支付宝回调参数 */ @Override public void paySuccess(String outTradeNo, String paymentType, Map paramsMap) { //1.修改本地支付表状态为已支付 LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(PaymentInfo::getOutTradeNo, outTradeNo); updateWrapper.eq(PaymentInfo::getPaymentType, paymentType); updateWrapper.set(PaymentInfo::getPaymentStatus, PaymentStatus.PAID.name()); updateWrapper.set(PaymentInfo::getTradeNo, paramsMap.get("trade_no")); updateWrapper.set(PaymentInfo::getCallbackTime, new Date()); updateWrapper.set(PaymentInfo::getCallbackContent, paramsMap.toString()); this.update(updateWrapper); //2.todo 新增代码 发送修改订单状态消息到MQ 通知 订单微服务 PaymentInfo paymentInfo = this.getPaymentInfo(outTradeNo, paymentType); rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_PAY, MqConst.ROUTING_PAYMENT_PAY, paymentInfo.getOrderId()); } ``` ### 1.1.4 service-order模块接收消息 `service-order`模块中创建OrderReceiver类添加方法 ```java package com.atguigu.gmall.order.receiver; import com.atguigu.gmall.common.constant.MqConst; import com.atguigu.gmall.model.enums.ProcessStatus; import com.atguigu.gmall.model.order.OrderInfo; import com.atguigu.gmall.order.service.OrderService; import com.rabbitmq.client.Channel; import lombok.SneakyThrows; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.Exchange; import org.springframework.amqp.rabbit.annotation.Queue; import org.springframework.amqp.rabbit.annotation.QueueBinding; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Map; /** **/ @Component public class OrderReceiver { @Autowired private OrderInfoService orderInfoService; /** * 监听到支付成功后消息,修改订单状态为已支付;发送扣减库存消息到MQ * * @param orderId * @param message * @param channel */ @SneakyThrows @RabbitListener(bindings = @QueueBinding( exchange = @Exchange(MqConst.EXCHANGE_DIRECT_PAYMENT_PAY), value = @Queue(MqConst.QUEUE_PAYMENT_PAY), key = {MqConst.ROUTING_PAYMENT_PAY} )) public void paySuccessUpdateOrder(Long orderId, Message message, Channel channel) { try { // 判断订单Id if (orderId != null) { log.info("【订单微服务】监听到支付成功的订单:ID为:{}", orderId); OrderInfo orderInfo = orderInfoService.getById(orderId); //通过业务字段判消息幂等性. if (orderInfo != null && !OrderStatus.PAID.name().equals(orderInfo.getOrderStatus())) { //更新订单 orderInfoService.updateOrderStatus(orderId, ProcessStatus.PAID); } } } catch (Exception e) { e.printStackTrace(); } channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } } ``` ## 1.2 订单模块发送减库存通知 订单模块除了接收到请求改变单据状态,还要发送库存系统 查看看《库存管理系统接口手册》中【减库存的消息队列消费端接口】中的描述,组织相应的消息数据进行传递。 ![](assets/image-20230127165931001.png) ### 1.1.1 OrderService接口 ```java /** * 发送扣减库存消息到MQ 通知 仓库系统 * 消息格式JSON字符串包含什么数据?查询订单订单明细 * * @param orderId */ void sendDeductStockMsg(Long orderId); /** * 将订单订单明细转为Map 后续该方法被复用 * @param orderInfo * @return */ Map initWareOrder(OrderInfo orderInfo); ``` ### 1.1.2 编写实现类 ```java /** * 发送扣减库存消息到MQ 通知 仓库系统 * 消息格式JSON字符串包含什么数据?查询订单订单明细 * * @param orderId */ @Override public void sendDeductStockMsg(Long orderId) { //1.根据订单ID查询订单详情跟订单明细(商品) OrderInfo orderInfo = this.getOrderInfo(orderId); //2.将得到消息对应java对象转为Map Map wareMap = initWareOrder(orderInfo); //3.发送消息到RabbitMQ rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK, MqConst.ROUTING_WARE_STOCK, JSON.toJSONString(wareMap)); } /** * 将得到订单以及明细转为Map * * @param orderInfo * @return */ @Override public Map initWareOrder(OrderInfo orderInfo) { HashMap mapResult = new HashMap<>(); //从orderInfo获取封装相关订单信息 mapResult.put("orderId", orderInfo.getId()); mapResult.put("consignee", orderInfo.getConsignee()); mapResult.put("consigneeTel", orderInfo.getConsigneeTel()); mapResult.put("orderComment", orderInfo.getOrderComment()); mapResult.put("orderBody", orderInfo.getTradeBody()); mapResult.put("deliveryAddress", orderInfo.getDeliveryAddress()); mapResult.put("paymentWay", "2"); //TODO 拆单响应结果中必选包含该字段:返回对应商品仓库ID,不然会报死循环 mapResult.put("wareId", orderInfo.getWareId()); //从orderInfo获取订单明细 封装相关明细信息 List orderDetailList = orderInfo.getOrderDetailList(); if (!CollectionUtils.isEmpty(orderDetailList)) { List> orderDetailMapList = orderDetailList.stream().map(orderDetail -> { HashMap detailMap = new HashMap<>(); detailMap.put("skuId", orderDetail.getSkuId()); detailMap.put("skuNum", orderDetail.getSkuNum()); detailMap.put("skuName", orderDetail.getSkuName()); return detailMap; }).collect(Collectors.toList()); mapResult.put("details", orderDetailMapList); } return mapResult; } ``` ## 1.3 消费减库存结果 给仓库系统发送减库存消息后,还要接受减库存成功或者失败的消息。 同样根据《库存管理系统接口手册》中【商品减库结果消息】的说明完成。消费该消息的消息队列监听程序。 接受到消息后主要做的工作就是更新订单状态。 在订单项目中OrderReceiver ```java /** * 监听到库存系统扣减库存结果,修改订单状态 * * @param stockJsonStr {"orderId":1,"satuts":"DEDUCTED"} * @param message * @param channel */ @RabbitListener(bindings = @QueueBinding( exchange = @Exchange(MqConst.EXCHANGE_DIRECT_WARE_ORDER), value = @Queue(MqConst.QUEUE_WARE_ORDER), key = MqConst.ROUTING_WARE_ORDER )) public void processDeductStockResult(String stockJsonStr, Message message, Channel channel) { try { if (StringUtils.isNotBlank(stockJsonStr)) { log.info("【订单微服务】监听到库存系统扣减库存结果:{}", stockJsonStr); //1.将扣减库存结果转为Map 得到订单ID以及扣款库存结果 Map map = JSON.parseObject(stockJsonStr, Map.class); String orderId = (String) map.get("orderId"); String status = (String) map.get("status"); //2.根据结果更新订单状态 if("DEDUCTED".equals(status)){ //扣减成功 orderInfoService.updateOrderStatus(Long.parseLong(orderId), ProcessStatus.WAITING_DELEVER); }else{ //扣减失败-方案:提供定时任务扫描订单中处理状态为:库存异常。将这些订单作为预警订单提醒工作人员处理 orderInfoService.updateOrderStatus(Long.parseLong(orderId), ProcessStatus.STOCK_EXCEPTION); } } channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } catch (IOException e) { e.printStackTrace(); log.error("【订单微服务】处理扣减库存结果异常:{}", e); } } ``` ## 1.4 拆单接口 > YAPI接口地址:http://192.168.200.128:3000/project/11/interface/api/747 ### 1.3.1 库存系统配置拆单回调接口 **application-dev.yml** ```yaml order: split: url: http://localhost:8204/api/order/orderSplit ``` ### 1.3.2 拆单接口控制器 ```java /** * 库存系统发起拆单请求 * 参数采用表单方式提交 * @param orderId "1" * @param wareSkuMapStr "[{"wareId":"1","skuIds":["26"]}]" * @return */ @PostMapping("/orderSplit") public String orderSplit(@RequestParam("orderId") Long orderId, @RequestParam("wareSkuMap") String wareSkuMapStr) { return orderInfoService.orderSplit(orderId, wareSkuMapStr); } ``` ### 1.3.3 订单实现拆单接口 ```java /** * 完成拆分订单业务 * @param orderId * @param wareSkuMap * @return */ String orderSplit(Long orderId, String wareSkuMapStr); ``` ### 1.3.4 拆单接口实现类 ```java /** * 拆分订单处理 * 1.根据提交订单ID查询原始的订单以及订单明细 * 2.遍历仓库跟商品SKU对应关系List 构建新的子订单 订单明细 进行保存 * 3.更新原始订单状态:SPLIT * 4.按照接口文档构建响应结果[{orderId:1,wareId:"出货仓库ID",orderBody:"",details:[{},{}]},{}] * * @param map * @return */ @Override public String orderSplit(Long orderId, String wareSkuMapStr) { List allSubOrderInfoList = new ArrayList<>(); //1.根据订单ID查询原始订单以及订单明细 OrderInfo orderInfoOrigin = this.getOrderInfo(orderId); //原始订单中所有订单商品明细 List orderDetailOriginList = orderInfoOrigin.getOrderDetailList(); //2.根据提交仓库跟SKU对应关系,构建新子订单以及订单明细并保存 //将得到的字符串转为List集合 List wareSkuMap = JSON.parseArray(wareSkuMapStr, Map.class); if (!CollectionUtils.isEmpty(wareSkuMap)) { //2.1 遍历仓库商品SKU对照集合 对应产生几个子订单 wareSkuMap.stream().forEach(skuWareMap -> { //获取仓库ID String wareId = (String) skuWareMap.get("wareId"); //获取仓库包含SKUID集合 List skuIds = (List) skuWareMap.get("skuIds"); //使用Stream流式变成进行对集合数据过滤 List subOrderDetailList = orderDetailOriginList.stream().filter(orderDetail -> { return skuIds.contains(orderDetail.getSkuId().toString()); }).collect(Collectors.toList()); //2.2 构建新子订单,设置上级订单;设置订单仓库ID;设置订单ID 执行保存 OrderInfo subOrderInfo = new OrderInfo(); BeanUtils.copyProperties(orderInfoOrigin, subOrderInfo); subOrderInfo.setId(null); //避免主键冲突 subOrderInfo.setParentOrderId(orderInfoOrigin.getId());//上级订单ID subOrderInfo.setWareId(wareId);// 订单对应出库仓库ID //重新计算新子订单总金额 subOrderInfo.setOrderDetailList(subOrderDetailList); //计算总金额 subOrderInfo.sumTotalAmount(); //执行保存子订单 this.save(subOrderInfo); //2.3 构建新子订单的订单明细,设置所属订单新子订单 执行保存 //保存子订单项 for (OrderDetail orderDetail : subOrderDetailList) { orderDetail.setOrderId(subOrderInfo.getId()); } orderDetailService.saveBatch(subOrderDetailList); allSubOrderInfoList.add(subOrderInfo); }); } //3.更新原始订单状态 this.updateOrderStatus(orderInfoOrigin.getId(), ProcessStatus.SPLIT); //4.按照接口文档构建响应结果"[{orderId:1,wareId:"出货仓库ID",orderBody:"",details:[{},{}]},{}]" List collect = allSubOrderInfoList.stream().map(orderInfo -> { Map map = initWareOrder(orderInfo); return map; }).collect(Collectors.toList()); return JSON.toJSONString(collect); } ``` # 2、超时订单业务补充 ## 2.1 在MqConst中添加常量 ```java /** * 关闭交易 */ public static final String EXCHANGE_DIRECT_PAYMENT_CLOSE = "exchange.direct.payment.close"; public static final String ROUTING_PAYMENT_CLOSE = "payment.close"; //队列 public static final String QUEUE_PAYMENT_CLOSE = "queue.payment.close"; ``` ## 2.2 在取消订单监听器发送关闭交易消息 `service-order`中修改com.atguigu.gmall.order.service.impl.OrderInfoServiceImpl#execExpiredOrder方法,发送消息 ```java /** * 监听关闭订单消息:将订单关闭;todo 关闭本地交易记录,支付宝交易记录 * * @param orderId 订单ID * @param message * @param channel */ @RabbitListener(queues = {MqConst.QUEUE_ORDER_CANCEL}) public void closeOrder(Long orderId, Message message, Channel channel) { try { //1.处理业务 if (orderId != null) { log.info("【订单微服务】关闭订单消息:{}", orderId); //1.1 根据订单ID查询订单状态 状态如果是未支付:将订单状态改为关闭 OrderInfo orderInfo = orderInfoService.getById(orderId); if (orderId != null && OrderStatus.UNPAID.name().equals(orderInfo.getOrderStatus()) && OrderStatus.UNPAID.name().equals(orderInfo.getProcessStatus())) { //1.2 修改订单状态-为关闭 orderInfoService.execExpiredOrder(orderId); //1.3 发送关闭订单消息-关闭本地交易记录 rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE, MqConst.ROUTING_PAYMENT_CLOSE, orderId); } } //2.手动应答 channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } catch (IOException e) { e.printStackTrace(); log.error("【订单微服务】关闭订单业务异常:{}", e); } } ``` ## 2.3 service-payment模块接收消息 ### 2.3.1 编写消费者 ```java package com.atguigu.gmall.payment.receiver; import com.atguigu.gmall.common.constant.MqConst; import com.atguigu.gmall.payment.service.PaymentInfoService; import com.rabbitmq.client.Channel; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.Exchange; import org.springframework.amqp.rabbit.annotation.Queue; import org.springframework.amqp.rabbit.annotation.QueueBinding; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.IOException; /** * @author: atguigu * @create: 2023-01-30 09:29 */ @Component @Slf4j public class PaymentReceiver { @Autowired private PaymentInfoService paymentInfoService; /** * 监听关闭本地交易记录消息,修改本地交易记录状态为CLose * @param orderId * @param message * @param channel */ @RabbitListener(bindings = @QueueBinding( exchange = @Exchange(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE), value = @Queue(MqConst.QUEUE_PAYMENT_CLOSE), key = {MqConst.ROUTING_PAYMENT_CLOSE} )) public void closePayment(Long orderId, Message message, Channel channel) { try { if (orderId != null) { log.info("【支付微服务】监听关闭本地交易记录消息:{}", orderId); paymentInfoService.closePayment(orderId); } channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } catch (IOException e) { e.printStackTrace(); log.error("【支付微服务】,关闭本地交易记录异常:{}", e); } } } ``` ### 2.3.2 关闭本地交易记录接口与实现类 PaymentInfoService ```java /** * 修改本地交易记录状态为关闭 * @param orderId */ void closePayment(Long orderId); /** * 根据订单Id支付方式查询本地交易记录 * @param orderId * @param paymentType * @return */ PaymentInfo getPaymentInfo(Long orderId, String paymentType); ``` PaymentInfoServiceImpl ```java /** * 修改本地交易记录状态为关闭 * * @param orderId */ @Override public void closePayment(Long orderId) { //1.根据条件订单ID,支付方式查询本地交易记录 PaymentInfo paymentInfo = this.getPaymentInfo(orderId, PaymentType.ALIPAY.name()); if (paymentInfo != null) { //2.修改状态为关闭 paymentInfo.setPaymentStatus(PaymentStatus.CLOSED.name()); this.updateById(paymentInfo); } } /** * 根据订单Id支付方式查询本地交易记录 * * @param orderId * @param paymentType * @return */ @Override public PaymentInfo getPaymentInfo(Long orderId, String paymentType) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(PaymentInfo::getOrderId, orderId); queryWrapper.eq(PaymentInfo::getPaymentType, paymentType); return this.getOne(queryWrapper); } ``` ## 2.4 支付宝关闭交易 > YAPI接口地址:http://192.168.200.128:3000/project/11/interface/api/854 ### 2.4.1 编写控制器 *AlipayController* ```java /** * 根据订单ID关闭支付宝交易记录 * @param orderId 订单ID * @return */ @GetMapping("closePay/{orderId}") public Boolean closePay(@PathVariable Long orderId){ Boolean aBoolean = alipayService.closePay(orderId); return aBoolean; } ``` ### 2.4.2 编写接口 AlipayService接口 ```java /*** * 关闭交易 * @param orderId * @return */ Boolean closePay(Long orderId); ``` ### 2.4.3 编写实现类 AlipayServiceImpl ```java /** * 根据订单ID关闭支付宝交易记录 * * @param orderId 订单ID * @return */ @Override public Boolean closePay(Long orderId) { try { //1.查询本地支付表信息 PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(orderId, PaymentType.ALIPAY.name()); //2.调用支付宝接口关闭支付宝交易 if (paymentInfo != null) { AlipayTradeCloseRequest request = new AlipayTradeCloseRequest(); JSONObject bizContent = new JSONObject(); bizContent.put("trade_no", paymentInfo.getTradeNo()); bizContent.put("out_trade_no", paymentInfo.getOutTradeNo()); request.setBizContent(bizContent.toString()); AlipayTradeCloseResponse response = alipayClient.execute(request); if (response.isSuccess()) { return true; } } } catch (AlipayApiException e) { e.printStackTrace(); } return false; } ``` ## 2.5 查询支付交易记录 > YAPI接口地址:http://192.168.200.128:3000/project/11/interface/api/863 ### 2.5.1 编写控制器 AlipayController ```java /** * 查看是否有交易记录 * @param orderId * @return */ @GetMapping("checkPayment/{orderId}") public Boolean checkPayment(@PathVariable Long orderId){ // 调用退款接口 boolean flag = alipayService.checkPayment(orderId); return flag; } ``` ### 2.5.1 编写接口 AlipayService ```java /** * 根据订单查询交易是否关闭 * @param orderId * @return */ Boolean checkPayment(Long orderId); ``` ### 2.5.2 编写实现类 AlipayServiceImpl ```java /** * 查看是否有交易记录状态 * * @param orderId * @return false:已关闭 true:未关闭 */ @Override public boolean checkPayment(Long orderId) { try { //1.查询本地交易记录 PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(orderId, PaymentType.ALIPAY.name()); //2.调用支付宝接口完成检查 if (paymentInfo != null) { AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); JSONObject bizContent = new JSONObject(); bizContent.put("out_trade_no", paymentInfo.getOutTradeNo()); bizContent.put("trade_no", paymentInfo.getTradeNo()); request.setBizContent(bizContent.toString()); AlipayTradeQueryResponse response = alipayClient.execute(request); if (response.isSuccess()) { if ("TRADE_CLOSED".equals(response.getTradeStatus())) { return false; } } } } catch (AlipayApiException e) { e.printStackTrace(); } return true; } ``` ## 2.6 整合关闭过期订单 ### 2.6.1 在PaymentApiController添加查询PaymentInfo 数据接口 ```java package com.atguigu.gmall.payment.controller; import com.atguigu.gmall.enums.model.PaymentType; import com.atguigu.gmall.payment.model.PaymentInfo; import com.atguigu.gmall.payment.service.PaymentInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author: atguigu * @create: 2023-01-27 20:52 */ @RestController @RequestMapping("/api/payment/") public class PaymentApiController { @Autowired private PaymentInfoService paymentInfoService; /** * 查询本地交易记录 * * @param orderId * @return */ @GetMapping("/getPaymentInfo/{orderId}") public PaymentInfo getPaymentInfo(@PathVariable Long orderId) { PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(orderId, PaymentType.ALIPAY.name()); if (null != paymentInfo) { return paymentInfo; } return null; } } ``` ### 2.6.2 创建service-payment-client ![image-20221209013717842](assets/day15/image-20221209013717842.png) PaymentFeignClient 远程调用API Feign接口 ```java package com.atguigu.gmall.payment.client; import com.atguigu.gmall.payment.client.impl.PaymentDegradeFeignClient; import com.atguigu.gmall.payment.model.PaymentInfo; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient(value = "service-payment", fallback = PaymentDegradeFeignClient.class) public interface PaymentFeignClient { /** * 查询本地交易记录 * @param orderId * @return */ @GetMapping("/api/payment/getPaymentInfo/{orderId}") public PaymentInfo getPaymentInfo(@PathVariable Long orderId); /** * 根据订单ID关闭支付宝交易记录 * @param orderId 订单ID * @return */ @GetMapping("/api/payment/alipay/closePay/{orderId}") public Boolean closePay(@PathVariable Long orderId); /** * 查看是否有交易记录 * @param orderId * @return */ @GetMapping("/api/payment/alipay/checkPayment/{orderId}") public Boolean checkPayment(@PathVariable Long orderId); } ``` 服务降级类 ```java package com.atguigu.gmall.payment.client.impl; import com.atguigu.gmall.payment.client.PaymentFeignClient; import com.atguigu.gmall.payment.model.PaymentInfo; import org.springframework.stereotype.Component; /** * @author: atguigu * @create: 2023-01-30 10:26 */ @Component public class PaymentDegradeFeignClient implements PaymentFeignClient { @Override public PaymentInfo getPaymentInfo(Long orderId) { return null; } @Override public Boolean closePay(Long orderId) { return null; } @Override public Boolean checkPayment(Long orderId) { return null; } } ``` ### 2.6.3 在订单service-order项目中添加依赖 ```xml com.atguigu.gmall service-payment-client 1.0 ``` ### 2.6.4 OrderReceiver 整合代码 修改订单监听器:OrderReceiver中监听关闭订单消息 ```java @Autowired private PaymentFeignClient paymentFeignClient; /** * 监听关闭订单消息:将订单关闭;todo 关闭本地交易记录,支付宝交易记录 * * @param orderId 订单ID * @param message * @param channel */ @RabbitListener(queues = {MqConst.QUEUE_ORDER_CANCEL}) public void closeOrder(Long orderId, Message message, Channel channel) { try { //1.处理业务 if (orderId != null) { log.info("【订单微服务】关闭订单消息:{}", orderId); //1.1 根据订单ID查询订单状态 状态如果是未支付:将订单状态改为关闭 OrderInfo orderInfo = orderInfoService.getById(orderId); if (orderId != null && OrderStatus.UNPAID.name().equals(orderInfo.getOrderStatus()) && OrderStatus.UNPAID.name().equals(orderInfo.getProcessStatus())) { //2.判断交易记录是否存在 PaymentInfo paymentInfo = paymentFeignClient.getPaymentInfo(orderId); if (paymentInfo != null) { //2.1 产生本地交易记录 要进行关闭 //2.2.发送关闭本地交易记录消息到MQ 通知支付微服务关闭本地交易记录 rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE, MqConst.ROUTING_PAYMENT_CLOSE, orderId); //3.查询支付宝交易记录是否关闭 Boolean flag = paymentFeignClient.checkPayment(orderId); if(flag){ //3.1 支付宝交易以及产生 需要关闭 paymentFeignClient.closePay(orderId); }else{ //3.2 支付宝交易没有产生 或者 以及关闭 } } //1.2 修改订单状态 orderInfoService.execExpiredOrder(orderId); } } //2.手动应答 channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } catch (IOException e) { e.printStackTrace(); log.error("【订单微服务】关闭订单业务异常:{}", e); } } ```