支付框架 ElegentPay学习

1. 支付框架 ElegentPay

1.1 知识预研-第三方支付官网

微信支付官网:https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml

支付宝支付官网:https://opendocs.alipay.com/open/194/106078?ref=api

1.2 支付框架ElegentPay快速入门

ElegentPay是封装了支付宝和微信支付的支付组件,该组件具有以下特点:

  1. 为支付宝和微信提供了统一的调用入口。
  2. 支持native支付、小程序支付、H5 、APP 等多种支付方式,并提供统一入口。
  3. 提供了统一的dto类作为前端的调用参数,并且只有5个参数,用户使用简便。
  4. 提供了扩展机制,用户可以自定义其它的支付方式。
  5. 对支付回调提供了幂等性校验。
  6. 提供了回调补偿功能。

阅读支付框架ElegentPay的readme文档,运行elegentPayDemo。

1.3 内网穿透-cpolar

内网穿透就是可以将本地运行的资源映射为一个临时域名, 别人可以通过互联网访问这个域名,以此来实现被调用的目的.

我们推荐使用内网穿透工具cpolar 极点云 (https://www.cpolar.com/) (资源提供【项目资料/开发工具】)

(1)注册账号 注册后选择免费套餐即可

(2)连接帐户,在命令行模式下输入

cpolar authtoken XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

密钥部分登录cpolar查看

(3)端口映射,在命令行模式下输入

cpolar http 要映射的端口

在这里插入图片描述
(4)更改配置文件,将回调地址修改为穿透的地址。

1.4 项目应用 ElegentPay

1.4.1 下单支付
集成elegentPay

(1)订单微服务的pom.xml 添加依赖

<dependency>
    <groupId>cn.elegent</groupId>
    <artifactId>elegent-pay</artifactId>
    <version>1.0.0</version>
</dependency>

(2)订单微服务配置文件添加以下内容:

  pay:
    wxpay:
      mchId: 1561414331
      appId: 自己的appId
      appSecret: 自己的appSecret
      mchSerialNo: 自己的mchSerialNo
      apiV3Key: 自己的apiV3Key
    alipay:
      appId: 自己的appId
    callback:
      domain: 自己的cpolar映射地址
      watch: false
      cycle: 10 

(3)添加支付宝公钥私钥和微信私钥文件(内容从支付平台获取)

编写代码

(1)订单微服务OrderController新增方法,调用创建订单逻辑,发起支付请求。

@Autowired
private OrderService orderService;

@Autowired
private ElegentPay elegentPay;


/**
 * 支付
 * @param payVO
 * @return
 */
@PostMapping("/requestPay/{tradeType}/{platform}")
public PayResponse requestPay(@RequestBody PayVO payVO,@PathVariable("tradeType") String tradeType,@PathVariable("platform") String platform){
    var orderEntity = orderService.createOrder(payVO,platform);//创建订单
    //封装支付请求对象调用支付
    var param=new PayRequest();
    param.setBody(orderEntity.getSkuName());//商品名称
    param.setOrderSn(orderEntity.getOrderNo());//订单编号
    param.setTotalFee(orderEntity.getAmount().intValue());//订单金额
    param.setOpenid(payVO.getOpenId());//openid
    return elegentPay.requestPay(param, tradeType, platform);
}

(2)在订单微服务新建支付回调类CallBackServiceImpl,实现CallBackService接口的successPay(支付成功的回调)、failPay(支付失败的回调)和isSuccessPay(是否修改完支付状态)方法。其余4个方法,我们先不实现。

/**
 * 支付回调类
 */
@Service
@Slf4j
public class CallBackServiceImpl implements CallBackService {

    @Autowired
    private OrderService orderService;

    /**
     * 订单成功支付的逻辑
     * @param orderSn
     */
    @Override
    public void successPay(String orderSn) {
        log.info("支付成功回调{}",orderSn);
        var orderEntity = orderService.getByOrderNo(orderSn);  //查询订单
        if(orderEntity!=null){
            orderEntity.setStatus(OrderStatus.ORDER_STATUS_PAYED);//支付成功
            orderEntity.setPayStatus(PayStatus.PAY_STATUS_PAYED);//支付成功
            orderService.updateById(orderEntity);//保存
            //todo: 发货
        }
    }

    /**
     * 支付失败日志记录
     * @param orderSn
     */
    @Override
    public void failPay(String orderSn) {
        log.info("支付失败回调!"+orderSn);
    }

    /**
     * 需要查询订单状态为已支付返回true
     * @param orderSn
     * @return
     */
    @Override
    public boolean isSuccessPay(String orderSn) {
        var orderEntity = orderService.getByOrderNo(orderSn);
        if( orderEntity!=null  && orderEntity.getPayStatus()==OrderStatus.ORDER_STATUS_PAYED){
            return true;
        }else {
            return false;
        }
    }

    /**
     * 修改订单状态为退款完成
     * @param orderSn
     */
    @Override
    public void successRefund(String orderSn) {
    }

    /**
     * 退款失败打日志记录--修改状态为已支付
     * @param orderSn
     */
    @Override
    public void failRefund(String orderSn) {
    }

    /**
     * 查询订单状态是否为退款完成
     * @param orderSn
     * @return
     */
    @Override
    public boolean isSuccessRefund(String orderSn) {
        return false;
    }

    /**
     * 查询所有未支付订单
     * @return
     */
    @Override
    public List<WatchDTO> watchPayOrderSnList() {
        return null;
    }
}
内网穿透与屏幕端测试

(1)使用cpolar进行端口映射,在命令行模式下输入

cpolar http 9008

9008为订单微服务的端口。 更改订单微服务配置的微信支付回调地址为映射的临时域名地址

(2)启动订单微服务、售货机微服务和C端网关。

(3)测试 打开【资料\前端运行\屏幕端\screen.zip】

运行index.html 并指定售货机编号。

index.html?innerCode=A1000001
1.4.2 小程序获取openId
获取openId

OrderController的requestPay方法,除了可以为屏幕端提供下单支付,还可以为小程序端提供下单支付,其中的
param.setOpenid(payVO.getOpenId()); 一句在小程序调用时会用到,那么openid是什么呢? 其实就是微信用户在当前应用的唯一标识。而这个openid 前端是无法直接获取的,是需要后端提供给前端的。
在这里插入图片描述

当小程序启动后,小程序前端会先调用后端的一个接口来获取openid,而前端会提交一个叫jscode的参数过来。那个jscode是什么?其实是前端可以获取的一个临时凭证,在很短时间就会失效。前端可以使用这个临时凭证来换取openid这个永久凭证。那么后端拿到这个jscode,怎么得到openId呢?当然是通过微信平台获取,不过我们不用那么麻烦,因为ElegentPay框架为我们提供了一个方法可以获得openId

elegentPay.getOpenid(jsCode,"wxpay");

OrderController新增方法

/**
 * 获取openId
 * @param jsCode
 * @return
 */
@GetMapping("/openid/{jsCode}")
public String getOpenid(@PathVariable("jsCode")  String jsCode){
    return elegentPay.getOpenid(jsCode,"wxpay");
}
小程序唤醒支付

小程序唤醒支付,需要后端提供一些数据,详见微信支付官网文档:
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml
在这里插入图片描述

小程序测试

老师使用微信开发者工具打开小程序前端代码演示下单支付的过程。

学员因为没有开发者权限,无法进行测试,观看老师演示即可。

1.4.3 支付结果定期巡检

(1)修改订单微服务新建支付回调类CallBackServiceImpl,实现CallBackService接口的watchPayOrderSnList方法。在这个方法中,查询订单表中所有的未支付订单,封装为WatchDTO的列表返回。

/**
 * 查询所有未支付订单
 * @return
 */
@Override
public List<WatchDTO> watchPayOrderSnList() {
    var result = new ArrayList<WatchDTO>();
    var qw = new LambdaQueryWrapper<OrderEntity>();
    qw.eq(OrderEntity::getStatus,OrderStatus.ORDER_STATUS_CREATE); //订单状态为未支付
    var list = orderService.list(qw);
    for(OrderEntity  order : list) {
        var watchDTO = new WatchDTO();
        watchDTO.setOrderSn(order.getOrderNo());//订单编号
        watchDTO.setPlatform(order.getPayType());//平台
        result.add(watchDTO);
    }
    return result;
}

(2)修改配置文件watch为true

elegent:
  pay:
    .........
    callback:
      domain: https://2b02aa84.r2.vip.cpolar.cn 
      watch: true
      cycle: 10
1.4.4 退款回调与测试

(1)修改订单微服务新建支付回调类CallBackServiceImpl,实现CallBackService接口的successRefund方法、failRefund方法和isSuccessRefund方法。

/**
 * 修改订单状态为退款完成
 * @param orderSn
 */
@Override
public void successRefund(String orderSn) {
    log.info("退款成功回调{}",orderSn);
    var orderEntity = orderService.getByOrderNo(orderSn);
    if(orderEntity!=null) {
        orderEntity.setPayStatus(PayStatus.PAY_STATUS_REFUNDIED);//将状态设置退款成功
        orderService.updateById(orderEntity);
    }
}

/**
 * 退款失败打日志记录--修改状态为已支付
 * @param orderSn
 */
@Override
public void failRefund(String orderSn) {
    log.info("退款失败回调{}",orderSn);
    var orderEntity = orderService.getByOrderNo(orderSn);
    if(orderEntity!=null) {
        orderEntity.setPayStatus(PayStatus.PAY_STATUS_PAYED);  //将状态再改回支付成功
        orderService.updateById(orderEntity);
    }
}

/**
 * 查询订单状态是否为退款完成
 * @param orderSn
 * @return
 */
@Override
public boolean isSuccessRefund(String orderSn) {
    var orderEntity = orderService.getByOrderNo(orderSn);
    if(orderEntity!=null && orderEntity.getPayStatus()==PayStatus.PAY_STATUS_REFUNDIED){
        return true;
    }else {
        return false;
    }
}

(2)运行elegentPayDemo,在浏览器打地址测试退款

http://localhost:8080/wxpay/refund/订单号

1.5 原理解析

1.5.1 系统架构图

在这里插入图片描述
ElegentPay框架组成

统一外观接口:提供了供用户直接调用的,创建订单,退款,关单,等API。

第三方平台类加载器:类加载器在服务启动的时候会加载所有第三方支付策略集到内存。

第三方平台选择器:平台选择器会基于前端传入的参数判断当前支付是哪一家第三方机构并从类加载器中拿取对应的第三方策略。

第三方策略集:支持目前市面上主流的第三方支付(微信,支付宝),和对应的配置相关信息。

订单追踪器:订单创建的时候会创建一个跟踪器来追踪订单状态,由微服务主动轮询向第三方支付平台发起查询订单消息。

统一回调接口: 基于回调功能提供的所有回调功能的入口,用户需要自行实现

第三方回调入口:供第三方支付完成支付和退款时接受第三方消息通知的Controller

1.5.2 源码跟我学
第三方策略类加载

在这里插入图片描述

在项目启动的时候会根据交易平台接口获取所有的第三方交易平台策略

目的是在第三方支付平台类加载器ElegentTradeLoader中构建一个Map集合

Key是:第三方交易平台名称(wxpay,alipay)

/**
 * PlatformLoader
 * @description 第三方支付平台类加载器
 * 服务启动的时候自动加载第三方支付组件
 * @author WGL
 * @date 2022/11/17 0:20
*/
@Component
@Slf4j
public class ElegentTradeLoader implements ApplicationContextAware {

    private static Map<String, ElegentTrade> payStrategyMap = new HashMap<String,ElegentTrade>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Collection<ElegentTrade> payStrategyList = applicationContext.getBeansOfType(ElegentTrade.class).values();
        payStrategyList.stream().forEach(e->{
            //通过反射拿到类上的平台注解
            TradePlatform annotation = e.getClass().getAnnotation(TradePlatform.class);
            if (annotation != null) {
                payStrategyMap.put(annotation.value(), e);
            }
        });
    }

    /**
     * 根据平台id获取具体的第三方平台
     * @param platform 平台id
     * @return
     */
    public static ElegentTrade getElegentTrade(String platform){
        ElegentTrade elegentPayTemplate = payStrategyMap.get(platform);
        if(elegentPayTemplate!=null){
            return elegentPayTemplate;
        }else{
            throw new TradeException("未找到适配的交易类型,交易平台id:"+platform);
        }
    }
}

