一文带你学会微信V3版本下单支付、退款、关单流程代码实操

目录

开篇介绍

一、微信支付-Maven依赖加入和代码参数准备

二、商户私钥证书代码读取

三、微信订单支付系列接口URL配置

四、快速验证统一下单接口

五、查询订单支付状态验证

六、关闭订单状态验证

七、微信支付-SDK自动完成支付签名流程解读 

 八、微信支付的退款注意事项

九、微信支付退款验证

​​十、查询退款结果


开篇介绍:

        本文介绍微信支付中的Native支付方式,版本是APIv3,其中Native和JSAPI的区别如下
Native支付:商家在系统中按微信支付协议生成支付二维码,用户扫码拉起微信收银台,确认并完成付款
JSAPI支付:商家张贴收款码物料,用户打开扫一扫,扫码后输入金额,完成付款
以下博文没有掺杂过多业务逻辑,对象数据都是固定写的,方便将注意力集中在微信支付的接口使用上。正式对接到项目里面,只需要改动支付的部分业务参数即可。

微信支付的文档还是很详细的,建议多看几遍,以下博文也都是根据官方文档的描述来操作的。

注意:微信支付个人无法对接操作,需要有公司商户账号,一般开发过程中是产品经理或者相关负责人提供。

微信支付接入指引 - 微信支付商户平台微信支付接入指引介绍了线下场所、公众号、小程序、PC网站、APP、企业微信等经营场景如何快速开通微信支付,实现商家在各类交易场景中用微信支付快速收款的需求。https://pay.weixin.qq.com/static/applyment_guide/applyment_index.shtml

一、微信支付-Maven依赖加入和代码参数准备

第一步application.properties:

#商户号
pay.wechat.mch-id=160164xxxx
#公众号id 需要和商户号绑定
pay.wechat.wx-pay-appid=wx5beac15xxxxx
#商户证书序列号,需要和证书对应
pay.wechat.mch-serial-no=7064ADC5FE84CA2A3Dxxxxxxxx
#api密钥
pay.wechat.api-v3-key=peYcTwRF581UOdaUqoxxxxxxx


#商户私钥路径(微信服务端会根据证书序列号,找到证书获取公钥进行解密数据)
pay.wechat.private-key-path=classpath:/cert/apiclient_key.pem
#支付成功页面跳转
pay.wechat.success-return-url=https://baidu.com
#支付成功,回调通知
pay.wechat.callback-url=http://api.xxx.com/shop-server/api/callback/order/v1/wechat

第二步:证书配置加入

 第三步:

Maven依赖加入
    微信支付API v3的Apache HttpClient扩展,实现了请求签名的生成和应答签名的验证。
    使用说明 https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient

 <!--微信支付扩展包-->
<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-apache-httpclient</artifactId>
    <version>0.3.0</version>
</dependency>

 第四步 第一步骤的配置读取:

package net.wnn.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "pay.wechat")
public class WechatPayConfig {

    /**
     * 商户号
     */
    private String mchId;

    /**
     * 公众号id 需要和商户号绑定
     */
    private String wxPayAppid;
    /**
     * 商户证书序列号,需要和证书对应
     */
    private String mchSerialNo;
    /**
     * API V3密钥
     */
    private String apiV3Key;
    /**
     * 商户私钥路径(微信服务端会根据证书序列号,找到证书获取公钥进行解密数据)
     */
    private String privateKeyPath;
    /**
     * 支付成功页面跳转
     */
    private String successReturnUrl;

    /**
     * 支付成功,回调通知
     */
    private String callbackUrl;



}

二、商户私钥证书代码读取

java加载商户证书私钥 以下部分内容来自微信支付文档样例
    https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient
    商户申请商户API证书时,会生成商户私钥,并保存在本地证书文件夹的文件apiclient_key.pem中
    商户开发者可以使用方法PemUtil.loadPrivateKey()加载证书

文档中样例:

# 示例:私钥存储在文件
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
        new FileInputStream("/path/to/apiclient_key.pem"));


# 示例:私钥为String字符串
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
        new ByteArrayInputStream(privateKey.getBytes("utf-8")));
 

代码加载读取秘钥/定时获取微信签名验证器/获取http请求对象,会自动的处理签名和验签:

package net.wnn.config;

import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.stream.Collectors;

@Configuration
@Slf4j
public class PayBeanConfig {

    @Autowired
    private WechatPayConfig payConfig;

