1. 程式人生 > >微信公眾號實現支付功能(基於官方sdk實現)--備忘001

微信公眾號實現支付功能(基於官方sdk實現)--備忘001

首先要明白微信支付相關的三個賬號

1:一定要認真閱讀官方開發文件,不然好多坑啊哭

官方sdk-maven

<dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
</dependency>

 開發的相關流程:

        a>:通過統一下單方法獲取到預付訂單資訊(prepay_id-預付訂單資訊)

        b>:對預付訂單進行二次簽名返回json資料給前端準備調起支付(二次簽名需要自己實現,微信不提供,可參考微信簽名方法)

        c>:前端根據獲取到的資料喚起支付頁面進行支付

2:根據自己專案需求寫相關的介面實現(從前端獲取官方文件中的相關引數)

3:調官方sdk填充資料的方法進行關鍵資訊的填充

//調官方sdk方法填充資料
data = wxPay.fillRequestData(data);
   /**
     * 向 Map 中新增 appid、mch_id、nonce_str、sign_type、sign <br>
     * 該函式適用於商戶適用於統一下單等介面,不適用於紅包、代金券介面
     *
     * @param reqData
     * @return
     * @throws Exception
     */
    public Map<String, String> fillRequestData(Map<String, String> reqData) throws Exception {
        reqData.put("appid", config.getAppID());
        reqData.put("mch_id", config.getMchID());
        reqData.put("nonce_str", WXPayUtil.generateNonceStr());
        if (SignType.MD5.equals(this.signType)) {
            reqData.put("sign_type", WXPayConstants.MD5);
        }
        else if (SignType.HMACSHA256.equals(this.signType)) {
            reqData.put("sign_type", WXPayConstants.HMACSHA256);
        }
        reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));
        return reqData;
    }

4:完成相關資料填充後調官方sdk的統一下單方法

//調官方sdk統一下單方法
Map<String, String> result = wxPay.unifiedOrder(data);
     /**
     * 作用:統一下單<br>
     * 場景:公共號支付、掃碼支付、APP支付
     * @param reqData 向wxpay post的請求資料
     * @return API返回資料
     * @throws Exception
     */
    public Map<String, String> unifiedOrder(Map<String, String> reqData) throws Exception {
        return this.unifiedOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
    }


    /**
     * 作用:統一下單<br>
     * 場景:公共號支付、掃碼支付、APP支付
     * @param reqData 向wxpay post的請求資料
     * @param connectTimeoutMs 連線超時時間,單位是毫秒
     * @param readTimeoutMs 讀超時時間,單位是毫秒
     * @return API返回資料
     * @throws Exception
     */
    public Map<String, String> unifiedOrder(Map<String, String> reqData,  int connectTimeoutMs, int readTimeoutMs) throws Exception {
        String url;
        if (this.useSandbox) {
            url = WXPayConstants.SANDBOX_UNIFIEDORDER_URL;
        }
        else {
            url = WXPayConstants.UNIFIEDORDER_URL;
        }
        String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
        return this.processResponseXml(respXml);
    }

5:對統一下單方法返回資料進行二次簽名準備返回給前端(注意該方法需要自己去實現,官方沒有單獨提供二次簽名方法,我是把官方簽名方法copy出來自己建了一個工具類,然後調自己的工具類進行的二次簽名,僅供參考)

if (req.getTradeType().equals(PayRequest.TRADE_TYPE_JSAPI)) {
    out.put("appId", result.get("appid"));
    out.put("nonceStr", String.valueOf(System.currentTimeMillis()));
    out.put("package", "prepay_id=" + result.get("prepay_id"));
    out.put("signType", "MD5");
    out.put("timeStamp", String.valueOf(System.currentTimeMillis()/1000));
    //##對返回資料進行二次簽名 TODO
    String packageSign = WXPayUtil.generateSignature(out,wxPayProperties.getKey());
    out.put("paySign", packageSign);				
} 
   /**
     * 生成簽名. 注意,若含有sign_type欄位,必須和signType引數保持一致。
     *
     * @param data 待簽名資料
     * @param key API金鑰
     * @param signType 簽名方式
     * @return 簽名
     */
    public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals(WXPayConstants.FIELD_SIGN)) {
                continue;
            }
            if (data.get(k).trim().length() > 0) // 引數值為空,則不參與簽名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(key);
        if (SignType.MD5.equals(signType)) {
            return MD5(sb.toString()).toUpperCase();
        }
        else if (SignType.HMACSHA256.equals(signType)) {
            return HMACSHA256(sb.toString(), key);
        }
        else {
            throw new Exception(String.format("Invalid sign_type: %s", signType));
        }
    }
/**
     * 生成 MD5
     *
     * @param data 待處理資料
     * @return MD5結果
     */
    public static String MD5(String data) throws Exception {
        java.security.MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

6:把簽名後的資料返回給前端,剩下的事就交給前端實現