微信支付 全套流程看完就會 pc掃碼支付


一:前期微信支付掃盲知識

前提條件是已經有申請了微信支付功能的公眾號,然后我們需要得到公眾號APPID和微信商戶號,這個分別在微信公眾號和微信支付商家平台上面可以發現。其實在你申請成功支付功能之后,微信會通過郵件把Mail轉給你的,有了這些信息之后,我們就可以去微信支付服務支持頁面:https://pay.weixin.qq.com/service_provider/index.shtml

打開這個頁面,點擊右上方的鏈接【開發文檔】會進入到API文檔說明頁面,看起來如下

 

選擇紅色圓圈的掃碼支付就是我們要做接入方式,鼠標移動到上面會提示你去查看開發文檔,如果這個都不知道怎么查看,可以洗洗睡了,你真的不合適做程序員,地址如下:

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1瀏覽器中打開之后會看到

一:前期微信支付掃盲知識

前提條件是已經有申請了微信支付功能的公眾號,然后我們需要得到公眾號APPID和微信商戶號,這個分別在微信公眾號和微信支付商家平台上面可以發現。其實在你申請成功支付功能之后,微信會通過郵件把Mail轉給你的,有了這些信息之后,我們就可以去微信支付服務支持頁面:https://pay.weixin.qq.com/service_provider/index.shtml

打開這個頁面,點擊右上方的鏈接【開發文檔】會進入到API文檔說明頁面,看起來如下

 

 

 

選擇紅色圓圈的掃碼支付就是我們要做接入方式,鼠標移動到上面會提示你去查看開發文檔,如果這個都不知道怎么查看,可以洗洗睡了,你真的不合適做程序員,地址如下:

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1瀏覽器中打開之后會看到

我們重點要關注和閱讀的內容我已經用紅色橢圓標注好了,首先閱讀【接口規則】里面的協議規范,開玩笑這個都不讀你就想做微信支付,這個就好比你要去泡妞,得先收集點基本背景信息,了解對方特點,不然下面還怎么溝通。事實證明只有會泡妞得程序員才是好銷售。跑題了我們接下來要看一下【場景介紹】中的案例與規范,只看一下記得一定要微信支付的LOGO下載下來,是為了最后放到我們自己的掃碼支付網頁上,這樣看上去比較專業一點。之后重點關注【模式二】

 

我們這里就是要采用模式二的方式實現PC端頁面掃碼支付功能。

 

微信官方對模式二的解釋是這樣的商戶后台系統先調用微信支付的統一下單接口,微信后台系統返回鏈接參數code_url,商戶后台系統將code_url值生成二維碼圖片,用戶使用微信客戶端掃碼后發起支付。注意:code_url有效期為2小時,過期后掃碼不能再發起支付。看明白了吧就是我們首先要調用微信提供統一下單接口,得到一個關鍵信息code_url(至於這個code_url是什么鬼,我也不知道),然后我們通過自己的程序把這個URL生成一個二維碼,生成二維碼我這里用了Googlezxing庫。然后把這個二維碼顯示在你的PC端網頁上就行啦。這樣終端用戶一掃碼就支付啦,支付就完成啦,看到這里你肯定很激動,發現微信支付如此簡單,等等還有個事情我們還不知道,客戶知道付錢了,我們服務器端還不知道呢,以微信開發人員的智商他們早就想到這個問題了,所以讓你在調用統一下單接口的時候其中有個必填的參數就是回調URL,就是如果客戶端付款成功之后微信會通過這個URL向我們自己的服務器提交一些數據,然后我們后台解析這些數據,完成我們自己操作。這樣我們才知道客戶是否真的已經通過微信付款了。這樣整個流程才結束,這個就是模式二。微信用一個時序圖示這樣表示這個過程的。

 

表達起來比較復雜,看上去比較吃力,總結一下其實我們服務器該做的事情就如下件:

 

1. 通過統一下單接口傳入正確的參數(當然要包括我們的回調URL)與簽名驗證,從返回數據中得到code_url的對應數據

 

2. 根據code_url的數據我們自己生成一個二維碼圖片,顯示在瀏覽器網頁上

 

3. 在回調的URL中添加我們自己業務邏輯處理。

 

至此掃盲結束了,你終於知道掃碼支付什么個什么樣的流程了,下面我們就一起來扒扒它的相關API使用,做好每步處理。

 

二:開發過程

 

在開發代碼之前,請先准備幾件事情。

 

1. 添加ZXingmaven依賴   也可以直接在前端使用第三方庫  生成二維碼

 

2. 添加jdommaven依賴

 

3.下載Java版本SDK演示程序,地址在這里

 

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1

 

