微信Native支付


微信Native支付對接(掃碼)

由於有業務需求對接了微信和paypal支付,這邊做個記錄

微信支付開發文檔:https://pay.weixin.qq.com/wiki/doc/api/index.html

一、支付方式

這邊有個坑,微信h5支付和Native支付都是微信外部使用的支付方式,但是h5支付適用於移動端,因為支付時是從外部喚醒本地移動端的微信app進行支付;而Native支付則是在pc端生成訂單后,用戶使用移動端的微信app掃碼完成支付

  1. 付款碼支付:需要用戶有掃碼槍.如:肯德基,麥當勞的支付
  2. JSAPI支付: 主要服務於微信內部調用的支付接口
  3. Native支付:掃碼支付
  4. h5支付:手機瀏覽器調用的支付

二、支付流程介紹

用戶:客戶

前端:ui界面,客戶端

后端:java寫的服務端

微信系統:包括生產訂單的接口等
流程:

  1. 用戶點擊前端的支付按鈕
  2. 前端將對應的訂單信息發送給后端
  3. 后端預處理訂單的信息(如在數據庫中生成對應的記錄),然后調用微信支付系統生成訂單的接口
  4. 微信支付系統返回對應訂單的支付地址給后端
  5. 后端將該訂單地址返還給前端,前端調用QRCode工具生成二維碼
  6. 用戶打開手機微信app掃碼完成支付(由於和我們業務並沒有直接的相關性,這個過程沒有直接在上圖中表現出來)
  7. 微信系統異步(有延時)收到微信支付成功的回調,回調函數中應該包括對於驗證訂單的有效性(如果被人攻破就麻煩了),存儲數據庫(確認訂單已結算),回復微信系統(否則微信會在一天之內多次發送回調信息)等步驟
  8. 后端可以通知前端訂單完成,以便后續的操作(具體的做法可以是從訂單生成之后,前端可以以一定的時間間隔詢問訂單的狀態)

注:其它支付手段的流程應該也是大致相同的

三、准備工作

首先必然是下載sdk(software development kit).值的注意的一點是,對比於網上的許多舊的微信博客,可以發現微信的api有了極大的改進,我們只要調用少許的接口即可完成開發.同時api的命名目前也是比較統一的

  1. 申請一個商機號

    注:商家號的申請是需要相關的營業執照的

  2. 上微信商戶號中開通Native支付的服務

  3. 准備調用訂單支付接口相關的參數(這里只展示一下必填項)

    字段名 變量名 描述
    公眾賬號ID appid 微信支付分配的公眾賬號ID
    商戶號 mch_id 微信支付分配的商戶號
    隨機字符串 nonce_str 由內置的隨機數生成算法生成
    簽名 sign 由內置的簽名算法生成
    商品描述 body 商品的簡單描述
    商品訂單號 out_trade_no 可以直接用訂單id
    標價金額 total_fee 單位為分(CNY)
    終端IP spbill_creat 服務器IP
    通知地址 notify_url 異步回調的地址(回調不能在本地測試)
    交易類型 trade_type NATIVE -Native支付
    商品ID product_id 商品id,Native必填
    密匙 key 商家自行設置的密匙
    • 微信商戶號后台獲得appid,mch_id,設置key
    • out_trade_no必須大於10,不能重復
    • total_fee不能有小數點(正常情況也不應該有小數點)
    • nonce_str變量用於提高生成的sign不確定
    • sign的算法是先將所有的參數進行排序,然后按key=value的形式拼接為字符串,最后加上key.最后,對拼接后字符串進行加密,加密方式一種是用MD5,一種使用HMAC-SHA256.具體的過程可以查看sdk原碼,實際使用只要傳入參數map給相關的api即可,但是了解一下有助於調試,另外附加一個微信官方的簽名校驗工具
    • key是保證整個支付過程加密以及回調地址不被攻破的關鍵!
    • 可以用額外的attach附加參數,如訂單id
  4. sdk下載地址(maven的相關地址大家可以自己去找找):https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1

