引子:
以下的部分代碼、思路來自于 CSDN的一位博客主 ,以及 后宮 —— 易水 的支持。
1.前期申請流程介紹:
在微信開放平臺注冊賬戶:
- 注冊成功后在頂部菜單欄選擇管理中心--移動應用--創建移動應用[業主需要準備應用的官網(沒有可寫域名或者www.baidu.com[有未知風險])、應用的logo2張,一張28*28,一張108*108]
應用創建完成之后申請開通微信支付接口:
- 在應用詳情里,取得APPID;
- 開放平臺需進行開發者資質認證后才可申請微信支付,認證費:300元/次;
- 認證后進行微信支付所需要的申請。[這里的申請需要提供APP應用的信息,一般情況下均提供APP頁面截圖,APP頁面截圖應該包含:APP首頁、APP版權信息頁、APP商品展示頁、APP支付方式頁。另外需要特別注意自己的應用是否涉及到了 網絡文化經營許可證 的范疇,微信人工審核會判別這一點,如果是需要提供此證。如申請不下這個證,則會有一定的法律風險]
- 微信支付接口申請好之后,微信會向申請時填寫的郵箱發送微信商戶平臺賬戶信息;[賬戶、密碼、微信商戶號等]
在微信商戶平臺設置32位密鑰:
- [該網址的密碼框控件不支持谷歌瀏覽器]
- 用郵箱里的賬戶信息登錄,第一次登錄微信會提示設置防釣魚標志,請牢記此值;
- Key設置路徑:微信商戶平臺--賬戶中心--API安全--API密鑰--密鑰設置[提供一個生成隨機碼的網頁]
其他說明:
- 在商戶平臺掃描首頁的二維碼,關注支付提醒信息
- 微信提現有周期間隔,支付的金額不會實時轉到業主銀行賬戶上,需要人為轉出
- 以上加粗標識的關鍵值均需業主提供給程序員,在代碼抒寫時有用到
2.支付流程示例:
商戶APP-----向商戶服務端發起請求--1--商戶服務端--2--向微信服務端發起請求得到唯一標識--3--返回給商戶APP;
商戶APP根據返回值調起微信支付,消費人支付成功;
微信服務端-----4-----向商戶服務端發起請求,商戶服務端完成自身業務;
其他:數字標志的含義,1代表處理自身業務,2代表按照微信要求請求微信,3按照微信要求解析返回值并同樣照要求返回APP,4代表按微信要求驗證參數,完成自己業務。
3.代碼結構以及使用說明:
下載:
包含了微信支付和支付寶支付,密碼為phqa
結構:
使用說明:
- 操作者只需要填寫Config所需的信息,根據自身業務抒寫Controller、service層即可,其他結構無需修改;在service里調用WxPayCore進行微信必要的步驟即可。
- WxPayConfig配置參數概覽:均為字符串
參數名 | 釋義或固定值 | 取得方式或固定值 |
---|---|---|
appid | 應用id | 參考前期業主申請操作 |
mch_id | 微信商戶號 | 同上 |
key | 密鑰 | 同上 |
notify_url | 接收微信支付異步通知回調地址;通知url必須為直接可訪問的url,不能攜帶參數 | 參考外網映射的配置方式https://www.ngrok.cc/ |
body | 商品描述交易字段 | APP名字-實際商品名稱比如:天天愛消除-游戲充值 |
以下值為固定值 | --- | --- |
spbill_create_ip | 客戶端ip地址 | 127.0.0.1[此值不影響] |
trade_type | 支付類型 | APP |
PACKAGE | --- | Sign=WXPay |
wxUrl | 微信統一下單接口請求地址 | https://api.mch.weixin.qq.com/pay/unifiedorder |
在Controller層抒寫兩個業務,處理APP調起支付和微信的回調;調起App的接口可以自定義參數,接收微信的回調參數無需修改。在Service里抒寫自己的具體業務,然后調用固定方法進行處理。
eg:A用戶要購買100元的衣服,提供給App的接口需要接收用戶的id,衣服的id,在Service層里處理訂單的業務之后,調用WxPayCore.createWxPayParam(out_trade_no,total_fee)方法,傳入商戶內部訂單號和用戶所要支付的金額,并將返回值返給前端即可;
前端接收到返回值調起微信SDK,用戶支付完畢;
微信會異步通知在Config里配置的回調地址,在回調的Service層里,調用WxPayCore.checkWxPayParam(request)進行驗證,判斷是否是微信發送來的通知以及是否支付成功,返回值不為NULL即可進行商品發貨或者填寫快遞訂單號等業務。兩個核心方法使用介紹:
1.SortedMap<Object, Object> wxAppparameters = WxPayCore.createWxPayParam(String out_trade_no,String total_fee);
a)拼接微信支付必要參數,加簽,并返回Map對象;
b)out_trade_no 傳入商戶內部訂單號,必須唯一;total_fee 所要支付的金額,格式必須為0.00,單位為元;
c)返回App端調起支付所需要的參數。
2.SortedMap<Object, Object> parameters = WxPayCore.checkWxPayParam(request);
a)支付成功的回調:檢測微信異步反饋是否真實,不為null為真實,null為校驗失敗。
b)返回的map中可以取得微信返回的參數,一般只取out_trade_no(商戶內部訂單號)、total_fee(充值的金額,單位為分)、transaction_id(微信支付訂單號)。
c)判斷parameters是否不為NULL,不為NULL拿商戶內部訂單號去查出充值的訂單數據,完成自己的業務。
- 特別注意:在處理的回調里,處理成功后需要向微信反饋成功:
Eg:out.print(HttpXmlUtil.backWeixin("SUCCESS","OK")); *
如果處理失敗則無需反饋;微信如果接收不到正確反饋,則會按照一定策略重復通知,代碼中應該有去重處理[判斷該訂單是否已經處理過*]
注意事項:
- WxPayCore類里的方法均不需要修改,和業務無關,直接調用即可。
引用jar:
- dom4j-1.6.1.jar
- jdom.jar
- 微信不提供sdk,上述jar包無需修改。
4.備注以及拓展:
文檔的第一步驟可以截取發給業主參考申請,讓業主提供加粗的參數信息;
- 本著程序員應全身心在開發上,避免不必要的時間浪費。
對WxPayCore.createWxPayParam()方法的解釋:
- 方法的作用就是按照微信的要求去請求微信并得到唯一的標識并返回給APP端;App端根據此返回值調起微信[微信所需要的是很多參數,不是字符串形式的];
- 返回的參數里包含著調起支付的唯一標識,[微信要扣多少錢、微信服務端給哪個地址發送支付成功的通知等信息都保存在 微信的服務端 了:通過服務端請求微信的那次請求,稱作 統一下單接口];
- 請求微信的規則是[微信簽名的規則]:
1.將參數的key值按照ascii碼的順序進行排序,并轉化成key=value&key=value的形式;
2.拼接完所有的非sign參數后,字符串末尾拼入key=32位字符串[上面提及的key值]然后進行MD5加密并轉為大寫,得到sign值; - 微信以上的2步是為了確保這個通知是商戶的自身發送出來的,拿key參與MD5運算,確保唯一性。[如果微信不這么做,訂單信息被別人篡改了,對雙方都將是最壞的結果];
- 微信請求以及返回值的形式都是xml形式,服務端請求微信前將map的值轉為xml發送請求[發送了這個請求就意味著微信服務端存儲了該訂單的信息],得到返回值解析出來,得到預支付訂單[唯一性的東西],再按照微信調起支付的參數要求繼續拼接,并用MD5生成sign字段;
對WxPayCore.checkWxPayParam()方法的解釋:
- 方法的作用就是檢測是否是微信發送來的通知,根據此通知進行支付成功的業務;
- 微信是不會發送支付失敗的通知的;
- 驗證也有相應的規則:
1.將微信的參數都取出[這里有個拓展,requesr.getParameterMap()就可以取出Map形式的參數];
2.取出sign字段,將剩余參數變成按照ascii碼排序的key=value&形式再次進行加簽;
3.自己加簽的簽名和取出的sign字段進行比較,查看是否一致; - 同理,微信需要這樣的驗證步驟,也是為了確保該通知是微信發出的,以防別人冒發送請求;
- 為防止意外,對訂單號、商戶的基本信息做驗證。
拓展:
- 關于數字簽名這里有一篇文章介紹的很全面:
- 將參數拼接密鑰進行加簽,接收者根據參數同樣進行加簽,驗證自己所加的簽名與發送者的是否一致,來達到信息的準確性;
- 也推薦關注該文章的翻譯者:阮一峰。