第15章-支付之后业务处理.md 28 KB

第15章-支付成功后续业务&取消关闭订单业务

学习目标:

  • 完成支付成功后续业务处理
    • 订单状态修改
    • 对接库存系统扣减库存
    • 订单拆单
  • 完成订单关闭后续业务处理
    • 修改订单状态
    • 关闭本地交易记录
    • 关闭支付宝交易记录

1、支付成功处理

1.1 更改订单状态

订单支付成功后,我们已经更改了订单支付记录状态,接下来我还有更改订单状态,因为他们是不同的微服务模块,所以我们采用消息队列的方式,保证数据最终一致性

1.1.1 在MqConst常量类添加变量

/**
 * 订单支付
 */
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 中添加依赖和配置

<dependency>
    <groupId>com.atguigu.gmall</groupId>
    <artifactId>rabbit-util</artifactId>
    <version>1.0</version>
</dependency>

1.1.3 支付成功发送消息

service-payment模块com.atguigu.gmall.payment.service.impl.PaymentInfoServiceImpl#paySuccess方法

@Autowired
private RabbitService rabbitService;

/**
 * 修改本地交易记录状态
 *
 * @param outTradeNo  订单编号
 * @param paymentType 支付方式
 * @param paramsMap   支付宝回调参数
 */
@Override
public void paySuccess(String outTradeNo, String paymentType, Map<String, String> paramsMap) {
    //1.修改本地支付表状态为已支付
    LambdaUpdateWrapper<PaymentInfo> 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类添加方法

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 订单模块发送减库存通知

订单模块除了接收到请求改变单据状态,还要发送库存系统

查看看《库存管理系统接口手册》中【减库存的消息队列消费端接口】中的描述,组织相应的消息数据进行传递。

1.1.1 OrderService接口

/**
 * 发送扣减库存消息到MQ 通知 仓库系统
 * 消息格式JSON字符串包含什么数据?查询订单订单明细
 *
 * @param orderId
 */
void sendDeductStockMsg(Long orderId);


/**
 * 将订单订单明细转为Map 后续该方法被复用
 * @param orderInfo
 * @return
 */
Map initWareOrder(OrderInfo orderInfo);

1.1.2 编写实现类

/**
 * 发送扣减库存消息到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<String, Object> 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<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
    if (!CollectionUtils.isEmpty(orderDetailList)) {
        List<HashMap<String, Object>> orderDetailMapList = orderDetailList.stream().map(orderDetail -> {
            HashMap<String, Object> 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

/**
 * 监听到库存系统扣减库存结果,修改订单状态
 *
 * @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

order:
  split:
    url: http://localhost:8204/api/order/orderSplit

1.3.2 拆单接口控制器

/**
 * 库存系统发起拆单请求
 * 参数采用表单方式提交
 * @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 订单实现拆单接口

/**
 * 完成拆分订单业务
 * @param orderId
 * @param wareSkuMap
 * @return
 */
String orderSplit(Long orderId, String wareSkuMapStr);

1.3.4 拆单接口实现类

/**
 * 拆分订单处理
 * 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<OrderInfo> allSubOrderInfoList = new ArrayList<>();
    //1.根据订单ID查询原始订单以及订单明细
    OrderInfo orderInfoOrigin = this.getOrderInfo(orderId);
    //原始订单中所有订单商品明细
    List<OrderDetail> orderDetailOriginList = orderInfoOrigin.getOrderDetailList();
    //2.根据提交仓库跟SKU对应关系,构建新子订单以及订单明细并保存
    //将得到的字符串转为List集合
    List<Map> 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<String> skuIds = (List<String>) skuWareMap.get("skuIds");
            //使用Stream流式变成进行对集合数据过滤
            List<OrderDetail> 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<Map> collect = allSubOrderInfoList.stream().map(orderInfo -> {
        Map map = initWareOrder(orderInfo);
        return map;
    }).collect(Collectors.toList());

    return JSON.toJSONString(collect);
}

2、超时订单业务补充

2.1 在MqConst中添加常量

/**
 * 关闭交易
 */
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方法,发送消息

/**
 * 监听关闭订单消息:将订单关闭;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 编写消费者

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

/**
 * 修改本地交易记录状态为关闭
 * @param orderId
 */
void closePayment(Long orderId);

/**
 * 根据订单Id支付方式查询本地交易记录
 * @param orderId
 * @param paymentType
 * @return
 */
PaymentInfo getPaymentInfo(Long orderId, String paymentType);

PaymentInfoServiceImpl

/**
 * 修改本地交易记录状态为关闭
 *
 * @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<PaymentInfo> 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

/**
 * 根据订单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接口

/***
 * 关闭交易
 * @param orderId
 * @return
 */
Boolean closePay(Long orderId);

2.4.3 编写实现类

AlipayServiceImpl

/**
 * 根据订单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

/**
 * 查看是否有交易记录
 * @param orderId
 * @return
 */
@GetMapping("checkPayment/{orderId}")
public Boolean checkPayment(@PathVariable Long orderId){
    // 调用退款接口
    boolean flag = alipayService.checkPayment(orderId);
    return flag;
}

2.5.1 编写接口

AlipayService

/**
 * 根据订单查询交易是否关闭
 * @param orderId
 * @return
 */
Boolean checkPayment(Long orderId);

2.5.2 编写实现类

AlipayServiceImpl

/**
 * 查看是否有交易记录状态
 *
 * @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 数据接口

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

PaymentFeignClient 远程调用API Feign接口

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);

}

服务降级类

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项目中添加依赖

<dependency>
    <groupId>com.atguigu.gmall</groupId>
    <artifactId>service-payment-client</artifactId>
    <version>1.0</version>
</dependency>

2.6.4 OrderReceiver 整合代码

修改订单监听器:OrderReceiver中监听关闭订单消息

@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);
    }
}