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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/414051.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[js] 写一个方法判断数组内元素是否全部相同

[js] 写一个方法判断数组内元素是否全部相同 const isSameArray function (array) {if (Array.isArray(array)) {return new Set(array).size 1;}return false; };个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎…

SQL Server中使用自定义指定顺序排序

SQL Server中使用自定义指定顺序排序 原文:SQL Server中使用自定义指定顺序排序比如需要对SQL表中的字段NAME进行如下的排序&#xff1a;张三&#xff08;Z&#xff09;李四&#xff08;L)王五&#xff08;W&#xff09;赵六&#xff08;Z&#xff09; 如果想按 “ 张三、李四、…

前后端分离项目,后端是如何处理前端传递的token?

前后端分离项目中&#xff0c;在不使用 SpringSecurity、Shiro 安全框架的情况下&#xff0c;后端是如何处理前段传递的 token 的呢&#xff1f; 简单说一个场景&#xff0c;在一个非常小的项目中&#xff0c;由于业务逻辑比较简单&#xff0c;也没有啥安全要求&#xff0c;所以…

[js] 说说防止重复发送ajax请求的方法有哪些?各自有什么优缺点?

[js] 说说防止重复发送ajax请求的方法有哪些&#xff1f;各自有什么优缺点&#xff1f; // 方法一 防抖function debounce(f, ms) { let time; return function(){ let arg Array.prototype.slice.call(arguments, 1); if(time) { clearTimeout(time); } time setTimeout(fu…

linux shell的here document用法(cat EOF)

什么是Here Document?Here Document 是在Linux Shell 中的一种特殊的重定向方式&#xff0c;它的基本的形式如下cmd << delimiter Here Document Contentdelimiter其作用是将两个 delimiter 之间的内容(Here Document Content 部分) 传递给cmd 作为输入参数;比如在终端…

面试必备:多线程学习(一)

这是2020年“水”的第23篇文章 面试中&#xff0c;多线程并发问题基本上是必问的&#xff0c;所以&#xff0c;不背上个线程相关的问题&#xff0c;都不好意思出去面试了。 一提到多线程&#xff0c;相信大部分小伙伴首先想到的一定是 Synchronize、Lock&#xff0c;再就是vola…

[js] 请使用 js 实现一个双向链表

[js] 请使用 js 实现一个双向链表 链表结构是我们在面试中经常会被问起的较为基础的数据结构问题&#xff0c;起初学习数据结构使用的是C语言&#xff0c;最近在做前端面试题的过程中没碰到了需要用js实现双链表的需求&#xff0c;百度出来的文章发现可很多错误&#xff0c;于…

MacOS中Nginx的安装「借助Homebrew」

本文Nginx的安装借助于Homebrew&#xff1b; 1、Homebrew2、Nginx安装 1、Homebrew 如果你已经安装过Homebrew了&#xff0c;那么你可以跳过这一步&#xff0c;直接进行Nginx安装步骤&#xff1b; Homebrew是一款MacOS平台下的软件包管理工具&#xff0c;拥有安装、卸载、更新、…

03、动态代理--CGLib引入增强

package com.offer.note.Java基础.动态代理.CGLib引入增强;public interface Browser {void visitInternet(); } package com.offer.note.Java基础.动态代理.CGLib引入增强;/*** 目标类&#xff1a;被代理类** author: xueguanfeng* date: 2018-05-15 09:57*/ public class Chr…

[js] ajax请求地址只支持http/https吗?能做到让它支持rtmp://等其它自定义协议吗 ?

[js] ajax请求地址只支持http/https吗&#xff1f;能做到让它支持rtmp://等其它自定义协议吗 &#xff1f; ajax只支持http/https协议&#xff0c; 可以通过自定义http头来间接支持自定义协议个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xf…

面试必备:HashMap底层数据结构?jdk1.8算法优化,hash冲突,扩容等问题

面试必备系列不会长篇理论求证&#xff0c;直接上答案&#xff0c;仅供参考&#xff0c;不喜勿喷。 1、能说说HashMap的底层原理吗&#xff1f; HashMap<String,String> map new HashMap<String,String>(); map.put(“key”,”value”); [<key1,value1>,<…

[js] 请写一个性能最好的深度克隆对象的方法

[js] 请写一个性能最好的深度克隆对象的方法 const deepClone (obj) > {const copy obj instance Array ? [] : {};for (let key in obj) {if (obj.hasOwnProperty(key)) {copy[key] typeof obj[key] object ? deepClone(obj[key]) : obj[key]}} return copy; }个人简…

快速下载||AnotherRedisDesktopManagerMedis-Redis可视化工具

尽管是在Gitee上下载这款软件&#xff0c;网速仍然是非常的慢&#xff0c;不知道是不是我的网络问题。 提供一份我的下载链接 MacOS&#xff1a;Another.Redis.Desktop.Manager.1.3.1.dmg Windows&#xff1a;Another.Redis.Desktop.Manager.1.3.1.exe 也许你还想试试Medis Mac…

[js] 使用ajax请求真的不安全吗?为什么?

[js] 使用ajax请求真的不安全吗&#xff1f;为什么&#xff1f; AJAX是发送HTTP请求的一种方式&#xff0c;只不过浏览器给它加了一个同源策略而已。 所以从这一点可以得出一个结论&#xff1a;AJAX本质上安全性和HTTP请求一样个人简介 我是歌谣&#xff0c;欢迎和大家一起交…

面试必备:synchronized的底层原理?

最近更新的XX必备系列适合直接背答案&#xff0c;不深究&#xff0c;不喜勿喷。 你能说简单说一下synchronize吗&#xff1f; 可别真简单一句话就说完了呀~ 参考回答&#xff1a; synchronize是java中的关键字&#xff0c;可以用来修饰实例方法、静态方法、还有代码块&#xff…

hadoop fs 命令详解

转载: https://blog.csdn.net/bgk083/article/details/49454209转载于:https://www.cnblogs.com/water-green/p/9050122.html

数组追加数组,小程序数组里面追加数组如何操作?

由于写错小程序生命周期函数方法名称「onLoad > onload」&#xff0c;一直以为自己用错了push… 需求描述 var arr[];var value [ a,b,c,d ]; 已有数组arr&#xff0c;获取的数据形式为数组value&#xff0c;需要将value追加值arr数组中&#xff0c;即[[],[]] 尝试过程 1、…

[js] 你有使用过pjax吗?它的原理是什么?

[js] 你有使用过pjax吗&#xff1f;它的原理是什么&#xff1f; pushState ajax pjax个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

Python3回文相关算法小结

[本文出自天外归云的博客园] 总结一下关于回文相关的算法&#xff1a; 判断字符串本身是否是回文返回字符串中的所有子串找到字符串中包含的所有回文判断字符串中是否包含回文将字符串变成一个不包含回文的字符串代码如下&#xff1a; # 判断字符串本身是否是回文 def is_huiwe…

面试必备:CAS无锁机制

CAS无锁机制原理&#xff0c;面试高频问题之一&#xff0c;其实&#xff0c;日常开发中并不会直接使用CAS无锁机制&#xff0c;都是通过一系列封装好的工具类来使用&#xff0c; 说不定面试官不提问&#xff0c;都不知道有这么个东西存在。 1、能说一下你对CAS的理解吗&#xf…