    /**
     * 加载秘钥
     *
     * @return
     * @throws IOException
     */
    public PrivateKey getPrivateKey() throws IOException {
        InputStream inputStream = new ClassPathResource(payConfig.getPrivateKeyPath()
                .replace("classpath:", "")).getInputStream();

        String content = new BufferedReader(new InputStreamReader(inputStream))
                .lines().collect(Collectors.joining(System.lineSeparator()));

        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");
            KeyFactory kf = KeyFactory.getInstance("RSA");

            PrivateKey finalPrivateKey = kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));

            return finalPrivateKey;

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }


    /**
     * 定时获取微信签名验证器,自动获取微信平台证书(证书里面包括微信平台公钥)
     *
     * @return
     */
    @Bean
    public ScheduledUpdateCertificatesVerifier getCertificatesVerifier() throws IOException {

        // 使用定时更新的签名验证器,不需要传入证书
        ScheduledUpdateCertificatesVerifier verifier = null;
            verifier = new ScheduledUpdateCertificatesVerifier(
                    new WechatPay2Credentials(payConfig.getMchId(),
                            new PrivateKeySigner(payConfig.getMchSerialNo(),
                                    getPrivateKey())),
                    payConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));

        return verifier;
    }


    /**
     * 获取http请求对象,会自动的处理签名和验签,
     * 并进行证书自动更新
     *
     * @return
     */
    @Bean("wechatPayClient")
    public CloseableHttpClient getWechatPayClient(ScheduledUpdateCertificatesVerifier verifier) throws IOException {
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(payConfig.getMchId(),payConfig.getMchSerialNo() , getPrivateKey())
                .withValidator(new WechatPay2Validator(verifier));

        // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
        CloseableHttpClient httpClient = builder.build();

        return httpClient;
    }



}

三、微信订单支付系列接口URL配置

package net.wnn.config;

public class WechatPayApi {
    /**
     * 微信支付主机地址
     */
    public static final String HOST = "https://api.mch.weixin.qq.com";


    /**
     * Native下单
     */
    public static final String NATIVE_ORDER = HOST+ "/v3/pay/transactions/native";



    /**
     * Native订单状态查询, 根据商户订单号查询
     */
    public static final String NATIVE_QUERY = HOST+ "/v3/pay/transactions/out-trade-no/%s?mchid=%s";


    /**
     * 关闭订单接口
     */
    public static final String NATIVE_CLOSE_ORDER = HOST+ "/v3/pay/transactions/out-trade-no/%s/close";



    /**
     * 申请退款接口
     */
    public static final String NATIVE_REFUND_ORDER = HOST+ "/v3/refund/domestic/refunds";
    /**
     * 退款状态查询接口
     */
    public static final String NATIVE_REFUND_QUERY = HOST+ "/v3/refund/domestic/refunds/%s";

}

四、快速验证统一下单接口

验证下单测试方法:

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.wnn.ShopApplication;
import net.wnn.config.PayBeanConfig;
import net.wnn.config.WechatPayApi;
import net.wnn.config.WechatPayConfig;
import net.wnn.util.CommonUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShopApplication.class)

@Slf4j
public class WechatPayTest {

    @Autowired
    private PayBeanConfig payBeanConfig;

    @Autowired
    private WechatPayConfig payConfig;

    @Autowired
    private CloseableHttpClient wechatPayClient;

    

    /**
     * 快速验证统一下单接口
     * @throws IOException
     */
    @Test
    public void testNativeOrder() throws IOException {

        String outTradeNo = CommonUtil.getStringNumRandom(32);

        /**
         * {
         * 	"mchid": "1900006XXX",
         * 	"out_trade_no": "native12177525012014070332333",
         * 	"appid": "wxdace645e0bc2cXXX",
         * 	"description": "Image形象店",
         * 	"notify_url": "https://weixin.qq.com/",
         * 	"amount": {
         * 		"total": 1,
         * 		"currency": "CNY"
         *        }
         * }
         */
        JSONObject payObj = new JSONObject();
        payObj.put("mchid",payConfig.getMchId());
        payObj.put("out_trade_no",outTradeNo);
        payObj.put("appid",payConfig.getWxPayAppid());
        payObj.put("description","王师傅的红包");
        payObj.put("notify_url",payConfig.getCallbackUrl());

        //订单总金额,单位为分。
        JSONObject amountObj = new JSONObject();
        amountObj.put("total",100);
        amountObj.put("currency","CNY");

        payObj.put("amount",amountObj);
        //附属参数,可以用在回调
        payObj.put("attach","{\"accountNo\":"+888+"}");


        String body = payObj.toJSONString();

        log.info("请求参数:{}",body);

        StringEntity entity = new StringEntity(body,"utf-8");
        entity.setContentType("application/json");

        HttpPost httpPost = new HttpPost(WechatPayApi.NATIVE_ORDER);
        httpPost.setHeader("Accept","application/json");
        httpPost.setEntity(entity);

        try(CloseableHttpResponse response = wechatPayClient.execute(httpPost)){

            //响应码
            int statusCode = response.getStatusLine().getStatusCode();
            //响应体
            String responseStr = EntityUtils.toString(response.getEntity());

            log.info("下单响应码:{},响应体:{}",statusCode,responseStr);

        }catch (Exception e){
            e.printStackTrace();
        }
    }




}

