快速上手,使用SDK只需三步即可接入“被掃支付”
第一步崔兴,初始化SDK
//--------------------------------------------------------------------
//第一步:初始化SDK(只需全局初始化一次即可)
//--------------------------------------------------------------------
WXPay.initSDKConfiguration(
//簽名算法需要用到的秘鑰
"40a8f8aa8ebe45a40bdc4e0f7307bc66",
//公眾賬號ID,成功申請公眾賬號后獲得
"wxf5b5e87a6a0fde94",
//商戶ID蛔翅,成功申請微信支付功能之后通過官方發(fā)出的郵件獲得
"10000097",
//子商戶ID敲茄,受理模式下必填;
"",
//HTTP證書在服務(wù)器中的路徑山析,用來加載證書用
"C:/wxpay_scanpay_java_cert/10000097.p12",
//HTTP證書的密碼堰燎,默認等于MCHID
"10000097"
);
第二步,準備好提交給API的數(shù)據(jù)(scanPayReqData
)
//--------------------------------------------------------------------
//第二步:準備好提交給API的數(shù)據(jù)(scanPayReqData)
//--------------------------------------------------------------------
//1)創(chuàng)建一個可以用來生成數(shù)據(jù)的bridge笋轨,這里用的是一個專門用來測試用的Bridge秆剪,商戶需要自己實現(xiàn)
BridgeForScanPayBusinessTest bridge = new BridgeForScanPayBusinessTest();
//2)從bridge里面拿到數(shù)據(jù),構(gòu)建提交被掃支付API需要的數(shù)據(jù)對象
ScanPayReqData scanPayReqData = new ScanPayReqData(
//這個是掃碼終端設(shè)備從用戶手機上掃取到的支付授權(quán)號爵政,有效期是1分鐘
bridge.getAuthCode(),
//要支付的商品的描述信息仅讽,用戶會在支付成功頁面里看到這個信息
bridge.getBody(),
//支付訂單里面可以填的附加數(shù)據(jù),API會將提交的這個附加數(shù)據(jù)原樣返回
bridge.getAttach(),
//商戶系統(tǒng)內(nèi)部的訂單號,32個字符內(nèi)可包含字母, 確保在商戶系統(tǒng)唯一
bridge.getOutTradeNo(),
//訂單總金額钾挟,單位為“分”洁灵,只能整數(shù)
bridge.getTotalFee(),
//商戶自己定義的掃碼支付終端設(shè)備號,方便追溯這筆交易發(fā)生在哪臺終端設(shè)備上
bridge.getDeviceInfo(),
//訂單生成的機器IP
bridge.getSpBillCreateIP(),
//訂單生成時間掺出,格式為yyyyMMddHHmmss徽千,如2009年12月25日9點10分10秒表示為20091225091010
bridge.getTimeStart(),
//訂單失效時間,格式同上
bridge.getTimeExpire(),
//商品標記汤锨,微信平臺配置的商品標記双抽,用于優(yōu)惠券或者滿減使用
bridge.getGoodsTag()
);
第三步,準備好一個用來處理各種結(jié)果分支的監(jiān)聽器(resultListener
)
//--------------------------------------------------------------------
//第三步:準備好一個用來處理各種結(jié)果分支的監(jiān)聽器(resultListener)
//--------------------------------------------------------------------
//這個是Demo里面寫的一個默認行為闲礼,商戶需要根據(jù)自身需求來進行完善
DefaultScanPayBusinessResultListener resultListener = new DefaultScanPayBusinessResultListener();
//--------------------------------------------------------------------
//搞定以上三步后執(zhí)行業(yè)務(wù)邏輯
//--------------------------------------------------------------------
WXPay.doScanPayBusiness(scanPayReqData,resultListener);
Demo簡單說明
最佳實踐
高級自定義
“被掃支付”高級知識
Demo包含的內(nèi)容
Demo里面需要大家關(guān)注的主要有三個地方:
四個業(yè)務(wù)Demo牍汹,位于
src/main/java/com/tencent/business/
目錄里面铐维,這些demo將會教大家如何調(diào)用SDK里面封裝好的業(yè)務(wù)邏輯。橋接器
bridge
柑贞,位于src/main/java/com/tencent/bridge/
目錄里面方椎。里面目前有4個bridge,分別對應4個業(yè)務(wù)demo钧嘶。這個東西是用來對接商戶系統(tǒng)邏輯棠众,產(chǎn)生SDK請求所需要的特定參數(shù)用的,請大家按照API文檔的說明實現(xiàn)這些參數(shù)的產(chǎn)生邏輯有决。監(jiān)聽器
listener
闸拿,位于src/main/java/com/tencent/listener/
目錄里面,這幾個listener
都是對業(yè)務(wù)邏輯各種可能返回事件的默認處理书幕,商戶需要自己實現(xiàn)更加具體的處理邏輯新荤。
Demo依賴的配置項
- 打開demo工程里的
wxpay.properties
文件可以看到里面有6個配置項(該demo里面用的是一個mchid為10000097的測試號)
這些關(guān)鍵配置項的作用分別為:
- | 名稱 | 用途 | 來源 |
---|---|---|---|
1 | KEY | 簽名算法需要用到的秘鑰 | 成功申請微信支付功能之后通過官方發(fā)出的郵件獲得 |
2 | APPID | 公眾賬號ID | 成功申請公眾賬號后獲得 |
3 | MCHID | 商戶ID | 成功申請微信支付功能之后通過官方發(fā)出的郵件獲得 |
4 | SUBMCHID | 子商戶ID | 受理模式下必須要有的一個子商戶ID |
5 | CERT_LOCAL_PATH | HTTP證書在服務(wù)器中的路徑,用來加載證書用 | 成功申請微信支付功能之后通過官方發(fā)出的郵件獲得“HTTPS證書”台汇,這個配置項就是“HTTP證書”在服務(wù)器上所部署的路徑(demo中需要的證書文件就是docs/https_cert_for_test/文件夾中的10000097.cert) |
6 | CERT_PASSWORD | HTTP證書的密碼苛骨,默認等于MCHID | 成功申請微信支付功能之后通過官方發(fā)出的郵件獲得 |
這些配置項用來對SDK進行一次初始化的時候使用。初始化方法見上面的“第一步苟呐,初始化SDK”
Demo需要商戶自己實現(xiàn)的IBridge

