本文是【淺析微信支付】系列文章的第五篇,主要講解如何調用統一下單接口生成預支付單及調起支付頁面。
淺析微信支付系列已經更新四篇了喲~,沒有看過的朋友們能夠看一下哦。php
上面是本文的前置文章,有前面幾篇文章的基礎之後看會更加明瞭,若是已經看過的小夥伴能夠忽略。github
首先咱們要明白這個問題,須要先行看一下微信的官方文檔:
https://pay.weixin.qq.com/wik...算法
官方解釋以下:數據庫
除被掃支付場景之外,商戶系統先調用該接口在微信支付服務後臺生成預支付交易單,返回正確的預支付交易會話標識後再按掃碼、JSAPI、APP等不一樣場景生成交易串調起支付。
什麼意思?簡單理解:就是說咱們要在調起微信支付窗口以前,須要先生成一個 預支付交易單
,這個單子至關於和咱們自身系統的 支付交易單
一一對應,也就是咱們每次支付須要記錄的訂單支付交易單。小程序
從上面咱們能夠獲得,在調用此接口以前,首先,咱們系統中確定已經須要有如下步驟:訂單提交 -> 生成訂單 -> 生成訂單對應的支付單 -> 調用統一下單接口api
好了,假設系統如今已經生成支付交易單,準備調用統一下單接口,咱們來看一下具體的實現方式。微信
PS:調用統一下單接口時,須要注意的是必須傳入異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數。示例以下:app
https://xxx.com/v1/weixin/pay/wxnotify
示例代碼:
/** * [微信支付統一下單] - 保存調用的相關記錄 <p> * [微信支付小程序] - 返回支付喚醒參數 * @param payment 付款對象 * @param user 當前用戶 * @return map * @throws Exception e * * @author yclimb * @date 2018/6/15 */ public Map<String, String> saveWxPayUnifiedOrder(Payment payment, User user) throws Exception { if (payment == null || user == null) { return null; } // 1.調用微信統一下單接口 WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance()); Map<String, String> resultMap = wxPay.unifiedOrder(...); // 1.1.記錄付款流水 ... // 下單失敗,進行處理 if (WXPayConstants.FAIL.equals(resultMap.get(WXPayConstants.RETURN_CODE)) || WXPayConstants.FAIL.equals(resultMap.get(WXPayConstants.RESULT_CODE))) { // 處理結果返回,無需繼續執行 resultMap.put(WXPayConstants.RESULT_CODE, WXPayConstants.FAIL); resultMap.put(WXPayConstants.ERR_CODE_DES, resultMap.get(WXPayConstants.RETURN_MSG)); return resultMap; } // 1.2.獲取prepay_id、nonce_str String prepay_id = resultMap.get("prepay_id"); String nonce_str = resultMap.get("nonce_str"); // 2.根據微信統一下單接口返回數據組裝微信支付參數,返回結果 return wxPay.chooseWXPayMap(prepay_id, nonce_str); }
以上爲一個調用統一下單的接口代碼,主要在於如下兩句:
// 實例化一個微信支付對象,使用單例配置的方式 WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance()); // 直接調用統一下單接口 Map<String, String> resultMap = wxPay.unifiedOrder(...);
微信支付對象WXPay
統一下單接口:
/** * 做用:統一下單<br> * 場景:商戶在小程序中先調用該接口在微信支付服務後臺生成預支付交易單,返回正確的預支付交易後調起支付。 * 接口連接:URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder * 是否須要證書:否 * 接口文檔地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1 * * @param notify_url 公衆號用戶openid * @param body 商品簡單描述,該字段請按照規範傳遞,例:騰訊充值中心-QQ會員充值 * @param out_trade_no 商戶系統內部訂單號,要求32個字符內,只能是數字、大小寫字母_-|*且在同一個商戶號下惟一 * @param total_fee 訂單總金額,傳入參數單位爲:元 * @param spbill_create_ip APP和網頁支付提交用戶端ip,Native支付填調用微信支付API的機器IP * @param goods_tag 訂單優惠標記,用於區分訂單是否能夠享受優惠 * @param detail 商品詳情 ,單品優惠活動該字段必傳 * @param timeStart 訂單生成時間,格式爲yyyyMMddHHmmss * @param timeExpire 訂單失效時間,格式爲yyyyMMddHHmmss,如2009年12月27日9點10分10秒錶示爲20091227091010 * @return API返回數據 * @throws Exception e */ public Map<String, String> unifiedOrder(String notify_url, String openid, String body, String out_trade_no, String total_fee, String spbill_create_ip, String goods_tag, String detail, Date timeStart, Date timeExpire) throws Exception { /** 構造請求參數數據 **/ Map<String, String> data = new HashMap<>(); // 字段名 變量名 必填 類型 示例值 描述 // 標價幣種 fee_type 否 String(16) CNY 符合ISO 4217標準的三位字母代碼,默認人民幣:CNY,詳細列表請參見貨幣類型 data.put("fee_type", WXPayConstants.FEE_TYPE_CNY); // 通知地址 notify_url 是 String(256) http://www.weixin.qq.com/wxpay/pay.php 異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數。 data.put("notify_url", notify_url); // 交易類型 trade_type 是 String(16) JSAPI 小程序取值以下:JSAPI,詳細說明見參數規定 data.put("trade_type", WXPayConstants.TRADE_TYPE); // 用戶標識 openid 否 String(128) oUpF8uMuAJO_M2pxb1Q9zNjWeS6o trade_type=JSAPI,此參數必傳,用戶在商戶appid下的惟一標識。openid如何獲取,可參考【獲取openid】。 data.put("openid", openid); // 商品描述 body 是 String(128) 騰訊充值中心-QQ會員充值 商品簡單描述,該字段請按照規範傳遞,具體請見參數規定 data.put("body", body); // 商戶訂單號 out_trade_no 是 String(32) 20150806125346 商戶系統內部訂單號,要求32個字符內,只能是數字、大小寫字母_-|*且在同一個商戶號下惟一。詳見商戶訂單號 data.put("out_trade_no", out_trade_no); // 標價金額 total_fee 是 Int 88 訂單總金額,單位爲分,詳見支付金額 // 默認單位爲分,系統是元,因此須要*100 data.put("total_fee", String.valueOf(new BigDecimal(total_fee).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue())); // 終端IP spbill_create_ip 是 String(16) 123.12.12.123 APP和網頁支付提交用戶端ip,Native支付填調用微信支付API的機器IP。 data.put("spbill_create_ip", spbill_create_ip); /** 如下參數爲非必填參數 **/ // 訂單優惠標記 goods_tag 否 String(32) WXG 訂單優惠標記,使用代金券或立減優惠功能時須要的參數,說明詳見代金券或立減優惠 if (StringUtils.isNotBlank(goods_tag)) { data.put("goods_tag", goods_tag); } // 商品詳情 detail 否 String(6000) 商品詳細描述,對於使用單品優惠的商戶,改字段必須按照規範上傳,詳見「單品優惠參數說明」 if (StringUtils.isNotBlank(detail)) { data.put("detail", detail); // 接口版本號 新增字段,接口版本號,區分原接口,默認填寫1.0。入參新增version後,則支付通知接口也將返回單品優惠信息字段promotion_detail,請確保支付通知的簽名驗證能經過。 data.put("version", "1.0"); } // 設備號 device_info 否 String(32) 013467007045764 自定義參數,能夠爲終端設備號(門店號或收銀設備ID),PC網頁或公衆號內支付能夠傳"WEB" data.put("device_info", "WEB"); // 交易起始時間 time_start 否 String(14) 20091225091010 訂單生成時間,格式爲yyyyMMddHHmmss,如2009年12月25日9點10分10秒錶示爲20091225091010。其餘詳見時間規則 data.put("time_start", DateTimeUtil.getTimeShortString(timeStart)); // 交易結束時間 time_expire 否 String(14) 20091227091010 訂單失效時間,格式爲yyyyMMddHHmmss,如2009年12月27日9點10分10秒錶示爲20091227091010。 // 訂單失效時間是針對訂單號而言的,因爲在請求支付的時候有一個必傳參數prepay_id只有兩小時的有效期,因此在重入時間超過2小時的時候須要從新請求下單接口獲取新的prepay_id。其餘詳見時間規則,建議:最短失效時間間隔大於1分鐘 data.put("time_expire", DateTimeUtil.getTimeShortString(timeExpire)); /*// 商品ID product_id 否 String(32) 12235413214070356458058 trade_type=NATIVE時(即掃碼支付),此參數必傳。此參數爲二維碼中包含的商品ID,商戶自行定義。 data.put("product_id", null); // 指定支付方式 limit_pay 否 String(32) no_credit 上傳此參數no_credit--可限制用戶不能使用信用卡支付 data.put("limit_pay", null); // 附加數據 attach 否 String(127) 深圳分店 附加數據,在查詢API和支付通知中原樣返回,可做爲自定義參數使用。 data.put("attach", null);*/ /** 如下五個參數,在 this.fillRequestData 方法中會自動賦值 **/ /*// 小程序ID appid 是 String(32) wxd678efh567hg6787 微信分配的小程序ID data.put("appid", WXPayConstants.APP_ID); // 商戶號 mch_id 是 String(32) 1230000109 微信支付分配的商戶號 data.put("mch_id", WXPayConstants.MCH_ID); // 隨機字符串 nonce_str 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 隨機字符串,長度要求在32位之內。推薦隨機數生成算法 data.put("nonce_str", nonce_str); // 簽名類型 sign_type 否 String(32) MD5 簽名類型,默認爲MD5,支持HMAC-SHA256和MD5。 data.put("sign_type", WXPayConstants.MD5); // 簽名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 經過簽名算法計算得出的簽名值,詳見簽名生成算法 data.put("sign", sign);*/ // 微信統一下單接口請求地址 Map<String, String> resultMap = this.unifiedOrder(data); WXPayUtil.getLogger().info("wxPay.unifiedOrder:" + resultMap); return resultMap; }
以上代碼詳細說明了每一個字段的含義,具體的代碼能夠看一下做者的github,文末有對應的地址。
下面說一個特殊狀況,在咱們支付的時候,有時候用戶會取消支付,等一段時間再從新調起,這時候,須要用到另一個方法,那就是二次支付,因此,在咱們數據庫中,必須保存兩個字段,用於二次支付時使用:預支付IDprepay_id
、隨機字符串nonce_str
,此兩個參數能夠生成微信支付調起時須要的驗證簽名。
如下爲二次調用時的代碼:
/** * 根據付款單號查詢微信付款參數 * @param relationId 交易編號 * @param type 支付類型 * @return payment * * @author yclimb * @date 2018/6/28 */ public Map<String, String> queryChooseWXPayMapByRelationId(Integer relationId, String type) throws Exception { // 微信支付對象 WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance()); // 1.查詢付款對象 Payment payment = this.queryPaymentByRelationId(relationId, type); // 2.根據微信統一下單接口返回數據組裝微信支付參數,返回結果 return wxPay.chooseWXPayMap(payment.getPrepayId(), payment.getNonceStr()); }
此時咱們已經調用微信統一下單接口成功,併爲咱們返回了須要的參數,下一步須要組裝爲微信支付調起時前端須要的參數。
下面爲組裝支付簽名的代碼:
/** * 做用:生成微信支付所需參數,微信支付二次簽名<br> * 場景:根據微信統一下單接口返回的 prepay_id 生成微信支付所需的參數 * 接口文檔地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6 * * @param prepay_id 預支付id * @param nonce_str 隨機字符串 * @return 支付方法調用所需參數map * @throws Exception e */ public Map<String, String> chooseWXPayMap(String prepay_id, String nonce_str) throws Exception { // 支付方法調用所需參數map Map<String, String> chooseWXPayMap = new HashMap<>(); chooseWXPayMap.put("appId", config.getAppID()); chooseWXPayMap.put("timeStamp", String.valueOf(WXPayUtil.getCurrentTimestamp())); chooseWXPayMap.put("nonceStr", nonce_str); chooseWXPayMap.put("package", "prepay_id=" + prepay_id); chooseWXPayMap.put("signType", WXPayConstants.MD5); WXPayUtil.getLogger().info("wxPay.chooseWXPayMap:" + chooseWXPayMap.toString()); // 生成支付簽名 String paySign = WXPayUtil.generateSignature(chooseWXPayMap, config.getKey()); chooseWXPayMap.put("paySign", paySign); WXPayUtil.getLogger().info("wxPay.paySign:" + paySign); return chooseWXPayMap; }
組裝好須要的參數之後,就能夠調起微信支付窗口了,若是是微信公衆號支付,須要使用如下的方式調起微信支付:
function weixinConfig(appid, timestamp, noncestr, signature) { wx.config({ debug : false, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 // debug : true, appId :appid, // 必填,公衆號的惟一標識 timestamp : timestamp, // 必填,生成簽名的時間戳 nonceStr : noncestr, // 必填,生成簽名的隨機串 signature : signature,// 必填,簽名,見附錄1 jsApiList: [ 'checkJsApi', 'chooseWXPay' // 必須增長此參數,用戶微信支付功能 ] // 必填,須要使用的JS接口列表,全部JS接口列表見附錄2 }); } wx.chooseWXPay({ appId: appId, timestamp: timeStamp, // 支付簽名時間戳,注意微信jssdk中的全部使用timestamp字段均爲小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符 nonceStr: nonceStr, // 支付簽名隨機串,不長於 32 位 package: package, // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=\*\*\*) signType: signType, // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5' paySign: paySign, // 支付簽名 success: function (res) { // 支付成功後的回調函數 alert('支付成功!'); }, cancel: function (res) { // 支付取消 }, fail: function (res) { // 支付失敗 alert("支付失敗!"); } });
PS:小程序調用方法相似,參數一致。
以上就是微信支付統一下單接口的調用方式了,具體的源碼能夠參考做者github,最好在開發以前先通讀一遍微信官方文檔,此時再使用做者源碼開發事半功倍,更易理解。
預告:下一篇文章,做者將講 支付結果通知
,敬請期待!!!
若是想要提早一覽源碼的小夥伴,能夠先看看個人 github,地址以下:
https://github.com/YClimb/wxpay-sdk/blob/master/README.md
加做者私人微信,做者微信號以下 yclimb
,標明 微信支付
可拉入微信支付討論羣與小夥伴一塊兒探討哦,必定要標明 微信支付
哦~
到此本文就結束了,關注公衆號查看更多推送!!!