微信支付—微信H5支付「非微信内部浏览器-QQ/UC浏览器等」

前言

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

一直计划着写一写微信支付相关的文章,希望能加深一下自己的印象,拖了一天又一天…

最近终于空出时间来填坑了,我将文章分为微信H5外部浏览器支付微信H5内部浏览器支付PC端扫码支付三篇来写。

本篇是微信H5外部浏览器支付:支付时会唤起微信APP进行支付。

扫盲补充:关于微信H5支付,分为内部浏览器支付 + 外部浏览器支付,两者还是稍微有点点区别的,内部浏览器即在微信内打开网页,进行支付,支付调用由前端发起「JSSDK」;而外部浏览器「比如QQ浏览器等」则通过后台返回的 mweb_url 交由前端唤起微信APP发起支付操作,微信官方提供了个测试网页 https://wxpay.wxutil.com/mch/pay/h5.v2.php,可以在手机浏览器打开体验一番。

本文开发环境: Java + SpringBoot + IDEA + WxJava(开源SDK)

再多啰嗦几句,最开始并没有选择 WxJava 开源SDK,因为没有仔细阅读官方文档,反正各种报错,比如:支付验证签名失败 等等~,最后妥协不重复造轮子了,如下为正文。

1、 引入依赖包

pom.xml文件中引入 WxJava 依赖「本文使用的是3.3.0版本

<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-pay</artifactId>
    <version>3.3.0</version>
</dependency>

2、基础配置

WxJava 提供了微信支付的Demo,可以参考 https://github.com/binarywang/weixin-java-pay-demo

2.1、增加支付配置信息

下面提供 application.ymlapplication.properties 两种格式,具体如下:

wx.pay.appId=#微信公众号或者小程序等的appid
wx.pay.mchId=#微信支付商户号
wx.pay.mchKey=#微信支付商户密钥
wx.pay.notifyUrl=#支付成功回调URL
wx.pay.keyPath=# p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)

# -----------------------------------------

wx:
  pay:
    appId: #微信公众号或者小程序等的appid
    mchId: #微信支付商户号
    mchKey: #微信支付商户密钥
    notifyUrl: #支付成功回调URL
    keyPath: # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)

补充:keyPath 用来指定证书路径,关于证书的用途:发红包/企业付款/退款等操作,本文不涉及,留空。

2.2、代码中的配置

一个是用来读取配置信息的实体类,一个是用来初始化支付SDKConfiguration

读取配置类:WxProperties.java

@Data
@Configuration
@ConfigurationProperties(prefix = "wx.pay")
public class WxProperties {
    /**
     * 设置微信公众号或者小程序等的appid
     */
    private String appId;

    /**
     * 微信支付商户号
     */
    private String mchId;

    /**
     * 微信支付商户密钥
     */
    private String mchKey;

    /**
     * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
     */
    private String keyPath;

    /**
     * 微信回调接口地址
     */
    private String notifyUrl;
}

初始化支付SDK类:WxConfig.java

@Configuration
public class WxConfig {

    @Autowired
    private WxProperties properties;

    @Bean
    @ConditionalOnMissingBean
    public WxPayService wxService() {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
        payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
        payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
        payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
        payConfig.setNotifyUrl(StringUtils.trimToNull(this.properties.getNotifyUrl()));
        // 可以指定是否使用沙箱环境
        payConfig.setUseSandboxEnv(false);
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }
}

2.3、微信支付接口

微信非内部浏览器支付,比如在手机QQ浏览器中发起支付,会唤起微信APP进行支付操作,此时调用微信接口返回的是一个 URL,返回结果如下:

weixin://wxpay/bizpayurl?pr=IzX8nS

下方是获取支付URL的后端接口方法:

@RequestMapping(value = "createOrder", method = {RequestMethod.POST})
public Result<Object> createQRCode(UserModel user, HttpServletResponse response,@RequestBody WechatOrderRequest obj) {

    Orders orders = null;
    if (StringUtils.isNotBlank(obj.getOrderId())) {
        orders = ordersService.searchOrder(user, obj.getOrderId());
    } else {
        orders = ordersService.createOrder(user, obj);
    }
    WechatOrderResponse wechatOrderResponse = new WechatOrderResponse();
    wechatOrderResponse.setCodeUrl(wechatService.createOrderInfo(orders,user.getPayType()));
    wechatOrderResponse.setOrderId(orders.getOrderId());
    return ResultUtil.success(wechatOrderResponse);
}

