微信支付—微信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,因為沒有仔細閱讀官方文檔,反正各種報錯,比如:支付驗證簽名失敗 等等~,最后妥協不重復造輪子了,如下為正文。

Java支付項目實戰教程,包括支付寶,微信等支付方式,不看虧!

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));
    wechatOrderResponse.setOrderId(orders.getOrderId());
    return ResultUtil.success(wechatOrderResponse);
}

該方法僅供參考,上方方法中對訂單id進行了一個判空操作,因為我這邊有可能是用戶未支付訂單,繼續支付的操作,代碼主要是 wechatService.createOrderInfo 方法,實現如下:

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());//金額需要擴大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.cnblogs.com/niceyoo

如果覺得這篇文章有丶東西,不放關注一下我,關注是對我最大的鼓勵~

18年專科畢業后,期間一度迷茫,最近我創建了一個公眾號用來記錄自己的成長。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM