從事JAVA開發一年多了,一直都在看博客園,CSDN的博客,從不少前人哪裏學習了不少,忽然以爲本身也要盡一份力,寫點博客本身給本身作作記錄,也給要開發微信人提提醒少遇點坑。php
不少人開發微信的時候,老是在抱怨微信的開發文檔很坑,裏面的參數和使用方式很含糊,其實有時候本身想一想,若是本身去研發API的時候,是否可以作的比微信更好呢?,大師都有一顆虔誠學徒的心,但願這篇文檔能給予從事微信公衆號H5支付焦頭爛額的朋友,一點幫助。html
先給你們提提從事微信開發,須要作的一些準備條件:一、去微信公共平臺和微信商戶平臺註冊一個帳號,這裏須要給微信交納300塊RMB成爲一個開發者擁有開發資質 ,微信公共平臺網址 、微信商戶平臺網址 二、申請一個服務號詳細流程我就不提醒了,服務號是須要企業認證的(若是沒有企業資格,又想練練手的朋友能夠去申請一個微信公衆號測試號,進行一些簡單的開發,微信測試號網址) 。三、注意看文檔,切記重要的事情說三遍!!!,作操做以前仔細理解文檔裏面的內容,參數裏面的關係,請求的格式之類的,這種錯誤是最難發現的,微信公共號開發文檔網址 ,微信支付文檔。前端
進行開發以前,先把思路理清楚瞭解,瞭解微信支付的類型,這裏類型有不少,咱們須要的是公衆號支付,經過官網文檔瞭解,這裏須要註冊一個微信商戶,這個我就不解釋了,按照官網的指示擼就好了,這裏展現一個官網的業務流程圖。ajax
沒有理解到的多看看流程圖少吃不少虧,也能夠帶入本身的業務模式,來考慮怎麼設計業務。算法
這裏咱們瞭解到,使用微信統一下單支付接口,前提是須要用戶的openid,這裏又要涉及到微信的受權登陸了,個人另外一篇文章: 網頁微信受權登陸文章json
好了咱們這裏提到微信支付流程第一步,統一下單支付接口,這裏貼上必填的參數:api
字段名 | 變量名 | 示例值 | 類型 | 描述 |
公衆帳號ID | appid | wxd678efh567hg6787 | String(32) | 微信支付分配的公衆帳號ID(企業號corpid即爲此appId) |
商戶號 | mch_id | 1230000109 | String(32) | 微信支付分配的商戶號 |
隨機字符串 | nonce_str | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS | String(32) | 隨機字符串,長度要求在32位之內。推薦隨機數生成算法 |
簽名 | sign | C380BEC2BFD727A4B6845133519F3AD6 | String(32) | 經過簽名算法計算得出的簽名值,詳見簽名生成算法 |
商品描述 | body | 騰訊充值中心-QQ會員充值 | String(128) | 商品簡單描述,該字段請按照規範傳遞,具體請見參數規定 |
商戶訂單號 | out_trade_no | 20150806125346 | String(32) | 商戶系統內部訂單號,要求32個字符內,只能是數字、大小寫字母_-|* 且在同一個商戶號下惟一。詳見商戶訂單號 |
標價金額 | total_fee | 88 | Int | 訂單總金額,單位爲分,詳見支付金額 |
終端IP | spbill_create_ip | 123.12.12.123 | String(16) | APP和網頁支付提交用戶端ip,Native支付填調用微信支付API的機器IP |
通知地址 | notify_url | http://www.weixin.qq.com/wxpay/pay.php | String(256) | 異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數 |
交易類型 | trade_type | JSAPI | String(16) | JSAPI 公衆號支付微信 NATIVE 掃碼支付微信開發 APP APP支付app 說明詳見參數規定 |
裏面要注意:簽名算法,不建議本身手寫,能夠用微信的支付工具類(微信官方工具類,裏面有不少的函數,例如生成sign,map組裝xml等實用功能,減小開發量),裏面有方法能夠填入參數就能夠生成sign
貼上我本身的代碼:
// 統一下單URL String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; IWXPayConfig config = new IWXPayConfig(); Map<String, String> data = new HashMap<String, String>(); data.put("appid", config.getAppID());//微信支付分配的公衆帳號ID(企業號corpid即爲此appId) data.put("mch_id", config.getMchID());//微信支付分配的商戶號 String str = WXPayUtil.generateNonceStr(); data.put("nonce_str", str); // 經過微信工具類生成 隨機字符串 data.put("body", "超級商品");//商品描述 data.put("out_trade_no", order.getOrderSn()); // 訂單惟一編號, 不容許重複 data.put("total_fee", new BigDecimal(100).multiply(order.getAmount()).setScale(0,BigDecimal.ROUND_DOWN).toString()); // 訂單金額, 單位分 data.put("spbill_create_ip", GetIp.getTrueIpAddr(request)); // 下單ip data.put("openid", order.getOpenId()); // 微信公衆號統一標示openid data.put("notify_url", "URL這裏填寫,你的回調域名"); // 訂單結果通知, 微信主動回調此接口 data.put("trade_type", "JSAPI"); // 固定填寫 // 生成帶有 sign 的 XML 格式字符串 String xmlparam = WXPayUtil.generateSignedXml(data, config.getKey()); // 發送請求 String resultStr = HttpRequest.sendPost(unifiedorder_url, xmlparam); logger.info("返回消息" + resultStr);
經過post請求微信會回調一個json回調信息,若是裏面return_code 回覆爲SUCCESS並且result_code 也爲SUCCESS的話,恭喜你就成功了一半了。這個時候能夠放鬆一下泡杯茶。
下一步,根據官方提示,須要把返回的json回調信息的,參數取出來進行二次封裝,組裝進map,而後返回前端發起支付請求(這裏有一個坑,頁面實際的支付路徑等於微信商戶平臺的設置支付目錄的下一級,切記!!!微信錯誤提示不足,致使我這裏卡了一下午)
這裏貼上個人代碼:
// 時間戳 String timeStamp = new Long(WXPayUtil.getCurrentTimestamp()).toString(); // 建立返回值 //組裝二次簽名 Map<String, String> resultMap = new HashMap<String, String>(); resultMap.put("appId", wxResultMap.get("appid")); resultMap.put("timeStamp", timeStamp); resultMap.put("nonceStr", str); resultMap.put("package", "prepay_id=" + wxResultMap.get("prepay_id")); resultMap.put("signType", "MD5"); // 生成簽名 String paySign = WXPayUtil.generateSignature(resultMap, config.getKey()); resultMap.put("paySign", paySign); return MsgJson.getmsg(false, resultMap, "簽名生成成功");
注意通常出現錯誤的地方都是參數錯誤,若是前端執行報錯請檢查參數,是否有填寫錯,大小寫是否有問題。
貼上前端代碼:
$.ajax({ type:"post", url: "/weixin/pay", dataType:"json", ontentType : "application/x-www-form-urlencoded", data:{orderId:'${orderId}'}, success:function(result) { console.log(result); var data = result; //var data = JSON.parse(result); if(data.status == '200'){ appId = data.data.appId; paySign = data.data.paySign; timeStamp = data.data.timeStamp; nonceStr = data.data.nonceStr; packageStr = data.data.package; signType = data.data.signType; callpay(); }else{ alert("統一下單失敗"); } } }); } function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":appId, //公衆號名稱,由商戶傳入 "timeStamp":timeStamp, //時間戳,自1970年以來的秒數 "nonceStr":nonceStr , //隨機串 "package":packageStr, //預支付交易會話標識 "signType":signType, //微信簽名方式 "paySign":paySign //微信簽名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { alert('支付成功'); window.location.replace("/eby/index"); }else if(res.err_msg == "get_brand_wcpay_request:cancel"){ alert('支付取消'); }else if(res.err_msg == "get_brand_wcpay_request:fail" ){ alert('支付失敗'); } //使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回 ok,但並不保證它絕對可靠。 } ); } function callpay(){ if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } }else{ onBridgeReady(); }
前端作完,這一步順利調出來微信支付的彈框
這裏就基本大功告成了,還有差一步處理支付的回調,根據微信官方提示前端返回的支付成功是不靠譜的,須要微信異步回調來驗證,一共有8次注意通知的延遲重複性,經過生成sign比對成功後才能夠確保此次支付成功了,下面貼上個人處理回調代碼:
HashMap map = new HashMap(); IWXPayConfig config = new IWXPayConfig(); try { InputStream inStream = request.getInputStream(); ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outSteam.write(buffer, 0, len); } outSteam.close(); inStream.close(); String resultStr = new String(outSteam.toByteArray(), "utf-8"); Map<String, String> resultMap = WXPayUtil.xmlToMap(resultStr);//將xml轉成排序以後的map logger.info("微信支付回調地址請求參數=requst:{}", resultMap.toString()); String result_code = resultMap.get("result_code");//業務結果 String is_subscribe = resultMap.get("is_subscribe");//是否關注了微信公衆號 String out_trade_no = resultMap.get("out_trade_no");//訂單號 String transaction_id = resultMap.get("transaction_id");//微信支付訂單號 相似於支付寶的交易號 String sign = resultMap.get("sign");//簽名 String total_fee = resultMap.get("total_fee");//訂單總金額 單位爲 分 String openid = resultMap.get("openid");//用戶在商戶appid下的惟一標識 String time_end = resultMap.get("time_end"); String bank_type = resultMap.get("bank_type"); //簽名驗證 resultMap.remove("sign"); String signStr = WXPayUtil.generateSignature(resultMap,config.getKey()); logger.warn("驗證= signStr:{},sign:{}", signStr, sign); if (!signStr.equals(sign)) { logger.warn("微信支付回調地址請求參數簽名驗證失敗= signStr:{},sign:{}", signStr, sign); map.put("return_code", "FAIL"); map.put("return_msg", "sign不正確"); return WXPayUtil.mapToXml(map); } if (result_code.equals("SUCCESS")) { logger.info("支付成功= 訂單號:{},交易號:{}", out_trade_no, transaction_id); BigDecimal bigDecimal_total_fee = new BigDecimal(total_fee); BigDecimal bigDecimal = bigDecimal_total_fee.divide(new BigDecimal(100)); // 支付成功處理業務邏輯 } //通知微信.異步確認成功.必寫.否則會一直通知後臺.八次以後就認爲交易失敗了. map.put("return_code","SUCCESS"); map.put("return_msg","OK");
總結的來講,微信支付坑仍是很多尤爲是是地址和參數,多注意一些仍是能夠避免的,其餘的注意點在我在場景代碼裏面提出來了,第一次寫文章若是有很差的地方,但願你們指出來,但願這篇文章能幫到你們。
文章純手寫,轉載請帶上做者。