由于所有的第三方支付平台都含有一个@Service注解所以每一个支付平台实现类都会是一个Spring组件,并且都实现了ElegentTrade接口

WxpayElegentTrade.class

@Service
@TradePlatform(Platform.WX)
@Slf4j
public class WxpayElegentTrade implements ElegentTrade {
	//...
}

AlipayElegentTrade.class

@Service
@TradePlatform(Platform.ALI)
@Slf4j
public class AlipayElegentTrade implements ElegentTrade {
	//...
}

所以在项目启动的时候可以从Spring的上下文中获取所有是ElegentTrade的类,即拿到所有的第三方支付组件类

//从Spring容器里拿到所有第三方支付策略类
Collection<ElegentTrade> payStrategyList = applicationContext.getBeansOfType(ElegentTrade.class).values();

添加到第三方类加载器的内存的Map中,key是第三方平台名称,value是第三方交易平台策略

private static Map<String, ElegentTrade> payStrategyMap = new HashMap<String,ElegentTrade>();

//在这里拿到所有的第三方交易平台策略
payStrategyList.stream().forEach(e->{
            //通过反射拿到类上的平台注解
            TradePlatform annotation = e.getClass().getAnnotation(TradePlatform.class);
            if (annotation != null) {
                payStrategyMap.put(annotation.value(), e);
            }
        });
