• 微信支付—微信H5支付「PC端扫码支付」


    前言

    微信支付-微信H5外部浏览器支付
    微信支付-微信H5内部浏览器支付
    微信支付-PC端扫码支付本文

    本篇是微信支付系列的第三篇,PC端扫码支付。

    开发环境:Java + SpringBoot + Vue +WxJava(开源SDK)

    流程补充:关于微信PC端扫码支付,首先前端传递商品金额给后端生成支付二维码内容「本案例二维码由前端生成」,获得后端返回的内容后,前端根据内容生成二维码然后展示给用户,用户扫码支付成功后,微信官方推送给后端接口用户支付信结果,再根据结果更新数据库订单信息。

    如下是正文部分。

    1、获取二维码内容

    需要后端创建二维码接口,具体代码如下:

    /**
     * 创建二维码
     */
    @RequestMapping(value = "createQRCode", method = {RequestMethod.POST})
    @ApiOperation(value = "创建二维码")
    public Result<Object> createQRCode(@RequestBody WechatOrderRequest obj) {
        Orders orders = null;
        if (StringUtils.isNotBlank(obj.getOrderId())) {
            orders = ordersService.searchOrder(obj.getUserId, obj.getOrderId());
        } else {
            orders = ordersService.createOrder(obj.getUserId, obj.getTotal_fee(), "new");
        }
        WechatOrderResponse wechatOrderResponse = new WechatOrderResponse();
        wechatOrderResponse.setCodeUrl(wechatService.createOrderInfo(orders);
        wechatOrderResponse.setOrderId(orders.getOrderId());
        return ResultUtil.success(wechatOrderResponse);
    }

    关于上方方法,WechatOrderRequest实体,包含前端商品金额,以及用户信息、创建订单方式「是新建订单,还是未支付订单再次支付」等,总之,主要作用就是创建订单实体,之所以判断一下 OrderId,是因为未支付订单再次支付调用的接口共用了。

    关于 createOrder() 创建订单的方法,大致如下:

    public Orders createOrder(String userId,String total_fee){
        String  orderId=ToolUtils.makeUUID();
        Orders orders=new Orders();
        orders.setOrderId(orderId);
        orders.setOrderStatus("0");
        orders.setAmount(new BigDecimal(total_fee));
        orders.setCreateTime(new Date());
        orders.setUserId(userId);
        orders.setInvoice("0");
        orders.setAppType(appType);
        orders.setNonceStr(ToolUtils.makeUUID().toUpperCase());
        ordersDao.insertOrders(orders);
        return  orders;
    }

    searchOrder() 订单实体查询的接口就不贴出来了,就是简单的查询数据库。

    我们接着来看主要的方法,wechatService.createOrderInfo()

    @Transactional
    public String createOrderInfo(Orders orders) {
        WxPayMwebOrderResult result = null;
        try {
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            orderRequest.setOutTradeNo(orders.getOrderId());
            orderRequest.setBody("我是商品描述");
            orderRequest.setTotalFee(orders.getAmount().multiply(new BigDecimal("100")).intValue());
            orderRequest.setSpbillCreateIp(DispatchParams.getInstance().getWechatSpbillCreateIp());
            orderRequest.setProductId(orders.getOrderId());
            orderRequest.setTradeType(WxPayConstants.TradeType.NATIVE);
            result = wxPayService.createOrder(orderRequest);
            return result.getCodeUrl();
        } catch (WxPayException e) {
            logger.error("[微信支付异常] 异常", e);
            throw 自定义异常;
        }
    }

    补充:由于使用了 WxJava,所以接口相对是非常简洁的,赋予 WxPayUnifiedOrderRequest 对象必须的参数,比如支付金额,商品描述,ip,支付类型等,然后调动 createOrder() 方法就能得到二维码内容了,具体请求过程可以自己进入源码查看。

    返回的内容格式:weixin://wxpay/bizpayurl?pr=1RhYbXa

    ok,我们再回到最开始的方法,我们将获得的二维码内容、订单id,返回给前端,二维码内容供前端生成二维码,而订单id的作用则是,在当前支付界面,前端根据订单id不停地请求后端订单查询接口,如果后端返回结果,给出响应的提示,比如支付成功,支付失败等。

    2、前端生成二维码

    前端生成二维码有许多方式,本文采用 qrcodejs2 生成,package.json 加入以下依赖:

    "dependencies": {
        "qrcodejs2""0.0.2"
    }

    代码中使用,如下代码精简过了,就两个主要方法,看个热闹就行哈,具体的自行实现:

    <template>
        <div>
            <div id="qrcode" class="wechat_code"></div>
        </div>
    </template>
    <script>
        import QRCode from 'qrcodejs2'
        export default {
            methods:{
                qrCode(){
                    ifthis.codeUrl &&  this.codeUrl!==''){
                        if(this.qrcode !== null){
                            this.qrcode.clear();
                            this.qrcode.makeCode(this.codeUrl);
                        }else{
                            this.qrcode = new QRCode('qrcode', {
                                width200,
                                height200// 高度
                                text: this.codeUrl // 二维码内容
                            })
                        }
                        this.setTimeout=setTimeout(this.queryOrder,3000)
                    }
                },
                queryOrder(){
                    if(this.orderId !== null &&  this.orderId !== ""){
                        定时查询后端,请自行修改接口
                        this.getRequest("请求路径"this.orderId).then(res => {
                          this.loading = false;
                          if (res.success) {
                             clearTimeout(this.setTimeout);
                             this.visible = false;
                             this.$Modal.success({
                                titlethis.$t('global.prompt'),
                                contentthis.$t('recharge.paySuccess',{ amount:this.money })
                             });
                             this.$emit('search-orders');
                          }else{
                             this.setTimeout=setTimeout(this.queryOrder,1500)
                          }
                        });
                    }
                }
           },
    </script>

    简单说一下这两个方法,qrCode() 用于根据后端返回的内容 codeUrl 创建二维码;
    queryOrder() 方法永不不停地请求后端接口查询订单信息,如果返回数据,就不再继续调用自身,这块这样做就是为了给用户有好的提示,比如下方是一个支付二维码的弹窗,用户支付成功了,不但没有提示,窗口还一直打开着,想想用户体验是多么的不好。

    3、微信推送支付结果

    用户扫码支付后,微信会自动回调后端 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图片上传、压缩
    数据库基本操作
    数组遍历
    CURL
    获取IP
    Memcached的实战笔记
    修bug总结 (基于java语言)
    java开发工作的总结
    多线程测试类
    可清除的单例对象获取类
  • 原文地址:https://www.cnblogs.com/niceyoo/p/12404473.html
Copyright © 2020-2023  润新知