java 微信支付v3 —8.微信支付之退款成功回调

Posted 明天的明天 永远的永远 未知的一切 我与你一起承担 ??

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 微信支付v3 —8.微信支付之退款成功回调相关的知识,希望对你有一定的参考价值。

正文

还记得WxPayCallbackUtil回调接口工具类吗,当时是用于支付成功的回调,我们接下来向里面添加一个退款成功的回调方法,在添加前我们先来做一个准备操作。

退款返回数据对象

@Data
@Slf4j
public class WxchatCallbackRefundData 

    /**
     * 商户订单号
     */
    private String orderId;


    /**
     * 商户退款单号,out_refund_no
     */
    private String refundId;

    /**
     * 微信支付系统生成的订单号
     */
    private String transactionId;

    /**
     * 微信支付系统生成的退款订单号
     */
    private String transactionRefundId;

    /**
     * 退款渠道
     * ORIGINAL:原路退款
     * BALANCE:退回到余额
     * OTHER_BALANCE:原账户异常退到其他余额账户
     * OTHER_BANKCARD:原银行卡异常退到其他银行卡
     */
    private String 	channel;

    /**
     * 退款成功时间
     * 当前退款成功时才有此返回值
     */
    private Date successTime;

    /**
     * 退款状态
     * 退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
     * SUCCESS:退款成功
     * CLOSED:退款关闭
     * PROCESSING:退款处理中
     * ABNORMAL:退款异常
     */
    private String 	status;

    /**
     * 退款金额
     */
    private BigDecimal refundMoney;


    public Date getSuccessTime() 
        return successTime;
    

    public void setSuccessTime(String successTime) 
        // Hutool工具包的方法,自动识别一些常用格式的日期字符串
        this.successTime = DateUtil.parse(successTime);
    

 

退款业务处理接口

还记得之前订单支付的回调接口的回调函数吗?这是用来处理业务的,相对于订单支付,退款的处理要略微复杂些。如果用户是银行卡支付,但是此时银行卡冻结了,那么我们就需要特殊处理。

微信官方会返回给我一个字段status,我们不能指望项目组的成员使用此方式时,都会进行是否退款成功的判断,以及退款失败的业务处理,因此我们使用自定义接口来达到限制的目的。

/**
 * 退款处理接口,为了防止项目开发人员,不手动判断退款失败的情况
 * 退款失败:退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款
 */
public interface WechatRefundCallback 

    /**
     * 退款成功处理情况
     */
    void success(WxchatCallbackRefundData refundData);

    /**
     * 退款失败处理情况
     */
    void fail(WxchatCallbackRefundData refundData);

 

微信退款回调方法

我们来看微信回调工具类,添加的方法吧。

