spring?boot+vue實(shí)現(xiàn)JSAPI微信支付的完整步驟
微信支付
最近公司要在微信公眾號(hào)上做一個(gè)活動(dòng)預(yù)報(bào)名,活動(dòng)的門票等需要在微信中支付。
微信支付前的準(zhǔn)備
微信支付需要一個(gè)微信支付商務(wù)號(hào)(https://pay.weixin.qq.com/index.php/apply/applyment_home/guide_normal),請(qǐng)自行去商務(wù)平臺(tái)申請(qǐng)。商務(wù)號(hào)申請(qǐng)完后,需要在 “微信公眾號(hào)平臺(tái)–>微信支付” 中接入。接入成功后還需要在 “微信公眾號(hào)平臺(tái)–>設(shè)置–>公眾號(hào)設(shè)置–>功能設(shè)置” 中將你的域名設(shè)置好,域名格式:http://baidu.com/ ,并將你的服務(wù)器ip設(shè)置成白名單,設(shè)置好之后 就可以開始開發(fā)微信支付了,

后臺(tái)開發(fā)
話不多說(shuō),直接上代碼吧,如果想細(xì)了解的請(qǐng)看官方文檔
控制層
@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>();
// 前端傳值總是會(huì)多一個(gè): 后臺(tái)截取掉 這個(gè)看情況 可能你不存在這種情況的
pay.setOpenid(pay.getOpenid().substring(0, pay.getOpenid().length()-1));
System.out.println(pay.getOpenid());
// 前端傳來(lái)的金額 后臺(tái)需要將它變成 元
Double prices = pay.getPrice()*100;
Integer total_fee = prices.intValue();
System.out.println(prices+"----"+pay.getPrice()+"----"+total_fee);
// 生成唯一訂單號(hào)
Integer out_trade_no = (int) (System.currentTimeMillis() / 1000+970516);
SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
parameterMap.put("appid", Parm.APPID); //微信公眾號(hào)的appid
parameterMap.put("mch_id", Parm.MCH_ID/*PayCommonUtil.MCH_ID*/); //商戶號(hào)
parameterMap.put("device_info", "WEB");
parameterMap.put("nonce_str", randomString); // 隨機(jī)字符串
parameterMap.put("body", "cheshi"); // 商品描述
parameterMap.put("out_trade_no", out_trade_no); // 商戶訂單號(hào)(唯一) 我是用當(dāng)前時(shí)間戳+隨意數(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)中的一個(gè)統(tǒng)一下單編號(hào) prepay_id
map = PayCommonUtil.doXMLParse(result);
// 時(shí)間戳 需要轉(zhuǎn)換成秒
map.put("timestamp", System.currentTimeMillis() / 1000);
// 二次簽名 微信支付簽名需要簽名兩次,第一次是用來(lái)獲取統(tǒng)一下單的訂單號(hào)
if ("SUCCESS".equals(map.get("result_code"))) {
SortedMap<String, Object> map2 = new TreeMap<String, Object>();
// 第二次支付簽名的 參數(shù) 需要將 第一次簽名中的 訂單號(hào)帶入簽名中
map2.put("appId", map.get("appid"));
map2.put("timeStamp", map.get("timestamp"));
//這邊的隨機(jī)字符串必須是第一次生成sign時(shí),微信返回的隨機(jī)字符串,不然支付時(shí)會(huì)報(bào)簽名錯(cuò)誤
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ù)器忙,請(qǐng)稍后再試");
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;
}
工具類(參考這個(gè)網(wǎng)址,或者使用微信官方提供的那個(gè)demo中的微信工具類)怎么選擇,看你個(gè)人

vue前端
// 微信支付
onBridgeReady() {
let that = this;
let param = {
openid: sessionStorage.getItem("openid"), // 當(dāng)前用戶微信的openid
price: that.ruleForm.price // 應(yīng)付金額
};
// 后臺(tái)支付簽名接口
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, //時(shí)間戳
nonceStr: ref.data.data.nonceStr, //隨機(jī)串
package: "prepay_id=" + ref.data.data.prepay_id, // 訂單號(hào)
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,但并不保證它絕對(duì)可靠。
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ù)庫(kù)中 保存
insertForecast(params).then(ref => {
if (ref.data.status == 200) {
that.$router.push({
path: "/ForeacstList"
});
} else {
that.$message.error("預(yù)報(bào)名失敗");
}
});
} else {
that.$message.error("支付失敗,請(qǐng)重新支付");
}
}
);
} 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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot異常錯(cuò)誤頁(yè)面實(shí)現(xiàn)方法介紹
在項(xiàng)目訪問的時(shí)候我們經(jīng)常會(huì)發(fā)生錯(cuò)誤或者頁(yè)面找不到,比如:資源找不到404,服務(wù)器500錯(cuò)誤,默認(rèn)情況下springboot的處理機(jī)制都是去跳轉(zhuǎn)內(nèi)部的錯(cuò)誤地址:/error 和與之對(duì)應(yīng)的一個(gè)錯(cuò)誤頁(yè)面2022-09-09
詳解Java實(shí)現(xiàn)的k-means聚類算法
這篇文章主要介紹了詳解Java實(shí)現(xiàn)的k-means聚類算法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
SpringBoot集成PostgreSQL并設(shè)置最大連接數(shù)
本文主要介紹了SpringBoot集成PostgreSQL并設(shè)置最大連接數(shù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11
Java調(diào)用WebService接口作測(cè)試
這篇文章主要介紹了Java調(diào)用WebService接口作測(cè)試,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Java中DecimalFormat用法及符號(hào)含義
DecimalFormat是NumberFormat的一個(gè)具體子類,用于格式化十進(jìn)制數(shù)字。這篇文章介紹了DecimalFormat的用法及符號(hào)含義,需要的朋友可以收藏下,方便下次瀏覽觀看2021-12-12
談?wù)凧ava利用原始HttpURLConnection發(fā)送POST數(shù)據(jù)
這篇文章主要給大家介紹java利用原始httpUrlConnection發(fā)送post數(shù)據(jù),設(shè)計(jì)到httpUrlConnection類的相關(guān)知識(shí),感興趣的朋友跟著小編一起學(xué)習(xí)吧2015-10-10
詳解SpringBoot中異步請(qǐng)求的實(shí)現(xiàn)與并行執(zhí)行
這篇文章主要為大家詳細(xì)介紹了在SpringBoot中如何是實(shí)現(xiàn)異步請(qǐng)求、并行執(zhí)行,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02
SpringBoot集成WebSocket的兩種方式(JDK內(nèi)置版和Spring封裝版)
這篇文章主要介紹了SpringBoot集成WebSocket的兩種方式,這兩種方式為JDK內(nèi)置版和Spring封裝版,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06

