spring?boot+vue實(shí)現(xiàn)JSAPI微信支付的完整步驟
微信支付
最近公司要在微信公眾號上做一個活動預(yù)報名,活動的門票等需要在微信中支付。
微信支付前的準(zhǔn)備
微信支付需要一個微信支付商務(wù)號(https://pay.weixin.qq.com/index.php/apply/applyment_home/guide_normal),請自行去商務(wù)平臺申請。商務(wù)號申請完后,需要在 “微信公眾號平臺–>微信支付” 中接入。接入成功后還需要在 “微信公眾號平臺–>設(shè)置–>公眾號設(shè)置–>功能設(shè)置” 中將你的域名設(shè)置好,域名格式:http://baidu.com/ ,并將你的服務(wù)器ip設(shè)置成白名單,設(shè)置好之后 就可以開始開發(fā)微信支付了,
后臺開發(fā)
話不多說,直接上代碼吧,如果想細(xì)了解的請看官方文檔
控制層
@RequestMapping(value = "/wxpay", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public Map<String, Object> weixinPrePay(@RequestBody Pay pay,HttpServletRequest request) throws Exception { Map<String,Object> maps = new HashMap<String,Object>(); // 前端傳值總是會多一個: 后臺截取掉 這個看情況 可能你不存在這種情況的 pay.setOpenid(pay.getOpenid().substring(0, pay.getOpenid().length()-1)); System.out.println(pay.getOpenid()); // 前端傳來的金額 后臺需要將它變成 元 Double prices = pay.getPrice()*100; Integer total_fee = prices.intValue(); System.out.println(prices+"----"+pay.getPrice()+"----"+total_fee); // 生成唯一訂單號 Integer out_trade_no = (int) (System.currentTimeMillis() / 1000+970516); SortedMap<String, Object> parameterMap = new TreeMap<String, Object>(); parameterMap.put("appid", Parm.APPID); //微信公眾號的appid parameterMap.put("mch_id", Parm.MCH_ID/*PayCommonUtil.MCH_ID*/); //商戶號 parameterMap.put("device_info", "WEB"); parameterMap.put("nonce_str", randomString); // 隨機(jī)字符串 parameterMap.put("body", "cheshi"); // 商品描述 parameterMap.put("out_trade_no", out_trade_no); // 商戶訂單號(唯一) 我是用當(dāng)前時間戳+隨意數(shù)字生成的 parameterMap.put("fee_type", "CNY"); //貨幣類型 CNY:人民幣 parameterMap.put("total_fee", total_fee); // 總金額 分為單位 parameterMap.put("notify_url", wxnotify); // 支付成功后的回調(diào)地址 填你 parameterMap.put("trade_type", "JSAPI");//JSAPI--JSAPI支付(或小程序支付)、NATIVE--Native支付、APP--app支付,MWEB--H5支付,不同trade_type決定了調(diào)起支付的方式 //trade_type為JSAPI是 openid為必填項(xiàng) parameterMap.put("openid", ASEUtil.AESdecrypt(pay.getOpenid())); // 加密格式 MD5 微信底層默認(rèn)加密是HMAC-SHA256 具體你可以去看微信的支付底層代碼(https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1) parameterMap.put("sign_type", "MD5"); // 生成支付簽名 參數(shù)值的參數(shù)按照參數(shù)名ASCII碼從小到大排序(字典序) String sign = PayCommonUtil.createSign("UTF-8", parameterMap); parameterMap.put("sign", sign); System.out.println(parameterMap); // 微信的統(tǒng)一下單接口 需要將集合中的參數(shù) 拼接成<xml></xml> 格式 String requestXML = PayCommonUtil.getRequestXml(parameterMap); System.out.println(requestXML); // 調(diào)用微信的統(tǒng)一下單接口 String result = PayCommonUtil.httpsRequest( "https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", requestXML); // 返回的數(shù)據(jù)是 xml 格式的數(shù)據(jù) System.out.println(result); Map<String, Object> map = null; try { // 微信統(tǒng)一下單接口返回的數(shù)據(jù) 也是xml 格式的 所以需要把它轉(zhuǎn)成map 集合,因?yàn)槲覀冎恍枰?dāng)中的一個統(tǒng)一下單編號 prepay_id map = PayCommonUtil.doXMLParse(result); // 時間戳 需要轉(zhuǎn)換成秒 map.put("timestamp", System.currentTimeMillis() / 1000); // 二次簽名 微信支付簽名需要簽名兩次,第一次是用來獲取統(tǒng)一下單的訂單號 if ("SUCCESS".equals(map.get("result_code"))) { SortedMap<String, Object> map2 = new TreeMap<String, Object>(); // 第二次支付簽名的 參數(shù) 需要將 第一次簽名中的 訂單號帶入簽名中 map2.put("appId", map.get("appid")); map2.put("timeStamp", map.get("timestamp")); //這邊的隨機(jī)字符串必須是第一次生成sign時,微信返回的隨機(jī)字符串,不然支付時會報簽名錯誤 map2.put("nonceStr", map.get("nonce_str")); // 訂單詳情擴(kuò)展字符串 統(tǒng)一下單接口返回的prepay_id參數(shù)值,提交格式如:prepay_id=*** map2.put("package", "prepay_id=" + map.get("prepay_id")); // 簽名方式 要和第一次簽名方式一直 map2.put("signType", "MD5"); // 支付簽名 String sign2 = PayCommonUtil.createSign("UTF-8", map2); // 將你前端需要的數(shù)據(jù) 放在集合中 Map<String,Object> payInfo = new HashMap<String,Object>(); payInfo.put("appId", map.get("appid")); payInfo.put("timeStamp", map.get("timestamp")); payInfo.put("nonceStr", map.get("nonce_str")); payInfo.put("prepay_id",map.get("prepay_id")); payInfo.put("signType", "MD5"); payInfo.put("paySign", sign2); // 返回給前端的集合數(shù)據(jù) maps.put("status", 200); maps.put("msg", "統(tǒng)一下單成功!"); maps.put("data", payInfo); }else { maps.put("status", 500); maps.put("msg", "服務(wù)器忙,請稍后再試"); maps.put("data", null); } } catch (JDOMException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return maps; }
工具類(參考這個網(wǎng)址,或者使用微信官方提供的那個demo中的微信工具類)怎么選擇,看你個人
vue前端
// 微信支付 onBridgeReady() { let that = this; let param = { openid: sessionStorage.getItem("openid"), // 當(dāng)前用戶微信的openid price: that.ruleForm.price // 應(yīng)付金額 }; // 后臺支付簽名接口 weixinPrePay(param).then(ref => { console.log(ref.data); if (ref.data.status == 200) { WeixinJSBridge.invoke( "getBrandWCPayRequest", { appId: ref.data.data.appId, // 微信的appid timeStamp: ref.data.data.timeStamp, //時間戳 nonceStr: ref.data.data.nonceStr, //隨機(jī)串 package: "prepay_id=" + ref.data.data.prepay_id, // 訂單號 signType: "MD5", //微信簽名方式: paySign: ref.data.data.paySign //微信簽名 }, function(res) { if (res.err_msg == "get_brand_wcpay_request:ok") { // 使用以上方式判斷前端返回,微信團(tuán)隊(duì)鄭重提示: //res.err_msg將在用戶支付成功后返回ok,但并不保證它絕對可靠。 var equipments = ""; if (that.ruleForm.region === 1) { equipments = "單人套餐(門票一張,帳篷一頂)"; } else { equipments = "雙人套餐(門票兩張,帳篷一頂)"; } let params = { SysUser: { name: that.ruleForm.username, mobile: that.ruleForm.phone, openid: sessionStorage.getItem("openid") }, Info_id: that.ruleForm.info, Participants: that.ruleForm.numbers, Equipments: equipments, price: that.ruleForm.price }; console.log(params); // 將支付用戶加入數(shù)據(jù)庫中 保存 insertForecast(params).then(ref => { if (ref.data.status == 200) { that.$router.push({ path: "/ForeacstList" }); } else { that.$message.error("預(yù)報名失敗"); } }); } else { that.$message.error("支付失敗,請重新支付"); } } ); } else { that.$message.error(ref.data.msg); } }); }, // 微信支付 WeixinJs() { console.log(this.ruleForm.price); 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 { this.onBridgeReady(); } }
微信支付就到此結(jié)束了。
總結(jié)
到此這篇關(guān)于spring boot+vue實(shí)現(xiàn)JSAPI微信支付的文章就介紹到這了,更多相關(guān)springboot vue實(shí)現(xiàn)微信支付內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot異常錯誤頁面實(shí)現(xiàn)方法介紹
在項(xiàng)目訪問的時候我們經(jīng)常會發(fā)生錯誤或者頁面找不到,比如:資源找不到404,服務(wù)器500錯誤,默認(rèn)情況下springboot的處理機(jī)制都是去跳轉(zhuǎn)內(nèi)部的錯誤地址:/error 和與之對應(yīng)的一個錯誤頁面2022-09-09詳解Java實(shí)現(xiàn)的k-means聚類算法
這篇文章主要介紹了詳解Java實(shí)現(xiàn)的k-means聚類算法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01SpringBoot集成PostgreSQL并設(shè)置最大連接數(shù)
本文主要介紹了SpringBoot集成PostgreSQL并設(shè)置最大連接數(shù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11談?wù)凧ava利用原始HttpURLConnection發(fā)送POST數(shù)據(jù)
這篇文章主要給大家介紹java利用原始httpUrlConnection發(fā)送post數(shù)據(jù),設(shè)計(jì)到httpUrlConnection類的相關(guān)知識,感興趣的朋友跟著小編一起學(xué)習(xí)吧2015-10-10詳解SpringBoot中異步請求的實(shí)現(xiàn)與并行執(zhí)行
這篇文章主要為大家詳細(xì)介紹了在SpringBoot中如何是實(shí)現(xiàn)異步請求、并行執(zhí)行,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02SpringBoot集成WebSocket的兩種方式(JDK內(nèi)置版和Spring封裝版)
這篇文章主要介紹了SpringBoot集成WebSocket的兩種方式,這兩種方式為JDK內(nèi)置版和Spring封裝版,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06