统一回调接口加载

当用户完成第三方支付以后和第三方完成退款之后,第三方支付平台会回调我们的微服务,这个过程需要我们暴露一个接口供第三方来进行调用,该接口是用来接收第三方处理通知的接口,而我们的ElegentPay提供了这样的一个Controller

调用关系图
在这里插入图片描述

默认提供的Controller

微信Controller

WxpayCallbackController.class

package cn.elegent.pay.strategys.wxpay;
/**
 * CallbackController
 * @description 系统默认提供的微信回调的Controller
 * @author WGL
 * @date 2022/11/16 18:05
*/
@RestController
@RequestMapping(WxpayConstant.DefaultMapping)
@Slf4j
public class WxpayCallbackController {

    @Autowired
    private ElegentPay elegentPay;

    @Autowired
    private CallBackService callBackService;

    /**
     * 系统提供的默认的微信回调的接口
     * @param httpEntity
     * @param response
     * @return
     */
    @RequestMapping(WxpayConstant.DefaultCallBack)
    public Map payCallBack(HttpEntity<String> httpEntity, HttpServletRequest request, HttpServletResponse response){

        try {
            ValidResponse validResponse = elegentPay.validPay(httpEntity, request, Platform.WX);
            String orderSn =validResponse.getOrderSn(); //订单号
            if(validResponse.isValid()){  //返回码成功
                log.info("用户成功支付,订单号为:"+orderSn);
                if(!callBackService.isSuccessPay(orderSn) ){
                    callBackService.successPay(validResponse.getOrderSn());
                }
                //返回成功消费
                return WxpayConstant.SUCCESS;
            }else{
                //微信返回的状态非正常
                if(!callBackService.isSuccessPay(orderSn) ){
                    callBackService.failPay(orderSn);
                }
                return WxpayConstant.FAIL;
            }
        }catch (Exception e){
            log.error("支付回调处理失败",e);
            //微信返回的状态非正常
            return WxpayConstant.FAIL;
        }
    }

