微信V3支付簽名及退款案例


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; }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM