亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

微信支付接入步驟

發布時間:2021-09-29 16:07:28 來源:億速云 閱讀:257 作者:iii 欄目:大數據

本篇內容主要講解“微信支付接入步驟”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“微信支付接入步驟”吧!

接入步驟

微信支付接入大概步驟如下:

  1. 獲取支付接口 URL

  2. 構建請求參數

  3. 發起請求

  4. 喚起支付

  5. 支付異步通知處理

步驟一中獲取支付接口 URL,需要考慮這幾點

  1. 如何同時支持國內微信支付與境外微信支付

  2. 如何同時支持普通的商戶模式以及服務商模式

步驟二中經常遇到的問題就是參數簽名驗證問題

  1. MD5 加密

  2. HMAC-SHA256 加密

步驟三中難點在于微信支付雙向證書的處理

步驟四中預付訂單二次簽名異常以及喚起支付提示各種配置錯誤

步驟五中異步通知驗證簽名、訂單重復通知以及敏感數據的解密問題

以上接入步驟中,你踩過那些坑呢?歡迎評論區分享交流

Talk is cheap. Show me the code

獲取微信支付接口 URL

有人會說「這不很簡單么」官方文檔接口中就有提供。對你說的沒錯,那如何做到一套系統同時支持國內微信支付與境外微信支付,又如何做跨城冗災方案呢?

微信域名

根據業務區域的不同微信提供了不同的域名來支持

  • api.mch.weixin.qq.com(建議接入點:中國國內)

  • api2.mch.weixin.qq.com(建議接入點:中國國內備用)

  • apihk.mch.weixin.qq.com(建議接入點:東南亞)

  • apius.mch.weixin.qq.com(建議接入點:其它)

  • api.mch.weixin.qq.com/sandboxnew(特殊:仿真測試)

聰明的你,不難就會想到枚舉,具體跨城冗災方案可以參考微信支付商戶系統跨城冗災升級指引

/**
 * <p>IJPay 讓支付觸手可及,封裝了微信支付、支付寶支付、銀聯支付常用的支付方式以及各種常用的接口。</p>
 *
 * <p>不依賴任何第三方 mvc 框架,僅僅作為工具使用簡單快速完成支付模塊的開發,可輕松嵌入到任何系統里。 </p>
 *
 * <p>IJPay 交流群: 723992875</p>
 *
 * <p>Node.js 版: https://gitee.com/javen205/TNW</p>
 *
 * <p>微信支付可用域名枚舉</p>
 *
 * @author Javen
 */
public enum WxDomain {
    /**
     * 中國國內
     */
    CHINA("https://api.mch.weixin.qq.com"),
    /**
     * 中國國內(備用域名)
     */
    CHINA2("https://api2.mch.weixin.qq.com"),
    /**
     * 東南亞
     */
    HK("https://apihk.mch.weixin.qq.com"),
    /**
     * 其它
     */
    US("https://apius.mch.weixin.qq.com");

    
    /**
     * 域名
     */
    private final String domain;

    WxDomain(String domain) {
        this.domain = domain;
    }

    public String getType() {
        return domain;
    }
}

至此獲取微信支付接口 URL 已解決掉了核心問題。剩下的就是根據不同的支付方式來拼接具體的支付接口 URL。

微信支付常用接口

付款碼支付、JSAPI支付、Native支付、App支付、H5支付、小程序支付、紅包、企業付款、酒店押金、刷臉支付常用的支付方式以及支付工具不完全統計接口大概有 90+

package com.ijpay.wxpay.enums;

/**
 * <p>IJPay 讓支付觸手可及,封裝了微信支付、支付寶支付、銀聯支付常用的支付方式以及各種常用的接口。</p>
 *
 * <p>不依賴任何第三方 mvc 框架,僅僅作為工具使用簡單快速完成支付模塊的開發,可輕松嵌入到任何系統里。 </p>
 *
 * <p>IJPay 交流群: 723992875</p>
 *
 * <p>Node.js 版: https://gitee.com/javen205/TNW</p>
 *
 * <p>微信支付接口枚舉</p>
 *
 * @author Javen
 */
