• 微信转账到零钱2种实现方式,SDK和API对接


    微信官方文档地址

    https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml#doc-main

    第一种:SDK方式

    首先引入微信官方的sdk包

    1. <dependency>
    2. <groupId>com.github.wechatpay-apiv3groupId>
    3. <artifactId>wechatpay-javaartifactId>
    4. <version>0.2.11version>
    5. dependency>

    代码如下:

    1. import cn.hutool.core.util.RandomUtil;
    2. import cn.hutool.core.util.StrUtil;
    3. import com.deliyun.transfer.util.UUIDUtil;
    4. import com.deliyun.transfer.util.WechatPayConstant;
    5. import com.wechat.pay.java.core.Config;
    6. import com.wechat.pay.java.core.RSAAutoCertificateConfig;
    7. import com.wechat.pay.java.service.transferbatch.TransferBatchService;
    8. import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
    9. import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
    10. import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput;
    11. import java.util.ArrayList;
    12. import java.util.List;
    13. public class BatchTransfer {
    14. /**
    15. * 商户号
    16. */
    17. public static String merchantId = "1********";
    18. /**
    19. * 商户API私钥路径
    20. */
    21. public static String privateKeyPath = "F:apiclient_key.pem";
    22. /**
    23. * 商户证书序列号
    24. */
    25. public static String merchantSerialNumber = "3860*********************E7447";
    26. /**
    27. * 商户APIV3密钥
    28. */
    29. public static String apiV3Key = "V**********************************V";
    30. public static TransferBatchService service;
    31. public static void main(String[] args) {
    32. Config config = new RSAAutoCertificateConfig.Builder()
    33. .merchantId(merchantId)
    34. .privateKeyFromPath(privateKeyPath)
    35. .merchantSerialNumber(merchantSerialNumber)
    36. .apiV3Key(apiV3Key)
    37. .build();
    38. service = new TransferBatchService.Builder().config(config).build();
    39. String out_batch_no = RandomUtil.randomNumbers(10);
    40. out_batch_no = StrUtil.concat(true, "sc", out_batch_no);
    41. InitiateBatchTransferRequest initiateBatchTransferRequest = new InitiateBatchTransferRequest();
    42. initiateBatchTransferRequest.setAppid(WechatPayConstant.APP_ID);
    43. initiateBatchTransferRequest.setOutBatchNo(out_batch_no);
    44. initiateBatchTransferRequest.setBatchName("2019年1月深圳分部报销单");
    45. initiateBatchTransferRequest.setBatchRemark("2019年1月深圳分部报销单");
    46. initiateBatchTransferRequest.setTotalAmount(100l);
    47. initiateBatchTransferRequest.setTotalNum(1);
    48. List transferDetailListList = new ArrayList<>();
    49. TransferDetailInput transferDetailInput = new TransferDetailInput();
    50. transferDetailInput.setOutDetailNo(UUIDUtil.getUUID());
    51. transferDetailInput.setTransferAmount(100l);
    52. transferDetailInput.setTransferRemark("2020年4月报销");
    53. transferDetailInput.setOpenid("o_***************************");
    54. // transferDetailInput.setUserName(
    55. // "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45");
    56. transferDetailListList.add(transferDetailInput);
    57. initiateBatchTransferRequest.setTransferDetailList(
    58. transferDetailListList);
    59. initiateBatchTransferRequest.setTransferSceneId("1000");
    60. InitiateBatchTransferResponse response =
    61. service.initiateBatchTransfer(initiateBatchTransferRequest);
    62. System.out.println(response);
    63. }
    64. }

    第二种:API方式

    协议对象

    1. public class Transfer {
    2. private String appid; // 直连商户的appid
    3. private String out_batch_no; // 商家批次单号
    4. private String batch_name = "分润红包"; // 该笔批量转账的名称:
    5. private String batch_remark = "分润红包"; // 转账说明,UTF8编码,最多允许32个字符
    6. private int total_amount; // 转账总金额:分
    7. private int total_num = 1; // 转账总笔数
    8. private List transfer_detail_list; // 发起批量转账的明细列表,最多三千笔
    9. public Transfer(String appid, String out_batch_no, int total_amount, List transfer_detail_list) {
    10. this.appid = appid;
    11. this.out_batch_no = out_batch_no;
    12. this.total_amount = total_amount;
    13. this.transfer_detail_list = transfer_detail_list;
    14. }
    15. public String getAppid() {
    16. return appid;
    17. }
    18. public void setAppid(String appid) {
    19. this.appid = appid;
    20. }
    21. public String getOut_batch_no() {
    22. return out_batch_no;
    23. }
    24. public void setOut_batch_no(String out_batch_no) {
    25. this.out_batch_no = out_batch_no;
    26. }
    27. public String getBatch_name() {
    28. return batch_name;
    29. }
    30. public void setBatch_name(String batch_name) {
    31. this.batch_name = batch_name;
    32. }
    33. public String getBatch_remark() {
    34. return batch_remark;
    35. }
    36. public void setBatch_remark(String batch_remark) {
    37. this.batch_remark = batch_remark;
    38. }
    39. public int getTotal_amount() {
    40. return total_amount;
    41. }
    42. public void setTotal_amount(int total_amount) {
    43. this.total_amount = total_amount;
    44. }
    45. public int getTotal_num() {
    46. return total_num;
    47. }
    48. public void setTotal_num(int total_num) {
    49. this.total_num = total_num;
    50. }
    51. public List getTransfer_detail_list() {
    52. return transfer_detail_list;
    53. }
    54. public void setTransfer_detail_list(List transfer_detail_list) {
    55. this.transfer_detail_list = transfer_detail_list;
    56. }
    57. public static class TransferDetailList {
    58. private String out_detail_no = UUIDUtil.getUUID(); // 商户系统内部区分转账批次单下不同转账明细单的唯一标识,要求此参数只能由数字、大小写字母组成
    59. private int transfer_amount; // 转账金额单位为分
    60. private String transfer_remark = "分润红包"; //转账备注
    61. private String openid; // 用户在直连商户应用下的用户标示
    62. public TransferDetailList( int transfer_amount, String openid) {
    63. this.transfer_amount = transfer_amount;
    64. this.openid = openid;
    65. }
    66. public String getOut_detail_no() {
    67. return out_detail_no;
    68. }
    69. public void setOut_detail_no(String out_detail_no) {
    70. this.out_detail_no = out_detail_no;
    71. }
    72. public int getTransfer_amount() {
    73. return transfer_amount;
    74. }
    75. public void setTransfer_amount(int transfer_amount) {
    76. this.transfer_amount = transfer_amount;
    77. }
    78. public String getTransfer_remark() {
    79. return transfer_remark;
    80. }
    81. public void setTransfer_remark(String transfer_remark) {
    82. this.transfer_remark = transfer_remark;
    83. }
    84. public String getOpenid() {
    85. return openid;
    86. }
    87. public void setOpenid(String openid) {
    88. this.openid = openid;
    89. }
    90. }
    91. }

    工具类 CertUtil.java

    1. public class CertUtil {
    2. public static String APICLIENT_KEY = "conf/cert/apiclient_key.pem";
    3. public static String APICLIENT_CERT = "conf/cert/apiclient_cert.pem";
    4. /**
    5. * 获取私钥。
    6. *
    7. * @return 私钥对象
    8. */
    9. public static PrivateKey getPrivateKey() throws IOException {
    10. InputStream instream = CertUtil.class.getClassLoader().getResourceAsStream(APICLIENT_KEY);
    11. String content = new String(ByteStreams.toByteArray(instream), StandardCharsets.UTF_8);
    12. // String content = new String(Files.readAllBytes(Paths.get(APICLIENT_KEY)), StandardCharsets.UTF_8);
    13. try {
    14. String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");
    15. KeyFactory kf = KeyFactory.getInstance("RSA");
    16. return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)));
    17. } catch (NoSuchAlgorithmException e) {
    18. throw new RuntimeException("当前Java环境不支持RSA", e);
    19. } catch (InvalidKeySpecException e) {
    20. throw new RuntimeException("无效的密钥格式");
    21. }
    22. }
    23. /**
    24. * 获取商户证书。
    25. *
    26. * @return X509证书
    27. */
    28. public static X509Certificate getCertificate() throws IOException {
    29. // InputStream fis = new FileInputStream(APICLIENT_CERT);
    30. InputStream fis = CertUtil.class.getClassLoader().getResourceAsStream(APICLIENT_CERT);
    31. ;
    32. try (BufferedInputStream bis = new BufferedInputStream(fis)) {
    33. CertificateFactory cf = CertificateFactory.getInstance("X509");
    34. X509Certificate cert = (X509Certificate) cf.generateCertificate(bis);
    35. cert.checkValidity();
    36. return cert;
    37. } catch (CertificateExpiredException e) {
    38. throw new RuntimeException("证书已过期", e);
    39. } catch (CertificateNotYetValidException e) {
    40. throw new RuntimeException("证书尚未生效", e);
    41. } catch (CertificateException e) {
    42. throw new RuntimeException("无效的证书文件", e);
    43. }
    44. }
    45. /**
    46. * 获取商户证书序列号
    47. *
    48. * @return
    49. * @throws IOException
    50. */
    51. public static String getSerialNo() throws IOException {
    52. X509Certificate certificate = getCertificate();
    53. return certificate.getSerialNumber().toString(16).toUpperCase();
    54. }
    55. public static void main(String[] args) {
    56. try {
    57. System.out.println(CertUtil.getCertificate());
    58. } catch (Exception e) {
    59. e.printStackTrace();
    60. }
    61. }
    62. }

    HttpUrl工具类

    1. public class HttpUrlUtil {
    2. public static String SCHEMA = "WECHATPAY2-SHA256-RSA2048";
    3. public static String merchantId = WechatPayConstant.MCH_ID; // 服务商
    4. public static String POST = "POST";
    5. public static String GET = "GET";
    6. public static String TRANSFER_URL = "https://api.mch.weixin.qq.com/v3/transfer/batches"; // 转账
    7. public static String postTransfer(String body) {
    8. String authorization = getToken(POST, TRANSFER_URL, body);
    9. String returnMsg = HttpRequest.post(TRANSFER_URL)
    10. .header("Authorization", authorization)
    11. .header("Wechatpay-Serial", WechatPayConstant.merchantSerialNumber)
    12. .body(body)
    13. .execute().body();
    14. JSONObject returnTransferInfo = JSON.parseObject(returnMsg);
    15. return returnTransferInfo.toJSONString();
    16. }
    17. /**
    18. * 获取加密串
    19. *
    20. * @param method
    21. * @param url
    22. * @param body
    23. * @return
    24. */
    25. public static String getToken(String method, String url, String body) {
    26. String nonceStr = UUIDUtil.getUUID();
    27. long timestamp = System.currentTimeMillis() / 1000;
    28. HttpUrl httpUrl = HttpUrl.parse(url);
    29. String message = buildMessage(method, httpUrl, timestamp, nonceStr, body);
    30. String signature = null;
    31. String certificateSerialNo = null;
    32. try {
    33. signature = sign(message.getBytes("utf-8"));
    34. certificateSerialNo = CertUtil.getSerialNo();
    35. } catch (Exception e) {
    36. e.printStackTrace();
    37. }
    38. return SCHEMA + " mchid=\"" + merchantId + "\"," + "nonce_str=\"" + nonceStr + "\"," + "timestamp=\"" + timestamp + "\"," + "serial_no=\""
    39. + certificateSerialNo + "\"," + "signature=\"" + signature + "\"";
    40. }
    41. /**
    42. * 得到签名字符串
    43. */
    44. public static String sign(byte[] message) throws Exception {
    45. Signature sign = Signature.getInstance("SHA256withRSA");
    46. PrivateKey privateKey = CertUtil.getPrivateKey();
    47. sign.initSign(privateKey);
    48. sign.update(message);
    49. return Base64.getEncoder().encodeToString(sign.sign());
    50. }
    51. public static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
    52. String canonicalUrl = url.encodedPath();
    53. if (url.encodedQuery() != null) {
    54. canonicalUrl += "?" + url.encodedQuery();
    55. }
    56. return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
    57. }

    UUID工具类

    1. public class UUIDUtil {
    2. public static String getUUID () {
    3. return UUID.randomUUID().toString().replace("-", "");
    4. }
    5. public static void main(String[] args) {
    6. System.out.println(UUIDUtil.getUUID());
    7. }
    8. }

    常量类 WechatPayConstant.java

    1. public class WechatPayConstant {
    2. /**
    3. * appId
    4. */
    5. public static String APP_ID = "wx64************";
    6. /**
    7. * 商户号
    8. */
    9. public static String MCH_ID = "1***********";
    10. /**
    11. * API_V3密钥
    12. */
    13. public static String API_V3KEY = "V*****************************";
    14. /**
    15. * 证书序列号
    16. */
    17. public static String merchantSerialNumber = "************************************";
    18. }

    转账业务类

    1. public class TransferService {
    2. public static void exe(String openId) {
    3. String out_batch_no = RandomUtil.randomNumbers(10);
    4. out_batch_no = StrUtil.concat(true, "sc", out_batch_no);
    5. int transfer_amount = 100;
    6. Transfer.TransferDetailList transferDetailList = new Transfer.TransferDetailList(transfer_amount, openId);
    7. List list = new ArrayList<>();
    8. list.add(transferDetailList);
    9. Transfer transfer = new Transfer(WechatPayConstant.APP_ID, out_batch_no, transfer_amount, list);
    10. String str = HttpUrlUtil.postTransfer(JSONObject.toJSONString(transfer));
    11. System.out.println("转账结果返回:" + str);
    12. }
    13. public static void main(String[] args) {
    14. String openId = "o_F*******************************";
    15. TransferService.exe(openId);
    16. }
    17. }

  • 相关阅读:
    CentOS Docker 安装 & 常用命令
    Java发展简史
    【数据结构】二叉树
    SpringBoot、MyBatis、PostgreSQL储存JSON、对象等自定义TypeHandler
    Vue工程化中创建全局组件、extend创建组件、extends配置组件、异步组件
    你的 Sleep 服务会梦到服务网格外的 bookinfo 吗
    Python学习一:基本内容
    基于ssm+vue员工工资管理系统
    jvm的jshell,学生的工具
    【C+】C++11 —— 线程库
  • 原文地址:https://blog.csdn.net/tm7796/article/details/132735094