【微信支付】“刷卡支付”、“被掃支付”開發(fā)JavaDemo

快速上手,使用SDK只需三步即可接入“被掃支付”

第一步,初始化SDK
    //--------------------------------------------------------------------
    //第一步:初始化SDK(只需全局初始化一次即可)
    //--------------------------------------------------------------------
    WXPay.initSDKConfiguration(
                //簽名算法需要用到的秘鑰
                "40a8f8aa8ebe45a40bdc4e0f7307bc66",
                //公眾賬號(hào)ID,成功申請(qǐng)公眾賬號(hào)后獲得
                "wxf5b5e87a6a0fde94",
                //商戶ID,成功申請(qǐng)微信支付功能之后通過官方發(fā)出的郵件獲得
                "10000097",
                //子商戶ID,受理模式下必填;
                "",
                //HTTP證書在服務(wù)器中的路徑,用來加載證書用
                "C:/wxpay_scanpay_java_cert/10000097.p12",
                //HTTP證書的密碼,默認(rèn)等于MCHID
                "10000097"
        );
第二步,準(zhǔn)備好提交給API的數(shù)據(jù)(scanPayReqData)
    //--------------------------------------------------------------------
    //第二步:準(zhǔn)備好提交給API的數(shù)據(jù)(scanPayReqData)
    //--------------------------------------------------------------------
    //1)創(chuàng)建一個(gè)可以用來生成數(shù)據(jù)的bridge,這里用的是一個(gè)專門用來測試用的Bridge,商戶需要自己實(shí)現(xiàn)
        BridgeForScanPayBusinessTest bridge = new BridgeForScanPayBusinessTest();
        //2)從bridge里面拿到數(shù)據(jù),構(gòu)建提交被掃支付API需要的數(shù)據(jù)對(duì)象
        ScanPayReqData scanPayReqData = new ScanPayReqData(
                //這個(gè)是掃碼終端設(shè)備從用戶手機(jī)上掃取到的支付授權(quán)號(hào),有效期是1分鐘
                bridge.getAuthCode(),
                //要支付的商品的描述信息,用戶會(huì)在支付成功頁面里看到這個(gè)信息
                bridge.getBody(),
                //支付訂單里面可以填的附加數(shù)據(jù),API會(huì)將提交的這個(gè)附加數(shù)據(jù)原樣返回
                bridge.getAttach(),
                //商戶系統(tǒng)內(nèi)部的訂單號(hào),32個(gè)字符內(nèi)可包含字母, 確保在商戶系統(tǒng)唯一
                bridge.getOutTradeNo(),
                //訂單總金額,單位為“分”,只能整數(shù)
                bridge.getTotalFee(),
                //商戶自己定義的掃碼支付終端設(shè)備號(hào),方便追溯這筆交易發(fā)生在哪臺(tái)終端設(shè)備上
                bridge.getDeviceInfo(),
                //訂單生成的機(jī)器IP
                bridge.getSpBillCreateIP(),
                //訂單生成時(shí)間,格式為yyyyMMddHHmmss,如2009年12月25日9點(diǎn)10分10秒表示為20091225091010
                bridge.getTimeStart(),
                //訂單失效時(shí)間,格式同上
                bridge.getTimeExpire(),
                //商品標(biāo)記,微信平臺(tái)配置的商品標(biāo)記,用于優(yōu)惠券或者滿減使用
                bridge.getGoodsTag()
        );
第三步,準(zhǔn)備好一個(gè)用來處理各種結(jié)果分支的監(jiān)聽器(resultListener)
    //--------------------------------------------------------------------
        //第三步:準(zhǔn)備好一個(gè)用來處理各種結(jié)果分支的監(jiān)聽器(resultListener)
        //--------------------------------------------------------------------
        //這個(gè)是Demo里面寫的一個(gè)默認(rèn)行為,商戶需要根據(jù)自身需求來進(jìn)行完善
        DefaultScanPayBusinessResultListener resultListener = new DefaultScanPayBusinessResultListener();

        //--------------------------------------------------------------------
        //搞定以上三步后執(zhí)行業(yè)務(wù)邏輯
        //--------------------------------------------------------------------
        WXPay.doScanPayBusiness(scanPayReqData,resultListener);

Demo簡單說明

  1. Demo中包含的內(nèi)容
  2. Demo依賴的配置項(xiàng)
  3. Demo需要商戶自己實(shí)現(xiàn)的IBridge

最佳實(shí)踐

  1. 被掃支付業(yè)務(wù)流程最佳實(shí)踐
  2. 支付業(yè)務(wù)邏輯分支處理最佳實(shí)踐
  3. 商戶系統(tǒng)接入SDK最佳實(shí)踐
  4. 商戶系統(tǒng)部署最佳實(shí)踐

高級(jí)自定義

  1. 自定義查詢流程和撤銷流程
  2. 使用自己的Https請(qǐng)求器

“被掃支付”高級(jí)知識(shí)

  1. 調(diào)用被掃支付API的協(xié)議規(guī)則
  2. 支付驗(yàn)證密碼規(guī)則

Demo包含的內(nèi)容

Demo里面需要大家關(guān)注的主要有三個(gè)地方:

  1. 四個(gè)業(yè)務(wù)Demo,位于src/main/java/com/tencent/business/目錄里面,這些demo將會(huì)教大家如何調(diào)用SDK里面封裝好的業(yè)務(wù)邏輯。

  2. 橋接器bridge,位于src/main/java/com/tencent/bridge/目錄里面。里面目前有4個(gè)bridge,分別對(duì)應(yīng)4個(gè)業(yè)務(wù)demo。這個(gè)東西是用來對(duì)接商戶系統(tǒng)邏輯,產(chǎn)生SDK請(qǐng)求所需要的特定參數(shù)用的,請(qǐng)大家按照API文檔的說明實(shí)現(xiàn)這些參數(shù)的產(chǎn)生邏輯。

  3. 監(jiān)聽器listener,位于src/main/java/com/tencent/listener/目錄里面,這幾個(gè)listener都是對(duì)業(yè)務(wù)邏輯各種可能返回事件的默認(rèn)處理,商戶需要自己實(shí)現(xiàn)更加具體的處理邏輯。

Demo依賴的配置項(xiàng)

  • 打開demo工程里的wxpay.properties文件可以看到里面有6個(gè)配置項(xiàng)(該demo里面用的是一個(gè)mchid為10000097的測試號(hào))
    這些關(guān)鍵配置項(xiàng)的作用分別為:
- 名稱 用途 來源
1 KEY 簽名算法需要用到的秘鑰 成功申請(qǐng)微信支付功能之后通過官方發(fā)出的郵件獲得
2 APPID 公眾賬號(hào)ID 成功申請(qǐng)公眾賬號(hào)后獲得
3 MCHID 商戶ID 成功申請(qǐng)微信支付功能之后通過官方發(fā)出的郵件獲得
4 SUBMCHID 子商戶ID 受理模式下必須要有的一個(gè)子商戶ID
5 CERT_LOCAL_PATH HTTP證書在服務(wù)器中的路徑,用來加載證書用 成功申請(qǐng)微信支付功能之后通過官方發(fā)出的郵件獲得“HTTPS證書”,這個(gè)配置項(xiàng)就是“HTTP證書”在服務(wù)器上所部署的路徑(demo中需要的證書文件就是docs/https_cert_for_test/文件夾中的10000097.cert)
6 CERT_PASSWORD HTTP證書的密碼,默認(rèn)等于MCHID 成功申請(qǐng)微信支付功能之后通過官方發(fā)出的郵件獲得

這些配置項(xiàng)用來對(duì)SDK進(jìn)行一次初始化的時(shí)候使用。初始化方法見上面的“第一步,初始化SDK