下单参数:

请求参数:{"amount":{"total":100,"currency":"CNY"},"mchid":"1601644*****","out_trade_no":"CikYMPk*****QILoJ4Ts3mjDA",

"appid":"wx5beac15ca20******","description":"王师傅的红包","attach":"{\"accountNo\":888}","notify_url":"http://api.*****.com/shop-server/api/callback/order/v1/wechat"}

下单返回结果:

下单响应码:200,响应体:{"code_url":"weixin://wxpay/bizpayurl?pr=JGRuZXAzz"}

返回的code_url是一个二维码地址,后端自测可以直接打开cli.im网址可以进入草料二维码页面,复制code_url右侧会出现二维码图像,打开手机微信扫一扫就能看到金额标题等信息。正式环境对接的时候前端有对应js获取后端返回code_url后展示支付二维码。

手机微信扫码后的结果:二维码有效时间2小时

 这样就完成下单支付的验证啦

五、查询订单支付状态验证

查询订单测试方法:

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.wnn.ShopApplication;
import net.wnn.config.PayBeanConfig;
import net.wnn.config.WechatPayApi;
import net.wnn.config.WechatPayConfig;
import net.wnn.util.CommonUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShopApplication.class)

@Slf4j
public class WechatPayTest {

    @Autowired
    private PayBeanConfig payBeanConfig;

    @Autowired
    private WechatPayConfig payConfig;

    @Autowired
    private CloseableHttpClient wechatPayClient;



    /**
     * 根据商户号订单号查询订单支付状态
     * 未支付的情况下返回的是如下json
     * {"amount":{"payer_currency":"CNY","total":100},"appid":"wx5beacxxxxx",
     * "mchid":"160164xxxx","out_trade_no":"fRAv2Ccpd8xxxxxx",
     * "promotion_detail":[],"scene_info":{"device_id":""},
     * "trade_state":"NOTPAY","trade_state_desc":"订单未支付"}
     *
     * @throws IOException
     */
    @Test
    public void testNativeQuery() throws IOException {

        String outTradeNo = "CikYMPkEmRPQILoJ4Ts3xxxxxx";
        String url = String.format(WechatPayApi.NATIVE_QUERY,outTradeNo,payConfig.getMchId());
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept","application/json");
        try(CloseableHttpResponse response = wechatPayClient.execute(httpGet)){

            //响应码
            int statusCode = response.getStatusLine().getStatusCode();
            //响应体
            String responseStr = EntityUtils.toString(response.getEntity());

            log.info("查询响应码:{},响应体:{}",statusCode,responseStr);

        }catch (Exception e){
            e.printStackTrace();
        }

    }
  }

 查询订单微信返回接口信息:

查询响应码:200,响应体:{"amount":{"currency":"CNY","payer_currency":"CNY","payer_total":100,"total":100},"appid":"wx5beac15caxxxxx",
"attach":"{\"accountNo\":888}","bank_type":"OTHERS","mchid":"1601x","outxxxx_trade_no":"CikYMPkEmRPQIxxxxxx",
"payer":{"openid":"oiNKG04YwwLSlcW_xxxxxx"},"promotion_detail":[],"success_time":"2022-02-15T22:00:35+08:00",
"trade_state":"SUCCESS","trade_state_desc":"支付成功","trade_type":"NATIVE","transaction_id":"420000139920220xxxxx"}

六、关闭订单状态验证

关闭订单测试方法:

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.wnn.ShopApplication;
import net.wnn.config.PayBeanConfig;
import net.wnn.config.WechatPayApi;
import net.wnn.config.WechatPayConfig;
import net.wnn.util.CommonUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShopApplication.class)

@Slf4j
public class WechatPayTest {

    @Autowired
    private PayBeanConfig payBeanConfig;

