https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml#doc-main
首先引入微信官方的sdk包
- <dependency>
- <groupId>com.github.wechatpay-apiv3groupId>
- <artifactId>wechatpay-javaartifactId>
- <version>0.2.11version>
- dependency>
代码如下:
-
- import cn.hutool.core.util.RandomUtil;
- import cn.hutool.core.util.StrUtil;
- import com.deliyun.transfer.util.UUIDUtil;
- import com.deliyun.transfer.util.WechatPayConstant;
- import com.wechat.pay.java.core.Config;
- import com.wechat.pay.java.core.RSAAutoCertificateConfig;
- import com.wechat.pay.java.service.transferbatch.TransferBatchService;
- import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
- import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
- import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput;
-
- import java.util.ArrayList;
- import java.util.List;
-
- public class BatchTransfer {
-
- /**
- * 商户号
- */
- public static String merchantId = "1********";
- /**
- * 商户API私钥路径
- */
- public static String privateKeyPath = "F:apiclient_key.pem";
- /**
- * 商户证书序列号
- */
- public static String merchantSerialNumber = "3860*********************E7447";
- /**
- * 商户APIV3密钥
- */
- public static String apiV3Key = "V**********************************V";
- public static TransferBatchService service;
-
- public static void main(String[] args) {
-
- Config config = new RSAAutoCertificateConfig.Builder()
- .merchantId(merchantId)
- .privateKeyFromPath(privateKeyPath)
- .merchantSerialNumber(merchantSerialNumber)
- .apiV3Key(apiV3Key)
- .build();
- service = new TransferBatchService.Builder().config(config).build();
-
- String out_batch_no = RandomUtil.randomNumbers(10);
- out_batch_no = StrUtil.concat(true, "sc", out_batch_no);
-
- InitiateBatchTransferRequest initiateBatchTransferRequest = new InitiateBatchTransferRequest();
- initiateBatchTransferRequest.setAppid(WechatPayConstant.APP_ID);
- initiateBatchTransferRequest.setOutBatchNo(out_batch_no);
- initiateBatchTransferRequest.setBatchName("2019年1月深圳分部报销单");
- initiateBatchTransferRequest.setBatchRemark("2019年1月深圳分部报销单");
- initiateBatchTransferRequest.setTotalAmount(100l);
- initiateBatchTransferRequest.setTotalNum(1);
-
- List
transferDetailListList = new ArrayList<>(); - TransferDetailInput transferDetailInput = new TransferDetailInput();
- transferDetailInput.setOutDetailNo(UUIDUtil.getUUID());
- transferDetailInput.setTransferAmount(100l);
- transferDetailInput.setTransferRemark("2020年4月报销");
- transferDetailInput.setOpenid("o_***************************");
- // transferDetailInput.setUserName(
- // "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45");
- transferDetailListList.add(transferDetailInput);
- initiateBatchTransferRequest.setTransferDetailList(
- transferDetailListList);
- initiateBatchTransferRequest.setTransferSceneId("1000");
- InitiateBatchTransferResponse response =
- service.initiateBatchTransfer(initiateBatchTransferRequest);
- System.out.println(response);
- }
- }
协议对象
- public class Transfer {
- private String appid; // 直连商户的appid
-
- private String out_batch_no; // 商家批次单号
- private String batch_name = "分润红包"; // 该笔批量转账的名称:
- private String batch_remark = "分润红包"; // 转账说明,UTF8编码,最多允许32个字符
-
- private int total_amount; // 转账总金额:分
- private int total_num = 1; // 转账总笔数
-
- private List
transfer_detail_list; // 发起批量转账的明细列表,最多三千笔 -
- public Transfer(String appid, String out_batch_no, int total_amount, List
transfer_detail_list) { - this.appid = appid;
- this.out_batch_no = out_batch_no;
- this.total_amount = total_amount;
- this.transfer_detail_list = transfer_detail_list;
- }
-
- public String getAppid() {
- return appid;
- }
-
- public void setAppid(String appid) {
- this.appid = appid;
- }
-
- public String getOut_batch_no() {
- return out_batch_no;
- }
-
- public void setOut_batch_no(String out_batch_no) {
- this.out_batch_no = out_batch_no;
- }
-
- public String getBatch_name() {
- return batch_name;
- }
-
- public void setBatch_name(String batch_name) {
- this.batch_name = batch_name;
- }
-
- public String getBatch_remark() {
- return batch_remark;
- }
-
- public void setBatch_remark(String batch_remark) {
- this.batch_remark = batch_remark;
- }
-
- public int getTotal_amount() {
- return total_amount;
- }
-
- public void setTotal_amount(int total_amount) {
- this.total_amount = total_amount;
- }
-
- public int getTotal_num() {
- return total_num;
- }
-
- public void setTotal_num(int total_num) {
- this.total_num = total_num;
- }
-
- public List
getTransfer_detail_list() { - return transfer_detail_list;
- }
-
- public void setTransfer_detail_list(List
transfer_detail_list) { - this.transfer_detail_list = transfer_detail_list;
- }
-
- public static class TransferDetailList {
-
- private String out_detail_no = UUIDUtil.getUUID(); // 商户系统内部区分转账批次单下不同转账明细单的唯一标识,要求此参数只能由数字、大小写字母组成
- private int transfer_amount; // 转账金额单位为分
- private String transfer_remark = "分润红包"; //转账备注
- private String openid; // 用户在直连商户应用下的用户标示
-
- public TransferDetailList( int transfer_amount, String openid) {
- this.transfer_amount = transfer_amount;
- this.openid = openid;
- }
-
- public String getOut_detail_no() {
- return out_detail_no;
- }
-
- public void setOut_detail_no(String out_detail_no) {
- this.out_detail_no = out_detail_no;
- }
-
- public int getTransfer_amount() {
- return transfer_amount;
- }
-
- public void setTransfer_amount(int transfer_amount) {
- this.transfer_amount = transfer_amount;
- }
-
- public String getTransfer_remark() {
- return transfer_remark;
- }
-
- public void setTransfer_remark(String transfer_remark) {
- this.transfer_remark = transfer_remark;
- }
-
- public String getOpenid() {
- return openid;
- }
-
- public void setOpenid(String openid) {
- this.openid = openid;
- }
- }
- }
工具类 CertUtil.java
- public class CertUtil {
-
- public static String APICLIENT_KEY = "conf/cert/apiclient_key.pem";
- public static String APICLIENT_CERT = "conf/cert/apiclient_cert.pem";
-
- /**
- * 获取私钥。
- *
- * @return 私钥对象
- */
- public static PrivateKey getPrivateKey() throws IOException {
- InputStream instream = CertUtil.class.getClassLoader().getResourceAsStream(APICLIENT_KEY);
- String content = new String(ByteStreams.toByteArray(instream), StandardCharsets.UTF_8);
-
- // String content = new String(Files.readAllBytes(Paths.get(APICLIENT_KEY)), 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("无效的密钥格式");
- }
- }
-
- /**
- * 获取商户证书。
- *
- * @return X509证书
- */
- public static X509Certificate getCertificate() throws IOException {
- // InputStream fis = new FileInputStream(APICLIENT_CERT);
- InputStream fis = CertUtil.class.getClassLoader().getResourceAsStream(APICLIENT_CERT);
- ;
- try (BufferedInputStream bis = new BufferedInputStream(fis)) {
- CertificateFactory cf = CertificateFactory.getInstance("X509");
- X509Certificate cert = (X509Certificate) cf.generateCertificate(bis);
- cert.checkValidity();
- return cert;
- } catch (CertificateExpiredException e) {
- throw new RuntimeException("证书已过期", e);
- } catch (CertificateNotYetValidException e) {
- throw new RuntimeException("证书尚未生效", e);
- } catch (CertificateException e) {
- throw new RuntimeException("无效的证书文件", e);
- }
- }
-
- /**
- * 获取商户证书序列号
- *
- * @return
- * @throws IOException
- */
- public static String getSerialNo() throws IOException {
- X509Certificate certificate = getCertificate();
- return certificate.getSerialNumber().toString(16).toUpperCase();
- }
-
- public static void main(String[] args) {
- try {
- System.out.println(CertUtil.getCertificate());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
HttpUrl工具类
- public class HttpUrlUtil {
-
- public static String SCHEMA = "WECHATPAY2-SHA256-RSA2048";
- public static String merchantId = WechatPayConstant.MCH_ID; // 服务商
-
- public static String POST = "POST";
- public static String GET = "GET";
-
- public static String TRANSFER_URL = "https://api.mch.weixin.qq.com/v3/transfer/batches"; // 转账
-
- public static String postTransfer(String body) {
- String authorization = getToken(POST, TRANSFER_URL, body);
- String returnMsg = HttpRequest.post(TRANSFER_URL)
- .header("Authorization", authorization)
- .header("Wechatpay-Serial", WechatPayConstant.merchantSerialNumber)
- .body(body)
- .execute().body();
- JSONObject returnTransferInfo = JSON.parseObject(returnMsg);
- return returnTransferInfo.toJSONString();
- }
-
- /**
- * 获取加密串
- *
- * @param method
- * @param url
- * @param body
- * @return
- */
- public static String getToken(String method, String url, String body) {
- String nonceStr = UUIDUtil.getUUID();
- long timestamp = System.currentTimeMillis() / 1000;
- HttpUrl httpUrl = HttpUrl.parse(url);
- String message = buildMessage(method, httpUrl, timestamp, nonceStr, body);
- String signature = null;
- String certificateSerialNo = null;
- try {
- signature = sign(message.getBytes("utf-8"));
- certificateSerialNo = CertUtil.getSerialNo();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return SCHEMA + " mchid=\"" + merchantId + "\"," + "nonce_str=\"" + nonceStr + "\"," + "timestamp=\"" + timestamp + "\"," + "serial_no=\""
- + certificateSerialNo + "\"," + "signature=\"" + signature + "\"";
- }
-
- /**
- * 得到签名字符串
- */
- public static String sign(byte[] message) throws Exception {
- Signature sign = Signature.getInstance("SHA256withRSA");
- PrivateKey privateKey = CertUtil.getPrivateKey();
- sign.initSign(privateKey);
- sign.update(message);
- return Base64.getEncoder().encodeToString(sign.sign());
- }
-
- public static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
- String canonicalUrl = url.encodedPath();
- if (url.encodedQuery() != null) {
- canonicalUrl += "?" + url.encodedQuery();
- }
- return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
- }
UUID工具类
- public class UUIDUtil {
-
- public static String getUUID () {
- return UUID.randomUUID().toString().replace("-", "");
- }
-
- public static void main(String[] args) {
- System.out.println(UUIDUtil.getUUID());
- }
- }
常量类 WechatPayConstant.java
- public class WechatPayConstant {
-
- /**
- * appId
- */
- public static String APP_ID = "wx64************";
-
- /**
- * 商户号
- */
- public static String MCH_ID = "1***********";
-
- /**
- * API_V3密钥
- */
- public static String API_V3KEY = "V*****************************";
-
- /**
- * 证书序列号
- */
- public static String merchantSerialNumber = "************************************";
- }
转账业务类
- public class TransferService {
-
- public static void exe(String openId) {
-
- String out_batch_no = RandomUtil.randomNumbers(10);
- out_batch_no = StrUtil.concat(true, "sc", out_batch_no);
-
-
- int transfer_amount = 100;
- Transfer.TransferDetailList transferDetailList = new Transfer.TransferDetailList(transfer_amount, openId);
- List
list = new ArrayList<>(); - list.add(transferDetailList);
- Transfer transfer = new Transfer(WechatPayConstant.APP_ID, out_batch_no, transfer_amount, list);
- String str = HttpUrlUtil.postTransfer(JSONObject.toJSONString(transfer));
- System.out.println("转账结果返回:" + str);
- }
-
- public static void main(String[] args) {
-
- String openId = "o_F*******************************";
- TransferService.exe(openId);
- }
-
- }