Demo需要商戶自己實(shí)現(xiàn)的IBridge

img
img

從上圖可見IBridge橋接器其實(shí)就是定義了請(qǐng)求API時(shí)需要提交的各種參數(shù)的產(chǎn)生接口,這些接口跟商戶自己的系統(tǒng)是緊密結(jié)合的,商戶自己需要根據(jù)具體業(yè)務(wù)系統(tǒng)的實(shí)際情況,按照API文檔定義的格式來產(chǎn)生相應(yīng)的參數(shù)給到調(diào)用API時(shí)使用。
舉個(gè)例子,IBridge里面定義了一個(gè)非常關(guān)鍵的接口,叫g(shù)etAuthCode(),這個(gè)接口的作用就是用來返回一個(gè)合法的“授權(quán)碼”供調(diào)用API時(shí)用。

/**
 * 獲取auth_code,這個(gè)是掃碼終端設(shè)備從用戶手機(jī)上掃取到的支付授權(quán)號(hào),這個(gè)號(hào)是跟用戶用來支付的銀行卡綁定的,有效期是1分鐘
 * @return 授權(quán)碼
 */
public String getAuthCode(){
    //由于這個(gè)authCode有效期只有1分鐘,所以實(shí)際測試SDK的時(shí)候也可以手動(dòng)將微信刷卡界面一維碼下的那串?dāng)?shù)字輸入進(jìn)來
    return "120242957324236112";
}

以上只是簡單的hardcode(用來先簡單手動(dòng)輸入“授權(quán)碼”調(diào)試API是否能正常返回?cái)?shù)據(jù)時(shí)用),實(shí)際上商戶自己在實(shí)現(xiàn)這個(gè)接口的時(shí)候就需要根據(jù)自己實(shí)際系統(tǒng)來進(jìn)行設(shè)計(jì)了,例如需要去監(jiān)聽“掃碼槍”等具備一維碼/二維碼掃描功能的外設(shè),當(dāng)成功掃描到這串“授權(quán)碼”的時(shí)候,將其保存下來,然后觸發(fā)提交支付的API調(diào)用,調(diào)用時(shí)讓IBridge橋接器中的getAuthCode()接口取得剛剛掃描到的授權(quán)碼,作為參數(shù)傳給支付API。

被掃支付業(yè)務(wù)流程最佳實(shí)踐

被掃支付整個(gè)完成流程將會(huì)涉及到“查詢”和“撤銷”等請(qǐng)求,這里給出建議實(shí)現(xiàn)的流程供大家參考,SDK里面的ScanPayBusiness就是按照這個(gè)流程來設(shè)計(jì)的:

img
img

從上圖可見主要流程分為四種情況:

  1. 直接扣款成功:直接返回成功
  2. 扣款明確失敗:走撤銷流程,返回失敗(建議提示具體的失敗信息,指示用戶進(jìn)行下一步操作)
  3. 需輸入密碼:走查單流程,如果查詢了一定時(shí)間還是沒有成功則當(dāng)失敗處理,直接走撤銷
  4. 扣款未知失敗:先走查單流程,如果查詢了一定時(shí)間還是沒有成功則當(dāng)失敗處理,直接走撤銷

兩個(gè)關(guān)鍵流程解釋:

  1. 有限次查詢流程:這里會(huì)根據(jù)設(shè)定的“查詢次數(shù)”(用戶可以自定義)和“查詢間隔”來進(jìn)行輪詢,超過了查詢次數(shù)之后還是沒有查詢到“支付成功”的情況會(huì)自動(dòng)轉(zhuǎn)入“撤銷流程”
  2. 撤銷流程:這里會(huì)根據(jù)設(shè)定的“查詢間隔”進(jìn)行不停地輪詢撤銷API,API會(huì)通過recall字段來告訴商戶側(cè)需不需要繼續(xù)輪詢,如果“recall=Y”或是“撤銷結(jié)果成功”都表示不需要再輪詢了,然后到達(dá)“支付失敗”的最終狀態(tài)。

