微信支付—微信H5支付「微信内部浏览器」
前言
微信支付-微信H5外部瀏覽器支付
微信支付-微信H5內部瀏覽器支付「本文」
微信支付-PC端掃碼支付「待寫」
本篇是微信支付系列的第二篇、微信H5內部瀏覽器支付,關于微信H5外部瀏覽器喚起微信APP支付,請參考上一篇文章。
開發環境:Java + SpringBoot + Vue +WxJava(開源SDK)
掃盲補充:關于微信內部瀏覽器支付,支付時會直接調起微信支付,不同于外部瀏覽器支付,內部瀏覽器支付首先需要獲得當前支付用戶對該公眾號的唯一標識 openId「是否關注都是唯一的」,拿到 openId 后,結合后端其他參數調用微信預支付接口,獲得預支付id,然后交由前端發起微信支付,支付成功后回調后端接口。
如下是正文部分。
1、獲取Code
要想獲得用戶唯一標識 openid,首先需要辦的事就是獲得 code。
code 部分在本文中交由前端去獲取「調用微信authorize授權方法」,拿到 code 后傳遞給后端換取 openid「用戶唯一標識」;通常這個操作都是在用戶登錄時去實現的,登錄成功后同時拿到 openid,而且還可以存(更新)到該用戶的數據庫方便后面使用。
前端獲取code,具體如下:
let?ua?=?navigator.userAgent.toLowerCase()if?(ua.match(/MicroMessenger/i)?==?'micromessenger')?{
????if?(!this.GetQueryString('code'))?{
????????alert("跳轉");
????????//?this.$vux.toast.text('微信授權中……',?'default')
????????let?currentUrl?=?encodeURIComponent(window.location.href)
????????window.location.href?=?'https://open.weixin.qq.com/connect/oauth2/authorize?appid=我是appid&redirect_uri='+currentUrl+'&response_type=code&scope=snsapi_base&state=STATE&connect_redirect=1#wechat_redirect'
????}?else?{
????????let?code?=?this.GetQueryString('code')
????????//?此處調用后端方法,通過?code?換取?openid
????}
}
補充:授權鏈接中的 scope 參數分為 snsapi_base、snsapi_userinfo,snsapi_base 可以獲得用戶的唯一標識 openid,snsapi_userinfo 則在此基礎上獲得用戶資料「昵稱、頭像等」
上述方法中 ua.match(/MicroMessenger/i) 是用來判斷是否是微信環境的, GetQueryString 方法用來獲取微信中的 code,如果當前瀏覽器 url 并沒有附帶 code 參數,那么就會調用微信的 authorize 方法進行授權,授權后獲得 code,該方法具體如下:
GetQueryString?(name)?{????let?url?=?new?RegExp('(^|&)'?+?name?+?'=([^&]*)(&|$)')
????let?newUrl?=?window.location.search.substr(1).match(url)
????if?(newUrl?!=?null)?{
????????return?unescape(newUrl[2])
????}?else?{
????????return?false
????}
},
2、換取openid
拿到 code 后,下一步就是調用后端接口換取 openid 了, 簡單看一下換取 openid 的后端方法:
try?{????String?url?=?"https://api.weixin.qq.com/sns/oauth2/access_token?appid=我是appid&secret=我是secret&grant_type=authorization_code"+
????????"&code="?+?loginRequest.getCode();
????String?body?=?RestTemplateUtils.get(url,new?JSONObject());
????JSONObject?jsonObject?=?JSONObject.parseObject(body);
????Integer?errcode?=?jsonObject.getInteger("errcode");
????if?(errcode?==?null?||?errcode?==?0)?{
????????String?openId?=?jsonObject.getString("openid");
????????//將此次登錄的openId,暫且放入user的域里面,支付的時候會用到
????????System.out.println("openId:"+openId);
????????loginRequest.setOpenId(openId);
????????return?ResultUtil.success(userService.login(loginRequest));
????}else{
????????logger.error("[微信第三方登錄]?異?!?;
????????拋出自定義異常
????????throw?new?CommonException("微信第三方登錄異常","");
????}
}?catch?(Exception?e)?{
????logger.error("[微信第三方登錄]?異常",?e);
????拋出自定義異常
????throw?new?CommonException("微信第三方登錄異常","");
}
簡單說一下該方法,前端傳遞 code 致后端方法,后端拿到 code 后,調用 access_token 接口獲取 openid,同時完成登錄操作。
至此,已經成功登錄并拿到用戶 openid 了,接下來就是調用支付接口。
3、預支付接口
上邊已經提到了,內部瀏覽器支付是交由前端發起的,但是又依賴于后端的 預支付接口,所以先來看一下后端預支付接口:
/**?*?生成訂單「微信內部瀏覽器」
?*?@return
?*/
@Transactional
public?Object?wxPrepay(Orders?orders,String?openId)?{
????Object?result?=?null;
????try?{
????????WxPayUnifiedOrderRequest?orderRequest?=?new?WxPayUnifiedOrderRequest();
????????orderRequest.setOutTradeNo(orders.getOrderId());
????????orderRequest.setOpenid(openId);
????????orderRequest.setBody(“我是商品描述信息");
????????orderRequest.setTotalFee(orders.getAmount().multiply(new?BigDecimal("100")).intValue());
????????orderRequest.setSpbillCreateIp(DispatchParams.getInstance().getWechatSpbillCreateIp());
????????orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
????????result?=?wxPayService.createOrder(orderRequest);
????????if?(result?instanceof?WxPayMpOrderResult)?{
????????????String?prepayId?=?((WxPayMpOrderResult)result).getPackageValue();
????????????String?paySign?=?((WxPayMpOrderResult)?result).getPaySign();
????????????prepayId?=?prepayId.replace("prepay_id=",?"");
????????????orders.setPrepayId(prepayId);
????????????orders.setSign(paySign);
????????????ordersDao.updateOrders(orders);
????????}
????}?catch?(WxPayException?e)?{
????????logger.error("[微信支付]?異常",?e);
????????拋出自定義全局異常
????????throw?new?CommonException(WechatStatusEn.WECHAT_CREATE_CODE_ERROR.getErrorMsg()+"':微信支付異常",?WechatStatusEn.WECHAT_CREATE_CODE_ERROR.getErrorCode());
????}?catch?(Exception?e)?{
????????logger.error("[預付款異常]",?e);
????????拋出自定義全局異常
????????throw?new?CommonException(WechatStatusEn.WECHAT_CREATE_CODE_ERROR.getErrorMsg()+"':預付款異常",?WechatStatusEn.WECHAT_CREATE_CODE_ERROR.getErrorCode());
????}
????return?result;
}
簡單說一下預支付方法,首先是根據自己情況創建訂單記錄,然后就是通過 openid 調用 wxPayService.createOrder 方法「WxJava」獲取預支付id,該方法返回的實體為 WxPayMpOrderResult,實體參數為前端調起微信支付的必要參數,具體如下:
private?String?appId;private?String?timeStamp;
private?String?nonceStr;
@XStreamAlias("package")
private?String?packageValue;
private?String?signType;
private?String?paySign;
為啥獲得的預支付id沒有用到呀?上方返回的參數并沒有看到呀!
其實不然,屬性 packageValue 的值為 prepay_id=預支付id ,該參數是必須的。
4、前端調用,發起支付
至此,后端基本完成了,我們將參數傳遞給前端調用,直接模擬返回后的數據:
假設下方是調用接口返回的數據console.log(“我是后端返回的數據?-?res:"+JSON.stringify(res))
const?payParam?=?{
????appId:?res.appId,
????nonceStr:?res.nonceStr,
????package:?res.packageValue,
????timeStamp:?res.timeStamp,
????signType:?res.signType,
????paySign:?res.paySign,
}
if?(typeof?WeixinJSBridge?===?'undefined')?{
????if?(document.addEventListener)?{
????????document.addEventListener('WeixinJSBridgeReady',?this.onBridgeReady(payParam),?false)
????}?else?if?(document.attachEvent)?{
????????document.attachEvent('WeixinJSBridgeReady',?this.onBridgeReady(payParam))
????????document.attachEvent('onWeixinJSBridgeReady',?this.onBridgeReady(payParam))
????}
}?else?{
????this.onBridgeReady(payParam)
}
發起支付的 onBridgeReady 方法:
onBridgeReady(res){????alert("發起請求:"+JSON.stringify(res));
????WeixinJSBridge.invoke(
????????'getBrandWCPayRequest',?{
????????????"appId":res.appId,?????//公眾號名稱,由商戶傳入
????????????"timeStamp":res.timeStamp,?//時間戳,自1970年以來的秒數
????????????"nonceStr":res.nonceStr,?//隨機串
????????????"package":res.package,?//?prepay_id=xxx
????????????"signType":res.signType,?//微信簽名方式:
????????????"paySign":res.paySign?//微信簽名
????????},
????????function(res){
????????????alert(JSON.stringify("我是支付返回的信息:\n"+res));
????????????alert("我是支付返回的信息:\n"+res.err_msg);
????????????if(res.err_msg?==?"get_brand_wcpay_request:ok"?){
????????????????//?使用以上方式判斷前端返回,微信團隊鄭重提示:
????????????????//res.err_msg將在用戶支付成功后返回ok,但并不保證它絕對可靠。
????????????????alert("支付成功了");
????????????}
????????}
????);
}
5、效果截圖
再來簡單總結一下,首先由前端獲取 code,獲取 code 后傳遞給后端換取 openid,openid 是預支付必須的參數,前端發起支付時,需要6個參數,此時調用后端預支付接口獲取「wxPayService.createOrder」,前端支付成功后同樣微信會自動回調后端 notify 接口,具體如下「代碼僅供參考」:
@RequestMapping(value?=?"/notify")@ResponseBody
public?String?notify(@RequestBody?String?body)?throws?Exception?{
????????WxPayOrderNotifyResult?result?=?null;
????????try?{
????????????result?=?wxPayService.parseOrderNotifyResult(body);
????????}?catch?(WxPayException?e)?{
????????????logger.error("[微信解析回調請求]?異常",?e);
????????????return?WxPayNotifyResponse.fail(e.getMessage());
????????}
????????logger.info("處理微信支付平臺的訂單支付");
????????logger.info(JSONObject.toJSONString(result));
????????String?appid?=?result.getAppid();//應用ID
????????String?attach?=?result.getAttach();//商家數據包
????????String?bank_type?=result.getBankType();//付款銀行
????????Integer?cash_fee?=?result.getCashFee();//現金支付金額
????????String?fee_type?=?result.getFeeType();//貨幣種類
????????String?is_subscribe?=?result.getIsSubscribe();//是否關注公眾賬號
????????String?mch_id?=?result.getMchId();//商戶號
????????String?nonce_str?=?result.getNonceStr();//隨機字符串
????????String?openid?=?result.getOpenid();//用戶標識
????????String?out_trade_no?=?result.getOutTradeNo();//?獲取商戶訂單號
????????String?result_code?=?result.getResultCode();//?業務結果
????????String?return_code?=?result.getReturnCode();//?SUCCESS/FAIL
????????String?sign?=?result.getSign();//?獲取簽名
????????String?time_end?=?result.getTimeEnd();//支付完成時間
????????Integer?total_fee?=?result.getTotalFee();//?獲取訂單金額
????????String?trade_type?=?result.getTradeType();//交易類型
????????String?transaction_id?=?result.getTransactionId();//微信支付訂單號
????????//如果成功寫入數據庫
????????if("SUCCESS".equals(return_code))?{//?如果微信返回的結果是success,則修改訂單狀態
????????????Orders?orders?=?ordersDao.selectByOrderId(out_trade_no);
????????????//?驗證簽名
????????????if(orders?!=?null){
????????????????if(!"1".equals(orders.getOrderStatus())){//判斷是否訂單已經完成了
????????????????????//?判斷金額是否跟數據庫訂單金額一致,放置人為修改
????????????????????if(orders.getAmount().multiply(new?BigDecimal("100")).compareTo(new?BigDecimal(total_fee))?==?0){
????????????????????????//更新訂單狀態
????????????????????????業務邏輯處理部分...
????????????????????????return?WxPayNotifyResponse.success("訂單已經處理成功!");
????????????????????}else{
????????????????????????logger.error("微信:金額不一致!");
????????????????????????return?WxPayNotifyResponse.fail("訂單金額不一致");
????????????????????}
????????????????}else?{
????????????????????return?WxPayNotifyResponse.success("訂單已經處理成功!");
????????????????}
????????????}else{
????????????????return?WxPayNotifyResponse.fail("商戶訂單號不匹配");
????????????}
????????}
????????System.out.println("回調成功");
????????System.out.println("----返回給微信的xml:"?+?result);
????????return?WxPayNotifyResponse.success("支付成功!");
}
最后
博客地址:https://www.cgblog.com/niceyoo
如果覺得這篇文章有丶東西,不放關注一下我,關注是對我最大的鼓勵~
18年專科畢業后,期間一度迷茫,最近我創建了一個公眾號用來記錄自己的成長。
總結
以上是生活随笔為你收集整理的微信支付—微信H5支付「微信内部浏览器」的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓动画基础讲解
- 下一篇: 2017年html5行业报告,云适配发布