    /**
     * 系统提供的默认的微信退款回调
     * @param httpEntity
     * @param response
     * @return
     */
    @RequestMapping(WxpayConstant.DefaultRefundCallBack)
    public Map refundCallBack(HttpEntity<String> httpEntity,HttpServletRequest httpServletRequest, HttpServletResponse response){

        try {
            ValidResponse validResponse = elegentPay.validRefund(httpEntity,httpServletRequest, Platform.WX);
            String orderSn = validResponse.getOrderSn();
            if(validResponse.isValid()){  //返回码成功
                log.info("用户退款成功,订单号为:"+orderSn);
                if(!callBackService.isSuccessRefund(orderSn) ){
                    callBackService.successRefund(validResponse.getOrderSn());
                }
                //返回成功消费
                return WxpayConstant.SUCCESS;
            }else{
                //微信返回的状态非正常
                if(!callBackService.isSuccessRefund(orderSn) ){
                    callBackService.failRefund(validResponse.getOrderSn());
                }
                return WxpayConstant.FAIL;
            }
        }catch (Exception e){
            log.error("支付回调处理失败",e);
            //微信返回的状态非正常
            return WxpayConstant.FAIL;
        }
    }
}

支付宝Controller

AlipayCallbackController.class

package cn.elegent.pay.strategys.alipay;

