Docking java implementation of V3 interface from wechat cash withdrawal to change
Recently, the project needs to realize the function of withdrawing cash to change with wechat, but it is found that the wechat payment interface has been upgraded to V3 version, which means that the previous general methods and SDK of wechat payment are not available, so it is necessary to re correspond to the SDK of v3. WeChat's docs have been very popular, and make complaints about them.
Wechat cash withdrawal is connected to the change V3 interface. I divide it into two tasks: 1. Wechat payment platform certificate download; 2. Wechat cash withdrawal to the change V3 interface.
Here are some key codes listed. For the complete code, please refer to the java implementation demo of docking from wechat cash withdrawal to change V3 interface.
Wechat platform payment certificate Download
Because the WeChat payment platform certificate is changing in real time, so we need to download and get the latest certificate every once in a while. This design is really wonderful, and I love the simplicity and friendliness of Alipay.
I use the regular program to download once every hour. After downloading, I save the latest wechat platform payment certificate number to the local database, as shown in the following code example (this code refers to the official wechat example code).
//Timed task @Component("wxpayCertDownTask") @Lazy(false) public class wxpayCertDownTask { @Autowired private ISysSetService sysSetService; private boolean isTest = Constant.PROGRAM_MODE; @Scheduled(cron = "${wechatpay.cert.down.task}") public void startWxpayCertDown() { CertificateDownloader downloader = new CertificateDownloader(); downloader.startDownWachatPayCert(); if (StringUtils.isNotEmpty(downloader.getWechatpayCertSerialNo())) { //... Omit some code System.out.println("---Wechat platform payment certificate serial number---:" + downloader.getWechatpayCertSerialNo()); sysSetService.updateSysSet(s);//Update and save the serial number of wechat platform payment certificate } } } //Definition of Downloader @Data public class CertificateDownloader { //Key for certificate decryption private String apiV3key; //Merchant number private String merchantId; //Merchant private key file private String privateKeyFilePath; //Merchant certificate serial number private String serialNo; //Certificate save path private String outputFilePath; //Wechat payment platform certificate for signature verification private String wechatpayCertificatePath; //Wechat payment platform certificate serial number private String wechatpayCertSerialNo; private static final String CertDownloadPath = "https://api.mch.weixin.qq.com/v3/certificates"; private List<PlainCertificateItem> downloadCertificate() throws IOException, GeneralSecurityException { WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() .withMerchant(merchantId, serialNo, PemUtil.loadPrivateKey(new FileInputStream(privateKeyFilePath))); if (wechatpayCertificatePath == null) { //No signature verification builder.withValidator(response -> true); } else { List<X509Certificate> certs = new ArrayList<>(); certs.add(PemUtil.loadCertificate(new FileInputStream(wechatpayCertificatePath))); builder.withWechatpay(certs); } HttpGet httpGet = new HttpGet(CertDownloadPath); httpGet.addHeader("Accept", "application/json"); try (CloseableHttpClient client = builder.build()) { CloseableHttpResponse response = client.execute(httpGet); int statusCode = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); if (statusCode == 200) { //System.out.println("body:" + body); CertificateList certList = JsonUtils.convertJsonToCertList(body); return decryptAndValidate(certList, response); } else { System.out.println("download failed,resp code=" + statusCode + ",body=" + body); throw new IOException("request failed"); } } } private List<PlainCertificateItem> decryptAndValidate(CertificateList certList, CloseableHttpResponse response) throws GeneralSecurityException, IOException { List<PlainCertificateItem> plainCerts = new ArrayList<>(); List<X509Certificate> x509Certs = new ArrayList<>(); AesUtil decryptor = new AesUtil(apiV3key.getBytes(StandardCharsets.UTF_8)); for (CertificateItem item : certList.getCerts()) { PlainCertificateItem plainCert = new PlainCertificateItem( item.getSerialNo(), item.getEffectiveTime(), item.getExpireTime(), decryptor.decryptToString( item.getEncryptCertificate().getAssociatedData().getBytes(StandardCharsets.UTF_8), item.getEncryptCertificate().getNonce().getBytes(StandardCharsets.UTF_8), item.getEncryptCertificate().getCiphertext())); ByteArrayInputStream inputStream = new ByteArrayInputStream(plainCert.getPlainCertificate().getBytes(StandardCharsets.UTF_8)); X509Certificate x509Cert = PemUtil.loadCertificate(inputStream); plainCerts.add(plainCert); x509Certs.add(x509Cert); } //From the downloaded certificate, obtain the certificate corresponding to the private key signing the message, and verify the signature to verify the accuracy of the certificate Verifier verifier = new CertificatesVerifier(x509Certs); Validator validator = new WechatPay2Validator(verifier); boolean isCorrectCert = validator.validate(response); //System.out.println(isCorrectCert ? "=== validate success ===" : "=== validate failed ==="); return isCorrectCert ? plainCerts : null; } private void saveCertificate(List<PlainCertificateItem> cert) throws IOException { for (PlainCertificateItem item : cert) { this.setWechatpayCertSerialNo(item.getSerialNo()); String outputAbsoluteFilename = outputFilePath + File.separator + Constant.WXPAY_WECHATPAY_pem; try (BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(outputAbsoluteFilename), StandardCharsets.UTF_8))) { writer.write(item.getPlainCertificate()); } } } public void startDownWachatPayCert() { this.setApiV3key(WechatConfigApp.apiV3Key); this.setMerchantId(WechatConfigApp.mchID4M); this.setSerialNo(WechatConfigApp.serialNo); this.setPrivateKeyFilePath( ClientCustomSSL.getProjectPath()+ File.separator +Constant.WXPAY_APP_CERT_APICLIENTKEY_PATH4M); this.setOutputFilePath(ClientCustomSSL.getProjectPath()); try { System.out.println("=== download begin ==="); List<PlainCertificateItem> plainCerts = downloadCertificate(); System.out.println("=== download done ==="); if (plainCerts != null) { System.out.println("=== save begin ==="); saveCertificate(plainCerts); System.out.println("=== save done ==="); } } catch (IOException | GeneralSecurityException e) { e.printStackTrace(); } } }
Wechat cash withdrawal to change V3 interface
Before implementing the interface, you should carefully read the official documents. Here are some key codes, which are sorted out on the basis of the official SDK.// Wechat withdrawal // Call the payment interface to withdraw, and construct parameters according to the interface document int tatalamount =new BigDecimal(accamount).multiply(new BigDecimal(100)).intValue();//Unit to minute Map<String,Object> transferDetail = new HashMap<String,Object>(); List<Map<String,Object>> detailList = new ArrayList<Map<String,Object>>(); transferDetail.put("out_detail_no", UUIDUtil.GeneratorUUIDKey()); transferDetail.put("transfer_amount", tatalamount); transferDetail.put("transfer_remark", Constant.JIANGLI_REDBOX); transferDetail.put("openid", u.getOpenid()); //User name encryption processing String wechatpaycert = ...; //Wechat payment platform certificate X509Certificate cert = PemUtil.loadCertificate(PemUtil.loadCertificateInStream(wechatpaycert)); String rsaString = RsaCryptoUtil.encryptOAEP( u.getRealname(),cert);//Withdrawal user real name encryption transferDetail.put("user_name", rsaString); detailList.add(transferDetail); //Wechat payment platform certificate serial number //... Omit String wechatPayserialNo = ;//Obtain the saved wechat payment platform certificate serial number from the data //Wechat withdrawal and transfer String resp = WechatPay.weixinTransferBat(detailList, tatalamount, Constant.JIANGLI_REDBOX, outBizNo, 1,wechatPayserialNo); JsonParser parser = new JsonParser(); JsonObject jsonObj = parser.parse(resp).getAsJsonObject(); // Payment successful if(jsonObj.get("batch_id")!=null){ //... Omit -------------------------------------------------------------------- public static String weixinTransferBat(List<Map<String,Object>> transferDetail,int total_amount,String decript, String orderNo,int total_num,String wechatPayserialNo) throws Exception { Map<String,Object> postMap=new HashMap<String,Object>(); postMap.put("appid", WechatConfigApp.appID4M); postMap.put("out_batch_no", orderNo); postMap.put("batch_name", decript); postMap.put("batch_remark", decript); postMap.put("total_amount", total_amount);//Unit: minute postMap.put("total_num", total_num); postMap.put("transfer_detail_list", transferDetail); String resStr = HttpUtil.postTransBatRequest(WechatConfigApp.TRANSFER_BAT_API, JsonUtil.beanToJson(postMap),wechatPayserialNo); System.out.println("weixinTransferBat ===== "+resStr); return resStr; } --------------------------------------------------------------------- /** * Initiate batch transfer API batch transfer to change * @param requestUrl * @param requestJson * @return */ public static String postTransBatRequest(String requestUrl,String requestJson ,String wechatPayserialNo) { //CloseableHttpClient httpClient = null; CloseableHttpClient httpclient = HttpClients.createDefault(); CloseableHttpResponse response = null; HttpEntity entity = null; try { //Merchant private key certificate String privatekeypath = ...; HttpPost httpPost = new HttpPost(requestUrl); // NOTE: it is recommended to specify charset=utf-8. Less than 4.4 Version 6 of HttpCore cannot set the character set correctly, which may lead to signature errors httpPost.addHeader("Content-Type", "application/json"); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Wechatpay-Serial", wechatPayserialNo);//"55E551E614BAA5A3EA38AE03849A76D8C7DA735A"); String strToken = VechatPayV3Util.getToken("POST", "/v3/transfer/batches", requestJson, WechatConfigApp.mchID4M, //Merchant wechat payment merchant ID WechatConfigApp.serialNo,//Merchant wechat payment certificate serial number privatekeypath);//Merchant wechat payment certificate private key // Add authentication information httpPost.addHeader("Authorization", "WECHATPAY2-SHA256-RSA2048" + " " + strToken); httpPost.setEntity(new StringEntity(requestJson, "UTF-8")); response = httpclient.execute(httpPost); entity = response.getEntity();//Get the returned data System.out.println("-----getHeaders.Request-ID:"+response.getHeaders("Request-ID")); return EntityUtils.toString(entity); } catch (Exception e) { e.printStackTrace(); } finally { // Close flow } return null; }
Some codes and brief descriptions are listed. I hope I can help those in need and leave notes for myself. Also, the source code in the demo of docking java implementation of wechat cash withdrawal to change V3 interface does not have a package structure. Please organize the package structure yourself.
END