public enum WxApiType {
    /**
     * 沙箱環境
     */
    SAND_BOX_NEW("/sandboxnew"),
    /**
     * 獲取沙箱環境驗簽秘鑰
     */
    GET_SIGN_KEY("/sandboxnew/pay/getsignkey"),
    /**
     * 統一下單
     */
    UNIFIED_ORDER("/pay/unifiedorder"),
    /**
     * 提交付款碼支付
     */
    MICRO_PAY("/pay/micropay"),
    /**
     * 查詢訂單
     */
    ORDER_QUERY("/pay/orderquery"),
    /**
     * 關閉訂單
     */
    CLOSE_ORDER("/pay/closeorder"),
    /**
     * 撤銷訂單
     */
    REVERSE("/secapi/pay/reverse"),
    /**
     * 申請退款
     */
    REFUND("/secapi/pay/refund"),
    /**
     * 查詢退款
     */
    REFUND_QUERY("/pay/refundquery"),
    /**
     * 下載對賬單
     */
    DOWNLOAD_BILL("/pay/downloadbill"),
    /**
     * 下載資金對賬單
     */
    DOWNLOAD_FUND_FLOW("/pay/downloadfundflow"),
    /**
     * 交易保障
     */
    REPORT("/payitil/report"),
    /**
     * 轉換短鏈接
     */
    SHORT_URL("/tools/shorturl"),
    /**
     * 授權碼查詢 openId
     */
    AUTH_CODE_TO_OPENID("/tools/authcodetoopenid"),
    /**
     * 拉取訂單評價數據
     */
    BATCH_QUERY_COMMENT("/billcommentsp/batchquerycomment"),
    /**
     * 企業付款
     */
    TRANSFER("/mmpaymkttransfers/promotion/transfers"),
    /**
     * 查詢企業付款
     */
    GET_TRANSFER_INFO("/mmpaymkttransfers/gettransferinfo"),
    /**
     * 企業付款到銀行卡
     */
    TRANSFER_BANK("/mmpaysptrans/pay_bank"),
    /**
     * 查詢企業付款到銀行卡
     */
    GET_TRANSFER_BANK_INFO("/mmpaysptrans/query_bank"),
    /**
     * 獲取 RSA 加密公鑰
     */
    GET_PUBLIC_KEY("/risk/getpublickey"),
    /**
     * 發放紅包
     */
    SEND_RED_PACK("/mmpaymkttransfers/sendredpack"),
    /**
     * 發放裂變紅包
     */
    SEND_GROUP_RED_PACK("/mmpaymkttransfers/sendgroupredpack"),
    /**
     * 查詢紅包記錄
     */
    GET_HB_INFO("/mmpaymkttransfers/gethbinfo"),
    /**
     * 小程序發紅包
     */
    SEND_MINI_PROGRAM_HB("/mmpaymkttransfers/sendminiprogramhb"),
    /**
     * 發放代金券
     */
    SEND_COUPON("/mmpaymkttransfers/send_coupon"),
    /**
     * 查詢代金券批次
     */
    QUERY_COUPON_STOCK("/mmpaymkttransfers/query_coupon_stock"),
    /**
     * 查詢代金券信息
     */
    QUERY_COUPONS_INFO("/mmpaymkttransfers/querycouponsinfo"),
    /**
     * 請求單次分賬
     */
    PROFIT_SHARING("/secapi/pay/profitsharing"),
    /**
     * 請求多次分賬
     */
    MULTI_PROFIT_SHARING("/secapi/pay/multiprofitsharing"),
    /**
     * 查詢分賬結果
     */
    PROFIT_SHARING_QUERY("/pay/profitsharingquery"),
    /**
     * 添加分賬接收方
     */
    PROFITS_HARING_ADD_RECEIVER("/pay/profitsharingaddreceiver"),
    /**
     * 刪除分賬接收方
     */
    PROFIT_SHARING_REMOVE_RECEIVER("/pay/profitsharingremovereceiver"),
    /**
     * 完結分賬
     */
    PROFIT_SHARING_FINISH("/secapi/pay/profitsharingfinish"),
    /**
     * 分賬回退
     */
    PROFIT_SHARING_RETURN("/secapi/pay/profitsharingreturn"),
    /**
     * 分賬回退結果查詢
     */
    PROFIT_SHARING_RETURN_QUERY("/pay/profitsharingreturnquery"),
    /**
     * 支付押金(人臉支付)
     */
    DEPOSIT_FACE_PAY("/deposit/facepay"),
    /**
     * 支付押金(付款碼支付)
     */
    DEPOSIT_MICRO_PAY("/deposit/micropay"),
    /**
     * 查詢訂單(押金)
     */
    DEPOSIT_ORDER_QUERY("/deposit/orderquery"),
    /**
     * 撤銷訂單(押金)
     */
    DEPOSIT_REVERSE("/deposit/reverse"),
    /**
     * 消費押金
     */
    DEPOSIT_CONSUME("/deposit/consume"),
    /**
     * 申請退款(押金)
     */
    DEPOSIT_REFUND("/deposit/refund"),
    /**
     * 查詢退款(押金)
     */
    DEPOSIT_REFUND_QUERY("deposit/refundquery"),
    /**
     * 公眾號純簽約
     */
    ENTRUST_WEB("/papay/entrustweb"),
    /**
     * 公眾號純簽約(服務商模式)
     */
    PARTNER_ENTRUST_WEB("/papay/partner/entrustweb"),
    /**
     * APP純簽約
     */
    PRE_ENTRUST_WEB("/papay/preentrustweb"),
    /**
     * APP純簽約(服務商模式)
     */
    PARTNER_PRE_ENTRUST_WEB("/papay/partner/preentrustweb"),
    /**
     * H5純簽約
     */
    H5_ENTRUST_WEB("/papay/h6entrustweb"),
    /**
     * H5純簽約(服務商模式)
     */
    PARTNER_H5_ENTRUST_WEB("/papay/partner/h6entrustweb"),
    /**
     * 支付中簽約
     */
    PAY_CONTRACT_ORDER("/pay/contractorder"),
    /**
     * 查詢簽約關系
     */
    QUERY_ENTRUST_CONTRACT("/papay/querycontract"),
    /**
     * 查詢簽約關系(服務商模式)
     */
    PARTNER_QUERY_ENTRUST_CONTRACT("/papay/partner/querycontract"),
    /**
     * 代扣申請扣款
     */
    PAP_PAY_APPLY("/pay/pappayapply"),
    /**
     * 代扣申請扣款(服務商模式)
     */
    PARTNER_PAP_PAY_APPLY("/pay/partner/pappayapply"),
    /**
     * 查詢代扣訂單
     */
    PAP_ORDER_QUERY("/pay/paporderquery"),
    /**
     * 查詢代扣訂單
     */
    PARTNER_PAP_ORDER_QUERY("/pay/partner/paporderquery"),
    /**
     * 代扣申請解約
     */
    DELETE_ENTRUST_CONTRACT("/papay/deletecontract"),
    /**
     * 代扣申請解約(服務商模式)
     */
    PARTNER_DELETE_ENTRUST_CONTRACT("/papay/partner/deletecontract"),
    /**
     * 刷臉支付
     */
    FACE_PAY("/pay/facepay"),
    /**
     * 查詢刷臉支付訂單
     */
    FACE_PAY_QUERY("/pay/facepayqueryy"),
    /**
     * 撤銷刷臉支付訂單
     */
    FACE_PAY_REVERSE("/secapi/pay/facepayreverse"),
    /**
     * 小微商戶申請入駐
     */
    MICRO_SUBMIT("/applyment/micro/submit"),
    /**
     * 查詢申請狀態
     */
    GET_MICRO_SUBMIT_STATE("/applyment/micro/getstate"),
    /**
     * 提交升級申請
     */
    MICRO_SUBMIT_UPGRADE("/applyment/micro/submitupgrade"),
    /**
     * 查詢升級申請單狀態
     */
    GET_MICRO_UPGRADE_STATE("/applyment/micro/getupgradestate"),
    /**
     * 查詢提現狀態
     */
    QUERY_AUTO_WITH_DRAW_BY_DATE("/fund/queryautowithdrawbydate"),
    /**
     * 修改結算銀行卡
     */
    MICRO_MODIFY_ARCHIVES("/applyment/micro/modifyarchives"),
    /**
     * 重新發起提現
     */
    RE_AUTO_WITH_DRAW_BY_DATE("/fund/reautowithdrawbydate"),
    /**
     * 修改聯系信息
     */
    MICRO_MODIFY_CONTACT_INFO("/applyment/micro/modifycontactinfo"),
    /**
     * 小微商戶關注功能配置
     */
    ADD_RECOMMEND_CONF("/secapi/mkt/addrecommendconf"),
    /**
     * 小微商戶開發配置新增支付目錄
     */
    ADD_SUB_DEV_CONFIG("/secapi/mch/addsubdevconfig"),
    /**
     * 小微商戶開發配置查詢
     */
    QUERY_SUB_DEV_CONFIG("/secapi/mch/querysubdevconfig");