/**
 * CallbackController
 * @description 系统默认提供的微信回调的Controller
 * @author WGL
 * @date 2022/11/16 18:05
*/
@RestController
@RequestMapping(AlipayConstant.DefaultMapping)
@Slf4j
public class AlipayCallbackController {

    @Autowired
    private ElegentPay elegentPay;


    @Autowired
    private CallBackService callBackService;

    /**
     * 系统提供的默认的微信回调的接口
     * @param httpEntity
     * @param response
     * @return
     */
    @PostMapping(AlipayConstant.DefaultCallBack)
    public String payCallBack(HttpEntity<String> httpEntity, HttpServletRequest request, HttpServletResponse response){

        try {
            ValidResponse validResponse = elegentPay.validPay(httpEntity,request, Platform.ALI);
            String orderSn =validResponse.getOrderSn();
            if(validResponse.isValid()){  //返回码成功
                log.info("用户成功支付,订单号为:"+orderSn);
                if(!callBackService.isSuccessPay(orderSn) ){
                    callBackService.successPay(validResponse.getOrderSn());
                }
                //返回成功消费
                return AlipayConstant.SUCCESS;
            }else{
                //微信返回的状态非正常
                if(!callBackService.isSuccessPay(orderSn) ){
                    callBackService.failPay(orderSn);
                }
                return AlipayConstant.FAIL;
            }
        }catch (Exception e){
            log.error("支付回调处理失败",e);
            //微信返回的状态非正常
            return AlipayConstant.SUCCESS;
        }
    }

    /**
     * 系统提供的默认的微信退款回调
     * @param httpEntity
     * @param response
     * @return
     */
    @RequestMapping(AlipayConstant.DefaultRefundCallBack)
    public String refundCallBack(HttpEntity<String> httpEntity,HttpServletRequest httpServletRequest, HttpServletResponse response){

        try {
            ValidResponse validResponse = elegentPay.validRefund(httpEntity,httpServletRequest, Platform.ALI);
            String orderSn = validResponse.getOrderSn();
            if(validResponse.isValid()){  //返回码成功

                log.info("用户成功支付,订单号为:"+orderSn);
                if(!callBackService.isSuccessRefund(orderSn) ){
                    callBackService.successRefund(validResponse.getOrderSn());
                }
                //返回成功消费
                return AlipayConstant.SUCCESS;
            }else{
                //微信返回的状态非正常
                if(!callBackService.isSuccessRefund(orderSn) ){
                    callBackService.failRefund(validResponse.getOrderSn());
                }
                return AlipayConstant.FAIL;
            }
        }catch (Exception e){
            log.error("支付回调处理失败",e);
            //微信返回的状态非正常
            return AlipayConstant.FAIL;
        }
    }
}

