最近在做一個項目,里面涉及到了支付功能,使用的是銀聯的在線支付功能(網關跳轉支付)。銀聯給的例子很坑爹,簡單的代碼注釋了一大堆,關鍵的部分一點兒注釋都沒有,很多工具類還沒有源碼。所以學習起來比較吃力。而網上這方面的資料有相對比較少,僅有的一些資料也比較陳舊。所以我打算記錄一下我的學習記錄,說不定會對別人也有一些幫助。
下載銀聯Demo
我做的是銀聯的網關跳轉支付功能,用戶在我的網頁上點擊跳轉按鈕以后會跳轉到銀聯在線支付頁面,支付完用戶可以點擊返回商家回到我們的網站(但是他可以不點,直接關閉頁面),然后我們的服務器后台會接受銀聯的用戶付款的通知,再更新自己數據庫的功能。
銀聯技術服務的首頁地址是https://open.unionpay.com/ajweb/index 很多資料可以在這里找到。
我下載的Demo在這里https://open.unionpay.com/ajweb/help/file/techFile?cateLog=Sample_code 這里有很多資料都可以選擇。但是其實很多是重復的,很多是用不到的(對於我做的功能來說)。所以選擇自己需要的就可以了。我選擇的是 下載資源類別里的開發包菜單(左側菜單) 下面的 跳轉網關支付產品技術開發包。
我寫這個項目的時候銀聯版本是2015-07-29的1.11版本(夠新了吧(⊙﹏⊙))
里面亂糟糟的一大堆東西。。。。。PHP啊Java啊ASP啊啥都有。。。。
我選擇Java版本的。
然后把示例代碼下面的src目錄下面的東西全部導入到自己建的web項目下。(是全部導入,所以除了.java以外還要導入acp_sdk.properties)
然后把依賴包下面的jar和upacp_sdk-1.0.0-20150703140550.jar導入到lib目錄下(我沒有導入json可選包)
給張圖說明一切問題
然后項目就搭建好了。。是不是超級容易呀。。然后我會將如何配置項目。。
配置Properties文件
然后我來說下如何配置properties文件。
properties文件打開注釋全部是unicode編碼。。。簡直坑爹。。看不懂可以去網上把unicode轉成中文看看注釋。。其實也沒有必要。后面我會介紹比較有用的幾個配置項。。其他沒啥用處。
acp_sdk.properties這個文件大家不要重命名。
因為這個文件名是銀聯寫死在配置類中的。改了名字會讀取不到。
前面各種Url配置大家不需要去改動,下載下來都是配好的測試地址。只有到了正式上線了才需要去配置成正式的地址(但是我的項目也沒上線。。所以我也不知道正式地址是啥。。但是銀聯官網上我看到是有資料寫的。大家可以去自己搜搜看)
后面的配置是和證書相關的,另外插一句。properties里少了幾行配置。。。坑了我幾天時間。。
把證書Cert文件夾里的入網測試環境的3個文件夾全部拷到桌面上。因為會用到。(我放桌面上是為了方便配置)
修改properties里的acpsdk.signCert.path的值為C:\\Users\\Administrator\\desktop\\入網測試環境\\商戶私鑰證書(簽名)PM_700000000000001_acp.pfx
大家對照路徑可以自己改,注意這里700000000000001這個數字。后面會用到(又被坑了幾天。。。)
這個證書在正式上線以后需要改為正式的證書,這個證書是測試使用。
acpsdk.signCert.pwd並不需要改,因為測試證書的密碼就是6個0。
同理,正式上線之后要修改成自己的密碼
acpsdk.signCert.type不需要修改,就是PKCS12
acpsdk.validateCert.dir的值修改為C:\\Users\\Administrator\\desktop\\入網測試環境\\銀聯公鑰證書(驗簽)
validateCert是用在銀聯給你發消息的時候判斷真偽用的(別人可能會偽造銀聯的信息,所以需要用這個證書驗證信息真偽),所以對於創建訂單付款來說沒有什么用處。但是后面銀聯通知你用戶付款的時候你要用這個證書驗證消息是不是真的來自銀聯。
增加acpsdk.encryptCert.path這個key,value為C:\\Users\\Administrator\\desktop\\入網測試環境\\加密證書 (根據業務需求選用)\\encrypt.cer
銀聯居然默認沒有這個配置。。坑爹啊。。。這個是你給銀聯發消息的時候銀聯要判斷這個訂單是不是指定商戶(你)發過來的。也是驗證真偽用的(加密)
完成這些配置就可以愉快(剁手)的和銀聯做交易了。
創建訂單
創建訂單方面其實可以直接參考Form_6_2_FrontConsume這個類。
SDKConfig.getConfig().loadPropertiesFromSrc();是去加載properties配置文件,但是要求配置文件放在.class的根目錄。就是和包文件com同級。
這個方法並不好用,因為你自己測試的時候和項目部署上去位置可能會經常變化。所以可以使用更好用的方法SDKConfig.getConfig().loadPropertiesFromPath("C:/Users/Administrator/desktop");
loadPropertiesFromPath的參數是properties文件所在的目錄,不用寫properties的文件名,原因我前面已經說了,名字被寫死在銀聯工具類里了。
另外銀聯的工具包都沒有源碼,大家可以反編譯一下看看源代碼,我記得還有一個讀取properties文件的方法可以使用。但是我是使用loadPropertiesFromPath這個方法的。
后面各種put參數我就說幾個重要的。
frontUrl是前端通知地址,就是客戶付完款以后銀聯會給一個返回商戶的按鈕,用戶點擊按鈕以后就到了你配置的這個url映射的網頁。同時會提交很多訂單數據給你。
backUrl是后台通知地址,客戶付完款以后銀聯會給你配置的這個后台url對應的Action發扣款的消息過來。數據和前端通知發送過來的消息是一樣的。
我覺得前端通知地址就用來展示訂單數據給用戶看就行了,用戶不一定會去點那個按鈕。
后台通知用來更新自己數據庫里的訂單數據。
然后是merId這個不是隨便寫的,因為你前面的證書是PM_700000000000001_acp.pfx。所以這里必須寫700000000000001。就是證書對應的商戶號,這點很重要。銀聯下載來的demo默認是888888888888888。坑爹哪這是。
然后就沒啥好說的了,運行Form_6_2_FrontConsume類以后會生成一段html代碼。比如:
1 <html> 2 <head> 3 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 4 </head> 5 <body> 6 <form id="pay_form" 7 action="https://101.231.204.80:5000/gateway/api/frontTransReq.do" 8 method="post"> 9 <input type="hidden" name="txnType" id="txnType" value="01" /><input 10 type="hidden" name="frontUrl" id="frontUrl" 11 value="http://localhost:8080/ACPTest/acp_front_url.do" /><input 12 type="hidden" name="currencyCode" id="currencyCode" value="156" /><input 13 type="hidden" name="channelType" id="channelType" value="08" /><input 14 type="hidden" name="merId" id="merId" value="700000000000001" /><input 15 type="hidden" name="txnSubType" id="txnSubType" value="01" /><input 16 type="hidden" name="txnAmt" id="txnAmt" value="1" /><input 17 type="hidden" name="version" id="version" value="5.0.0" /><input 18 type="hidden" name="signMethod" id="signMethod" value="01" /><input 19 type="hidden" name="backUrl" id="backUrl" 20 value="http://222.222.222.222:8080/ACPTest/acp_back_url.do" /><input 21 type="hidden" name="certId" id="certId" 22 value="124876885185794726986301355951670452718" /><input 23 type="hidden" name="encoding" id="encoding" value="UTF-8" /><input 24 type="hidden" name="bizType" id="bizType" value="000201" /><input 25 type="hidden" name="signature" id="signature" 26 value="UfR4EHEma3rnwsQPIQOsdzEiVgEyT/tEza6vXiy1AjnlSS5C2qVVeV1TWClTXVA6OPh5Y9E7OyOwQYbWeuK+a4hCreY/R7oESNiF9gZs7KCphGp54daKOjRV1zNRcL2pDT2YhleBGQPgH/dwdhrOuprrFtvJBhi0TbRxFX2LSBU=" /><input 27 type="hidden" name="orderId" id="orderId" value="20150829171948" /><input 28 type="hidden" name="accessType" id="accessType" value="0" /><input 29 type="hidden" name="txnTime" id="txnTime" value="20150829171948" /> 30 </form> 31 </body> 32 <script type="text/javascript"> 33 document.all.pay_form.submit(); 34 </script> 35 </html>
把這段代碼刷到用戶瀏覽器上用戶就會跳轉到銀聯界面上去了。
然后測試付款可以使用demo里readMe.txt里的銀行卡號和密碼。
用戶付完款點了返回商戶按鈕以后會跳轉到你寫的前台通知地址上去。
我覺得原理和你讓客戶跳轉到銀聯去的方法差不多,可能也是銀聯刷了一個html在客戶機器上,然后客戶提交了一個post請求到你的前台通知地址。(不過我知道銀聯是怎么實現的,我覺得也是這個原理)
然后就完成付款了。
值得注意的是銀聯給你后台的通知可能有N次。。。反正我經常受到不只一次的同一訂單付款了的提醒。
至於通知會返回什么數據。大家自己試一次就OK了,數據還是很多的。
有朋友可能會想:要是壞人給我后台通知的地址發假冒的銀聯信息怎么辦呢。這個不用擔心,銀聯發送回來的數據也是用證書加密過的,你也需要先驗證真偽,是真的再更新數據庫。假的就無視好啦。
至於怎么驗證真偽,BackRcvResponse這個類,這個類就是模擬后台接受銀聯信息用的。
查詢訂單情況
有時候可能自己服務器有問題或者網絡不好,會收不到銀聯后台通知地址。而前台通知地址又不可靠,因為用戶可能會不去點擊它。
這種情況下你也要去更新訂單的情況,那么可以使用主動去銀聯查詢訂單情況的方法。
可以參考Form_6_5_Query這個類。
put的大部分數據大家不要更改,只需要更改merId,orderId,txnTime為前面提交時候的信息就可以完成查詢工作啦。
我這里就貼出一個我前面完成的訂單的查詢結果好了(就是前面那段html對應的訂單)
打印返回報文:accNo=6216***********0018&accessType=0&bizType=000000¤cyCode=156&encoding=UTF-8&issuerIdentifyMode=0&merId=700000000000001&orderId=20150829171948&origRespCode=00&origRespMsg=成功[0000000]&queryId=201508291719485608648&respCode=00&respMsg=成功[0000000]&settleAmt=1&settleCurrencyCode=156&settleDate=0829&signMethod=01&traceNo=560864&traceTime=0829171948&txnAmt=1&txnSubType=01&txnTime=20150829171948&txnType=01&version=5.0.0&certId=3474813271258769001041842579301293446&signature=VREVdo+eEtKaNY2HpVsGiEVab711cxwfjx6OHbb6wX3XdisIyftVRz1DAlboN34G/OhsDMFfy1HHKZvpSb8A+dVbVe58VKm1ZWpa6VaXTssBtNBj9WNozatJKk7Df7CmodEcBmye7oUaB8diYc0yqqdODBllWDdw6GlEzKe3rerheo92p9Q7RxmfV6CEXsCeNhlWL550OMKE1cvJYV/lBLqEMVQ6ec5ED2QglVBasGZO+ehFKKAb7TzgY6y9D/MWGhgLegDN7Sl7TSkTsjqbYGbA31dsZX3YcsdTLSqCbhOdC+yD9buFMM9Y29XehSEhyAp/7J5PQu5mi71E6LvUDQ== 請求報文=[{txnType=00, channelType=08, merId=700000000000001, txnSubType=00, version=5.0.0, signMethod=01, certId=124876885185794726986301355951670452718, encoding=UTF-8, bizType=000000, signature=PuT1JKdoa2NXxAC4LSVeSdQLJy5ZIo7OfBVDDIR3NxtACsK3KBkjrwcuM0JyZA8AOegFSwWv9gMWuIuyBpSjusc1GTXKTd3uJy9whun3QIYSJKSNNj9Zoe+m088+N6QjzQ7CCx4ncIdaMlo3rcdaDnIxEKW/Dji2OFRZroT3v9k=, orderId=20150829171948, txnTime=20150829171948, accessType=0}] 應答報文=[{respCode=00, origRespMsg=成功[0000000], origRespCode=00, txnSubType=01, txnAmt=1, version=5.0.0, signMethod=01, settleAmt=1, encoding=UTF-8, traceTime=0829171948, respMsg=成功[0000000], queryId=201508291719485608648, signature=VREVdo+eEtKaNY2HpVsGiEVab711cxwfjx6OHbb6wX3XdisIyftVRz1DAlboN34G/OhsDMFfy1HHKZvpSb8A+dVbVe58VKm1ZWpa6VaXTssBtNBj9WNozatJKk7Df7CmodEcBmye7oUaB8diYc0yqqdODBllWDdw6GlEzKe3rerheo92p9Q7RxmfV6CEXsCeNhlWL550OMKE1cvJYV/lBLqEMVQ6ec5ED2QglVBasGZO+ehFKKAb7TzgY6y9D/MWGhgLegDN7Sl7TSkTsjqbYGbA31dsZX3YcsdTLSqCbhOdC+yD9buFMM9Y29XehSEhyAp/7J5PQu5mi71E6LvUDQ==, orderId=20150829171948, txnType=01, currencyCode=156, merId=700000000000001, settleDate=0829, accNo=6216***********0018, certId=3474813271258769001041842579301293446, settleCurrencyCode=156, bizType=000000, traceNo=560864, issuerIdentifyMode=0, accessType=0, txnTime=20150829171948}]
研究一下應答報文就知道哪些功能是能做的那些是不能做的了。比如就不能知道客戶的完整付款賬戶號,其中多的位數被打*了。
差不多這些就是我在這個項目中對銀聯跳轉網關支付功能的理解啦。