天天看點

H5調起支付寶支付

1.H5調起支付寶支付,我這裡是的方法是H5通過通路後端接口,由背景生成一個隐藏的form表單,将form表單作為一個字元串傳回給H5,H5将form表單渲染到頁面上,通過送出form表單調起支付寶支付。

form表單大緻是這樣的,這裡我從别處找到

<form name="punchout_form" method="post" action="https://openapi.alipay.com/gateway.do?charset=UTF-8&method=alipay.trade.wap.pay&sign=DEpMkI**********************eWUs6EW3QKlt9OHYv%2FqkporO8Sr5%2Bay5VA9dpx3pAbIiPPajQ2gEcWHvz5bm*******kxH8ZvHUXahQL9S69p9wKNXpXOxYadlsxE8QKGUc4cO5rrgGq08%2BpiOq%2FOz4fLogEBWANXILUMWXNzJn8YryNifZ416Pd%2BxkKgXs%2Fo%2FQDcqEUg*********VXXPRq7IGRGQg%2FpZkOhxCH%2Fq%2B9hnWEncAfQLlAXfPqjdcQTNJ0TJdVr1X1ENOdAr5LQkydWw2EQ8g%3D%3D&return_url=+https%3A%2F%2**********&notify_url=+https%3A%2F%*********Fpub%2Fapi%2Fv1%2F********allback1&version=1.0&app_id=20********57&sign_type=R***&timestamp=2019-0******55&alipay_sdk=al*******.49.ALL&format=json">
    <input type="hidden" name="biz_content" value="{&quot;body&quot;:&quot;&quot;,&quot;enable_pay_channels&quot;:&quot;balance,moneyFund,bankPay,debitCardExpress,creditCardExpress,creditCard,pcredit,pcreditpayInstallment,coupon,point,voucher,mdiscount,honeyPay&quot;,&quot;out_trade_no&quot;:&quot;132ecf937ad84487aa6cbaeb2ec157fe&quot;,&quot;product_code&quot;:&quot;13&quot;,&quot;subject&quot;:&quot;SpringBoot 2.x微信支付線上教育網站項目實戰&quot;,&quot;timeout_express&quot;:&quot;20m&quot;,&quot;total_amount&quot;:&quot;98&quot;}">
    <input type="submit" value="立即支付" style="display:none" >
</form>
<script>document.forms[0].submit();</script>      

2.如何生成form表單并傳回給H5,這裡隻是使用了支付寶sdk裡面的方法 生成form表單,不用請求支付寶背景,與微信統一下單接口有所差別。需要注意傳回值類型Map<String,StringBuffer>,使用StringBuffer傳回給H5可以正常收到,如果使用String類型,map被包裝類包裝後序列化到H5可能接收不到。

/**
   * 支付寶下單參數          json.put("out_trade_no", ""); //商戶訂單号
          json.put("total_amount", "0.01");  //總金額,元為機關
   * @param map
   * @return
   * @throws Exception
   */
  public static  Map<String,StringBuffer> aliPay(Map<String,String> map) throws Exception 
                //這裡采用RSA2 加密方式
    AlipayClient client = new DefaultAlipayClient(AliPayProperties.URL, aliPayProperties.getAppid(), Configs.getPrivateKey(), AliPayProperties.FORMAT, AliPayProperties.CHARSET, Configs.getAlipayPublicKey(),AliPayProperties.SIGNTYPE);
    AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();

    JSONObject json = new JSONObject();
    json.putAll(map); //包含商戶訂單号,金額
    json.put("product_code", "QUICK_WAP_WAY"); 
    json.put("subject", aliPayProperties.getSubject());  //商品的标題/交易标題/訂單标題/訂單關鍵字等。

    request.setBizContent(json.toString());
    request.setNotifyUrl(aliPayProperties.getNotifyUrl()); //設定回調位址
    request.setReturnUrl(aliPayProperties.getReturnUrl()); //設定傳回位址
    Map<String,StringBuffer> resmap = null;
    AlipayTradeWapPayResponse response;
    try {
      response = client.pageExecute(request);
      StringBuffer sb = new StringBuffer();
      String data =response.getBody() ; //擷取form表單字元串
      log.info("支付寶下單參數拼接:"+data);
      sb.append(data);
      resmap = new HashMap<String,StringBuffer>();
      resmap.put("from", sb);
    } catch (AlipayApiException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    return resmap;
  }      

2.支付寶回調方法,最主要兩點,一個是如何接受參數,另一個是驗簽 ,這裡需要将支付寶回調的參數轉為map