    /**
     * 類型
     */
    private final String type;

    WxApiType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }
}

獲取完整URL 方案

同時支持任意接口任意域名的切換,為跨城冗災打下良好基礎

	/**
     * 獲取接口請求的 URL
     *
     * @param wxApiType {@link WxApiType} 支付 API 接口枚舉
     * @return {@link String} 返回完整的接口請求URL
     */
    public static String getReqUrl(WxApiType wxApiType) {
        return getReqUrl(wxApiType, null, false);
    }

    /**
     * 獲取接口請求的 URL
     *
     * @param wxApiType {@link WxApiType} 支付 API 接口枚舉
     * @param isSandBox 是否是沙箱環境
     * @return {@link String} 返回完整的接口請求URL
     */
    public static String getReqUrl(WxApiType wxApiType, boolean isSandBox) {
        return getReqUrl(wxApiType, null, isSandBox);
    }

    /**
     * 獲取接口請求的 URL
     *
     * @param wxApiType {@link WxApiType} 支付 API 接口枚舉
     * @param wxDomain  {@link WxDomain} 支付 API 接口域名枚舉
     * @param isSandBox 是否是沙箱環境
     * @return {@link String} 返回完整的接口請求URL
     */
    public static String getReqUrl(WxApiType wxApiType, WxDomain wxDomain, boolean isSandBox) {
        if (wxDomain == null) {
            wxDomain = WxDomain.CHINA;
        }
        return wxDomain.getType()
                .concat(isSandBox ? WxApiType.SAND_BOX_NEW.getType() : "")
                .concat(wxApiType.getType());
    }

