微信、支付宝H5支付

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30641447/article/details/85128781

思路:

第一次做H5支付,在网上看到了很多文章,大多说怎么调用openId什么的。

其实H5支付不需要获取openId,而是根据用户的ip地址作为识别。

大体思路如下:

前端采用vue:

生成订单:

 // 生成订单
    submitOrder: function () {
  
      let param = {userId: this.userId }
      this.$http
        .post('/api/xxxx', param, { emulateJSON: true })
        .then(res => {
      
          headerId = []
          var arr = []
          if (res.data.success == true) {
            for (var i = 0; i < res.data.orders.length; i++) {
              arr.push(res.data.orders[i].id)
            }
            headerId = arr//这里保存订单id
            this.pay()//这里调用支付
          } else {
            Indicator.open({
              text: '网络出错...',
              spinnerType: 'fading-circle'
            })
          }
        })
    },

支付--调用统一订单

 pay: function () {
      var arr = headerId.join(',')
      let param = {
        total_fee: this.total,
        attach: 'H5支付',
        openId: '',
        body: 'H5支付',
        userId: this.userId,
        requestNum: '',
        payWays: this.payWay,//支付方式:11 微信  10 支付宝
        headerIds: arr}
      this.$http
        .post('/api/xxxx', param, {emulateJSON: true})
        .then(res => {
          // eslint-disable-next-line eqeqeq
          if (this.payWay == '11') {
            window.location.href = res.body.data.payUrl + '&redirect_url=http%3a%2f%2fxxx.com' //这里的redirect_url 需要进行urlencode处理
          } else {
            var bhtml = res.body.data.payUrl
            document.getElementById('alipay').innerHTML = bhtml
            document.forms[0].submit()
          }
        })
    },

