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

  • 相关阅读:
    Template(模板)模式
    Android活动(Activity)创建及生命周期
    Android--SharedPreferences数据存储方案
    Adapter适配器模式--图解设计模式
    准时制生产(Just in Time,JIT)
    术语
    制造资源计划(Manufacturing Resource Planning,Mrp II)
    Angualr6表单提交验证并跳转
    Android PDA扫描枪广播接搜条码并使用
    Java统计代码行数
  • 原文地址:https://www.cnblogs.com/niceyoo/p/12232215.html
Copyright © 2011-2022 走看看