從上圖可見IBridge橋接器其實就是定義了請求API時需要提交的各種參數(shù)的產(chǎn)生接口痒芝,這些接口跟商戶自己的系統(tǒng)是緊密結(jié)合的,商戶自己需要根據(jù)具體業(yè)務(wù)系統(tǒng)的實際情況牵素,按照API文檔定義的格式來產(chǎn)生相應的參數(shù)給到調(diào)用API時使用严衬。
舉個例子,IBridge里面定義了一個非常關(guān)鍵的接口笆呆,叫g(shù)etAuthCode()请琳,這個接口的作用就是用來返回一個合法的“授權(quán)碼”供調(diào)用API時用。
/**
* 獲取auth_code赠幕,這個是掃碼終端設(shè)備從用戶手機上掃取到的支付授權(quán)號俄精,這個號是跟用戶用來支付的銀行卡綁定的,有效期是1分鐘
* @return 授權(quán)碼
*/
public String getAuthCode(){
//由于這個authCode有效期只有1分鐘劣坊,所以實際測試SDK的時候也可以手動將微信刷卡界面一維碼下的那串數(shù)字輸入進來
return "120242957324236112";
}
以上只是簡單的hardcode
(用來先簡單手動輸入“授權(quán)碼”調(diào)試API是否能正常返回數(shù)據(jù)時用)嘀倒,實際上商戶自己在實現(xiàn)這個接口的時候就需要根據(jù)自己實際系統(tǒng)來進行設(shè)計了,例如需要去監(jiān)聽“掃碼槍”等具備一維碼/二維碼掃描功能的外設(shè)局冰,當成功掃描到這串“授權(quán)碼”的時候测蘑,將其保存下來,然后觸發(fā)提交支付的API調(diào)用康二,調(diào)用時讓IBridge
橋接器中的getAuthCode()
接口取得剛剛掃描到的授權(quán)碼碳胳,作為參數(shù)傳給支付API。
被掃支付業(yè)務(wù)流程最佳實踐
被掃支付整個完成流程將會涉及到“查詢”和“撤銷”等請求沫勿,這里給出建議實現(xiàn)的流程供大家參考挨约,SDK里面的ScanPayBusiness
就是按照這個流程來設(shè)計的:

從上圖可見主要流程分為四種情況:
- 直接扣款成功:直接返回成功
- 扣款明確失斘痘臁:走撤銷流程,返回失斀氩选(建議提示具體的失敗信息翁锡,指示用戶進行下一步操作)
- 需輸入密碼:走查單流程,如果查詢了一定時間還是沒有成功則當失敗處理夕土,直接走撤銷
- 扣款未知失敼菹巍:先走查單流程,如果查詢了一定時間還是沒有成功則當失敗處理怨绣,直接走撤銷
兩個關(guān)鍵流程解釋:
- 有限次查詢流程:這里會根據(jù)設(shè)定的“查詢次數(shù)”(用戶可以自定義)和“查詢間隔”來進行輪詢角溃,超過了查詢次數(shù)之后還是沒有查詢到“支付成功”的情況會自動轉(zhuǎn)入“撤銷流程”
- 撤銷流程:這里會根據(jù)設(shè)定的“查詢間隔”進行不停地輪詢撤銷API,API會通過recall字段來告訴商戶側(cè)需不需要繼續(xù)輪詢篮撑,如果“recall=Y”或是“撤銷結(jié)果成功”都表示不需要再輪詢了减细,然后到達“支付失敗”的最終狀態(tài)。
(以上最佳實踐已經(jīng)在SDK的ScanPayBusiness
里面封裝好了)
支付業(yè)務(wù)邏輯分支處理最佳實踐