構建請求參數

Model 構建實現機制

這里構建請求參數使用的是 Lombok + Java 反射機制來實現。

封裝 Model 自動生成簽名

BaseModel 實現將 Lombok builder 后對象中的屬性以及值轉為 Map并提供創建簽名的方法自動生成 sign (同時支持 MD5 以及 HMAC-SHA256)。以微信支付中的統一下單為例代碼如下

public class BaseModel {

    /**
     * 將建構的 builder 轉為 Map
     *
     * @return 轉化后的 Map
     */
    public Map<String, String> toMap() {
        String[] fieldNames = getFiledNames(this);
        HashMap<String, String> map = new HashMap<String, String>(fieldNames.length);
        for (int i = 0; i < fieldNames.length; i++) {
            String name = fieldNames[i];
            String value = (String) getFieldValueByName(name, this);
            if (StrUtil.isNotEmpty(value)) {
                map.put(name, value);
            }
        }
        return map;
    }

    /**
     * 構建簽名 Map
     *
     * @param partnerKey API KEY
     * @param signType   {@link SignType} 簽名類型
     * @return 構建簽名后的 Map
     */
    public Map<String, String> createSign(String partnerKey, SignType signType) {
        return createSign(partnerKey,signType,true);
    }

    /**
     * 構建簽名 Map
     *
     * @param partnerKey   API KEY
     * @param signType     {@link SignType} 簽名類型
     * @param haveSignType 簽名是否包含 sign_type 字段
     * @return 構建簽名后的 Map
     */
    public Map<String, String> createSign(String partnerKey, SignType signType, boolean haveSignType) {
        return WxPayKit.buildSign(toMap(), partnerKey, signType,haveSignType);
    }