这两个Controller是框架提供的,并集成了自动装配,用户只需要引入该框架这两个接口就已经默认提供好了,避免用户重复造轮子。

发起请求

用户只需要注入ElegentPay接口,调用其中的API即可完成与第三方的交互,如下所示:

@RestController
@RequestMapping("/wx")
public class WXController {

    @Autowired
    private ElegentPay elegentPay;

    /**
     * 创建订单
     * @return
     */
    @GetMapping("/createOrder")
    public PayResponse createOrder(){
        PayRequest payRequest = new PayRequest();
        payRequest.setTotalFee(1);
        payRequest.setOrderSn(System.currentTimeMillis()+"");
        payRequest.setBody("elegent-支付");
        PayResponse payResponse = elegentPay.requestPay(payRequest, TradeType.NATIVE,  Platform.WX);
        return payResponse;
    }
}

在这里插入图片描述

这个过程用户需要构建一个统一的支付的业务对象PayRequest,并将前端提供的平台名称和支付方式传递给统一接口ElegentPay

PayRequest.class

/**
 * PayRequest
 * @description 支付请求外观类
 * @author WGL
 * @date 2022/11/10 14:48
*/
@Data
public class PayRequest {

    private String body;//商品描述

    private String orderSn; //订单号

    private int totalFee; //订单金额

    private String openid;//用户id  (小程序的用户id)

}

统一模板ElegentPay,该接口提供了所有的第三方支付相关的API

/**
 * create by: wgl
 * desc: 支付策略
 */
public interface ElegentPay {
    /**
     * 统一下单接口
     * 该接口基于设计模式实现,对接了微信V3版支付代码和支付宝支付sdk
     * 业务编写人员仅仅只需要准备好请求参数调用该方法即可完成下单请求
     * @return 交易数据对象 包含有native支付的二维码+jsApi支付的支付组件
     */
    PayResponse requestPay(PayRequest payRequest,String tradeType,String platform) throws TradeException;

    /**
     * 支付结果通知校验
     * 该接口基于设计模式实现,对接了微信V3版支付代码和支付宝支付sdk
     * 业务编写人员在接收到微信或支付宝回调的时候可以使用该方法验证回调是否成功,是否是伪回调
     * @return 交易数据对象
     */
    ValidResponse validPay(HttpEntity<String> httpEntity, HttpServletRequest request, String platform) throws TradeException;

    /**
     * 退款结果通知校验
     * 该接口基于设计模式实现,对接了微信V3版支付代码和支付宝支付sdk
     * 业务编写人员在接收到微信或支付宝回调的时候可以使用该方法验证回调是否成功,是否是伪回调
     */
    ValidResponse validRefund(HttpEntity<String> httpEntity, HttpServletRequest request, String platform) throws TradeException;

    /**
     * 关闭订单
     * 该结构基于设计模式实现,对接了微信V3版支付代码和支付宝支付sdk
     * 业务编写人员在处理超时订单的时候需要 通知微信 由于是超时订单需要进行远程关闭
     */
    Boolean closePay(String orderSn, String platform) throws TradeException;

    /**
     * 退款
     * 该接口基于设计模式实现,对接了微信V3版支付代码和支付宝支付sdk
     * 业务编写人员在处理业务执行失败时需要进行退款
     */
    Boolean refund(RefundRequest refundRequest,String platform) throws TradeException;


    /**
     * 商户订单号查询 根据订单号查询订单
     * 该接口基于生成的订单号来进行订单的查询
     * 可以基于查询的结果判断用户订单是否支付成功
     */
    QueryResponse queryTradingOrderNo(String orderSn , String platform) throws TradeException;


    /**
     * 查询单笔退款API
     */
    QueryRefundResponse queryRefundTrading(String orderSn , String platform) throws TradeException;
}

这个时候我们是没有拿到具体的第三方的,再经过第三方平台选择器根据平台名称找到具体的第三方策略类来向第三方发送请求,由于在我们服务器启动的时候在第三方平台类加载器ElegentTradeLoader里已经加载了我们的第三方策略类到一个Map里key为平台名称,value是具体的第三方策略类,在我们的第三方选择器ElegentPayImpl里提供了一个获取第三方支付平台策略类的方法,该方法会基于前端传入的第三方平台名称获取第三方平台策略。

