微信支付V3版本,微信SDK,内部封装了部分方法,参照着官方Demo,下载地址:
GitHub - wechatpay-apiv3/wechatpay-apache-httpclient: 微信支付 APIv3 Apache HttpClient装饰器(decorator)
<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>
构造微信接口通讯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);
}
}
前置:
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();
}
}
微信接口说明地址:开发文档-微信支付批量转账到零钱
代码如下:
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开发指南