    /**
     * 獲取屬性名數組
     *
     * @param obj 對象
     * @return 返回對象屬性名數組
     */
    public String[] getFiledNames(Object obj) {
        Field[] fields = obj.getClass().getDeclaredFields();
        String[] fieldNames = new String[fields.length];
        for (int i = 0; i < fields.length; i++) {
            fieldNames[i] = fields[i].getName();
        }
        return fieldNames;
    }

    /**
     * 根據屬性名獲取屬性值
     *
     * @param fieldName 屬性名稱
     * @param obj       對象
     * @return 返回對應屬性的值
     */
    public Object getFieldValueByName(String fieldName, Object obj) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = new StringBuffer().append("get")
                    .append(firstLetter)
                    .append(fieldName.substring(1))
                    .toString();
            Method method = obj.getClass().getMethod(getter, new Class[]{});
            return method.invoke(obj, new Object[]{});
        } catch (Exception e) {
            return null;
        }
    }

}

UnifiedOrderModel 微信統一下單

/**
 * <p>IJPay 讓支付觸手可及,封裝了微信支付、支付寶支付、銀聯支付常用的支付方式以及各種常用的接口。</p>
 *
 * <p>不依賴任何第三方 mvc 框架,僅僅作為工具使用簡單快速完成支付模塊的開發,可輕松嵌入到任何系統里。 </p>
 *
 * <p>IJPay 交流群: 723992875</p>
 *
 * <p>Node.js 版: https://gitee.com/javen205/TNW</p>
 *
 * <p>統一下單 Model</p>
 *
 * @author Javen
 */
package com.ijpay.wxpay.model;

import com.ijpay.core.model.BaseModel;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class UnifiedOrderModel extends BaseModel {
    private String appid;
    private String mch_id;
    private String sub_appid;
    private String sub_mch_id;
    private String device_info;
    private String nonce_str;
    private String sign;
    private String sign_type;
    private String body;
    private String detail;
    private String attach;
    private String out_trade_no;
    private String fee_type;
    private String total_fee;
    private String spbill_create_ip;
    private String time_start;
    private String time_expire;
    private String goods_tag;
    private String notify_url;
    private String trade_type;
    private String product_id;
    private String limit_pay;
    private String openid;
    private String sub_openid;
    private String receipt;
    private String scene_info;
}

UnifiedOrderModel 中是熟悉字段完全來自官方接口文檔。遺憾的是 Model 不能遵守小駝峰式命名規則。

簽名算法實現

MD5 以及 HMAC-SHA256 簽名算法實現使用的是 Hutool 提供的工具類來實現

	public static String hmacSha256(String data, String key) {
        return SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(data, CharsetUtil.UTF_8);
    }

    public static String md5(String data) {
        return SecureUtil.md5(data);
    }

構建簽名邏輯如下

	/**
     * 構建簽名
     *
     * @param params     需要簽名的參數
     * @param partnerKey 密鑰
     * @param signType   簽名類型
     * @return 簽名后的 Map
     */
    public static Map<String, String> buildSign(Map<String, String> params, String partnerKey, SignType signType) {
        return buildSign(params,partnerKey,signType,true);
    }

    /**
     * 構建簽名
     *
     * @param params       需要簽名的參數
     * @param partnerKey   密鑰
     * @param signType     簽名類型
     * @param haveSignType 簽名是否包含 sign_type 字段
     * @return 簽名后的 Map
     */
    public static Map<String, String> buildSign(Map<String, String> params, String partnerKey, SignType signType, boolean haveSignType) {
        if(haveSignType){
            params.put(FIELD_SIGN_TYPE, signType.getType());
        }
        String sign = createSign(params, partnerKey, signType);
        params.put(FIELD_SIGN, sign);
        return params;
    }

	/**
     * 生成簽名
     *
     * @param params     需要簽名的參數
     * @param partnerKey 密鑰
     * @param signType   簽名類型
     * @return 簽名后的數據
     */
    public static String createSign(Map<String, String> params, String partnerKey, SignType signType) {
        if (signType == null) {
            signType = SignType.MD5;
        }
        // 生成簽名前先去除sign
        params.remove(FIELD_SIGN);
        String tempStr = PayKit.createLinkString(params);
        String stringSignTemp = tempStr + "&key=" + partnerKey;
        if (signType == SignType.MD5) {
            return md5(stringSignTemp).toUpperCase();
        } else {
            return hmacSha256(stringSignTemp, partnerKey).toUpperCase();
        }
    }

