进入正题之前先吐槽一下微信官方文档吧!一开始在官网上下载了微信支付版本V3的Demo,下载下来基本上难以投入使用,要学会使用的话,就要去看源码,看文档,稍微错过一点就会有一大堆的坑等着你跳,相比之下,阿里的文档就简单易懂,而且官方的文档下载下来之后,稍微改下参数就可以run!!
正文:
批量转账到零钱(服务商)的接入示例:
(微信文档地址:开发文档-微信支付批量转账到零钱)
微信支付V3版本,微信SDK,内部封装了部分方法(微信支付API v3的Apache HttpClient扩展,实现了请求签名的生成和应答签名的验证。)
第一步:在项目中引入Maven
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.4.8</version>
</dependency>
1
2
3
4
5
6
第二步:构造微信接口通讯Client,构造隐私数据加密公钥,每次调用微信V3的接口都需要用Client来发起,敏感数据需通过平台公钥加密。
package cn.schoolgroup.config.until;
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 org.springframework.core.io.ClassPathResource;
import java.io.IOException;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;
/**
* @Author lulu
* @Date 2022/09/07
*/
public class WeChatClient {
/**
* 微信通讯client
* @return CloseableHttpClient
* 作者的文件都放在resour文件下的
*/
public static CloseableHttpClient getClient() throws IOException {
/**商户私钥文件*/
ClassPathResource classPathResource = new ClassPathResource("/cert/apiclient_key.pem");
InputStream mchPrivateKeyInputStream = classPathResource.getInputStream();
/**微信平台公钥文件*/
ClassPathResource classPathResource1 = new ClassPathResource("/cert/wechatpay_64124ADAF002CDEEBA0A58215D8572D270F2A854.pem");
InputStream platformKeyInputStream = classPathResource1.getInputStream();
PrivateKey mchPrivateKey = PemUtil.loadPrivateKey(mchPrivateKeyInputStream);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant("自己的商户号", "自己的商户证书序列号", mchPrivateKey)
.withWechatPay(Arrays.asList(PemUtil.loadCertificate(platformKeyInputStream)));
CloseableHttpClient httpClient = builder.build();
return httpClient;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
第三步:调起商家转账API
需要在《转账到用户零钱》产品的开发设置中,添加安全ip,接口才能访问
/**
* 发起商家转账API
*
* @Author lulu
* @Date 2022/07/09
*/
public static void merchantTransfers() throws IllegalBlockSizeException, IOException {
CloseableHttpClient httpClient = WeChatClient.getClient();
Map<String, Object> map = new HashMap<>();
map.put("appid", "小程序appid");
map.put("out_batch_no", "zcx04");
map.put("batch_name", "1元");
map.put("batch_remark", "1元");
map.put("total_amount", 100);
map.put("total_num", 1);
List<Map> list = new ArrayList<>();
Map<String, Object> subMap = new HashMap<>(4);
subMap.put("out_detail_no", "detail1");
subMap.put("transfer_amount", 100);
subMap.put("transfer_remark", "1元");
subMap.put("openid", "用户openid");
//明细转账金额 >= 2000,收款用户姓名必填
//subMap.put("user_name", RsaCryptoUtil.encryptOAEP("收款用户姓名", zcx));
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 result= EntityUtils.toString(response.getEntity());
System.out.println("返回参数:" + result);
//业务逻辑自己处理
} finally {
response.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
第四步:商家批次单号查询批次单API
/**
* 商家批次单号查询批次单API
* @throws URISyntaxException
* @throws IOException
*/
public static void queryBatch() throws URISyntaxException, IOException {
CloseableHttpClient httpClient = WeChatClient.getClient();
//批次号
String batchCode = "zcx03";
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 (AjaxResult.me().getCode().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();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
获取平台证书的方法
————————————————
版权声明:本文为CSDN博主「暴脾气_lulu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_49706389/article/details/126754921
联系客服