Micro-channel pay - pay H5 micro letter "micro-channel internal browser."

Foreword

Micro-channel pay - micro letter H5 external browser payments
micro-channel pay - micro letter H5 internal browser payment " paper "
micro-channel pay -PC end of the scan code to pay " to be written ."

Benpian micro-channel payment is the second in the series, micro-channel pay H5 internal browser, on micro-channel H5 external browser evoke APP micro-channel payment, please refer to the previous article.

Development Environment: Java + SpringBoot + Vue + WxJava (open source SDK)

Literacy added: internal browser on micro-channel payment, when payment will be directly transferred from the micro-channel pay, unlike an external browser payment, internal browser payment first need to get the current pay users to uniquely identify openId "the number of public concern is whether the only the "get the openId, in conjunction with other parameters of the back-end call micro-channel pre-payment interface, access to pre-pay the id, and then handed over to the front launched micro-channel payment, after the payment of success callback backend interface.

The following is a body part.

1, access Code

To get the user to uniquely identify openid, you first need to do something is to get code.

After this operation is usually when users log on to achieve, the login is successful; code section referred to herein as the front end to get "call micro-channel authorization authorize" get the code passed to the backend exchange openid "that uniquely identifies the user." Meanwhile get openid, but may also be stored (updated) to the subscriber database easier to select.

Get the front end code, as follows:

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

Supplementary: scope parameter authorization link into unique identification openid snsapi_base, snsapi_userinfo, snsapi_base can get user, snsapi_userinfo the user to obtain information "nickname, avatar, etc." On this basis,

上述方法中 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年专科毕业后,期间一度迷茫,最近我创建了一个公众号用来记录自己的成长。

Guess you like

Origin www.cnblogs.com/niceyoo/p/12235649.html