(以上最佳實(shí)踐已經(jīng)在SDK的ScanPayBusiness里面封裝好了)

支付業(yè)務(wù)邏輯分支處理最佳實(shí)踐

img
img

ScanPayBusiness里面的ResultListener接口定義了支付流程中可能走到的8個(gè)分支,分別是:

 public interface ResultListener {
        //API返回ReturnCode不合法,支付請(qǐng)求邏輯錯(cuò)誤,請(qǐng)仔細(xì)檢測傳過去的每一個(gè)參數(shù)是否合法,或是看API能否被正常訪問
        void onFailByReturnCodeError(ScanPayResData scanPayResData);
        //API返回ReturnCode為FAIL,支付API系統(tǒng)返回失敗,請(qǐng)檢測Post給API的數(shù)據(jù)是否規(guī)范合法
        void onFailByReturnCodeFail(ScanPayResData scanPayResData);
        //支付請(qǐng)求API返回的數(shù)據(jù)簽名驗(yàn)證失敗,有可能數(shù)據(jù)被篡改了
        void onFailBySignInvalid(ScanPayResData scanPayResData);
        //用戶用來支付的二維碼已經(jīng)過期,提示收銀員重新掃一下用戶微信“刷卡”里面的二維碼
        void onFailByAuthCodeExpire(ScanPayResData scanPayResData);
        //授權(quán)碼無效,提示用戶刷新一維碼/二維碼,之后重新掃碼支付"
        void onFailByAuthCodeInvalid(ScanPayResData scanPayResData);
        //用戶余額不足,換其他卡支付或是用現(xiàn)金支付
        void onFailByMoneyNotEnough(ScanPayResData scanPayResData);
        //支付失敗
        void onFail(ScanPayResData scanPayResData);
        //支付成功
        void onSuccess(ScanPayResData scanPayResData);
    }

Demo里面用到的DefaultScanPayBusinessResultListener就是實(shí)現(xiàn)了以上這8個(gè)接口。
這里有幾點(diǎn)處理建議:

  1. onFailByReturnCodeErroronFailByReturnCodeFailonFailBySignInvalid這3種屬于程序邏輯問題,建議商戶自己做好日志監(jiān)控,發(fā)現(xiàn)問題要及時(shí)讓工程師進(jìn)行定位處理;
  2. onFailByAuthCodeExpireonFailByAuthCodeInvalidonFailByMoneyNotEnough這三種屬于用戶自身的問題,建議商戶把具體出錯(cuò)信息提示給用戶,指導(dǎo)用戶進(jìn)行下一步操作。(具體出錯(cuò)信息可以通過scanPayResData.getErr_code_des()獲取得到)

商戶系統(tǒng)接入SDK最佳實(shí)踐

  1. 生成一個(gè)新的訂單out_trade_no
  2. 輸入訂單金額total_fee
  3. 啟動(dòng)掃碼槍功能供用戶進(jìn)行掃碼
  4. 掃碼器獲取授權(quán)碼auth_code,并回傳給SDK
  5. SDK提交支付請(qǐng)求
  6. SDK處理API返回的數(shù)據(jù)


    img
    img

商戶系統(tǒng)部署最佳實(shí)踐

  1. 由于整套系統(tǒng)必須采用HTTPS來保證安全性,所以這里的支付請(qǐng)求必須由商戶的后臺(tái)系統(tǒng)來發(fā)起;
  2. 商戶系統(tǒng)跟SDK的對(duì)接主要就是實(shí)現(xiàn)IBridge里面的接口;
  3. 從本demo里面有JUnit單元測試用例,商戶開發(fā)者可以參考下這個(gè)示例;


    img
    img

高級(jí)自定義:1)自定義查詢流程和撤銷流程

