微信內網站微信支付對接


文章包括以下內容

  1. 支付場景簡介
  2. 第一步:申請微信支付申請(注冊微信支付商戶號)
  3. 第二步:獲取商戶號的支付參數
  4. 第三步:SDK下載(java版本)
  5. 第四步:支付過程了解
  6. 第五步:開始設計和編碼

 

支付場景簡介

目前微信支付有6個場景,分別是以下6個(2019-04-06)

  1. 我有線下場所
  2. 我有公眾號
  3. 我有小程序
  4. 我有pc網站
  5. 我有App
  6. 我有企業微信

https://pay.weixin.qq.com/static/applyment_guide/applyment_index.shtml

第一步:申請微信支付申請(注冊微信支付商戶號)

這一步完成后那么就擁有了支付接口權限了。

我的支付場景是公眾號支付,所以首先你先要有一個公眾號。有了公眾號之后就可以申請付款碼支付和JSAPI支付產品了,我習慣成這個產品為支付接口。也就是有了2個支付接口權限了,

  1. 根據自身的屬性申請准備對應的申請材料
  2. 交申請費用(目前幾百就行了)
  3. 3個申請流程

https://pay.weixin.qq.com/static/applyment_guide/applyment_detail_public.shtml

 

第二步:獲取商戶號的支付參數

支付參數都是登錄商戶號頁面里面獲取的,參數用於對接用

需要4參數:

  1. appid(appid)
  2. mchid(商戶id)
  3. key(支付key)
  4. certPath(證書路徑)

說明:以上參數是sdk需要的參數

第三步:SDK下載(java版本)

首先下載微信支付sdk,我選擇的是java開發

下載地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

解壓之后的目錄是這樣的

文件說明

src:源代碼目錄

pom.xml:該庫依賴的第三庫

README.md:微信提供的示例,這個一定要打開看看,里面有關於怎么使用這個sdk的例子。

把下載下來的代碼引入到工程下目錄是這樣的

第四步:支付過程了解

對應的微信支付文檔地址:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3

下面這個時序圖是從用戶下單到支付完成過程,涉及的應用包括微信客戶端,商戶app客戶端,上后后台系統,微信支付系統。

大概的過程是這樣的

  1. 用戶打開商戶系統選擇商品下單,這時候商戶系統后台生成訂單和訂單明細,記錄到數據庫中(購物車)
  2. 用戶向商戶系統發送支付請求(帶上訂單id)
  3. 商戶系統系統根據訂單id計算金額等一些信息(收集一些支付參數)
  4. 向微信發起支付請求(生成預支付訂單),並且返回預支付參數(用於調起微信支付界面)
  5. 商戶系統接收微信系統的支付結果推送。
  6. 商戶系統根據推送結果更新訂單狀態

基本上我們關注的是商戶系統的開發,比如購物車(生成訂單和訂單明細),更新訂單支付狀態這些功能點了

APP支付時序圖

第五步:開始設計和編碼

了解以上微信支付的過程后接下來要編碼就簡單多了,

首先我們需要有個訂單和訂單明細表,如customer_order,customer_order_detail,

customer_order主要的字段包括:

字段名稱 類型 說明
id string  
pay_time datatime 支付時間
total_fee int 訂單金額(單位:分)
customer_id string 用戶id
order_state string 訂單狀態
     
     

 

customer_order_detail主要字段包括:

字段名稱 類型 說明
id string  
order_id string 訂單主鍵
good_id string 商品id
count int 商品數量
unit_price int 單價(分)

 

 

 

調用微信統一支付接口代碼

public Map<String, String> pay(String orderId,String ip, boolean debug,String openid) throws Exception {
        
        OrderInfo order = orderInfoDao.get(orderId);
        if(order == null)
        {
            throw new ServiceException(ErrorCode.ORDER_ERR3);
        }
        
        if(!OrderState.NOT_PAY.getValue().equals(order.getOrderState())){
            throw new ServiceException(ErrorCode.ORDER_ERR4);
        }
        
        if(!order.getOpenid().equals(openid)){
            throw new ServiceException(ErrorCode.ORDER_ERR6);
        }
        Map<String, String> resp = null;
        Map<String, String> res = new HashMap<String, String>();
        if(debug){
            resp = new HashMap<String, String>();
            resp.put("debug", "true");
            resp.put("totalFee",order.getTotalFee().toString());
            
        }else{
            
            System.out.println("-----------------appid=" + config.getAppID());
            System.out.println("-----------------mchid=" + config.getMchID());
            
            log.debug("--------appid="+config.getAppID());
            log.debug("--------mchid="+config.getMchID());
            log.debug("--------key="+config.getKey());
            config.print();
            // 生成微信支付
            WXPay wxpay = new WXPay(config);
            Map<String, String> wxData = new HashMap<String, String>();
            String timeStamp = String.valueOf(new Date().getTime()/1000);
            wxData.put("body", order.getTableId());
//            wxData.put("body", "999999999999");
            wxData.put("out_trade_no", order.getId());
            wxData.put("openid", openid);
            wxData.put("device_info","device_info");
            wxData.put("fee_type", "CNY");
            wxData.put("total_fee", "1");
            //wxData.put("total_fee", String.valueOf(Double.valueOf(order.getTotalFee()).intValue()));
            log.info("訂單金額:" + wxData.get("total_fee"));
            wxData.put("spbill_create_ip", ip);
            wxData.put("notify_url", notifyUrl);
            wxData.put("timeStamp", timeStamp);
            wxData.put("openid", openid);
            wxData.put("trade_type", "JSAPI");  // 
            
            //boolean b = new File("conf/apiclient_cert.p12").exists();
            log.info("============正在調用支付接口參數" + wxData);
//            wxData.put("product_id",course.getId());
            resp = wxpay.unifiedOrder(wxData);
            log.info("下單返回結果:"+resp);
            
           
            res.put("appId", resp.get("appid"));
            res.put("timeStamp", timeStamp);
            res.put("nonceStr", resp.get("nonce_str"));
            res.put("signType", "MD5");
            res.put("package", "prepay_id="+resp.get("prepay_id"));
            
            String paySign = WXPayUtil.generateSignature(res, config.getKey(), SignType.MD5);
            res.put("paySign", paySign);
        }
        
        order.preUpdate();
        int result = orderInfoDao.update(order);
        if(result != 1)
        {
            throw new ServiceException(ErrorCode.COMMON_SYS_BUSY);
        }
        
        return res;
       
    }

 