调用统一订单接口:

  @Override
  public String orderPay(String outTradeNo) {
    List<Map<String, Object>> jsonArray = new ArrayList<Map<String, Object>>();
    TradeInfo tradeInfo = tradeInfoService.selectByOutTradeNo(outTradeNo);
    String totle = String.valueOf(tradeInfo.getAmount());
    DecimalFormat decimalFormat = new DecimalFormat("###################.###########");
    totle = String.valueOf(decimalFormat.format(Double.parseDouble(totle)));
    String appid = WECHAT_APPID;// 小程序ID-->替换为自己的ID
    String mch_id = WECHAT_MCH_ID;// 商户号-->替换为自己的商户号
    String nonce_str = UUIDHexGenerator.generate();// 随机字符串
    String out_trade_no = outTradeNo;// 商户订单号mch_id + today + code
    String notify_url = RETURN_URL + "/api/wx/payBack/notifyOrder";// 通知地址

    // 交易类型JSAPI---NATIVE---MWEB
    String trade_type = null;
    String body = "xxxx";
    String openId = null;
    String spbillCreateIp = null;
   if (tradeInfo.getTradeWay() == TradeWay.WECHAT_H5){
        trade_type = "MWEB";
        notify_url = RETURN_URL + "/api/xxx";// 通知地址--自己controler接口
      Gson gson = new Gson();
      @SuppressWarnings("unchecked")
          Map<String, String> resultMap = gson.fromJson(tradeInfo.getExtraParams(), Map.class);
      spbillCreateIp = resultMap.get("spbill_create_ip");
    } 
    PaymentPo paymentPo = new PaymentPo();
    paymentPo.setAppid(appid);
    paymentPo.setMch_id(mch_id);
    paymentPo.setNonce_str(nonce_str);
    String newbody = new String(body);// 以utf-8编码放入paymentPo,微信支付要求字符编码统一采用UTF-8字符编码
    paymentPo.setBody(newbody);
    paymentPo.setOut_trade_no(out_trade_no);
    paymentPo.setTotal_fee(String.valueOf(decimalFormat.format(Double.parseDouble(totle) * 100)));
    paymentPo.setNotify_url(notify_url);
    paymentPo.setTrade_type(trade_type);
    paymentPo.setOpenid(openId);
    paymentPo.setSpbill_create_ip(spbillCreateIp);
    // 把请求参数打包成数组
    Map<String, String> sParaTemp = new HashMap<String, String>();
    sParaTemp.put("appid", paymentPo.getAppid());
    sParaTemp.put("mch_id", paymentPo.getMch_id());
    sParaTemp.put("nonce_str", paymentPo.getNonce_str());
    sParaTemp.put("body", paymentPo.getBody());
    sParaTemp.put("out_trade_no", paymentPo.getOut_trade_no());
    sParaTemp.put("total_fee", paymentPo.getTotal_fee());
    sParaTemp.put("notify_url", paymentPo.getNotify_url());
    sParaTemp.put("trade_type", paymentPo.getTrade_type());
    sParaTemp.put("openid", paymentPo.getOpenid());
    sParaTemp.put("spbill_create_ip", paymentPo.getSpbill_create_ip());
    // 除去数组中的空值和签名参数
    Map<String, String> sPara = PayUtil.paraFilter(sParaTemp);
    String prestr = PayUtil.createLinkString(sPara); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
    String key = "&key=" + WECHAT_MERC_KEY; // 商户支付密钥
    // MD5运算生成签名
    String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
    paymentPo.setSign(mysign);
    // 打包要发送的xml
    String respXml = MessageUtil.messageToXML(paymentPo);
    // 打印respXml发现,得到的xml中有“__”不对,应该替换成“_”
    respXml = respXml.replace("__", "_");
    // 统一下单API接口链接
    String result = PayUtil.httpRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", respXml);
    // 保存请求参数(忽略)
    


    // 返回预支付单信息prepay_id
    // 将解析结果存储在HashMap中
    Map<String, String> map = new HashMap<String, String>();
    InputStream in = new ByteArrayInputStream(result.getBytes());
    // 读取输入流
    SAXReader reader = new SAXReader();
    Document document = null;
    try {
      document = reader.read(in);
    } catch (DocumentException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    // 得到xml根元素
    if(null != document){
      Element root = document.getRootElement();
      // 得到根元素的所有子节点
      @SuppressWarnings("unchecked")
      List<Element> elementList = root.elements();
      for (Element element : elementList) {
        map.put(element.getName(), element.getText());
      }
    }
    // 返回信息
    String return_code = map.get("return_code");// 返回状态码
    Map<String, Object> jsonObject = new HashMap<String, Object>();

    if (return_code == "SUCCESS" || return_code.equals("SUCCESS")) {
      // 业务结果
      jsonObject.put("out_trade_no", out_trade_no);
      jsonObject.put("return_code", return_code);
      String prepay_id = map.get("prepay_id");// 返回的预付单信息
      String nonceStr = UUIDHexGenerator.generate();
      jsonObject.put("nonceStr", nonceStr);
      jsonObject.put("package", "prepay_id=" + prepay_id);
      Long timeStamp = System.currentTimeMillis() / 1000;
      jsonObject.put("timeStamp", timeStamp + "");
      String stringSignTemp =
          "appId=" + appid + "&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + timeStamp;
      jsonObject.put("signType", "MD5");
      jsonObject.put("codeUrl", map.get("code_url"));
      // H5跳转URL
      jsonObject.put("mweb_url", map.get("mweb_url"));
      // 再次签名
      String paySign = PayUtil.sign(stringSignTemp, "&key=" + WECHAT_MERC_KEY, "utf-8").toUpperCase(); // 替换为自己的密钥
      jsonObject.put("paySign", paySign);
      jsonArray.add(jsonObject);

    } else {
      jsonObject.put("return_code", return_code);
    }

    Gson gson = new Gson();
    //这里操作订单 (略)   
    
    return gson.toJson(jsonObject);
  }

其他工具类可以参考小程序支付的文章:

https://blog.csdn.net/qq_30641447/article/details/73222648

H5支付所遇到的坑:

第一:ip地址,本地公网ip,本地用request获取的都是127.0.0.1,所以在测试的时候最好先写死公网ip

第二:域名配置,需要在公众号配置而且前端(前后端分离的)的映射访问域名要一致,不然微信会检测referer与配置的域名是否一致

第三:微信、支付宝支付成功跳转到本系统页面(回调页面)配置:

    微信

    需要在MWEB_URL后拼接上redirect_url参数: 就是在返回的payUrl上拼接redirect_url(redirect_url进行urlencode处理)

 支付宝

支付宝需要在支付宝回调的时候 在后端重定向到对应页面

由于返回后 前端的数据可能会丢失,所以第一可以一开始可以把前端的数据保存到本地缓存,第二在跳转的时候传参,返回页面的时候再获取

常见问题:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4

猜你喜欢

转载自blog.csdn.net/qq_30641447/article/details/85128781