ScanPayBusiness
里面的ResultListener
接口定義了支付流程中可能走到的8個分支赢笨,分別是:
public interface ResultListener {
//API返回ReturnCode不合法未蝌,支付請求邏輯錯誤,請仔細檢測傳過去的每一個參數(shù)是否合法茧妒,或是看API能否被正常訪問
void onFailByReturnCodeError(ScanPayResData scanPayResData);
//API返回ReturnCode為FAIL树埠,支付API系統(tǒng)返回失敗,請檢測Post給API的數(shù)據(jù)是否規(guī)范合法
void onFailByReturnCodeFail(ScanPayResData scanPayResData);
//支付請求API返回的數(shù)據(jù)簽名驗證失敗嘶伟,有可能數(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
就是實現(xiàn)了以上這8個接口毕匀。
這里有幾點處理建議:
-
onFailByReturnCodeError
铸鹰、onFailByReturnCodeFail
、onFailBySignInvalid
這3種屬于程序邏輯問題皂岔,建議商戶自己做好日志監(jiān)控蹋笼,發(fā)現(xiàn)問題要及時讓工程師進行定位處理; -
onFailByAuthCodeExpire
躁垛、onFailByAuthCodeInvalid
剖毯、onFailByMoneyNotEnough
這三種屬于用戶自身的問題,建議商戶把具體出錯信息提示給用戶教馆,指導用戶進行下一步操作逊谋。(具體出錯信息可以通過scanPayResData.getErr_code_des()
獲取得到)
商戶系統(tǒng)接入SDK最佳實踐
- 生成一個新的訂單
out_trade_no
- 輸入訂單金額
total_fee
- 啟動掃碼槍功能供用戶進行掃碼
- 掃碼器獲取授權(quán)碼
auth_code
,并回傳給SDK - SDK提交支付請求
-
SDK處理API返回的數(shù)據(jù)
img
商戶系統(tǒng)部署最佳實踐
- 由于整套系統(tǒng)必須采用HTTPS來保證安全性土铺,所以這里的支付請求必須由商戶的后臺系統(tǒng)來發(fā)起胶滋;
- 商戶系統(tǒng)跟SDK的對接主要就是實現(xiàn)IBridge里面的接口板鬓;
-
從本demo里面有JUnit單元測試用例,商戶開發(fā)者可以參考下這個示例究恤;
img
高級自定義:1)自定義查詢流程和撤銷流程
商戶可以根據(jù)自己的實際需要來配置支付業(yè)務(wù)流程中的“查詢流程”的“查詢次數(shù)”和“查詢間隔”俭令;“撤銷流程”的“查詢間隔”,例如:
//自定義調(diào)用查詢接口的間隔
scanPayBusiness.setWaitingTimeBeforePayQueryServiceInvoked(3000);
//自定義調(diào)用查詢接口的次數(shù)
scanPayBusiness.setPayQueryLoopInvokedCount(1);
//自定義調(diào)用撤銷接口的間隔
scanPayBusiness.setWaitingTimeBeforeReverseServiceInvoked(2000);
高級自定義:2)使用自己的Https請求器
可能有些商戶自己系統(tǒng)里面已經(jīng)擁有自己封裝得很完善的Https請求器了部宿,想讓SDK的服務(wù)統(tǒng)一都走自己的Https請求器來發(fā)起請求的話抄腔,這里提供了一個配置項可以實現(xiàn)這個功能:
//自定義底層的HttpsRequest
Configure.setHttpsRequestClassName("com.tencent.httpsrequest.HttpsRequestForTest");
溫馨提示:自己實現(xiàn)的Https請求器必須實現(xiàn)IServiceRequest這個接口,可以參考SDK里面的HttpRequest的實現(xiàn)窟赏。
調(diào)用被掃支付API的協(xié)議規(guī)則
序號||
:-:|-|-
1|傳輸方式|為保證交易安全性妓柜,采用HTTPS傳輸
2|提交方式|采用POST方法提交
3|數(shù)據(jù)格式|提交和返回數(shù)據(jù)都為XML格式,根節(jié)點名為xml
4|字符編碼|統(tǒng)一采用UTF-8字符編碼
5|簽名算法|MD5
6|簽名要求|請求和接收數(shù)據(jù)均需要校驗簽名涯穷,簽名的方法在SDK里面已經(jīng)封裝好了
7|證書要求|調(diào)用申請退款棍掐、撤銷訂單接口需要商戶證書
8|判斷邏輯|先判斷協(xié)議字段返回,再判斷業(yè)務(wù)返回拷况,最后判斷交易狀態(tài)
支付驗證密碼規(guī)則
- 支付金額>300元的交易需要驗證用戶支付密碼作煌;
- 用戶賬號每天最多有10筆交易可以免密,超過后需要驗證密碼赚瘦;
- 微信支付后臺判斷用戶支付行為有異常情況粟誓,符合免密規(guī)則的交易也會要求驗證密碼;