public static void main(String[] args) {
try {
Map<String, Object> refundParams = new HashMap<>();
refundParams.put("out_trade_no", "ET1000000722");
refundParams.put("out_refund_no", "ET10000007223");
Map<String, Integer> amount = new HashMap<>();
amount.put("total", 1);
amount.put("refund", 1);
refundParams.put("amount", amount);
String response = sendRefundRequest(refundParams);
System.out.println("退款接口返回结果:" + response);
} catch (Exception e) {
e.printStackTrace();
}
}
private static PrivateKey loadPrivateKey(String certPath) throws Exception {
try (InputStream inputStream = new FileInputStream(certPath)) {
return PemUtil.loadPrivateKey(inputStream);
}
}
public static String sendRefundRequest(Map<String, Object> params) throws Exception {
Gson gson = new Gson();
String requestBody = gson.toJson(params);
PrivateKey privateKey = loadPrivateKey(CERT_PATH);
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = generateNonceStr();
String signature = generateSignature(timestamp, nonceStr, API_V3_KEY, privateKey, params);
String authorization = String.format("WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%s\",signature=\"%s\"",
MCH_ID, nonceStr, timestamp, signature);
CloseableHttpClient httpClient = getHttpClientWithCert(CERT_PATH);
HttpPost httpPost = new HttpPost(REFUND_URL);
httpPost.addHeader("Authorization", authorization);
httpPost.addHeader("Content-Type", "application/json");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("User-Agent", "WeChatJavaClient/1.0");
httpPost.setEntity(new StringEntity(requestBody, "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity responseEntity = response.getEntity();
String responseBody = EntityUtils.toString(responseEntity, "UTF-8");
response.close();
httpClient.close();
return responseBody;
}
private static String generateSignature(String timestamp, String nonceStr, String apiV3Key, PrivateKey privateKey, Map<String, Object> params) throws Exception {
String body = params == null || params.isEmpty() ? "" : sha256(new Gson().toJson(params));
String signStr = String.format("POST\n%s\n%s\n%s\n%s\n", REFUND_URL, timestamp, nonceStr, body);
java.security.Signature signature = java.security.Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(signStr.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(signature.sign());
}
private static String sha256(String input) throws Exception {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(input.getBytes("UTF-8"));
return bytesToHex(hash);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
private static String generateNonceStr() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
private static CloseableHttpClient getHttpClientWithCert(String certPath) throws Exception {
PrivateKey privateKey = loadPrivateKey(certPath);
KeyManager[] keyManagers = new KeyManager[]{new CustomX509KeyManager(privateKey)};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, null, null);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
static class CustomX509KeyManager implements X509KeyManager {
private final PrivateKey privateKey;
public CustomX509KeyManager(PrivateKey privateKey) {
this.privateKey = privateKey;
}
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
return "dummyAlias";
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
return null;
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return null;
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return new String[]{"dummyAlias"};
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return null;
}
@Override
public PrivateKey getPrivateKey(String alias) {
return privateKey;
}
}
https://pay.weixin.qq.com/doc/v3/merchant/4012365352按这个指引自己获取下请求body参数、签名字符串、Authorization和签名值,然后用工具校验下签名值