1. 程式人生 > 實用技巧 >微信支付 (jsapi 方式)

微信支付 (jsapi 方式)

首先說注意幾點,其實要說難不難,都是細節問題

  • 進行簽名的引數注意大小寫
  • 簽名用的key是微信支付金鑰,不是身份金鑰
  • 返回給前端的預訂單號格式一定要注意
  • 配置的安全域名一定是https的

1 微信配置安全域名,這裡不多說,自行百度

2 後端引入微信支付依賴

  

<!-- 微信支付 -->
<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>0.0.3</version>
</dependency>

3 前端向後端發請求支付,後端呼叫微信同一下單 api 介面,關鍵是簽名,有十個引數是必須進行簽名的,分別如下

  • body                支付專案描述
  • out_trade_no         我們自己生成的訂單號
  • total_fee           支付金額,單位(分)
  • spbill_create_ip     付款客戶的ip地址
  • notify_url          付款成功或失敗的微信通知我們的地址,自己在後臺建立一個回撥地址
  • trade_type           因為我現在整合 jsapi 方式支付, 所以直接寫 JSAPI 即可
  • openid              jsapi 方式支付必須攜帶此引數
  • appid               公眾號ID,微信支付平臺獲取,在申請支付時微信提供的
  • mch_id              商戶號,微信支付平臺獲取,在申請支付時微信提供的
  • nonce_str           隨機字串,有個 WXPayUtil 類有提供,也可以自己隨便輸入也行


public PayDTO createUnifiedorder(MonitorTypeEnum type, String body, TradeType tradeType, String openid, String ip, String phone, String tradeNo) { log.info(
"進入微信支付"); Map<String, String> map = new HashMap<>(); map.put("body", body); // 引數1 map.put("out_trade_no", tradeNo); // 引數2 BigDecimal big = new BigDecimal(type.getFee()); map.put("total_fee", String.valueOf((int)(big.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue() * 100))); // 引數3 map.put("spbill_create_ip", ip); // 引數4 map.put("notify_url", notifyUrl); // 引數5 map.put("trade_type", tradeType.name()); // 引數6 map.put("openid", openid); // 引數7 try {
        // MyWXPayConfig 類是自己建立的,實現了 WXPayConfig 介面,裡面定義了 appid, mchid 和 key, 這個key是微信支付金鑰,不是身份金鑰,千萬不要搞錯 MyWXPayConfig config
= new MyWXPayConfig();
        // 這個類是微信提供的類,將上面的配置類傳入即可 WXPay pay
= new WXPay(config);
        // 呼叫微信提供的統一下單介面,他會自動將另外的三個引數傳入(appid, mch_id, nonce_str)進行簽名後,呼叫微信統一下單 api 介面,生成預支付訂單 Map
<String, String> returnMap = pay.unifiedOrder(map); log.info("微信預支付請求引數【{}】",JSON.toJSONString(map)); log.info("微信預支付返回結果【{}】", JSON.toJSONString(returnMap)); String returnCode = returnMap.get("return_code"); String resultCode = returnMap.get("result_code");
        // 判斷生成預支付訂單是否成功
if("SUCCESS".equalsIgnoreCase(resultCode) && "SUCCESS".equalsIgnoreCase(returnCode)) { String sign = returnMap.get("sign"); // 取出需要引數 String nonceStr = returnMap.get("nonce_str"); String appid = returnMap.get("appid"); String trade_type = returnMap.get("trade_type"); String mchId = returnMap.get("mch_id"); String prepayId = returnMap.get("prepay_id"); String timeStamp = String.valueOf(System.currentTimeMillis() / 1000); PayDTO dto = new PayDTO(); Map<String, String> map1 = new HashMap<>();
          // 下面這幾個引數是將返回給前端的欄位進行簽名並生成 sign 簽名欄位,然後欄位連同簽名一起返回給前端 map1.put(
"appId", appid); map1.put("timeStamp", timeStamp); map1.put("nonceStr", nonceStr); map1.put("package", "prepay_id=" +prepayId); // 這個預訂單號格式要注意 map1.put("signType","MD5"); String sign2 = WXPayUtil.generateSignature(map1, config.getKey());
          // 下面的引數是返回給前端的 dto.setNonceStr(nonceStr); dto.setAppid(appid); dto.setTradeType(trade_type); dto.setMchId(mchId); dto.setPrepayId(prepayId); dto.setTimeStamp(timeStamp);
// 這個簽名是傳入前端的簽名 dto.setSign(sign2); payTradeRecordService.updateTradeStatusByTradeNo(tradeNo, TradeStatusEnum.UNPAID); return dto; } } catch (Exception e) { log.error("生成微信簽名錯誤", e); } return null; }

4 前端拿到後端返回的引數後,就可以調起微信支付的頁面

// 請求微信支付
      fetchPayUnifiedorder(type, body) {
        let _this = this
        if (this.openId) {
          // 有openId用jsapi支付
          this.$http({
            url: this.$http.adornUrl('/weChat/pay/unifiedorder'),
            method: 'POST',
            data: this.$http.adornData({
              openId: this.openId,
              tradeType: 'JSAPI',
              body: body,
              type: type,
              phone: this.phone
            })
          }).then(({ data }) => {
            if (data.code === 0) {
              let pay = data.pay
        // 這個物件只有在微信內部開啟的 h5 頁面才有的物件 window.WeixinJSBridge.invoke(
'getBrandWCPayRequest', { 'appId': pay.appid, // 公眾號名稱,由商戶傳入 'timeStamp': pay.timeStamp, // 時間戳,自1970年以來的秒數 'nonceStr': pay.nonceStr, // 隨機串 'package': `prepay_id=${pay.prepayId}`, // 這裡需要注意 'signType': 'MD5', // 微信簽名方式 'paySign': pay.sign // 微信簽名 }, function (res) { console.log('支付返回結果', res) if (res.err_msg === 'get_brand_wcpay_request:ok') { // 支付成功後查詢訂單資訊 _this.fetchPaySuccessOrder() } else { _this.$swal({ icon: 'error', title: '支付失敗', showConfirmButton: false, timer: 1500 }) } }) } else { _this.$swal({ icon: 'error', title: data.msg, showConfirmButton: false, timer: 1500 }) } }) } else { this.$swal({ icon: 'warning', title: '對不起,目前僅支援在微信APP內開啟的網頁進行支付', showConfirmButton: false, timer: 1500 }) } }