商家转账到零钱为商户提供同时向多个用户微信零钱转账的能力,具有高效、免费、快速到账、安全等优点。
微信账户平台API字典:发起商家转账API
示例
pom文件中引入
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.10</version>
</dependency>
代码
public String transferAccounts() {
// 商户号
String mchid = "商户号";
// 商户证书路径(在你本机测试时放你本机路径中的就可以)
Map<String, Object> postMap = new HashMap<>();
// 申请商户号的appid或商户号绑定的appid(企业号corpid即为此appid)
postMap.put("appid", "appid");
// 商家批次单号 长度 1~32
postMap.put("out_batch_no", IdUtil.getSnowflake(0, 0).nextIdStr());
// 该笔批量转账的名称
postMap.put("batch_name", "测试转账");
// 转账说明,UTF8编码,最多允许32个字符
postMap.put("batch_remark", "测试转账");
// 总金额 单位为“分”
postMap.put("total_amount", 10);
// 转账总笔数
postMap.put("total_num", 1);
// 转账明细列表
List<Map<String, Object>> list = new ArrayList<>();
// 转账明细
Map<String, Object> subMap = new HashMap<>(4);
// 商家批次单号
subMap.put("out_detail_no", IdUtil.getSnowflake(0, 0).nextIdStr());
// 转账金额
subMap.put("transfer_amount", 10);
// 转账备注
subMap.put("transfer_remark", "明细备注");
// 用户在直连商户应用下的用户标示
subMap.put("openid", "openid");
list.add(subMap);
postMap.put("transfer_detail_list", list);
// 发起转账操作
return postTransBatRequest(JSON.toJSONString(postMap), mchid);
}
/**
* 发起批量转账API 批量转账到零钱
* 证书下载地址:需要指到文件 例如:D:\XXX.pem
*
* @param requestJson 组合参数
* @param mchID4M 商户号
* @return String
*/
public static String postTransBatRequest(String requestJson, String mchID4M) {
try {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/transfer/batches");
// NOTE: 建议指定charset=utf-8。低于4.4.6版本的HttpCore,不能正确的设置字符集,可能导致签名错误
httpPost.addHeader("Content-Type", "application/json");
httpPost.addHeader("Accept", "application/json");
// 文档证书序列号
httpPost.addHeader("Wechatpay-Serial", "文档证书序列号");
// -------------------------核心认证 start-----------------------------------------------------------------
String strToken = getToken("POST",
"/v3/transfer/batches",
requestJson, mchID4M, "文档证书序列号", "证书下载地址");
// 添加认证信息
httpPost.addHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 " + strToken);
// ---------------------------核心认证 end---------------------------------------------------------------
httpPost.setEntity(new StringEntity(requestJson, "UTF-8"));
// 发起转账请求
CloseableHttpResponse response = httpclient.execute(httpPost);
// 获取返回的数据
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @param method 请求方法 post
* @param canonicalUrl 请求地址
* @param body 请求参数
* @param merchantId 这里用的商户号
* @param certSerialNo 商户证书序列号
* @param keyPath 商户证书地址
* @return String
*/
public static String getToken(String method, String canonicalUrl, String body, String merchantId,
String certSerialNo, String keyPath) throws Exception {
// 获取32位随机字符串
String nonceStr = getRandomString(32);
// 当前系统运行时间
long timestamp = System.currentTimeMillis() / 1000;
if (StringUtils.isEmpty(body)) body = "";
String message = method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
// 签名操作
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(getPrivateKey(keyPath));
sign.update(message.getBytes(StandardCharsets.UTF_8));
String signature = Base64.encodeBase64String(sign.sign());
// 组装参数
return "mchid=\"" + merchantId + "\",timestamp=\"" + timestamp + "\",nonce_str=\"" + nonceStr +
"\",serial_no=\"" + certSerialNo + "\",signature=\"" + signature + "\"";
}
/**
* 微信支付-前端唤起支付参数-获取商户私钥
*
* @param filename 私钥文件路径 (required)
* @return 私钥对象
*/
public static PrivateKey getPrivateKey(String filename) throws IOException {
String content = new String(Files.readAllBytes(Paths.get(filename)), StandardCharsets.UTF_8);
try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}
public static String getRandomString(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
常见错误
接口返回没有开通API支付之类的话,是因为微信商户平台没有打开API转账权限
开通方法:产品中心
-商家转账到零钱
-前往功能
,已开通如下图所示
接口返回当前ip没有权限访问接口之类的话,是因为ip没有添加白名单
IP百度可以查到,直接搜索IP即可
添加白名单方法:
产品中心
-商家转账到零钱
-前往功能
-接口安全 设置
-添加