springboot版本:
2.2.0.BUILD-SNAPSHOT
可使用場景:企業付款到零錢/提現/微信退款等場景
企業提現零錢付款場景下:
下面是能跑通的代碼,減少踩坑時間.
兩套方案:一套使用注入bean的方式:
("商戶號".toCharArray(),商戶號就是證書密碼)
@Configuration public class RestTemplateCert { @Qualifier("RestTemplateWithCert") @Bean public RestTemplate getRestTemplateWithCert() { RestTemplate restTemplate = null; try { KeyStore keyStore = KeyStore.getInstance("PKCS12");//eg. PKCS12 // 這個之前嘗試放在resources目錄下來讀取,結果這個居然是證書錯誤的源頭,使用下面的直接從路徑讀取就能成功了,證書讀取有問題spring沒有報錯,大坑 // InputStream cp = this.getClass().getResourceAsStream("apiclient_cert.p12"); FileInputStream instream = new FileInputStream(new File("C:\\extend\\apiclient_cert.p12")); keyStore.load(instream, "商戶號".toCharArray()); // Trust own CA and all self-signed certs SSLContext sslcontext = SSLContextBuilder.create() .loadKeyMaterial(keyStore, "商戶號".toCharArray()) .build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, NoopHostnameVerifier.INSTANCE); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); restTemplate = new RestTemplate(factory); //將轉換器的編碼換成utf-8 restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("utf-8"))); //System.out.println("restTemplate.hashCode():" + restTemplate.hashCode()); } catch (Exception e) { e.printStackTrace(); } return restTemplate; } @Primary @Bean public RestTemplate getRestTemplate() { RestTemplate restTemplate = new RestTemplate(); //將轉換器的編碼換成utf-8 restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("utf-8"))); return restTemplate; } }
攜帶微信api證書: @Qualifier("RestTemplateWithCert") @Resource private RestTemplate restTemplateWithCert; 常規請求: @Resource private RestTemplate restTemplate;
微信提現請求:
HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); String body = "xml數據"; String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; HttpEntity<String> request = new HttpEntity<>(body, headers); ResponseEntity<String> res = restTemplateWithCert.postForEntity(url, request, String.class); System.out.println(res.getBody());
第二個解決方案:
需要依賴:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency>
public class WxSSLTestTemplate { public static String TransferRestTemplate(String url, String data) throws KeyStoreException, IOException, UnrecoverableKeyException, KeyManagementException, CertificateException, NoSuchAlgorithmException { KeyStore keyStore = KeyStore.getInstance("PKCS12"); FileInputStream instream = new FileInputStream(new File("C:\\extend\\apiclient_cert.p12")); keyStore.load(instream, "商戶號".toCharArray()); // Trust own CA and all self-signed certs SSLContext sslcontext = SSLContextBuilder.create() .loadKeyMaterial(keyStore, "商戶號".toCharArray()) .build(); // Allow TLSv1 protocol only HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, hostnameVerifier); CloseableHttpClient httpclient = HttpClients.custom() .setSSLSocketFactory(sslsf) .build(); HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpclient); RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory); HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.add("Connection", "keep-alive"); requestHeaders.add("Accept", "*/*"); requestHeaders.add("Content-Type", "application/x-www-form-urlencoded"); requestHeaders.add("Host", "api.mch.weixin.qq.com"); requestHeaders.add("X-Requested-With", "XMLHttpRequest"); requestHeaders.add("Cache-Control", "max-age=0"); requestHeaders.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) "); // 如果使用這個方法,就不能使用下面的這個實例化,而要使用下面第一條使用中的request,否則會報jackson的錯誤,就算配置忽略bean的檢測也沒用 // org.springframework.http.HttpEntity<String> requestEntity = // new org.springframework.http.HttpEntity(new StringEntity(data, "UTF-8"), requestHeaders); HttpEntity<String> request = new HttpEntity<>(data, requestHeaders); ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, request, String.class); return response.getBody(); } }
微信提現請求:
String body = "xml數據"; String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; String result = WxSSLTestTemplate.TransferRestTemplate(url, body); System.out.println(result);
這樣就可以完美跑通了