WeChatで払います.知りたいことは全部ここにあります.


個人でも企業でも、業務が現金化され、広告以外の一番いい方法は入金されます.私たちがよく使うWeChatの支払いはどうやって迅速に技術ドッキングを完成しますか?国内での支払いと海外での支払いはどうやってサポートされますか?どうやってクロスカントリーを作りますか?干物が多くて、話が少ないです.これからゆっくり話します.
記事の目次
  • アクセスステップ
  • マイクロクレジット支払いインターフェースURL
  • を取得する.
  • マイクロクレジットのドメイン名
  • WeChat支払い用インターフェース
  • 完全URL方式
  • を取得する.
  • 構築要求パラメータ
  • Model構築実現機構
  • カプセル化Model自動生成署名
  • 署名アルゴリズムは
  • を実現する.
  • Modelでxmlデータを構築する
  • 開始要求
  • 支払を喚起する
  • 支払い非同期通知
  • 認証署名パッケージ
  • マイクロクレジットの返金データの復号
  • アクセスステップ
    WeChat支払いアクセスの大体のステップは以下の通りである.1、支払いインターフェースURL 2の取得、構築要求パラメータ3、イニシャル要求4、支払いを喚起する5、非同期通知処理
    ステップ1で支払インターフェースURLを取得するには、この点を考慮する必要があります.
    1、国内のWeChat支払いと海外のWeChat支払いをどう同時にサポートするか?
    ステップ2でよく出会う問題はパラメータ署名検証問題です.
    1、MD 5暗号化2、HMAC-SHA 256暗号化
    ステップ3の難点は、WeChatが双方向証明書を支払う処理にある.
    手順四において前払注文書の二次署名異常及び支払い提示の各種構成エラーを喚起する.
    ステップ5において、非同期通知認証署名、注文繰り返し通知及び敏感データの復号問題
    以上のアクセスステップで、それらのピットを踏んだことがありますか?コメントエリアの交流を歓迎します.
    Talk is chap.Show me the code
    WeChat支払いインターフェースのURLを取得する
    「これは簡単ではないですか?」と言う人がいます.公式文書のインターフェイスに提供されています.あなたの言ったのは間違いないです.国内のWeChat支払いと海外のWeChat支払いを同時にサポートするシステムをどうやって実行しますか?
    WeChatドメイン名
    サービスエリアによって異なるWeChatは異なるドメイン名を提供してサポートしています.
  • api.mch.weixin.qq.com(アクセスポイント:中国国内)
  • api 2.mch.weixin.qq.com(アクセスポイント:中国国内予備)
  • apihk.mch.weixin.qq.com(アクセスポイント:東南アジア)
  • apius.mch.weixin.qq.com(推奨アクセスポイント:その他)
  • api.mch.weixin.q.com/sandbox new(特殊:シミュレーションテスト)
  • 聡明なあなたは、列挙することが容易ではないです.具体的には、都市を跨ぐ万障災害の方案はWeChatを参考にして商業家システムを支払って、都市を跨ぐ万障災害を昇格させることができます.
    /**
     * 

    IJPay , 、 、 。

    * *

    mvc , , 。

    * *

    IJPay : 723992875

    * *

    Node.js : https://gitee.com/javen205/TNW

    * *

    * * @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; } }
    これによりWeChat決済インターフェースURLを取得し、コア問題を解決しました.残りは支払い方法によって具体的な支払インターフェースのURLをつなぎ合わせます.
    WeChat支払い常用インターフェース
    支払いコード、JSAPI支払い、Native支払い、App支払い、H 5支払い、小プログラム支払い、紅包、企業決済、ホテルの保証金、顔決済のための一般的な支払い方法及び支払ツールの不完全な統計インターフェースは90+ぐらいあります.
    package com.ijpay.wxpay.enums;
    
    /**
     * 

    IJPay , 、 、 。

    * *

    mvc , , 。

    * *

    IJPay : 723992875

    * *

    Node.js : https://gitee.com/javen205/TNW

    * *

    * * @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/h5entrustweb"), /** * H5 ( ) */ PARTNER_H5_ENTRUST_WEB("/papay/partner/h5entrustweb"), /** * */ 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は、Lombook builder後のオブジェクトの属性および値をMapに変換し、署名を作成する方法を自動的にsignを生成することを実現する(MD 5およびHMAC-SHA 256を同時にサポートする).WeChatで支払った統一注文を例コードとして下記の通りです.
    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;
            }
        }
    
    }
    
    UnifiedOrder Model WeChatをまとめて注文します.
    /**
     * 

    IJPay , 、 、 。

    * *

    mvc , , 。

    * *

    IJPay : 723992875

    * *

    Node.js : https://gitee.com/javen205/TNW

    * *

    Model

    * * @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; }
    UnifiedOrder Modelでは、熟知しているフィールドは、公式インターフェースドキュメントから完全に来ています.残念なことに、Modelは小さいこぶ式の命名規則を守れません.
    署名アルゴリズムの実装
    MD 5およびHMAC-SHA 256署名アルゴリズムは、Hutolが提供するツールクラスを使用して実装される.
    	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でWeChat決済インターフェースを構築するために必要な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を参考にお願いします.
    支払いを喚起する
    ここでよく見られる問題は前払注文の二次署名異常と支払い提示の様々な構成エラーです.例えば、ライセンスディレクトリは設定されていません.
    事前注文の二次サイン入り
    	/**
         * 

    -

    *

    * * @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; } /** *

    APP -

    *

    * * @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; } /** *

    -

    *

    * * @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-pringBootを参照してください.
    非同期支払いの通知
    現在のWeChatの支払いに関する非同期通知には、支払い結果の非同期通知、WeChatの払い戻しの非同期通知があります.
    注意事項:1、適時に対応する応答2、非同期通知は注文番号に基づいて処理を行います.3、支払い結果の非同期通知署名方法は統一注文の署名方式と一致しなければなりません.
    署名パッケージを検証
    /**
         *           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);
        }
    
    WeChat支払いの結果は、非同期的に業務処理ロジックに通知する擬似コードです.
    	/**
         *     
         */
        @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;
        }
    
    WeChat払い戻しデータの復号
    WeChatの返金データの復号の詳細は、以下の公式文書を参照してください.Hutolを使用してSecureUtilを提供します.
    	/**
         * AES   
         *
         * @param base64Data        
         * @param key          
         * @return       
         */
        public static String decryptData(String base64Data, String key) {
            return SecureUtil.aes(md5(key).toLowerCase().getBytes()).decryptStr(base64Data);
        }
    
    WeChat払い戻し通知業務処理ロジックの疑似コード
    	/**
         *     
         */
        @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;
        }
    
    個人の能力は有限で、もし間違いがあれば、指摘を歓迎します.もし漏れがあれば、補充を歓迎します.質問があれば、メッセージを歓迎します.