该方法仅供参考,上方方法中对订单id进行了一个判空操作,因为我这边有可能是用户未支付订单,继续支付的操作,代码主要是 wechatService.createOrderInfo 方法,实现如下:

public String createOrderInfo(Orders orders,String payType) {
    WxPayMwebOrderResult result = null;
    try {
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setOutTradeNo(orders.getOrderId());
        orderRequest.setBody("我是商品描述");
        orderRequest.setTotalFee(orders.getAmount().multiply(new BigDecimal("100")).intValue());//金额需要扩大100倍:1代表支付时是0.01
        orderRequest.setSpbillCreateIp(DispatchParams.getInstance().getWechatSpbillCreateIp());
        orderRequest.setProductId(orders.getOrderId());
        orderRequest.setTradeType(WxPayConstants.TradeType.MWEB);// h5网页支付
        result = wxPayService.createOrder(orderRequest);
        return result.getMwebUrl();
    } catch (WxPayException e) {
        logger.error("[微信支付异常] 异常", e);
        // 抛出一个自定义全局异常「自己定义」
        throw new CommonException(微信支付异常提示信息 , 状态码 );
    }
}

具体参数就不啰嗦了,详细请看官方支付文档。

综上,当前端调用 createOrder 方法,将 weixin://wxpay/bizpayurl?pr=IzX8nS 返回给前端,那么前端怎么调用呢?

下面是我的一个测试例子,其中 res.codeUrl 为后端返回的 URL

