1、獲取token
package com.operation.admin.utils.wx; import com.alibaba.fastjson.JSON; import com.operation.admin.utils.log.LogUtils; import org.springframework.core.io.ClassPathResource; import org.springframework.util.Base64Utils; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.*; import java.security.cert.X509Certificate; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @Version 1.0.0 * @Description */ public class KeyPairFactory { private final static Object lock = new Object(); //序列號 public static String serialNo = ""; public static void main(String[] args)throws Exception { //獲取別名,通過簽名文件獲取 keyAlias,keyAlias獲取私鑰和序列號要用到 System.out.println("開始==="); KeyStore keyStore1 = KeyStore.getInstance("PKCS12"); String keyPath = "C:\\Users\\zwk\\Desktop\\新建文件夾\\apiclient_cert.p12"; //ClassPathResource resource = new ClassPathResource(keyPath); FileInputStream fis = new FileInputStream(new File(keyPath)); System.out.println("借宿==="); keyStore1.load(fis, WxPayUtils.mch_id.toCharArray()); System.out.println("dljfdjlf d"); System.out.println(JSON.toJSONString(keyStore1.aliases())); } /** * 獲取微信驗證簽名 * @param keyPath apiclient_cert.p12證書路徑 * @param url * @param timestamp * @param nonceStr * @param body * @return */ public static String getToken(String keyPath,String url, long timestamp, String nonceStr, String body){ KeyPair keyPair = createPKCS12(keyPath,WxPayUtils.keyAlias,WxPayUtils.mch_id); String sign = sign("POST",url,timestamp,nonceStr,body,keyPair); String token = token(WxPayUtils.mch_id,nonceStr ,timestamp , serialNo, sign); return token; } /** * 獲取公私鑰. * * @param keyPath the key path * @param keyAlias the key alias * @param keyPass password 這里的keyPass為商戶號 mch_id * @return the key pair */ public static KeyPair createPKCS12(String keyPath, String keyAlias, String keyPass) { KeyStore store = null; try { //從項目中讀取簽名文件 ClassPathResource resource = new ClassPathResource(keyPath); InputStream is = resource.getInputStream(); //InputStream is = new FileInputStream(new File(keyPath)); char[] pem = keyPass.toCharArray(); synchronized (lock) { if (store == null) { synchronized (lock) { store = KeyStore.getInstance("PKCS12"); store.load(is, pem); } } } X509Certificate certificate = (X509Certificate) store.getCertificate(keyAlias); certificate.checkValidity(); // 證書的序列號 也有用 serialNo = certificate.getSerialNumber().toString(16).toUpperCase(); // 證書的 公鑰 PublicKey publicKey = certificate.getPublicKey(); // 證書的私鑰 PrivateKey storeKey = (PrivateKey) store.getKey(keyAlias, pem); return new KeyPair(publicKey, storeKey); } catch (Exception e) { LogUtils.error("createPKCS12==", e); } return null; } /** * V3 SHA256withRSA 簽名. * * @param method 請求方法 GET POST PUT DELETE 等 * @param canonicalUrl 例如 https://api.mch.weixin.qq.com/v3/pay/transactions/app?version=1 ——> /v3/pay/transactions/app?version=1 * @param timestamp 當前時間戳 因為要配置到TOKEN 中所以 簽名中的要跟TOKEN 保持一致 * @param nonceStr 隨機字符串 要和TOKEN中的保持一致 * @param body 請求體 GET 為 "" POST 為JSON * @param keyPair 商戶API 證書解析的密鑰對 實際使用的是其中的私鑰 * @return the string */ public static String sign(String method, String canonicalUrl, long timestamp, String nonceStr, String body, KeyPair keyPair) { try { String signatureStr = Stream.of(method, canonicalUrl, String.valueOf(timestamp), nonceStr, body) .collect(Collectors.joining("\n", "", "\n")); Signature sign = Signature.getInstance("SHA256withRSA"); sign.initSign(keyPair.getPrivate()); sign.update(signatureStr.getBytes(StandardCharsets.UTF_8)); return Base64Utils.encodeToString(sign.sign()); }catch (Exception e){ LogUtils.error("sign==",e ); } return null; } /** * 生成Token. * * @param mchId 商戶號 * @param nonceStr 隨機字符串 * @param timestamp 時間戳 * @param serialNo 證書序列號 * @param signature 簽名 * @return the string */ public static String token(String mchId, String nonceStr, long timestamp, String serialNo, String signature) { final String TOKEN_PATTERN = "mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\""; // 生成token return String.format(TOKEN_PATTERN, mchId, nonceStr, timestamp, serialNo, signature); } }
退款案例
package com.operation.admin.utils.wx; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.operation.admin.config.ConfigParam; import com.operation.admin.utils.common.ResultUtils; import com.operation.admin.utils.common.StringUtils; import com.operation.admin.utils.http.HttpUtils; import com.operation.admin.utils.log.LogUtils; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * 微信支付工具類 * @Version 1.0.0 * @Description */ public class WxPayUtils { //微信退款URL public static final String WX_REFUND_URL = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"; //微信退款URI public static final String WX_REFUND_URI = "/v3/refund/domestic/refunds"; //商戶號 public static final String mch_id = "11111112"; //別名 public static final String keyAlias = "tenpay certificate"; //簽名文件路徑 public static final String keyPath = "/sign/apiclient_cert.p12"; //public static final String keyPath = "C:\\Users\\zwk\\Desktop\\新建文件夾\\apiclient_cert.p12"; //微信退款 public static Map<String,Object> refund(Map<String,Object> policyInfo){ try { Map<String,Object> reqMap = new HashMap<>(); //微信商戶支付訂單號(支付成功后返回的訂單號) String transaction_id = "420000134220220301231262"; //商戶訂單號 (創建支付訂單時返回的訂單號) String out_trade_no = "94895255037012144"; //商戶退款單號 String out_refund_no = UUID.randomUUID().toString().replace("-","" ); String reason = "退保退款"; //退款金額(以分為單位) BigDecimal policyFee = (BigDecimal)policyInfo.get("policyFee"); Integer amountInt = policyFee.multiply(new BigDecimal(100)).intValue(); Integer refund = 1; //交易訂單總金額(以分為單位) Integer total = 1; String runE = ConfigParam.runEnvironment; //如果是正式環境的,則使用正常的投保金額 if(runE.equals("prod")){ refund = amountInt; total = amountInt; } //幣種 String currency = "CNY"; Map<String,Object> amount = new HashMap<>(); amount.put("refund", refund); amount.put("total", total); amount.put("currency", currency); reqMap.put("transaction_id",transaction_id ); reqMap.put("out_trade_no", out_trade_no); reqMap.put("out_refund_no",out_refund_no ); reqMap.put("reason", reason); reqMap.put("amount", amount); String reqParam = JSON.toJSONString(reqMap); //簽名文件 String nonceStr = UUID.randomUUID().toString().replace("-","" ); String token = KeyPairFactory.getToken(keyPath, WX_REFUND_URI, System.currentTimeMillis()/1000, nonceStr, reqParam); LogUtils.app("微信退款請求參數:"+ reqParam); LogUtils.app("微信退款路徑:"+WX_REFUND_URL); String result = HttpUtils.wxHttpRequest(WX_REFUND_URL, reqParam,token); LogUtils.app("微信退款響應消息:"+result); return null; }catch (Exception e){ LogUtils.error("WxPayUtils%refund==",e ); } return ResultUtils.paramError("退款失敗"); } public static void main(String[] args) { //refund(); } }
http請求 /**
* 微信支付 * @param url * @param params * @param token * @return */ public static String wxHttpRequest(String url, String params,String token) { HttpPost httpRequest = new HttpPost(url); CloseableHttpResponse httpResponse = null; try { //設置微信支付請求頭 httpRequest.addHeader("Content-Type", "application/json;charset=utf-8"); httpRequest.addHeader("Connection", "keep-alive"); httpRequest.addHeader("Accept", "application/json");
httpRequest.addHeader("Authorization","WECHATPAY2-SHA256-RSA2048 "+ token ); if (params != null) { httpRequest.setEntity(new StringEntity(params, "UTF-8")); } httpResponse = getHttpClient().execute(httpRequest); int status = httpResponse.getStatusLine().getStatusCode(); if (status >= 200 && status < 300) { return EntityUtils.toString(httpResponse.getEntity()); } else { httpRequest.abort(); String str = EntityUtils.toString(httpResponse.getEntity()); LogUtils.app(str); return str; } } catch (Exception e) { LogUtils.error("HttpUtils%sendPostRequest:", e); } finally { httpRequest.releaseConnection(); try { if (httpResponse != null) { httpResponse.close(); } } catch (IOException e) { LogUtils.error("HttpUtils%sendPostRequest:關閉資源失敗", e); } } return null; }