我們需要MD5Util.javaXMLUtil.java兩個文件

 

4. 我們使用HttpClient版本是4.5.1,記得添加Maven依賴

 

上面准備工作做好以后,繼續往下看:

 

首先我們要調用微信的統一下單接口,我們點擊【API列表】中的統一下單會看到這樣頁面:

 

 

 

我們重點要關注和閱讀的內容我已經用紅色橢圓標注好了,首先閱讀【接口規則】里面的協議規范,開玩笑這個都不讀你就想做微信支付,這個就好比你要去泡妞,得先收集點基本背景信息,了解對方特點,不然下面還怎么溝通。事實證明只有會泡妞得程序員才是好銷售。跑題了我們接下來要看一下【場景介紹】中的案例與規范,只看一下記得一定要微信支付的LOGO下載下來,是為了最后放到我們自己的掃碼支付網頁上,這樣看上去比較專業一點。之后重點關注【模式二】

我們這里就是要采用模式二的方式實現PC端頁面掃碼支付功能。

微信官方對模式二的解釋是這樣的商戶后台系統先調用微信支付的統一下單接口,微信后台系統返回鏈接參數code_url,商戶后台系統將code_url值生成二維碼圖片,用戶使用微信客戶端掃碼后發起支付。注意:code_url有效期為2小時,過期后掃碼不能再發起支付。看明白了吧就是我們首先要調用微信提供統一下單接口,得到一個關鍵信息code_url(至於這個code_url是什么鬼,我也不知道),然后我們通過自己的程序把這個URL生成一個二維碼,生成二維碼我這里用了Googlezxing庫。然后把這個二維碼顯示在你的PC端網頁上就行啦。這樣終端用戶一掃碼就支付啦,支付就完成啦,看到這里你肯定很激動,發現微信支付如此簡單,等等還有個事情我們還不知道,客戶知道付錢了,我們服務器端還不知道呢,以微信開發人員的智商他們早就想到這個問題了,所以讓你在調用統一下單接口的時候其中有個必填的參數就是回調URL,就是如果客戶端付款成功之后微信會通過這個URL向我們自己的服務器提交一些數據,然后我們后台解析這些數據,完成我們自己操作。這樣我們才知道客戶是否真的已經通過微信付款了。

這樣整個流程才結束,這個就是模式二。微信用一個時序圖示這樣表示這個過程的。

 

package com........util;

 

 

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

import java.util.SortedMap;

 

import javax.servlet.http.HttpServletRequest;

public class ConstantUtil {

/**

 * 商家可以考慮讀取配置文件

 */

public static String GATEURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//獲取預支付id的接口url

public static String QUERYURL = "https://api.mch.weixin.qq.com/pay/orderquery";//獲取微信支付訂單支付情況url

public static String BODY="";//支付介紹看微信介紹

//微信掃碼支付配置--start--微信公眾平台APPID

public static String WECHAT_APP_ID="";//公司提供

public static String WECHAT_MCH_ID="";//公司提供

    public static String WECHAT_APP_KEY="";//公司提供微信公眾平台支付商戶平台系統內的API密鑰

public static String WECHAT_NOTIFY_URL="http://www.*******.com/weixinPayReturn";//微信掃碼支付配置   回調路徑--end--

    public static String createSign(String Encoding, SortedMap<String, String> parameters){

        StringBuffer sb = new StringBuffer();

        Set es = parameters.entrySet();

        Iterator it = es.iterator();

        while(it.hasNext()) {

            Map.Entry entry = (Map.Entry)it.next();

            String k = (String)entry.getKey();

            Object v = entry.getValue();

            if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {

                sb.append(k + "=" + v + "&");

            }

        }

        sb.append("key=" + ConstantUtil.WECHAT_APP_KEY);

        String sign = MD5Util.MD5Encode(sb.toString(), Encoding).toUpperCase();

        return sign;

    }

    public static boolean IsNumeric(String str) {

        return str.matches("\\d *");

    }

    public  static String parametersToXml(Map<String, String> parameters) {

        String xml = "<xml>";

        Set es = parameters.entrySet();

        Iterator it = es.iterator();

        while(it.hasNext()) {

         Map.Entry entry = (Map.Entry)it.next();

            String key = (String)entry.getKey();

            String val = (String)entry.getValue();

            if(IsNumeric(val)) {

                xml = xml + "<" + key + ">" + val + "</" + key + ">";

            } else {

                xml = xml + "<" + key + "><![CDATA[" + val + "]]></" + key + ">";

            }

        }

 

        xml = xml + "</xml>";

        return xml;

}

