微信公眾號 掃碼支付 模式二 demo


掃碼支付

本文附有代碼,在下方,如果不熟悉場景的可以看看下面的場景介紹

用戶掃描商戶展示在各種場景的二維碼進行支付。

步驟1:商戶根據微信支付的規則,為不同商品生成不同的二維碼(如圖6.1),展示在各種場景,用於用戶掃描購買。

步驟2:用戶使用微信“掃一掃”(如圖6.2)掃描二維碼后,獲取商品支付信息,引導用戶完成支付(如圖6.3)。

支付二維碼

圖6.1 支付二維碼

打開微信掃一掃二維碼

圖6.2 打開微信掃一掃二維碼

確認支付頁面

圖6.3 確認支付頁面

步驟(3):用戶確認支付,輸入支付密碼(如圖6.4)。

步驟(4):支付完成后會提示用戶支付成功(如圖6.5),商戶后台得到支付成功的通知,然后進行發貨處理。

用戶確認支付,輸入密碼

圖6.4 用戶確認支付,輸入密碼

支付成功提示

圖6.5 支付成功提示

模式二與模式一相比,流程更為簡單,不依賴設置的回調支付URL。商戶后台系統先調用微信支付的統一下單接口,微信后台系統返回鏈接參數code_url,商戶后台系統將code_url值生成二維碼圖片,用戶使用微信客戶端掃碼后發起支付。注意:code_url有效期為2小時,過期后掃碼不能再發起支付。

業務流程時序圖

原生支付模式二時序圖

圖6.9 原生支付模式二時序圖

業務流程說明:

(1)商戶后台系統根據用戶選購的商品生成訂單。

(2)用戶確認支付后調用微信支付【統一下單API】生成預支付交易;

(3)微信支付系統收到請求后生成預支付交易單,並返回交易會話的二維碼鏈接code_url。

(4)商戶后台系統根據返回的code_url生成二維碼。

(5)用戶打開微信“掃一掃”掃描二維碼,微信客戶端將掃碼內容發送到微信支付系統。

(6)微信支付系統收到客戶端請求,驗證鏈接有效性后發起用戶支付,要求用戶授權。

(7)用戶在微信客戶端輸入密碼,確認支付后,微信客戶端提交授權。

(8)微信支付系統根據用戶授權完成支付交易。

(9)微信支付系統完成支付交易后給微信客戶端返回交易結果,並將交易結果通過短信、微信消息提示用戶。微信客戶端展示支付交易結果頁面。

(10)微信支付系統通過發送異步消息通知商戶后台系統支付結果。商戶后台系統需回復接收情況,通知微信后台系統不再發送該單的支付通知。

(11)未收到支付通知的情況,商戶后台系統調用【查詢訂單API】。

(12)商戶確認訂單已支付后給用戶發貨。

生成二維碼規則

對應鏈接格式:weixin://wxpay/bizpayurl?sr=XXXXX。請商戶調用第三方庫將code_url生成二維碼圖片。該模式鏈接較短,生成的二維碼打印到結賬小票上的識別率較高。

例如,將weixin://wxpay/s/An4baqw生成二維碼見圖6.10。

原生支付“模式二”二維碼示例

圖6.10 原生支付“模式二”二維碼示例

 

下面上代碼:

這里特要注意的就是key,這個key不是公眾號下面的key,而是商戶下的key,這個key是自己生成的32位字符串,

調用的是微信統一下單接口:

 

 

getWxPayQRCode() 返回的就是要掃的二維碼中的值;只要把這個值塞到二維中即可!
/**
     * 微信掃碼支付 模式二
     * @return返回的就是二維中的值
     * @throws Exception
     */
    public String getWxPayQRCode() throws Exception{
        //商戶key
        String key = "mlqho2dwhxxxxxxxxxxxv81m1r6i28";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        Map<String,String> map = new HashMap<String, String>();
        //公眾賬號ID
        map.put("appid","wssssssxxxxxxxxxe0e5b");
        //商戶號
        map.put("mch_id","1xxxxxxxxx2");
        //隨機數
        map.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));
        //商品描述
        map.put("body","香辣雞腿堡");
        //訂單號
        map.put("out_trade_no",sdf.format(new Date()));
        //總金額單位分
        map.put("total_fee","1");
        InetAddress ia = InetAddress.getLocalHost();
        //ip
        map.put("spbill_create_ip",ia.getHostAddress());
        //通知地址
        map.put("notify_url","www.niudao.com");
        //交易類型
        map.put("trade_type","NATIVE");
        //商品ID
        map.put("product_id","10000");
        //簽名
        map.put("sign", QRSign.getSign(map, key));
        //請求地址及請求數據
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String data = MapToXmlUtil.mapToXml(map);
        //發送請求
        ClientRequest request = new ClientRequest(url);
        request.body("text/xml;charset=utf-8",data);
        ClientResponse response = request.post(String.class);
        //xml字符串轉化成json對象
        String result = XMLAndJsonUtil.xmlChangeJson(response.getEntity().toString());
        result = result.replaceAll("\r\n","");
        JSONObject jsonObject = JSONObject.fromObject(result);
        //二維碼內容
        String qrCode = "";
        if(jsonObject.get("return_code").toString().equals("SUCCESS")){
            qrCode = jsonObject.get("code_url").toString();
        }
        return qrCode;
    }

 工具類