通過 Model 構建 xml 數據

通過上面的封裝后不到 20 行代碼就可以通過 Model 構建出微信支付接口所需要的 xml 數據

        WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();

        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(wxPayApiConfig.getAppId())
                .mch_id(wxPayApiConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .body("IJPay 讓支付觸手可及-公眾號支付")
                .attach("Node.js 版:https://gitee.com/javen205/TNW")
                .out_trade_no(WxPayKit.generateStr())
                .total_fee("1000")
                .spbill_create_ip(ip)
                .notify_url(notifyUrl)
                .trade_type(TradeType.JSAPI.getTradeType())
                .openid(openId)
                .build()
                .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
        String xml = WxPayKit.toXml(params);
        log.info(xml);

發起請求

由于篇幅原因這里不做詳細介紹,請參考 擴展 Http 請求

喚起支付

這里常見的問題就是預付訂單二次簽名異常以及喚起支付提示各種配置錯誤,比如授權目錄沒有配置

預付訂單二次簽名封裝

	/**
     * <p>公眾號支付-預付訂單再次簽名</p>
     * <p>注意此處簽名方式需與統一下單的簽名類型一致</p>
     *
     * @param prepayId   預付訂單號
     * @param appId      應用編號
     * @param partnerKey API Key
     * @param signType   簽名方式
     * @return 再次簽名后的 Map
     */
    public static Map<String, String> prepayIdCreateSign(String prepayId, String appId, String partnerKey, SignType signType) {
        Map<String, String> packageParams = new HashMap<String, String>(6);
        packageParams.put("appId", appId);
        packageParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        packageParams.put("nonceStr", String.valueOf(System.currentTimeMillis()));
        packageParams.put("package", "prepay_id=" + prepayId);
        if (signType == null) {
            signType = SignType.MD5;
        }
        packageParams.put("signType", signType.getType());
        String packageSign = WxPayKit.createSign(packageParams, partnerKey, signType);
        packageParams.put("paySign", packageSign);
        return packageParams;
    }

    /**
     * <p>APP 支付-預付訂單再次簽名</p>
     * <p>注意此處簽名方式需與統一下單的簽名類型一致</p>
     *
     * @param appId      應用編號
     * @param partnerId  商戶號
     * @param prepayId   預付訂單號
     * @param partnerKey API Key
     * @param signType   簽名方式
     * @return 再次簽名后的 Map
     */
    public static Map<String, String> appPrepayIdCreateSign(String appId, String partnerId, String prepayId, String partnerKey, SignType signType) {
        Map<String, String> packageParams = new HashMap<String, String>(8);
        packageParams.put("appid", appId);
        packageParams.put("partnerid", partnerId);
        packageParams.put("prepayid", prepayId);
        packageParams.put("package", "Sign=WXPay");
        packageParams.put("noncestr", String.valueOf(System.currentTimeMillis()));
        packageParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        if (signType == null) {
            signType = SignType.MD5;
        }
        String packageSign = createSign(packageParams, partnerKey, signType);
        packageParams.put("sign", packageSign);
        return packageParams;
    }

    /**
     * <p>小程序-預付訂單再次簽名</p>
     * <p>注意此處簽名方式需與統一下單的簽名類型一致</p>
     *
     * @param appId      應用編號
     * @param prepayId   預付訂單號
     * @param partnerKey API Key
     * @param signType   簽名方式
     * @return 再次簽名后的 Map
     */
    public static Map<String, String> miniAppPrepayIdCreateSign(String appId, String prepayId, String partnerKey, SignType signType) {
        Map<String, String> packageParams = new HashMap<String, String>(6);
        packageParams.put("appId", appId);
        packageParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        packageParams.put("nonceStr", String.valueOf(System.currentTimeMillis()));
        packageParams.put("package", "prepay_id=" + prepayId);
        if (signType == null) {
            signType = SignType.MD5;
        }
        packageParams.put("signType", signType.getType());
        String packageSign = createSign(packageParams, partnerKey, signType);
        packageParams.put("paySign", packageSign);
        return packageParams;
    }

具體使用案例請參考 IJPay-Demo-SpringBoot

支付異步通知

目前微信支付異步通知有兩種:支付結果異步通知、微信退款異步通知

注意事項: 1、及時響應對應的應答 2、異步通知需要根據訂單號做去重處理 3、支付結果的異步通知簽名方法必須與統一下單的簽名方式保持一致 4、微信退款異步通知出現 java.security.InvalidKeyException: Illegal key size 異常 解決方案

驗證簽名封裝

/**
     * 支付異步通知時校驗 sign
     *
     * @param params     參數
     * @param partnerKey 支付密鑰
     * @param signType   {@link SignType}
     * @return
     */
    public static boolean verifyNotify(Map<String, String> params, String partnerKey, SignType signType) {
        String sign = params.get("sign");
        String localSign = createSign(params, partnerKey, signType);
        return sign.equals(localSign);
    }

微信支付結果異步通知業務處理邏輯的偽代碼

	/**
     * 異步通知
     */
    @RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String payNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        log.info("支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");

        // 注意重復通知的情況,同一訂單號可能收到多次通知,請注意一定先判斷訂單狀態
        // 注意此處簽名方式需與統一下單的簽名類型一致
        if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                // 更新訂單信息
                // 發送通知等
                Map<String, String> xml = new HashMap<String, String>(2);
                xml.put("return_code", "SUCCESS");
                xml.put("return_msg", "OK");
                return WxPayKit.toXml(xml);
            }
        }
        return null;
    }