ElegentPayImpl.class

package cn.elegent.pay.core;

/**
 * ElegentPayImpl
 * @description 统一模板 在模板层进行第三方平台的选择
 * @author WGL
 * @date 2022/11/17 14:09
*/
@Component
public class ElegentPayImpl implements ElegentPay {

    /**
     * 统一下单接口
     * @param payRequest
     * @return
     */
    @Override
    public PayResponse requestPay(PayRequest payRequest,String tradeType,String platform) throws TradeException {
        //获取交易策略
        return  getPlatFormService(platform).createOrder(payRequest,tradeType);
    }

	//.....

    /**
     * 跟进具体内容获取实现类的方法
     * @param platForm
     * @return
     */
    private ElegentTrade getPlatFormService(String platForm) {
        return ElegentTradeLoader.getElegentTrade(platForm);
    }

}

拿到具体的第三方平台策略类之后向第三方平台发起请求

订单跟踪

在我们创建订单,或发起退款之后,这个过程已经就已经是C端用户和第三方直接的交互了,我们的系统是无法干预的,这个过程我们要想得到结果业界常用的处理方式一般有两种,一种是开启回调接口等待第三方支付平台回调,另一种就是开启轮询,周期性的主动询问第三方平台订单的状态。而我们的订单跟踪功能就是第二种又我们的业务系统主动询问第三方支付平台,订单是否完成,通过第三方支付平台返回的结果来判断订单是否完成(支付或退款)。
在这里插入图片描述

CallbackWatch.class

@Component
@ConditionalOnProperty(prefix = "elegent.pay.callback",name = "watch",havingValue = "true")
@Slf4j
public class CallbackWatch {

    @Autowired
    private CallBackService callBackService;

    @Autowired
    private CallBackConfig callBackConfig;

    @Autowired
    private ElegentPay elegentPay;

    @PostConstruct
    public void queryWatch(){
        log.info("开启支付结果定期巡检");
        Timer timer = new Timer();
        // 2、创建 TimerTask 任务线程
        TimerTask task=new TimerTask() {
            @Override
            public void run() {

            List<WatchDTO> watchDTOList = callBackService.watchPayOrderSnList();
            log.info("定期巡检,{}",watchDTOList);
            if(watchDTOList!=null && callBackConfig.getCycle()>0){
                for( WatchDTO watchDTO: watchDTOList ){
                    //查询订单是否支付成功
                    QueryResponse queryResponse = elegentPay.queryTradingOrderNo(watchDTO.getOrderSn(), watchDTO.getPlatform());
                    if("SUCCESS".equals(queryResponse.getTrade_state())){
                        //如果用户成功支付--调用支付成功的
                        if(!callBackService.isSuccessPay(queryResponse.getOrder_sn())){
                            callBackService.successPay(queryResponse.getOrder_sn());
                        }
                    }
                }
            }

            }
        };
        // 4、启动定时任务
        timer.schedule(task, callBackConfig.getCycle()*1000,callBackConfig.getCycle()*1000);
    }

}

这里我们ElegentPay框架默认提供了一种轮询实现策略,该策略是通过JDK提供的默认定时器Timer来进行订单状态查询的,会调用ElegentPay统一接口里的queryTradingOrderNo根据订单号查询订单的方法来进行订单的查询。我们需要用户先手动的开起这个功能,即在配置文件里加上elegent.pay.callback.watch为true,然后需要查询订单的时候需要实现watchPayOrderSnList()方法,返回所有需要查询的订单的订单号。

@Autowired
private CallBackService callBackService;

//....
//该方法需要返回所有的需要追踪的订单的订单号--该订单号需要用户来进行提供
List<WatchDTO> watchDTOList = callBackService.watchPayOrderSnList();

该watchPayOrderSnList方法需要用户自己来进行实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值