    @Autowired
    private WechatPayConfig payConfig;

    @Autowired
    private CloseableHttpClient wechatPayClient;

    @Test
    public void testNativeCloseOrder() throws IOException {
        String outTradeNo = "2p9tZ05bve1ZcdfcgZxxxx";
        JSONObject payObj = new JSONObject();
        payObj.put("mchid",payConfig.getMchId());
        String body = payObj.toJSONString();

        log.info("请求参数:{}",body);
        //将请求参数设置到请求对象中
        StringEntity entity = new StringEntity(body,"utf-8");
        entity.setContentType("application/json");

        String url = String.format(WechatPayApi.NATIVE_CLOSE_ORDER,outTradeNo);
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Accept","application/json");
        httpPost.setEntity(entity);

        try(CloseableHttpResponse response = wechatPayClient.execute(httpPost)){
            //响应码
            int statusCode = response.getStatusLine().getStatusCode();
            log.info("关闭订单响应码:{},无响应体",statusCode);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

关闭订单测试方法返回 结果:

 请求参数:{"mchid":"16016xxxx"}
2022-02-15 22:16:44.085  INFO 91680 --- [           main] WechatPayTest                            : 关闭订单响应码:204,无响应体

再次使用商户订单号查询订单状态:

已成功关闭啦

查询响应码:200,响应体:{"appid":"wx5beac1xxxx","attach":"{\"accountNo\":888}","mchid":"1601644xxxx","out_trade_no":"2p9tZ05bve1Zcxxxx","payer":{},"promotion_detail":[],"trade_state":"CLOSED","trade_state_desc":"订单已关闭"}

七、微信支付-SDK自动完成支付签名流程解读 

微信支付过程中包含签名验证等过程,在V3版本当中是SDK自动完成支付签名的验证操作,详情查看以下文档,本博客以下单验证接口为例子,截取部分构造签名串和设置http头信息的日志表明自动支付签名的过程。

微信支付签名规则文档
    https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml

构造签名串日志

 设置Http头

 日志输出:

 八、微信支付的退款注意事项

1、交易时间超过一年的订单无法提交退款

2、微信支付退款支持单笔交易分多次退款(不超50次),多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号

3、错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次

4、每个支付订单的部分退款次数不能超过50次

5、如果同一个用户有多笔退款,建议分不同批次进行退款,避免并发退款导致退款失败

6、申请退款接口的返回仅代表业务的受理情况,具体退款是否成功,需要通过退款查询接口获取结果

7、一个月之前的订单申请退款频率限制为:5000/min

8、同一笔订单多次退款的请求需相隔1分钟

九、微信支付退款验证

退款验证代码:

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.wnn.ShopApplication;
import net.wnn.config.PayBeanConfig;
import net.wnn.config.WechatPayApi;
import net.wnn.config.WechatPayConfig;
import net.wnn.util.CommonUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShopApplication.class)

@Slf4j
public class WechatPayTest {

    @Autowired
    private PayBeanConfig payBeanConfig;

    @Autowired
    private WechatPayConfig payConfig;

    @Autowired
    private CloseableHttpClient wechatPayClient;


    /**
    * 订单退款操作
     * @throws IOException
     */
    @Test
    public void testNativeRefundOrder() throws IOException {

        String outTradeNo = "CikYMPkEmRPQILoxxxxxxxxxx";
        String refundNo = CommonUtil.getStringNumRandom(32);

        // 请求body参数
        JSONObject refundObj = new JSONObject();
        //订单号
        refundObj.put("out_trade_no", outTradeNo);
        //退款单编号,商户系统内部的退款单号,商户系统内部唯一,
        // 只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔
        refundObj.put("out_refund_no", refundNo);
        refundObj.put("reason","商品已售完");
        refundObj.put("notify_url", payConfig.getCallbackUrl());

        JSONObject amountObj = new JSONObject();
        //退款金额
        amountObj.put("refund", 10);
        //实际支付的总金额
        amountObj.put("total", 100);
        amountObj.put("currency", "CNY");

        refundObj.put("amount", amountObj);


        String body = refundObj.toJSONString();

        log.info("请求参数:{}",body);

        StringEntity entity = new StringEntity(body,"utf-8");
        entity.setContentType("application/json");

        HttpPost httpPost = new HttpPost(WechatPayApi.NATIVE_REFUND_ORDER);
        httpPost.setHeader("Accept","application/json");
        httpPost.setEntity(entity);

        try(CloseableHttpResponse response = wechatPayClient.execute(httpPost)){

            //响应码
            int statusCode = response.getStatusLine().getStatusCode();
            //响应体
            String responseStr = EntityUtils.toString(response.getEntity());

            log.info("申请订单退款响应码:{},响应体:{}",statusCode,responseStr);

        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

退款验证请求参数:

请求参数:{"reason":"商品已售完","amount":{"total":100,"currency":"CNY","refund":10},"out_trade_no":"CikYMPkEmRPQxxx","out_refund_no":"jKgEPCt3GtWSTsxxxx","notify_url":"http://api.open1024.com/shop-server/api/callback/order/v1/wechat"}
 

退款返回结果:

申请订单退款响应码:200,响应体:{"amount":{"currency":"CNY","discount_refund":0,"from":[],"payer_refund":10,"payer_total":100,"refund":10,"settlement_refund":10,"settlement_total":100,"total":100},"channel":"ORIGINAL","create_time":"2022-02-15T22:51:14+08:00","funds_account":"AVAILABLE","out_refund_no":"jKgEPCt3GtWSTsxxxxxxxx","oxxxut_trade_no":"CikYMPkEmRPQILxxxx","promotion_detail":[],"refund_id":"5030220093202xxxxxxxx","status":"PROCESSING","transaction_id":"420000139920xxxx","user_receivexxxd_account":"支付用户零钱"}
 

十、查询退款结果

怎么知道退款结果呢?微信回调通知和主动查询,本博客介绍主动查询

 查询退款验证方法:

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.wnn.ShopApplication;
import net.wnn.config.PayBeanConfig;
import net.wnn.config.WechatPayApi;
import net.wnn.config.WechatPayConfig;
import net.wnn.util.CommonUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShopApplication.class)

@Slf4j
public class WechatPayTest {

    @Autowired
    private PayBeanConfig payBeanConfig;

    @Autowired
    private WechatPayConfig payConfig;

    @Autowired
    private CloseableHttpClient wechatPayClient;

    /**
     查询退款结果
     *      * @throws IOException
     */
    @Test
    public void testNativeRefundQuery() throws IOException {


        String refundNo = "jKgEPCt3GtWSTssEqzFBbUDVgM235WKY";

        String url = String.format(WechatPayApi.NATIVE_REFUND_QUERY,refundNo);
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept","application/json");

        try(CloseableHttpResponse response = wechatPayClient.execute(httpGet)){

            //响应码
            int statusCode = response.getStatusLine().getStatusCode();
            //响应体
            String responseStr = EntityUtils.toString(response.getEntity());

            log.info("查询订单退款 响应码:{},响应体:{}",statusCode,responseStr);

        }catch (Exception e){
            e.printStackTrace();
        }



    }

查询退款返回结果:

查询订单退款 响应码:200,响应体:{"amount":{"currency":"CNY","discount_refund":0,"from":[],"payer_refund":10,"payer_total":100,"refund":10,"settlement_refund":10,"settlement_total":100,"total":100},"channel":"ORIGINAL","create_time":"2022-02-15T22:51:14+08:00","funds_account":"AVAILABLE","out_refund_no":"jKgEPCt3GtWSTssxxxx","out_trade_no":"CikYMPkEmRPQILoJ4Txxxx","promotion_detail":[],"refund_id":"50302200932022xxxxx","status":"SUCCESS","success_time":"2022-02-15T22:51:21+08:00","transaction_id":"42000013992022xxxx","user_received_account":"支付用户零钱"}

        到这微信Native支付方式的下单、查询、退款、关单操作就通过测试工具类验证完成啦,以上内容没有掺杂过多业务逻辑,对象数据都是固定写的,方便将注意力集中在微信支付的接口使用中。正式对接到项目里面,只需要改动支付的部分业务参数即可。

整合进实际项目中,加了业务逻辑和设计模式的微信支付,也就是以上内容的续集,看下下面这篇博文即可。

微信V3版本支付下单、查询支付订单状态、订单退款接入正式项目中并引入策略模式实操_8年开发工作经验的老王,积极分享工作中遇到的问题~-CSDN博客

微信回调+验签流程

微信支付V3版本回调+验签流程_8年开发工作经验的老王,积极分享工作中遇到的问题~-CSDN博客回调验签流程介绍 官方文档 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_5.shtml https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml注意: 同样的通知可能会多次发送给商户系统,商户系统必须能够正确处理重复的通知 确保回调URL是外部可正常访问的,且不能携带后缀参数https://blog.csdn.net/wnn654321/article/details/123298162

  • 41
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 26
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值