 public static String generateString(int length) {  

        StringBuffer sb = new StringBuffer();  

        Random random = new Random();  

        for (int i = 0; i < length; i++) {  

            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));  

        }  

        return sb.toString();  

    }  

    public static String getIpAddress(HttpServletRequest request) {  

        String ip = request.getHeader("x-forwarded-for");  

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  

            ip = request.getHeader("Proxy-Client-IP");  

        }  

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  

            ip = request.getHeader("WL-Proxy-Client-IP");  

        }  

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  

            ip = request.getHeader("HTTP_CLIENT_IP");  

        }  

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  

            ip = request.getHeader("HTTP_X_FORWARDED_FOR");  

        }  

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  

            ip = request.getRemoteAddr();  

        }  

        return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;

    }  

 

}

先准備下單接口

window.location.href = "weixinPay?Oid=" + data;

 @RequestMapping(value = "/weixinPay", method = RequestMethod.GET, produces = MediaType.ALL_VALUE)

    public String weixinPay(Model model,String Oid) {

        System.out.println("\n*****************開啟微信掃碼界面******\n");

       // 付款金額,必填

        /*JSONObject jObject =new JSONObject();*/

        long date = System.currentTimeMillis();

        SortedMap<String, String> sParaTemp = new TreeMap<String, String>();

        sParaTemp.put("appid", ConstantUtil.WECHAT_APP_ID);

        sParaTemp.put("mch_id", ConstantUtil.WECHAT_MCH_ID);

        sParaTemp.put("nonce_str", date + ConstantUtil.generateString(10));//最好是當前時間在隨機數

        sParaTemp.put("sign_type", "MD5");

        sParaTemp.put("body", ConstantUtil.BODY);

        sParaTemp.put("out_trade_no", Oid);//此處改成商城orderID

        sParaTemp.put("total_fee", "1");    //為一分錢 

        sParaTemp.put("spbill_create_ip", ConstantUtil.getIpAddress(request));

        sParaTemp.put("trade_type", "NATIVE");

        sParaTemp.put("notify_url", ConstantUtil.WECHAT_NOTIFY_URL);//notify_url

        String signString = ConstantUtil.createSign("utf-8", sParaTemp);

        sParaTemp.put("sign", signString);

        String paramXml = ConstantUtil.parametersToXml(sParaTemp);

        try {//一下發送請求至微信的下單接口

            CloseableHttpClient httpClient = HttpClientBuilder.create().build();

            HttpPost post = new HttpPost(ConstantUtil.GATEURL);

            post.addHeader("Content-Type", "text/xml; charset=UTF-8");

            StringEntity xmlEntity = new StringEntity(paramXml, ContentType.APPLICATION_JSON);//UTF-8

            post.setEntity(xmlEntity);

            CloseableHttpResponse httpResponse = httpClient.execute(post);

            String responseXML = EntityUtils.toString(((org.apache.http.HttpResponse) httpResponse).getEntity(), "UTF-8");

            @SuppressWarnings("unchecked")

            Map<String, String> resultMap = XMLUtil.parseXmlToMap(responseXML);

            if (resultMap.get("return_code").equals("SUCCESS") && resultMap.get("result_code").equals("SUCCESS")) {

                String codeurl = resultMap.get("code_url");

                if (codeurl != null && !"".equals(codeurl)) {

                    model.addAttribute("data", codeurl);//一切正常返回一個url 頁面接收生成二維碼

                } else {

                    model.addAttribute("data", "");

                }

            }

            post.releaseConnection();

        } catch (Exception e) {

            e.printStackTrace();

        }

        return "/weixinPay";

}

//發送的請求主要是注意驗簽那塊。只要告訴提供的信息沒有問題。一切都ok

 

頁面展示

weixinPay.jsp

獲取以上的data頁面使用第三方工具庫生成二維碼

<script src="${pageContext.request.contextPath}/resources/js/jquery-1.12.0.min.js" type="text/javascript"></script>

<script src="${pageContext.request.contextPath}/resources/js/jquery.qrcode.min.js" type="text/javascript"></script>

$(function(){

var str = toUtf8("${data}");//展示二維碼

$("#code").qrcode({

 render: "canvas", // 渲染方式有table方式和canvas方式

 width: 220,   //默認寬度

 height: 200, //默認高度

 text: str, //二維碼內容

 typeNumber: -1,   //計算模式一般默認為-1

 correctLevel: 2, //二維碼糾錯級別

 background: "#ffffff",  //背景顏色

 foreground: "#000000"  //二維碼顏色

});

 

 

})

到最后一步微信的二維碼就展示在頁面上了。  然后還有掃碼回調和訂單查詢不懂的可以留言


免責聲明!

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



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