摘要:本文是淺析微信支付系列文章的第五篇,主要講解如何調(diào)用統(tǒng)一下單接口生成預(yù)支付單及調(diào)起支付頁面。淺析微信支付系列已經(jīng)更新四篇了喲,沒有看過的朋友們可以看一下哦。
本文是【淺析微信支付】系列文章的第五篇,主要講解如何調(diào)用統(tǒng)一下單接口生成預(yù)支付單及調(diào)起支付頁面。
淺析微信支付系列已經(jīng)更新四篇了喲~,沒有看過的朋友們可以看一下哦。
淺析微信支付:微信公眾號(hào)網(wǎng)頁授權(quán)
淺析微信支付:開發(fā)前的準(zhǔn)備
上面是本文的前置文章,有前面幾篇文章的基礎(chǔ)以后看會(huì)更加明了,如果已經(jīng)看過的小伙伴可以忽略。
1、什么是[統(tǒng)一下單接口]?首先我們要明白這個(gè)問題,需要先行看一下微信的官方文檔:
https://pay.weixin.qq.com/wik...
官方解釋如下:
除被掃支付場(chǎng)景以外,商戶系統(tǒng)先調(diào)用該接口在微信支付服務(wù)后臺(tái)生成預(yù)支付交易單,返回正確的預(yù)支付交易會(huì)話標(biāo)識(shí)后再按掃碼、JSAPI、APP等不同場(chǎng)景生成交易串調(diào)起支付。
什么意思?簡(jiǎn)單理解:就是說我們要在調(diào)起微信支付窗口之前,需要先生成一個(gè) 預(yù)支付交易單,這個(gè)單子相當(dāng)于和我們自身系統(tǒng)的 支付交易單 一一對(duì)應(yīng),也就是我們每次支付需要記錄的訂單支付交易單。
從上面我們可以得到,在調(diào)用此接口之前,首先,我們系統(tǒng)中肯定已經(jīng)需要有以下步驟:訂單提交 -> 生成訂單 -> 生成訂單對(duì)應(yīng)的支付單 -> 調(diào)用統(tǒng)一下單接口
好了,假設(shè)系統(tǒng)現(xiàn)在已經(jīng)生成支付交易單,準(zhǔn)備調(diào)用統(tǒng)一下單接口,我們來看一下具體的實(shí)現(xiàn)方式。
PS:調(diào)用統(tǒng)一下單接口時(shí),需要注意的是必須傳入異步接收微信支付結(jié)果通知的回調(diào)地址,通知url必須為外網(wǎng)可訪問的url,不能攜帶參數(shù)。示例如下:
https://xxx.com/v1/weixin/pay/wxnotify
2、調(diào)用接口示例代碼:
/** * [微信支付統(tǒng)一下單] - 保存調(diào)用的相關(guān)記錄* [微信支付小程序] - 返回支付喚醒參數(shù) * @param payment 付款對(duì)象 * @param user 當(dāng)前用戶 * @return map * @throws Exception e * * @author yclimb * @date 2018/6/15 */ public Map
saveWxPayUnifiedOrder(Payment payment, User user) throws Exception { if (payment == null || user == null) { return null; } // 1.調(diào)用微信統(tǒng)一下單接口 WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance()); Map resultMap = wxPay.unifiedOrder(...); // 1.1.記錄付款流水 ... // 下單失敗,進(jìn)行處理 if (WXPayConstants.FAIL.equals(resultMap.get(WXPayConstants.RETURN_CODE)) || WXPayConstants.FAIL.equals(resultMap.get(WXPayConstants.RESULT_CODE))) { // 處理結(jié)果返回,無需繼續(xù)執(zhí)行 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.根據(jù)微信統(tǒng)一下單接口返回?cái)?shù)據(jù)組裝微信支付參數(shù),返回結(jié)果 return wxPay.chooseWXPayMap(prepay_id, nonce_str); }
以上為一個(gè)調(diào)用統(tǒng)一下單的接口代碼,主要在于以下兩句:
// 實(shí)例化一個(gè)微信支付對(duì)象,使用單例配置的方式 WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance()); // 直接調(diào)用統(tǒng)一下單接口 MapresultMap = wxPay.unifiedOrder(...);
微信支付對(duì)象WXPay統(tǒng)一下單接口:
/** * 作用:統(tǒng)一下單
* 場(chǎng)景:商戶在小程序中先調(diào)用該接口在微信支付服務(wù)后臺(tái)生成預(yù)支付交易單,返回正確的預(yù)支付交易后調(diào)起支付。 * 接口鏈接: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 公眾號(hào)用戶openid * @param body 商品簡(jiǎn)單描述,該字段請(qǐng)按照規(guī)范傳遞,例:騰訊充值中心-QQ會(huì)員充值 * @param out_trade_no 商戶系統(tǒng)內(nèi)部訂單號(hào),要求32個(gè)字符內(nèi),只能是數(shù)字、大小寫字母_-|*且在同一個(gè)商戶號(hào)下唯一 * @param total_fee 訂單總金額,傳入?yún)?shù)單位為:元 * @param spbill_create_ip APP和網(wǎng)頁支付提交用戶端ip,Native支付填調(diào)用微信支付API的機(jī)器IP * @param goods_tag 訂單優(yōu)惠標(biāo)記,用于區(qū)分訂單是否可以享受優(yōu)惠 * @param detail 商品詳情 ,單品優(yōu)惠活動(dòng)該字段必傳 * @param timeStart 訂單生成時(shí)間,格式為yyyyMMddHHmmss * @param timeExpire 訂單失效時(shí)間,格式為yyyyMMddHHmmss,如2009年12月27日9點(diǎn)10分10秒表示為20091227091010 * @return API返回?cái)?shù)據(jù) * @throws Exception e */ public MapunifiedOrder(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 { /** 構(gòu)造請(qǐng)求參數(shù)數(shù)據(jù) **/ Map data = new HashMap<>(); // 字段名 變量名 必填 類型 示例值 描述 // 標(biāo)價(jià)幣種 fee_type 否 String(16) CNY 符合ISO 4217標(biāo)準(zhǔn)的三位字母代碼,默認(rèn)人民幣:CNY,詳細(xì)列表請(qǐng)參見貨幣類型 data.put("fee_type", WXPayConstants.FEE_TYPE_CNY); // 通知地址 notify_url 是 String(256) http://www.weixin.qq.com/wxpay/pay.php 異步接收微信支付結(jié)果通知的回調(diào)地址,通知url必須為外網(wǎng)可訪問的url,不能攜帶參數(shù)。 data.put("notify_url", notify_url); // 交易類型 trade_type 是 String(16) JSAPI 小程序取值如下:JSAPI,詳細(xì)說明見參數(shù)規(guī)定 data.put("trade_type", WXPayConstants.TRADE_TYPE); // 用戶標(biāo)識(shí) openid 否 String(128) oUpF8uMuAJO_M2pxb1Q9zNjWeS6o trade_type=JSAPI,此參數(shù)必傳,用戶在商戶appid下的唯一標(biāo)識(shí)。openid如何獲取,可參考【獲取openid】。 data.put("openid", openid); // 商品描述 body 是 String(128) 騰訊充值中心-QQ會(huì)員充值 商品簡(jiǎn)單描述,該字段請(qǐng)按照規(guī)范傳遞,具體請(qǐng)見參數(shù)規(guī)定 data.put("body", body); // 商戶訂單號(hào) out_trade_no 是 String(32) 20150806125346 商戶系統(tǒng)內(nèi)部訂單號(hào),要求32個(gè)字符內(nèi),只能是數(shù)字、大小寫字母_-|*且在同一個(gè)商戶號(hào)下唯一。詳見商戶訂單號(hào) data.put("out_trade_no", out_trade_no); // 標(biāo)價(jià)金額 total_fee 是 Int 88 訂單總金額,單位為分,詳見支付金額 // 默認(rèn)單位為分,系統(tǒng)是元,所以需要*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和網(wǎng)頁支付提交用戶端ip,Native支付填調(diào)用微信支付API的機(jī)器IP。 data.put("spbill_create_ip", spbill_create_ip); /** 以下參數(shù)為非必填參數(shù) **/ // 訂單優(yōu)惠標(biāo)記 goods_tag 否 String(32) WXG 訂單優(yōu)惠標(biāo)記,使用代金券或立減優(yōu)惠功能時(shí)需要的參數(shù),說明詳見代金券或立減優(yōu)惠 if (StringUtils.isNotBlank(goods_tag)) { data.put("goods_tag", goods_tag); } // 商品詳情 detail 否 String(6000) 商品詳細(xì)描述,對(duì)于使用單品優(yōu)惠的商戶,改字段必須按照規(guī)范上傳,詳見“單品優(yōu)惠參數(shù)說明” if (StringUtils.isNotBlank(detail)) { data.put("detail", detail); // 接口版本號(hào) 新增字段,接口版本號(hào),區(qū)分原接口,默認(rèn)填寫1.0。入?yún)⑿略鰒ersion后,則支付通知接口也將返回單品優(yōu)惠信息字段promotion_detail,請(qǐng)確保支付通知的簽名驗(yàn)證能通過。 data.put("version", "1.0"); } // 設(shè)備號(hào) device_info 否 String(32) 013467007045764 自定義參數(shù),可以為終端設(shè)備號(hào)(門店號(hào)或收銀設(shè)備ID),PC網(wǎng)頁或公眾號(hào)內(nèi)支付可以傳"WEB" data.put("device_info", "WEB"); // 交易起始時(shí)間 time_start 否 String(14) 20091225091010 訂單生成時(shí)間,格式為yyyyMMddHHmmss,如2009年12月25日9點(diǎn)10分10秒表示為20091225091010。其他詳見時(shí)間規(guī)則 data.put("time_start", DateTimeUtil.getTimeShortString(timeStart)); // 交易結(jié)束時(shí)間 time_expire 否 String(14) 20091227091010 訂單失效時(shí)間,格式為yyyyMMddHHmmss,如2009年12月27日9點(diǎn)10分10秒表示為20091227091010。 // 訂單失效時(shí)間是針對(duì)訂單號(hào)而言的,由于在請(qǐng)求支付的時(shí)候有一個(gè)必傳參數(shù)prepay_id只有兩小時(shí)的有效期,所以在重入時(shí)間超過2小時(shí)的時(shí)候需要重新請(qǐng)求下單接口獲取新的prepay_id。其他詳見時(shí)間規(guī)則,建議:最短失效時(shí)間間隔大于1分鐘 data.put("time_expire", DateTimeUtil.getTimeShortString(timeExpire)); /*// 商品ID product_id 否 String(32) 12235413214070356458058 trade_type=NATIVE時(shí)(即掃碼支付),此參數(shù)必傳。此參數(shù)為二維碼中包含的商品ID,商戶自行定義。 data.put("product_id", null); // 指定支付方式 limit_pay 否 String(32) no_credit 上傳此參數(shù)no_credit--可限制用戶不能使用信用卡支付 data.put("limit_pay", null); // 附加數(shù)據(jù) attach 否 String(127) 深圳分店 附加數(shù)據(jù),在查詢API和支付通知中原樣返回,可作為自定義參數(shù)使用。 data.put("attach", null);*/ /** 以下五個(gè)參數(shù),在 this.fillRequestData 方法中會(huì)自動(dòng)賦值 **/ /*// 小程序ID appid 是 String(32) wxd678efh567hg6787 微信分配的小程序ID data.put("appid", WXPayConstants.APP_ID); // 商戶號(hào) mch_id 是 String(32) 1230000109 微信支付分配的商戶號(hào) data.put("mch_id", WXPayConstants.MCH_ID); // 隨機(jī)字符串 nonce_str 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 隨機(jī)字符串,長(zhǎng)度要求在32位以內(nèi)。推薦隨機(jī)數(shù)生成算法 data.put("nonce_str", nonce_str); // 簽名類型 sign_type 否 String(32) MD5 簽名類型,默認(rèn)為MD5,支持HMAC-SHA256和MD5。 data.put("sign_type", WXPayConstants.MD5); // 簽名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 通過簽名算法計(jì)算得出的簽名值,詳見簽名生成算法 data.put("sign", sign);*/ // 微信統(tǒng)一下單接口請(qǐng)求地址 Map resultMap = this.unifiedOrder(data); WXPayUtil.getLogger().info("wxPay.unifiedOrder:" + resultMap); return resultMap; }
以上代碼詳細(xì)說明了每個(gè)字段的含義,具體的代碼可以看一下作者的github,文末有對(duì)應(yīng)的地址。
下面說一個(gè)特殊情況,在我們支付的時(shí)候,有時(shí)候用戶會(huì)取消支付,等一段時(shí)間再重新調(diào)起,這時(shí)候,需要用到另外一個(gè)方法,那就是二次支付,所以,在我們數(shù)據(jù)庫中,必須保存兩個(gè)字段,用于二次支付時(shí)使用:預(yù)支付IDprepay_id、隨機(jī)字符串nonce_str,此兩個(gè)參數(shù)可以生成微信支付調(diào)起時(shí)需要的驗(yàn)證簽名。
以下為二次調(diào)用時(shí)的代碼:
/** * 根據(jù)付款單號(hào)查詢微信付款參數(shù) * @param relationId 交易編號(hào) * @param type 支付類型 * @return payment * * @author yclimb * @date 2018/6/28 */ public MapqueryChooseWXPayMapByRelationId(Integer relationId, String type) throws Exception { // 微信支付對(duì)象 WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance()); // 1.查詢付款對(duì)象 Payment payment = this.queryPaymentByRelationId(relationId, type); // 2.根據(jù)微信統(tǒng)一下單接口返回?cái)?shù)據(jù)組裝微信支付參數(shù),返回結(jié)果 return wxPay.chooseWXPayMap(payment.getPrepayId(), payment.getNonceStr()); }
此時(shí)我們已經(jīng)調(diào)用微信統(tǒng)一下單接口成功,并為我們返回了需要的參數(shù),下一步需要組裝為微信支付調(diào)起時(shí)前端需要的參數(shù)。
生成支付簽名下面為組裝支付簽名的代碼:
/** * 作用:生成微信支付所需參數(shù),微信支付二次簽名
* 場(chǎng)景:根據(jù)微信統(tǒng)一下單接口返回的 prepay_id 生成微信支付所需的參數(shù) * 接口文檔地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6 * * @param prepay_id 預(yù)支付id * @param nonce_str 隨機(jī)字符串 * @return 支付方法調(diào)用所需參數(shù)map * @throws Exception e */ public MapchooseWXPayMap(String prepay_id, String nonce_str) throws Exception { // 支付方法調(diào)用所需參數(shù)map Map 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; }
組裝好需要的參數(shù)以后,就可以調(diào)起微信支付窗口了,如果是微信公眾號(hào)支付,需要使用以下的方式調(diào)起微信支付:
function weixinConfig(appid, timestamp, noncestr, signature) { wx.config({ debug : false, // 開啟調(diào)試模式,調(diào)用的所有api的返回值會(huì)在客戶端alert出來,若要查看傳入的參數(shù),可以在pc端打開,參數(shù)信息會(huì)通過log打出,僅在pc端時(shí)才會(huì)打印。 // debug : true, appId :appid, // 必填,公眾號(hào)的唯一標(biāo)識(shí) timestamp : timestamp, // 必填,生成簽名的時(shí)間戳 nonceStr : noncestr, // 必填,生成簽名的隨機(jī)串 signature : signature,// 必填,簽名,見附錄1 jsApiList: [ "checkJsApi", "chooseWXPay" // 必須增加此參數(shù),用戶微信支付功能 ] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2 }); } wx.chooseWXPay({ appId: appId, timestamp: timeStamp, // 支付簽名時(shí)間戳,注意微信jssdk中的所有使用timestamp字段均為小寫。但最新版的支付后臺(tái)生成簽名使用的timeStamp字段名需大寫其中的S字符 nonceStr: nonceStr, // 支付簽名隨機(jī)串,不長(zhǎng)于 32 位 package: package, // 統(tǒng)一支付接口返回的prepay_id參數(shù)值,提交格式如:prepay_id=***) signType: signType, // 簽名方式,默認(rèn)為"SHA1",使用新版支付需傳入"MD5" paySign: paySign, // 支付簽名 success: function (res) { // 支付成功后的回調(diào)函數(shù) alert("支付成功!"); }, cancel: function (res) { // 支付取消 }, fail: function (res) { // 支付失敗 alert("支付失敗!"); } });
PS:小程序調(diào)用方法類似,參數(shù)一致。
結(jié)語以上就是微信支付統(tǒng)一下單接口的調(diào)用方式了,具體的源碼可以參考作者github,最好在開發(fā)之前先通讀一遍微信官方文檔,此時(shí)再使用作者源碼開發(fā)事半功倍,更易理解。
預(yù)告:下一篇文章,作者將講 支付結(jié)果通知,敬請(qǐng)期待?。?!
?如果想要提前一覽源碼的小伙伴,可以先看看我的 github,地址如下:
?https://github.com/YClimb/wxpay-sdk/blob/master/README.md
加作者私人微信,作者微信號(hào)如下 yclimb,標(biāo)明 微信支付 可拉入微信支付討論群與小伙伴一起探討哦,一定要標(biāo)明 微信支付 哦~
到此本文就結(jié)束了,關(guān)注公眾號(hào)查看更多推送?。?!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/72028.html
摘要:本文是淺析微信支付系列文章的第二篇,主要講解一下普通商戶接入的支付方式以及其中的不同之處。淺析微信支付前篇大綱微信支付是集成在微信客戶端的支付功能,用戶可以通過手機(jī)完成快速的支付流程。目前微信支付支持手機(jī)系統(tǒng)有蘋果安卓和。 本文是【淺析微信支付】系列文章的第二篇,主要講解一下普通商戶接入的支付方式以及其中的不同之處。 上篇文章講了本系列的大綱,沒有看過的朋友們可以看一下。 淺析微信支...
摘要:本文是淺析微信支付系列文章的第六篇,主要講解支付成功后,微信回調(diào)商戶支付結(jié)果通知的處理。微信支付支付回調(diào)接口該鏈接是通過統(tǒng)一下單中提交的參數(shù)設(shè)置,如果鏈接無法訪問,商戶將無法接收到微信通知。 本文是【淺析微信支付】系列文章的第六篇,主要講解支付成功后,微信回調(diào)商戶支付結(jié)果通知的處理。 淺析微信支付系列已經(jīng)更新五篇了喲~,沒有看過的朋友們可以看一下哦。 淺析微信支付:統(tǒng)一下單接口 淺析...
摘要:本文是淺析微信支付系列文章的第七篇,主要講解微信商戶平臺(tái)的訂單查詢和關(guān)閉接口的使用。查詢訂單以下為微信官方的查詢訂單文檔應(yīng)用場(chǎng)景該接口提供所有微信支付訂單的查詢,商戶可以通過查詢訂單接口主動(dòng)查詢訂單狀態(tài),完成下一步的業(yè)務(wù)邏輯。 本文是【淺析微信支付】系列文章的第七篇,主要講解微信商戶平臺(tái)的訂單查詢和關(guān)閉接口的使用。 淺析微信支付系列已經(jīng)更新六篇了喲~,沒有看過的朋友們可以看一下哦。 ...
摘要:淺析微信支付前篇大綱本文是淺析微信支付系列文章的第一篇,主要會(huì)介紹一下為何寫下這個(gè)系列以及對(duì)于微信支付的一點(diǎn)小經(jīng)驗(yàn),與君共勉。下面講一下我是如何去學(xué)習(xí)微信支付的。 淺析微信支付:前篇大綱 本文是【淺析微信支付】系列文章的第一篇,主要會(huì)介紹一下為何寫下這個(gè)系列以及對(duì)于微信支付的一點(diǎn)小經(jīng)驗(yàn),與君共勉。 以下會(huì)分幾個(gè)步驟講一下我學(xué)習(xí)微信支付的過程,也是一部辛酸史,也是希望朋友們不要再次跌進(jìn)...
摘要:本文是淺析微信支付系列文章的第十四篇,主要講解在如何開通商戶平臺(tái)的代金券或立減優(yōu)惠功能,商家向指定用戶發(fā)送代金券,查詢發(fā)送記錄,代金券信息等。代金券微信支付代金券業(yè)務(wù)是基于微信支付,為了協(xié)助商戶方便地實(shí)現(xiàn)營(yíng)銷優(yōu)惠措施。 本文是【淺析微信支付】系列文章的第十四篇,主要講解在如何開通商戶平臺(tái)的代金券或立減優(yōu)惠功能,商家向指定用戶發(fā)送代金券,查詢發(fā)送記錄,代金券信息等。 淺析微信支付系列已...
閱讀 4065·2021-09-27 13:35
閱讀 1182·2021-09-24 09:48
閱讀 2968·2021-09-22 15:42
閱讀 2403·2021-09-22 15:28
閱讀 3209·2019-08-30 15:43
閱讀 2680·2019-08-30 13:52
閱讀 3036·2019-08-29 12:48
閱讀 1541·2019-08-26 13:55