一文带你学会微信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 {@Autowiredprivate 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*/@Beanpublic 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 {@Autowiredprivate PayBeanConfig payBeanConfig;@Autowiredprivate WechatPayConfig payConfig;@Autowiredprivate CloseableHttpClient wechatPayClient;/*** 快速验证统一下单接口* @throws IOException*/@Testpublic 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 {@Autowiredprivate PayBeanConfig payBeanConfig;@Autowiredprivate WechatPayConfig payConfig;@Autowiredprivate 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*/@Testpublic 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 {@Autowiredprivate PayBeanConfig payBeanConfig;@Autowiredprivate WechatPayConfig payConfig;@Autowiredprivate CloseableHttpClient wechatPayClient;@Testpublic 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 {@Autowiredprivate PayBeanConfig payBeanConfig;@Autowiredprivate WechatPayConfig payConfig;@Autowiredprivate CloseableHttpClient wechatPayClient;/*** 订单退款操作* @throws IOException*/@Testpublic 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 {@Autowiredprivate PayBeanConfig payBeanConfig;@Autowiredprivate WechatPayConfig payConfig;@Autowiredprivate CloseableHttpClient wechatPayClient;/**查询退款结果* * @throws IOException*/@Testpublic 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
一文带你学会微信V3版本下单支付、退款、关单流程代码实操相关推荐
- 10分钟带你学会微信小程序的反编译
以xxxxx小程序为例10分钟带你学会微信小程序的反编译 2019-11-28 12:59:26 以一个简单的例子介绍下小程序反编译操作流程 实验环境 前置准备 模拟器内软件安装 获取小程序包 开始解 ...
- 一文带你学会linux系统 史上最全linux命令大全
一文带你学会linux系统 史上最全linux命令大全 文章目录 linux系统简介 linux命令 1.启动网络命令 2.pwd命令 2.ls命令 3.cd命令 4.mkdir命令 5.rmdir命 ...
- 一文带你全面了解电商在线支付
本文由作者 书丰 发布于社区 在电商系统中,方便的在线支付功能大大推进了电商的发展,可以说没有在线支付的发展就没有今天发展完善的电商系统,本文就来讨论一下在线支付相关的内容. 01 网银支付 1. 什 ...
- java环境变量的配置_一文带你学会Java环境变量配置(小白向)
很多人初学Java的时候,因为Java环境变量的配置卡的心烦意乱. 又有很多人百度上翻来翻去,得到的答案五花八门,让你头晕眼花. 你肯定也在想,不就是个环境变量的配置吗?为什么搜了那么多答案,依然不能 ...
- 从原理到应用,一文带你了解微信小程序插件能力
3月13日,微信小程序插件功能上线:8月底,在时隔半年后,为进一步推广插件功能,微信在开发者社区上线了插件版块. 小程序插件是可以被开发者添加到小程序内直接使用的,能为用户提供具体服务的功能组件-- ...
- 一文带你学会java的jvm精华知识点
前言 本文分为20多个问题,通过问题的方式,来逐渐理解jvm,由浅及深.希望帮助到大家. Java类实例化时,JVM执行顺序? 正确的顺序如下: 1父类静态代码块 2父类静态变量 3子类静态代码块 3 ...
- 变现利器!一文带你学会应用内添加「贴片广告」
什么是贴片广告 贴片广告是一种在视频播放过程中插入的视频或图片广告.视频广告一般是15s, 可以点跳过按钮直接进入视频播放界面,也可以等广告展示结束自动进入视频播放界面. 贴片广告的优势 相较于其他形 ...
- 一文带你学会AB实验最佳流程
如果你对数据分析感兴趣,希望学习更多的方法论,希望听听经验分享, 欢迎移步公众号「小火龙说数据」,更多精彩原创文章与你分享! 「经验」带你掌握AB实验最佳流程https://mp.weixin.qq. ...
- python绘制饼状图图例_Python图表绘制很简单,一文带你学会如何生成带图例的饼图...
matplotlib库,作为Python数据可视化的常用库和经典库,咱们已经探讨了多次,并了解了内部多个函数的使用,上次咱们聊了如何在图表中添加各种样式的图例,今天呢,咱们接着上次的内容继续深入聊聊, ...
最新文章
- 搜索引擎ElasticSearchV5.4.2系列二之ElasticSearchV5.4.2+kibanaV5.4.2+x-packV5.4.2安装
- TCP服务端收到syn但是不回复syn ack问题分析
- Xen的内存布局及其启动
- django 业务逻辑写在view里吗?_Python Web框架Django简介
- 机器学习(一)梯度下降算法的实现及过程分析
- Java高并发入门-线程初步
- 【报告分享】2019年全球数字化风险调查报告-德勤.pdf(附下载链接)
- android.view.VelocityTracker
- 除了被动阅读,用户想要的更多
- python学习笔记-递归函数
- 一台机器安装两个LINUX系统的操作与经验
- LINUX 游戏服务器之旅1_SSH连接
- apex乱码_[请教]apex安装简体中文语言包的步骤
- 武汉大学计算机学院选考要求,武汉大学高考必选科目-考武汉大学需要选哪三科...
- mysql数据库迁移工具_MysqlToMsSql(数据库迁移工具)
- HDL4SE:软件工程师学习Verilog语言(七)
- 《刷新》读书笔记1-3章
- 3d打开无法下载star.php,下载的3dmax模型打开失败的原因及解决方法
- OR(odd ratios)
- WaWa的奇妙冒险(第二周集训自闭现场)
热门文章
- 用python生成和解析二维码
- 计算机配置怎么复制,怎么设置别人无法使用U盘复制你的电脑文件 防止拷贝操作方法...
- Parallels 16已可在支持Windows的M1 Mac上运行
- Cocos2d-x 3.2 大富翁游戏项目开发-第五部分 单机游戏-关卡选择ScrollView
- 如何将Excel文件中数据导入数据库
- oa审核费用到oracle,oa协同管理平台费用申请操作
- Java(十四)----Junit测试
- Acwing 2326:王者之剑(网格图之网络流 最大权独立集)
- var、let与const的区别
- 论文阅读-基于深度强化学习的方法解决多智能体防御和攻击问题