700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 微信支付—微信H5支付「微信内部浏览器」

微信支付—微信H5支付「微信内部浏览器」

时间:2020-07-17 12:08:20

相关推荐

微信支付—微信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,具体如下:

letua=navigator.userAgent.toLowerCase()

if(ua.match(/MicroMessenger/i)=='micromessenger'){

if(!this.GetQueryString('code')){

alert("跳转");

//this.$vux.toast.text('微信授权中……','default')

letcurrentUrl=encodeURIComponent(window.location.href)

window.location.href='https://open./connect/oauth2/authorize?appid=我是appid&redirect_uri='+currentUrl+'&response_type=code&scope=snsapi_base&state=STATE&connect_redirect=1#wechat_redirect'

}else{

letcode=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){

leturl=newRegExp('(^|&)'+name+'=([^&]*)(&|$)')

letnewUrl=window.location.search.substr(1).match(url)

if(newUrl!=null){

returnunescape(newUrl[2])

}else{

returnfalse

}

},

2、换取openid

拿到 code 后,下一步就是调用后端接口换取 openid 了, 简单看一下换取 openid 的后端方法:

try{

Stringurl="https://api./sns/oauth2/access_token?appid=我是appid&secret=我是secret&grant_type=authorization_code"+

"&code="+loginRequest.getCode();

Stringbody=RestTemplateUtils.get(url,newJSONObject());

JSONObjectjsonObject=JSONObject.parseObject(body);

Integererrcode=jsonObject.getInteger("errcode");

if(errcode==null||errcode==0){

StringopenId=jsonObject.getString("openid");

//将此次登录的openId,暂且放入user的域里面,支付的时候会用到

System.out.println("openId:"+openId);

loginRequest.setOpenId(openId);

returnResultUtil.success(userService.login(loginRequest));

}else{

logger.error("[微信第三方登录]异常”);

抛出自定义异常

thrownewCommonException("微信第三方登录异常","");

}

}catch(Exceptione){

logger.error("[微信第三方登录]异常",e);

抛出自定义异常

thrownewCommonException("微信第三方登录异常","");

}

简单说一下该方法,前端传递 code 致后端方法,后端拿到 code 后,调用 access_token 接口获取 openid,同时完成登录操作。

至此,已经成功登录并拿到用户 openid 了,接下来就是调用支付接口。

3、预支付接口

上边已经提到了,内部浏览器支付是交由前端发起的,但是又依赖于后端的 预支付接口,所以先来看一下后端预支付接口:

/**

*生成订单「微信内部浏览器」

*@return

*/

@Transactional

publicObjectwxPrepay(Ordersorders,StringopenId){

Objectresult=null;

try{

WxPayUnifiedOrderRequestorderRequest=newWxPayUnifiedOrderRequest();

orderRequest.setOutTradeNo(orders.getOrderId());

orderRequest.setOpenid(openId);

orderRequest.setBody(“我是商品描述信息");

orderRequest.setTotalFee(orders.getAmount().multiply(newBigDecimal("100")).intValue());

orderRequest.setSpbillCreateIp(DispatchParams.getInstance().getWechatSpbillCreateIp());

orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);

result=wxPayService.createOrder(orderRequest);

if(resultinstanceofWxPayMpOrderResult){

StringprepayId=((WxPayMpOrderResult)result).getPackageValue();

StringpaySign=((WxPayMpOrderResult)result).getPaySign();

prepayId=prepayId.replace("prepay_id=","");

orders.setPrepayId(prepayId);

orders.setSign(paySign);

ordersDao.updateOrders(orders);

}

}catch(WxPayExceptione){

logger.error("[微信支付]异常",e);

抛出自定义全局异常

thrownewCommonException(WechatStatusEn.WECHAT_CREATE_CODE_ERROR.getErrorMsg()+"':微信支付异常",WechatStatusEn.WECHAT_CREATE_CODE_ERROR.getErrorCode());

}catch(Exceptione){

logger.error("[预付款异常]",e);

抛出自定义全局异常

thrownewCommonException(WechatStatusEn.WECHAT_CREATE_CODE_ERROR.getErrorMsg()+"':预付款异常",WechatStatusEn.WECHAT_CREATE_CODE_ERROR.getErrorCode());

}

returnresult;

}

简单说一下预支付方法,首先是根据自己情况创建订单记录,然后就是通过 openid 调用 wxPayService.createOrder 方法「WxJava」获取预支付id,该方法返回的实体为 WxPayMpOrderResult,实体参数为前端调起微信支付的必要参数,具体如下:

privateStringappId;

privateStringtimeStamp;

privateStringnonceStr;

@XStreamAlias("package")

privateStringpackageValue;

privateStringsignType;

privateStringpaySign;

为啥获得的预支付id没有用到呀?上方返回的参数并没有看到呀!

其实不然,属性 packageValue 的值为prepay_id=预支付id,该参数是必须的。

4、前端调用,发起支付

至此,后端基本完成了,我们将参数传递给前端调用,直接模拟返回后的数据:

假设下方是调用接口返回的数据

console.log(“我是后端返回的数据-res:"+JSON.stringify(res))

constpayParam={

appId:res.appId,

nonceStr:res.nonceStr,

package:res.packageValue,

timeStamp:res.timeStamp,

signType:res.signType,

paySign:res.paySign,

}

if(typeofWeixinJSBridge==='undefined'){

if(document.addEventListener){

document.addEventListener('WeixinJSBridgeReady',this.onBridgeReady(payParam),false)

}elseif(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

publicStringnotify(@RequestBodyStringbody)throwsException{

WxPayOrderNotifyResultresult=null;

try{

result=wxPayService.parseOrderNotifyResult(body);

}catch(WxPayExceptione){

logger.error("[微信解析回调请求]异常",e);

returnWxPayNotifyResponse.fail(e.getMessage());

}

logger.info("处理微信支付平台的订单支付");

logger.info(JSONObject.toJSONString(result));

Stringappid=result.getAppid();//应用ID

Stringattach=result.getAttach();//商家数据包

Stringbank_type=result.getBankType();//付款银行

Integercash_fee=result.getCashFee();//现金支付金额

Stringfee_type=result.getFeeType();//货币种类

Stringis_subscribe=result.getIsSubscribe();//是否关注公众账号

Stringmch_id=result.getMchId();//商户号

Stringnonce_str=result.getNonceStr();//随机字符串

Stringopenid=result.getOpenid();//用户标识

Stringout_trade_no=result.getOutTradeNo();//获取商户订单号

Stringresult_code=result.getResultCode();//业务结果

Stringreturn_code=result.getReturnCode();//SUCCESS/FAIL

Stringsign=result.getSign();//获取签名

Stringtime_end=result.getTimeEnd();//支付完成时间

Integertotal_fee=result.getTotalFee();//获取订单金额

Stringtrade_type=result.getTradeType();//交易类型

Stringtransaction_id=result.getTransactionId();//微信支付订单号

//如果成功写入数据库

if("SUCCESS".equals(return_code)){//如果微信返回的结果是success,则修改订单状态

Ordersorders=ordersDao.selectByOrderId(out_trade_no);

//验证签名

if(orders!=null){

if(!"1".equals(orders.getOrderStatus())){//判断是否订单已经完成了

//判断金额是否跟数据库订单金额一致,放置人为修改

if(orders.getAmount().multiply(newBigDecimal("100")).compareTo(newBigDecimal(total_fee))==0){

//更新订单状态

业务逻辑处理部分...

returnWxPayNotifyResponse.success("订单已经处理成功!");

}else{

logger.error("微信:金额不一致!");

returnWxPayNotifyResponse.fail("订单金额不一致");

}

}else{

returnWxPayNotifyResponse.success("订单已经处理成功!");

}

}else{

returnWxPayNotifyResponse.fail("商户订单号不匹配");

}

}

System.out.println("回调成功");

System.out.println("----返回给微信的xml:"+result);

returnWxPayNotifyResponse.success("支付成功!");

}

最后

博客地址:/niceyoo

如果觉得这篇文章有丶东西,不放关注一下我,关注是对我最大的鼓励~

专科毕业后,期间一度迷茫,最近我创建了一个公众号用来记录自己的成长。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。