window.open(res.codeUrl, '_blank’);

是的,就是这么简单,新窗口打开就可以了,看一下运行调起微信的截图「我手机装了两个微信」:

支付成功后会回调后端接口,具体由后端参数配置的 return_url 控制。

2.4、微信回调接口

当支付完成后,微信会自动回调该接口,我们可以根据返回的信息修改订单状态,看一下方法,代码仅供参考:

@RequestMapping(value = "/notify")
@ResponseBody
public String notify(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("支付成功!");
}

如上代码,微信返回的是 XML ,经过 wxPayService.parseOrderNotifyResult() 方法转换后得到 WxPayOrderNotifyResult 实体,具体参数我上边罗列出来了「尽管没用到」,然后就是修改数据库订单状态等操作。

最后

博客地址:https://www.cgblog.com/niceyoo

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

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

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

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

相关文章

[js] 如何避免JS浮点运算的精度问题(例:0.1+0.7=0.7999999999999999)

[js] 如何避免JS浮点运算的精度问题&#xff08;例&#xff1a;0.10.70.7999999999999999&#xff09; function precision(num1,num2){num1Length num1.toString().length;num2Length num2.toString().length;let len num1Length > num2Length ? num1Length : num2Len…

多线程小结(1)

原文出处 定义就不多说了&#xff0c;直接上代码 1 /// <summary> 2 /// 单线程应用 3 /// </summary> 4 class Program 5 { 6 static void Main(string[] args) 7 { 8 Console.WriteLine("进入主线程"); 9 …

uniapp中使用微信jssdk

在做自定义分享时&#xff0c;用到了微信jssdk&#xff0c;记录一下。 声明&#xff1a;本文演示uniapp中使用jssdk&#xff0c;示例为网页自定义分享 npm方式使用下方指令进行安装&#xff0c;正文部分为非npm方式。 npm install jweixin-module --save 1、下载导入jssdk文件…

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

前言 微信支付-微信H5外部浏览器支付微信支付-微信H5内部浏览器支付「本文」微信支付-PC端扫码支付「待写」 本篇是微信支付系列的第二篇、微信H5内部浏览器支付&#xff0c;关于微信H5外部浏览器唤起微信APP支付&#xff0c;请参考上一篇文章。 开发环境&#xff1a;Java Spr…

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

前言 微信支付-微信H5外部浏览器支付微信支付-微信H5内部浏览器支付微信支付-PC端扫码支付「本文」 本篇是微信支付系列的第三篇&#xff0c;PC端扫码支付。 开发环境&#xff1a;Java SpringBoot Vue WxJava(开源SDK) 流程补充&#xff1a;关于微信PC端扫码支付&#xff0c;…

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

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

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

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

MacOS中Nginx的安装「借助Homebrew」

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

快速下载||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…

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

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

支付宝手机h5网页支付不再提供「继续浏览器付款」按钮了吗

来自圈友的疑惑&#xff0c;记录一下 之前写过一篇「支付宝手机h5支付的文章」&#xff0c;如果下载运行过Demo的小伙伴肯定发现了一个问题 > 「Demo中有显示继续浏览器付款按钮&#xff0c;但自己实际环境并没有」 难道是操作不对&#xff1f; 其实不然&#xff0c;这是两个…

.NETFramework-Web.Mvc:ViewResult

ylbtech-.NETFramework-Web.Mvc&#xff1a;ViewResult1.程序集 System.Web.Mvc, Version5.2.3.0, Cultureneutral, PublicKeyToken31bf3856ad364e35返回顶部 1、#region 程序集 System.Web.Mvc, Version5.2.3.0, Cultureneutral, PublicKeyToken31bf3856ad364e35 // c:\users\…

ConcurrentHashMap底层原理?

本文为面试必备系列篇&#xff0c;不深入叙述&#xff0c;具体细节可自行查询。 可能会问的问题 1、用过ConcurrentHashMap吗&#xff1f;2、为什么要用ConcurrentHashMap&#xff1f;3、HashMap与HashTable的区别&#xff0c;引出ConcurrentHashMap…4、HashMap在多线程环境下…

支付宝支付-当面付之扫码支付「扫码支付」

前言 支付宝支付—沙箱环境使用支付宝支付-支付宝PC端扫码支付支付宝支付-手机浏览器H5支付支付宝支付-当面付之扫码支付「本文」 当面付包含两种支付方式&#xff1a;商品条形码支付 扫码支付 经过前面两篇PC端扫码支付、手机H5支付&#xff0c;我们可以看到一个共同的特点就…

MybatisCodeHelperNew-2.8.1-191-201插件使用

本文测试环境IDEA_2020.1&#xff0c;文中提供了MacOS用户操作截图 1、文件解压后放置plugs插件目录「Windows」 扫码回复「139」 下载后将文件解压&#xff0c;将压缩包内的 MyBatisCodeHelper-Pro 放入 IDEA 安装目录的 plugins 目录。 2、如果你是MacOS用户「MacOS」 同样找…

Redis简单案例(四) Session的管理

Redis简单案例(四) Session的管理 原文:Redis简单案例(四) Session的管理负载均衡&#xff0c;这应该是一个永恒的话题&#xff0c;也是一个十分重要的话题。毕竟当网站成长到一定程度&#xff0c;访问量自然也是会跟着增长&#xff0c;这个时候&#xff0c; 一般都会对其进行负…

MacOS中Elasticsearch的安装「借助Homebrew」

1、Homebrew 如果你已经安装过Homebrew了&#xff0c;那么你可以跳过这一步&#xff0c;直接进行Elasticsearch安装步骤&#xff1b; Homebrew是一款MacOS平台下的软件包管理工具&#xff0c;拥有安装、卸载、更新、查看、搜索等很多实用的功能&#xff0c;强烈推荐安装。 请…

负载均衡中使用 Redis 实现共享 Session

最近在研究Web架构方面的知识&#xff0c;包括数据库读写分离&#xff0c;Redis缓存和队列&#xff0c;集群&#xff0c;以及负载均衡&#xff08;LVS&#xff09;&#xff0c;今天就来先学习下我在负载均衡中遇到的问题&#xff0c;那就是session共享的问题。 一、负载均衡 负…

Typora中使用Gitee图床

1、前言 之前好友写了一篇「使用gitee作为图床 ,写markdown自动上传文件」&#xff0c;初衷是由于我一直使用的是Typora来写博客「力推」&#xff0c;但之前的版本都不支持图床功能&#xff0c;现在新版本已经有了图床功能了&#xff0c;赶紧入坑。 本篇环境&#xff1a;MacOS…

【NOIP2017模拟6.25】小W的动漫

题目 小W最近迷上了日本动漫&#xff0c;每天都有无数部动漫的更新等着他去看&#xff0c;所以他必须将所有的动漫排个顺序&#xff0c;当然&#xff0c;虽然有无数部动漫&#xff0c;但除了1号动漫&#xff0c;每部动漫都有且仅有一部动漫是它的前传&#xff08;父亲&#xff…