微信退款數據解密

微信退款數據解密詳細步驟請參考官方文檔,以下是使用 Hutool 提供 SecureUtil 實現

	/**
     * AES 解密
     *
     * @param base64Data 需要解密的數據
     * @param key        密鑰
     * @return 解密后的數據
     */
    public static String decryptData(String base64Data, String key) {
        return SecureUtil.aes(md5(key).toLowerCase().getBytes()).decryptStr(base64Data);
    }

微信退款通知業務處理邏輯的偽代碼

	/**
     * 退款通知
     */
    @RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String refundNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        log.info("退款通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");
        // 注意重復通知的情況,同一訂單號可能收到多次通知,請注意一定先判斷訂單狀態
        if (WxPayKit.codeIsOk(returnCode)) {
            String reqInfo = params.get("req_info");
            String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey());
            log.info("退款通知解密后的數據=" + decryptData);
            // 更新訂單信息
            // 發送通知等
            Map<String, String> xml = new HashMap<String, String>(2);
            xml.put("return_code", "SUCCESS");
            xml.put("return_msg", "OK");
            return WxPayKit.toXml(xml);
        }
        return null;
    }

到此,相信大家對“微信支付接入步驟”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

繁昌县| 东乡县| 岗巴县| 晋中市| 苏尼特右旗| 龙胜| 武功县| 内黄县| 赣州市| 吐鲁番市| 竹溪县| 昌吉市| 嵊泗县| 潞西市| 徐州市| 应城市| 姚安县| 双柏县| 桐梓县| 赫章县| 夹江县| 隆昌县| 祁东县| 利辛县| 通榆县| 蕲春县| 卢龙县| 宜川县| 开平市| 克山县| 西畴县| 建阳市| 饶阳县| 沐川县| 沁源县| 邵东县| 大洼县| 汉阴县| 沈阳市| 五华县| 普兰县|