商戶可以根據(jù)自己的實(shí)際需要來配置支付業(yè)務(wù)流程中的“查詢流程”的“查詢次數(shù)”和“查詢間隔”;“撤銷流程”的“查詢間隔”,例如:

    //自定義調(diào)用查詢接口的間隔
    scanPayBusiness.setWaitingTimeBeforePayQueryServiceInvoked(3000);
    //自定義調(diào)用查詢接口的次數(shù)
    scanPayBusiness.setPayQueryLoopInvokedCount(1);
    //自定義調(diào)用撤銷接口的間隔
    scanPayBusiness.setWaitingTimeBeforeReverseServiceInvoked(2000);

高級(jí)自定義:2)使用自己的Https請(qǐng)求器

可能有些商戶自己系統(tǒng)里面已經(jīng)擁有自己封裝得很完善的Https請(qǐng)求器了,想讓SDK的服務(wù)統(tǒng)一都走自己的Https請(qǐng)求器來發(fā)起請(qǐng)求的話,這里提供了一個(gè)配置項(xiàng)可以實(shí)現(xiàn)這個(gè)功能:

 //自定義底層的HttpsRequest
    Configure.setHttpsRequestClassName("com.tencent.httpsrequest.HttpsRequestForTest");

溫馨提示:自己實(shí)現(xiàn)的Https請(qǐng)求器必須實(shí)現(xiàn)IServiceRequest這個(gè)接口,可以參考SDK里面的HttpRequest的實(shí)現(xiàn)。

調(diào)用被掃支付API的協(xié)議規(guī)則

序號(hào)||
:-:|-|-
1|傳輸方式|為保證交易安全性,采用HTTPS傳輸
2|提交方式|采用POST方法提交
3|數(shù)據(jù)格式|提交和返回?cái)?shù)據(jù)都為XML格式,根節(jié)點(diǎn)名為xml
4|字符編碼|統(tǒng)一采用UTF-8字符編碼
5|簽名算法|MD5
6|簽名要求|請(qǐng)求和接收數(shù)據(jù)均需要校驗(yàn)簽名,簽名的方法在SDK里面已經(jīng)封裝好了
7|證書要求|調(diào)用申請(qǐng)退款、撤銷訂單接口需要商戶證書
8|判斷邏輯|先判斷協(xié)議字段返回,再判斷業(yè)務(wù)返回,最后判斷交易狀態(tài)

支付驗(yàn)證密碼規(guī)則

  1. 支付金額>300元的交易需要驗(yàn)證用戶支付密碼;
  2. 用戶賬號(hào)每天最多有10筆交易可以免密,超過后需要驗(yàn)證密碼;
  3. 微信支付后臺(tái)判斷用戶支付行為有異常情況,符合免密規(guī)則的交易也會(huì)要求驗(yàn)證密碼;

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 快速上手 什么是“被掃支付”、“刷卡支付”刷卡支付是用戶展示微信錢包內(nèi)的“刷卡條碼/二維碼”給商戶系統(tǒng)掃描后直接完...
    指尖的跳躍閱讀 6,155評(píng)論 2 3
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,557評(píng)論 25 708
  • 前言:本篇文章目的在于梳理知識(shí),鞏固思想,學(xué)習(xí)總結(jié)。有什么好的建議,都可以留言。互相促進(jìn)!總觀,微信支付,也沒心思...
    麥穗0615閱讀 10,097評(píng)論 8 70
  • 昨晚上抱著手機(jī)聽著燕子的新媒體直播課程,手上拿著筆和本子用思維導(dǎo)圖的方式作筆記,然后我就這樣睡著了……不確...
    胡永群閱讀 561評(píng)論 0 50
  • 我知道,地球是圓的,所以從一個(gè)點(diǎn)往前走,總會(huì)回到最初的地方,不過我收獲了一路的風(fēng)景 我知道,雨后會(huì)天晴,所以即使在...
    小紫蘇閱讀 200評(píng)論 0 0