微信支付V3(商户)》批量转账到零钱
微信支付V3版本,微信SDK,内部封装了部分方法,参照着官方Demo,下载地址:
GitHub - wechatpay-apiv3/wechatpay-apache-httpclient: 微信支付 APIv3 Apache HttpClient装饰器(decorator)
1. 引入微信SDK依赖
<dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.3.0</version>
</dependency><!--另外需要使用到的依赖-->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.6.6</version>
</dependency>
2. 下载微信支付平台证书
构造微信接口通讯Client,构造隐私数据加密公钥,每次调用微信V3的接口都需要用Client来发起,敏感数据需通过平台公钥加密。下载他们的jar包去获取平台公钥。
下载地址在这里:
GitHub - wechatpay-apiv3/CertificateDownloader: Java 微信支付 APIv3 平台证书的命令行下载工具
具体的配置方法,在文档地址里面都有说明,需要详细阅读,按照步骤操作即可。
以下参数都需要从微信商户后台获取或设置:
mchId:商户号(例如:1161161166)
mchSerialNo:商户证书序列号(例如:3A936D302300073457C8B22CB1111DAA1111DDDD)
mchPrivateKeyFilePath:商户证书私钥地址(例如:E:\wechat\apiclient_key.pem)
apiV3key:商户API V3密钥(例如:4a9f2c433adcc2698ba7704faedeaf82)MD5加密生成密钥在微信商户后台设置
outputFilePath:保存下载微信支付平台证书文件地址(例如:E:\wechat)
下载证书文件解压后得到 apiclient_cert.p12,apiclient_cert.pem(公钥),apiclient_key.pem(私钥)
我执行jar包的命令:
java -jar CertificateDownloader.jar -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath}
完整的执行命令为:
java -jar CertificateDownloader.jar -k 4a9f2c433adcc2698ba7704faedeaf82 -m 1161161166 -f E:\wechat\apiclient_key.pem -s 3A936D302300073457C8B22CB1111DAA1111DDDD -o E:\wechat
获取后,保存下来平台公钥、平台公钥序列号,可多次使用。
例如下载文件为:E:\wechat\wechatpay_61A8BC31485A8BD61CAC935EDEB9D5F0CF6EEEEE.pem
平台公钥:wechatpay_61A8BC31485A8BD61CAC935EDEB9D5F0CF6EEEEE.pem 后续改名为 wechatpay.pem
平台公钥序列号:61A8BC31485A8BD61CAC935EDEB9D5F0CF6EEEEE
期间遇到问题参考文献【下载微信支付平台证书及首次下载报错处理】
下面是构造微信Client的代码:
package Util;import cn.hutool.core.io.FileUtil;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.impl.client.CloseableHttpClient;import java.io.File;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;/*** @Author jakori* @Date 2022/07/20 10:00*/
public class WeChatClient {/*** 微信通讯client* @return CloseableHttpClient */public static CloseableHttpClient getClient() {/**商户私钥文件*/File mchPrivateKeyFile = new File("E:\\wechat\\apiclient_key.pem");InputStream mchPrivateKeyInputStream = FileUtil.getInputStream(mchPrivateKeyFile);/**微信平台公钥文件*/File platformKeyFile = new File("E:\\wechat\\wechatpay.pem");InputStream platformKeyInputStream = FileUtil.getInputStream(platformKeyFile);PrivateKey mchPrivateKey = PemUtil.loadPrivateKey(mchPrivateKeyInputStream);WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant("商户号", "商户证书序列号", mchPrivateKey).withWechatPay(Arrays.asList(PemUtil.loadCertificate(platformKeyInputStream)));CloseableHttpClient httpClient = builder.build();return httpClient;}/*** 微信敏感数据加密公钥* @return*/public static X509Certificate getSaveCertificates() {/**商户公钥证书文件*/File mchPublicKeyFile = new File("E:\\wechat\\apiclient_cert.pem");InputStream mchPublicKeyInputStream = FileUtil.getInputStream(mchPublicKeyFile);return PemUtil.loadCertificate(mchPublicKeyInputStream);}}
3. 发起批量转账API
前置:
1、需用户与小程序绑定,获取用户的openId;
2、也需在特约商户后台,服务商后台绑定对应的小程序的appId。
具体步骤可以参考:
商家商户号与AppID账号关联管理
绑定成功后,即可用调用接口,
微信接口说明地址:开发文档-微信支付批量转账到零钱
代码如下:
import Util.WeChatClient;
import cn.hutool.json.JSONUtil;
import com.wechat.pay.contrib.apache.httpclient.util.RsaCryptoUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
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 javax.crypto.IllegalBlockSizeException;
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import static org.apache.http.HttpHeaders.ACCEPT;
import static org.apache.http.HttpHeaders.CONTENT_TYPE;
import static org.apache.http.entity.ContentType.APPLICATION_JSON;/*** @Author zkinghao* @Date 2022/1/11 14:19*/
public class TestBatch {/*** 发起批量转账API** @Author jakori* @Date 2022/07/20 10:00*/public static void batchPay() throws IllegalBlockSizeException, IOException {CloseableHttpClient httpClient = WeChatClient.getClient();X509Certificate x509Certificate = WeChatClient.getSaveCertificates();Map<String, Object> map = new HashMap<>();map.put("appid", "服务商的appid");map.put("out_batch_no", "batch01");map.put("batch_name", "测试3");map.put("batch_remark", "批次备注出款");map.put("total_amount", 50);map.put("total_num", 1);List<Map> list = new ArrayList<>();Map<String, Object> subMap = new HashMap<>(4);subMap.put("out_detail_no", "detail01");subMap.put("transfer_amount", 50);subMap.put("transfer_remark", "明细备注1");subMap.put("openid", "收款用户openid");//明细转账金额 >= 2000,收款用户姓名必填//subMap.put("user_name", RsaCryptoUtil.encryptOAEP("收款用户姓名", x509Certificate));list.add(subMap);map.put("transfer_detail_list", list);String body = JSONUtil.toJsonStr(map);System.out.println("请求参数:" + body);HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/transfer/batches");httpPost.addHeader(ACCEPT, APPLICATION_JSON.toString());httpPost.addHeader(CONTENT_TYPE, APPLICATION_JSON.toString());httpPost.addHeader("Wechatpay-Serial", "商户证书序列号");httpPost.setEntity(new StringEntity(body, "UTF-8"));CloseableHttpResponse response = httpClient.execute(httpPost);try {String bodyAsString = EntityUtils.toString(response.getEntity());System.out.println("返回参数:" + bodyAsString);} finally {response.close();}}public static void main(String[] args) throws Exception {/**发起批量转账API*/batchPay();}
}
3. 商家明细单号查询明细单API
微信接口说明地址:开发文档-微信支付批量转账到零钱
代码如下:
import Util.WeChatClient;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;import java.io.IOException;
import java.net.URISyntaxException;import static org.apache.http.HttpHeaders.ACCEPT;
import static org.apache.http.entity.ContentType.APPLICATION_JSON;/*** @Author jakori* @Date 2022/07/20 10:00*/
public class TestQueryBatch {public static final Integer SUCCESS_CODE = 200;/*** 商家明细单号查询明细单API* @throws URISyntaxException* @throws IOException*/public static void queryBatch() throws URISyntaxException, IOException {CloseableHttpClient httpClient = WeChatClient.getClient();//批次号String batchCode = "batch01";//明细号String detailCode = "detail01";StringBuilder url = new StringBuilder("https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/");url.append(batchCode).append("?need_query_detail=true").append("&detail_status=ALL");URIBuilder uriBuilder = new URIBuilder(url.toString());HttpGet httpGet = new HttpGet(uriBuilder.build());httpGet.addHeader(ACCEPT, APPLICATION_JSON.toString());CloseableHttpResponse response = httpClient.execute(httpGet);try {String bodyAsString = EntityUtils.toString(response.getEntity());System.out.println("微信支付查询返回:" + bodyAsString);JSONObject jsonObject = JSONUtil.parseObj(bodyAsString);if (SUCCESS_CODE.equals(response.getStatusLine().getStatusCode())) {//转账批次单基本信息JSONObject transferBatch = jsonObject.getJSONObject("transfer_batch");//批次状态String batchStatus = transferBatch.getStr("batch_status");System.out.println("交易状态:" + batchStatus);//已完成if ("FINISHED".equals(batchStatus)){JSONArray transferDetailList = jsonObject.getJSONArray("transfer_detail_list");for (int i = 0; i < transferDetailList.size(); i++){JSONObject detail = (JSONObject) transferDetailList.get(i);//明细单号String outDetailNo = detail.getStr("out_detail_no");//明细状态String detailStatus = detail.getStr("detail_status");System.out.println("交易明细单号:"+ outDetailNo +",明细状态:" + detailStatus);}}else if ("CLOSED".equals(batchStatus)){//批次关闭原因String closeReason = transferBatch.getStr("close_reason");System.out.println("交易关闭原因:" + closeReason);}} else {//失败}} finally {response.close();}}public static void main(String[] args) throws Exception {/**商家明细单号查询明细单API*/queryBatch();}
}
参考文献:微信支付API V3版本JAVA开发指南