@RequestMapping(value = "/alyPayNotify")
    public String alyPayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException {
            log.info("支付寶支付成功回調");
            //這裡拿到支付寶通知資料
             Map<String, Object> params = convertRequestParamsToMap(request); // 将異步通知中收到的待驗證所有參數都存放到map中
                String paramsJson = JSON.toJSONString(params);
                log.info("支付寶回調,{}"+ paramsJson);
                Map<String, String> map = JSON.parseObject(paramsJson, new TypeReference<Map<String, String>>(){});
             return  aliPayService.aliPayNotify(map, response);

 }

     // 将request中的參數轉換成Map
    private static Map<String, Object> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String,Object> returnMap = new HashMap<String,Object>();
        Map<String,String[]> map = new HashMap<String,String[]>();
        map = request.getParameterMap();
        Iterator entries = map.entrySet().iterator();
        Map.Entry entry;
        String name ="";
        String value=null;
        while (entries.hasNext()){
            entry=(Map.Entry)entries.next();
            name = (String) entry.getKey();
            Object objvalue = entry.getValue();
            if(objvalue == null){
                value = null;
            }else if(objvalue instanceof String[]){
                /**條件如果成立,objvalue就是一個數組,需要将它轉換成為字元串,并拼接上逗号,并吧末尾的逗号去掉*/
                String[] values = (String[]) objvalue;
                for(int i=0;i<values.length;i++){
                    value = values[i]+",";//這裡我拼接的是英文的逗号。
                }
                value = value.substring(0,value.length()-1);//截掉最後一個逗号。
            }else{
                value = objvalue.toString();
            }
            log.info("key:"+name);
            log.info("value:"+value);
            returnMap.put(name , value);
        }
        Iterator it = returnMap.keySet().iterator();
        while (it.hasNext()){
            Object key = it.next();
            if(returnMap.get(key) == null || "".equals (((String)returnMap.get(key)).trim())){
                returnMap.put((String) key, null);
            }
        }
        return returnMap; 

    }      

3,支付寶回調驗簽,這裡需要選擇輸出流的形式傳回success ,return 方式支付寶好像不接受,不知道是不是因為版本原因,代碼我就不一一修改了。這裡簽名驗證方式與網上的有些方法也略有差別,參數不同。具體可參考我的另一篇支付寶部落格

位址:

@Override
    public String aliPayNotify(Map<String, String> map, HttpServletResponse response) {
        // 調用SDK驗證簽名
        try {
            String sign = (String) map.get("sign");
            String content = AlipaySignature.getSignCheckContentV1(map);
            boolean signVerified = AlipaySignature.rsaCheck(content, sign, Configs.getAlipayPublicKey(), AliPayProperties.CHARSET, AliPayProperties.SIGNTYPE);

            if (signVerified) {
                log.info("支付寶回調簽名認證成功");
                // 按照支付結果異步通知中的描述,對支付結果中的業務内容進行1\2\3\4二次校驗,校驗成功後在response中傳回success,校驗失敗傳回failure
                //檢查金額是否一緻
                //this.check(params);
                // 支付寶建議 另起線程處理業務
                Executors.newFixedThreadPool(20).execute(new Runnable() {
                    @Override
                    public void run() {
                        log.info("ZFB回調參數" + map);
                        String trade_status = map.get("trade_status");
                        log.info("trade_status:" + trade_status);
                        // 支付成功
                        if (trade_status.equals("TRADE_SUCCESS")) {
                            // 處理支付成功邏輯
                            try {
                                // 處理業務邏輯。。。
                                String out_trade_no = map.get("out_trade_no");
                                String trade_no = map.get("trade_no");
                                String total_amount = map.get("total_amount");

                            } catch (Exception e) {
                                log.error("支付寶回調業務處理報錯,params:" + e);
                            }
                        } else {
                            log.error("沒有處理支付寶回調業務,支付寶交易狀态:{},params:{}", trade_status);
                        }
                    }
                });
                BufferedOutputStream out = null;
                try {
                    out = new BufferedOutputStream(response.getOutputStream());
                    out.write("success".getBytes());
                    out.flush();
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return "success";

            } else {
                log.info("支付寶回調簽名認證失敗,signVerified=false, paramsJson:{}");
                return "failure";
            }

        } catch (AlipayApiException e) {

            log.error("支付寶回調簽名認證失敗,paramsJson:{},errorMsg:{}", e.getMessage());
            return "failure";
        }
    }      

因為相信,是以看見.