RandomStringGenerator 傳入一個n,生成n位隨機字符串
import java.util.Random;

/**
 * User: rizenguo
 * Date: 2014/10/29
 * Time: 14:18
 */
public class RandomStringGenerator {

    /**
     * 獲取一定長度的隨機字符串
     * @param length 指定字符串長度
     * @return 一定長度的字符串
     */
    public static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

}
QRSign 傳入的數據生成簽名,
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Map;

/**
 * Created by Administrator on 16-12-1.
 */
public class QRSign {

    /**
     * 微信支付簽名算法sign
     * @param map 請求微支付body
     * @param key 商戶key (不是公眾號key)
     * @return
     */
    public static String getSign(Map<String,String> map,String key) {
        StringBuffer sb = new StringBuffer();
        String[] keyArr = (String[]) map.keySet().toArray(new String[map.keySet().size()]);//獲取map中的key轉為array
        Arrays.sort(keyArr);//對array排序
        for (int i = 0, size = keyArr.length; i < size; ++i) {
            if ("sign".equals(keyArr[i])) {
                continue;
            }
            sb.append(keyArr[i] + "=" + map.get(keyArr[i]) + "&");
        }
        sb.append("key=" + key);
        String sign = string2MD5(sb.toString());
        return sign;
    }

    /***
     * MD5加密 生成32位md5碼
     */
    public static String string2MD5(String str){
        if (str == null || str.length() == 0) {
            return null;
        }
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'a', 'b', 'c', 'd', 'e', 'f' };

        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(str.getBytes("UTF-8"));

            byte[] md = mdTemp.digest();
            int j = md.length;
            char buf[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf).toUpperCase();
        } catch (Exception e) {
            return null;
        }
    }
}

MapToXmlUtil作用:

  由於微信支付接口傳入的參數是xml格式的,因此此類是將map轉化為xml格式

 

import java.util.Map;

/**
 * Created by Administrator on 16-12-1.
 */
public class MapToXmlUtil {
    /**
     * 將map 轉化成 xml
     * @param map
     * @return
     */
    public static String mapToXml(Map<String,String> map)throws Exception{
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sb.append("<" + entry.getKey() + ">" + entry.getValue().toString() + "</" + entry.getKey() + ">");
        }
        sb.append("</xml>");
        return sb.toString();
    }
}

最終返回的結果也是xml格式的,為了方便取值,本人轉成json格式;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by Administrator on 16-12-1.
 */
public class XMLAndJsonUtil {

    //用於判斷是否有子節點,若有就將子節點也進行拼接,若無則返回""
    public static String checkChildEle(Element element) throws DocumentException {
        String json="";
        List<Element> list = new ArrayList<Element>();
        list=element.elements();
        if (list.size()>0) {
            for (Element ele : list) {
                json+= "'" + ele.getName() + "'" + ":" + "'" + ele.getText() + "'" + "," + "\r\n" + checkChildEle(ele);
            }
        }
        return json;
    }
    //這個方法是將xml字符串轉成Json
    public static String xmlChangeJson(String XML) throws DocumentException{
        Document document= DocumentHelper.parseText(XML);
        Element root=document.getRootElement();
        Iterator it=root.elementIterator();
        String json="{";
        while (it.hasNext()) {
            Element element =(Element)it.next();
            String j=checkChildEle(element);
            if (j=="") {
                json+= "'" + element.getName() + "'" + ":" + "'" + element.getText() + "'" + ","+"\r\n";
            }else {
                json+=j;
            }

        }
        json+="}";
        return json;
    }
    //這個方法是將xml文件轉成Json
    public static String xmlChangeJson(File XML) throws DocumentException{
        SAXReader reader=new SAXReader();
        Document document=reader.read(XML);
        Element root=document.getRootElement();
        Iterator it=root.elementIterator();
        String json="{";
        while (it.hasNext()) {
            Element element =(Element)it.next();
            String j=checkChildEle(element);
            if (j=="") {
                json+=element.getName()+":"+element.getText()+","+"\r\n";
            }else {
                json+=j;
            }

        }
        json+="}";
        return json;
    }
}

如果報簽名錯誤可以到下面這個網址去驗證sign生成的結果是否一致

https://pay.weixin.qq.com/wiki/tools/signverify/

 

 

 

 

 

 


免責聲明!

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



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