@Slf4j
public class WxPayCallbackUtil 

    /**
     * 微信支付申请退款回调方法
     *
     * @param verifier       证书
     * @param wxPayConfig    微信配置
     * @param refundCallback 回调方法,用于处理业务逻辑,包含退款成功处理于退款失败处理
     * @return json格式的string数据,直接返回给微信
     */
    public static String wxPayRefundCallback(HttpServletRequest request, HttpServletResponse response, Verifier verifier, WxPayConfig wxPayConfig, WechatRefundCallback refundCallback) 
        Gson gson = new Gson();

        // 1.处理通知参数
        final String body = HttpUtils.readData(request);
        HashMap<String, Object> bodyMap = gson.fromJson(body, HashMap.class);

        // 2.签名验证
        WechatPayValidatorForRequest wechatForRequest = new WechatPayValidatorForRequest(verifier, body, (String) bodyMap.get("id"));
        try 
            if (!wechatForRequest.validate(request)) 
                // 通知验签失败
                response.setStatus(500);
                final HashMap<String, Object> map = new HashMap<>();
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return gson.toJson(map);
            
         catch (IOException e) 
            e.printStackTrace();
        


        // 3.获取明文数据
        String plainText = decryptFromResource(bodyMap, wxPayConfig);
        HashMap<String, Object> plainTextMap = gson.fromJson(plainText, HashMap.class);
        log.info("退款plainTextMap:", plainTextMap);
        // 4.封装微信返回的数据
        WxchatCallbackRefundData refundData = getRefundCallbackData(plainTextMap);


        if ("SUCCESS".equals(refundData.getStatus())) 
            // 执行业务逻辑
            refundCallback.success(refundData);
         else 
            // 特殊情况退款失败业务处理,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款
            refundCallback.fail(refundData);
        

        // 5.成功应答
        response.setStatus(200);
        final HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", "SUCCESS");
        resultMap.put("message", "成功");
        return gson.toJson(resultMap);
    

    private static WxchatCallbackRefundData getRefundCallbackData(HashMap<String, Object> plainTextMap) 
        Gson gson = new Gson();
        WxchatCallbackRefundData refundData = new WxchatCallbackRefundData();
        String successTime = String.valueOf(plainTextMap.get("success_time"));
        if (StringUtils.isNoneBlank(successTime)) 
            refundData.setSuccessTime(successTime);
        
        refundData.setOrderId(String.valueOf(plainTextMap.get("out_trade_no")));
        refundData.setRefundId(String.valueOf(plainTextMap.get("out_refund_no")));
        refundData.setTransactionId(String.valueOf(plainTextMap.get("transaction_id")));
        refundData.setTransactionRefundId(String.valueOf(plainTextMap.get("refund_id")));
        refundData.setChannel(String.valueOf(plainTextMap.get("channel")));
        final String status = String.valueOf(plainTextMap.get("status"));
        refundData.setStatus(status);
        String amount = String.valueOf(plainTextMap.get("amount"));
        HashMap<String, Object> amountMap = gson.fromJson(amount, HashMap.class);
        String refundMoney = String.valueOf(amountMap.get("refund"));
        refundData.setRefundMoney(new BigDecimal(refundMoney).movePointLeft(2));
        log.info("refundData:", refundData);
        return refundData;
    


    /**
     * 对称解密
     */
    private static String decryptFromResource(HashMap<String, Object> bodyMap, WxPayConfig wxPayConfig) 
        // 通知数据
        Map<String, String> resourceMap = (Map) bodyMap.get("resource");
        // 数据密文
        String ciphertext = resourceMap.get("ciphertext");
        // 随机串
        String nonce = resourceMap.get("nonce");
        // 附加数据
        String associateData = resourceMap.get("associated_data");
        AesUtil aesUtil = new AesUtil(wxPayConfig.getKey().getBytes(StandardCharsets.UTF_8));
        try 
            return aesUtil.decryptToString(associateData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
         catch (GeneralSecurityException e) 
            e.printStackTrace();
            throw new DefaultException("解密失败");
        
    

 

使用方法

这里的使用方法,使用的不是函数式接口,这个用lambda是无法解决的,那么我们看看是怎样使用的吧。

@Autowired
private WxPayConfig wxPayConfig;

@Autowired
private CloseableHttpClient wxPayClient;

@Autowired
private Verifier verifier;

 

@ApiOperation("微信退款回调接口")
@PostMapping("/wx/refund/callback")
public String refundWechatCallback(HttpServletRequest request, HttpServletResponse response) 
    return WxPayCallbackUtil.wxPayRefundCallback(request, response, verifier, wxPayConfig, new WechatRefundCallback() 
        @Override
        public void success(WxchatCallbackRefundData refundData) 
            // TODO 退款成功的业务逻辑,例如更改订单状态为退款成功等
        

        @Override
        public void fail(WxchatCallbackRefundData refundData) 
            // TODO 特殊情况下退款失败业务处理,例如银行卡冻结需要人工退款,此时可以邮件或短信提醒管理员,并携带退款单号等关键信息
        
    );

 

 

 

————————————————————————————————

java微信支付v3系列——1.微信支付准备工作
java微信支付v3系列——2.微信支付基本配置
java微信支付v3系列——3.订单创建准备操作
java微信支付v3系列——4.创建订单的封装及使用
java微信支付v3系列——5.微信支付成功回调
java微信支付v3系列——6.微信支付查询订单API
java微信支付v3系列——7.微信支付之申请退款
java微信支付v3系列——8.微信支付之退款成功回调
java微信支付v3系列——9.微信支付之商家转账API
————————————————————————————————
版权声明:本文为CSDN博主「CV大魔王」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45740561/article/details/128402504

以上是关于java 微信支付v3 —8.微信支付之退款成功回调的主要内容,如果未能解决你的问题,请参考以下文章

微信支付——微信退款实战教程(Java版)

微信支付之退款

微信小程序支付开发之申请退款

小黑式烂代码之微信APP支付 + 退款(JAVA实现)

微信支付退款中发现的一个问题

微信支付之退款