首页 > 技术文章 > 微信支付 (jsapi 方式)

wujiaxing 2020-09-15 11:50 原文

首先说注意几点,其实要说难不难,都是细节问题

  • 进行签名的参数注意大小写
  • 签名用的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 }) } }

  不懂可以加我 QQ: 287475833

推荐阅读