四、開發工作

這里主要說明一下后端接口的調用

  1. 調用接口生成訂單

        public String getWxQrCode(HashMap<String,Object> paraMap) throws Exception {
            /*數據庫操作*/
            Integer maxId = userMapper.getMaxUserId();
            Integer id = maxId==null?1:maxId+1;
            paraMap.put("user_id",id);
            userMapper.addUser(paraMap);
            /*獲得code_url*/
            Map<String, String> map = new HashMap<>();
            map.put("appid",wxPayConfigBean.getAppID());
            map.put("mch_id",wxPayConfigBean.getMchID());
            map.put("body",wxPayConfigBean.getBody());
            map.put("out_trade_no",id.toString());
            map.put("total_fee",paraMap.get("order_amount").toString());
            map.put("spbill_create_ip",paraMap.get("ip").toString());
            map.put("notify_url",wxPayConfigBean.getNotifyUrl());
            map.put("trade_type",wxPayConfigBean.getTradeType());
            map.put("attach",id.toString());
            //Native必傳
            map.put("product_id",paraMap.get("order_productid").toString());
            //獲得sign
            WXPay wxPay = new WXPay(wxPayConfigBean);
            Map<String, String> backMap = wxPay.unifiedOrder(map);
            HashMap<String, Object> resMap = new HashMap<>();
            resMap.put("url",backMap.get("code_url"));
            resMap.put("id",id);
            return JsonUtil.toJsonString(resMap);
        }
    
  2. 回調

        public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
            //拿到微信回調信息(以字節流的方式)
            InputStream inputStream = request.getInputStream();
            BufferedReader in = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
            //String是字符串變量,StringBuffer是字符串變量
            StringBuffer sb = new StringBuffer();
            //將字節流轉換為字符串
            String line;
            while ((line = in.readLine()) != null){
                //每次用line讀取一行的字節流,如果這一行不為空就擴展到sb上
                sb.append(line);
            }
            System.out.println("*****************************sb**************************");
            System.out.println(sb);
            System.out.println("*****************************sb**************************");
            //關閉
            in.close();
            inputStream.close();
            String strXml = sb.toString();
            Map<String, String> toMap = WXPayUtil.xmlToMap(strXml);
            System.out.println(toMap);
    
            //獲取業務信息
            String outTradeNo = toMap.get("out_trade_no");
            String totalFee = toMap.get("total_fee");
            String appId = toMap.get("appId");
            String mchId = toMap.get("mch_id");
            String resultCode = toMap.get("result_code");
            String attach = toMap.get("attach");  //附加數據
    
            //該對象用於通知微信
            PrintWriter writer = response.getWriter();
    
            //驗簽
            String res = null;
            Map<String,String> paraMap = WXPayUtil.xmlToMap(strXml);
            boolean signatureValid = WXPayUtil.isSignatureValid(paraMap, wxPayConfigBean.getKey(), WXPayConstants.SignType.HMACSHA256);  //注:注意返回時有nonce_str
            if (signatureValid){
                System.out.println("驗證成功~");
                if ("SUCCESS".equals(toMap.get("result_code"))){
                    System.out.println("返回的是SUCCESS");
                    /*自己的業務邏輯*/
                    }
                    //返回值——仍然有問題,不斷刷回復
                    String noticeStr = setXML("SUCCESS","");
                    writer.write(noticeStr);
                    writer.flush();  //情況緩存區,並完成文件寫入操作
                }
            }else{
                System.out.println("驗證失敗");
                String noticeStr = setXML("FATL","");
                writer.write(noticeStr);
                writer.flush();
            };
        }
      private static String setXML(String return_code, String return_msg) {
            return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
        }
    

注:

  • 有時候回調好像沒有正確地返還個微信支付系統,對java的輸入輸出不太了解,麻煩有大佬知道問題的請留言
  • 在最開始嘗試對接微信支付時查閱了較多的博客,代碼,在這里表示感謝.但因為實在太過龐雜,就不一一列出了.


免責聲明!

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



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