這里要注意的就是返回的結果中要有個對參數進行簽名,sdk中提供的是掃描支付號線更沒有加入最后一行的簽名,我這里遇到了一坑花了好長時間,其實時序圖中已經寫明了要進行簽名,所以吸取個教訓,一定要看清楚文檔。

拉起微信支付界面

 

這里需要利用上一步的參數,然后調用微信內置瀏覽器的函數拉起微信支付,所以這里一定要在微信內打開才能拉起支付,在別的手機瀏覽器或者電腦瀏覽器打開是不行的。

function onBridgeReady(data) {

            var payPare = {
                "appId" : data.appId, //公眾號名稱,由商戶傳入     
                "timeStamp" : data.timeStamp, //時間戳,自1970年以來的秒數     
                "nonceStr" : data.nonceStr, //隨機串     
                "package" : data.package,//"prepay_id=u802345jgfjsdfgsdg888",     
                "signType" : "MD5", //微信簽名方式:     
                "paySign" : data.paySign
            //微信簽名 
            };

            WeixinJSBridge.invoke('getBrandWCPayRequest', payPare,
                    function(res) {
                        if (res.err_msg == "get_brand_wcpay_request:ok") {
                            // 使用以上方式判斷前端返回,微信團隊鄭重提示:
                            //res.err_msg將在用戶支付成功后返回ok,但並不保證它絕對可靠。
                        }
                    });
        }

 

 

如果程序正常調用該函數應該會拉起微信支付界面,這里值得說下的是維系貌似有提供沙箱模式給開發者測試用的,但是沒必要開發過程中可以先把金額調整1分錢就行了,就像下圖這樣。真實環境開干啊。

 

最后一步:更新支付狀態(訂單狀態)

這里需要說下在調用預支付(統一支付接口)的時候有個參數是設置回調的連接,notify_url,這個連接是用戶支付之后微信用這個鏈接來告訴你支付結果的,這里要注意更新訂單的時候要判斷下微信是否已經支付過了(判重),好像微信不止推送一次的,如果訂單不止未支付和已支付2個狀態那么一定要做一下判重。

public AppResponse payResult(HttpServletRequest request) {
        boolean debug = "true".equals(Global.getConfig("debug"));
        
        if(debug){
            String orderId = request.getParameter("orderId");
            
            orderService.updateOrderByOutTradeNo(orderId,
                    orderId, "",true);
            return new AppResponse(ErrorCode.COMMON_SUCCESS.getKey(),ErrorCode.COMMON_SUCCESS.getMsg(),orderId);
        }
        
        loger.debug("收到微信支付成功通知");
        InputStream inStream;
        String outTradeNo = null;
        try {
            inStream = request.getInputStream();

            int _buffer_size = 1024;

            if (inStream == null)
                return null;

            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            byte[] tempBytes = new byte[_buffer_size];
            int count = -1;
            while ((count = inStream.read(tempBytes, 0, _buffer_size)) != -1) {
                outStream.write(tempBytes, 0, count);
            }
            tempBytes = null;
            outStream.flush();
            // 將流轉換成字符串
            String result = new String(outStream.toByteArray(), "UTF-8");

            WXPay wxpay = new WXPay(config);

            Map<String, String> notifyMap = WXPayUtil.xmlToMap(result); // 轉換成map

            
            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
                loger.debug("簽名成功");
                // 簽名正確
                // 進行處理。
                // 注意特殊情況:訂單已經退款,但收到了支付結果成功的通知,不應把商戶側訂單狀態從退款改成支付成功
                String payResult = notifyMap.get("return_code");

                outTradeNo = notifyMap.get("out_trade_no"); // 商戶訂單號
                String transactionId = notifyMap.get("transaction_id"); // 微信訂單號
                loger.debug("-------------微信訂單號:transaction_id="+transactionId);
                loger.debug("-------------outTradeNo:outTradeNo="+outTradeNo);
                orderService.updateOrderByOutTradeNo(outTradeNo,
                        transactionId, payResult,false);
                
            } else {
                // 簽名錯誤,如果數據里沒有sign字段,也認為是簽名錯誤
            }
        } catch (ServiceException e) {
            e.printStackTrace();
            loger.debug(e.getMessage());
        } catch (IOException e) {
            loger.debug(e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            loger.debug(e.getMessage());
            e.printStackTrace();
        }

        return null;
    }

 

 

以上就是基本的支付流程了,我遇到的問題大概就是支付參數獲取麻煩(商戶號不是我的),和少了次簽名,導致花了好多時間。

完畢,謝謝大家


免責聲明!

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



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