1. 程式人生 > >微信開發三--帶引數二維碼

微信開發三--帶引數二維碼

一、獲取access_token

官方文件:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183
可使用微信公眾平臺介面除錯工具進行除錯(登入公眾號後,在左側導航欄可找到“開發者工具”,選擇第二項“線上介面除錯工具”即可進行介面除錯。):https://mp.weixin.qq.com/debug?token=1803714957&lang=zh_CN
在這裡插入圖片描述
首先我們需要獲取access_token,有效期7200s,一天獲取上限為2000次
程式碼例項:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.json.JSONObject;

public class xiaoqiang {
	
	public static final String appid = "xxxxxxxxxxxxxxxxxx";
	public static final String appsecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

	private static Logger loger = LoggerFactory.getLogger(xiaoqiang.class);
	
	public static void main(String args[]) {
		System.out.println(getWXAccessToken());
	}
	
    public static String getWXAccessToken() {
        String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?" +
                "grant_type=client_credential" +
                // 此處填寫你自己的appid
                "&appid=" + appid +
                // 此處填寫你自己的appsecret
                "&secret=" + appsecret;
        JSONObject jsonObject = httpsRequest(accessTokenUrl, "GET", null);
        return (String) jsonObject.get("access_token");
    }
    
    /**
     * 傳送https請求
     * @param requestUrl 請求地址
     * @param requestMethod 請求方式(GET、POST)
     * @param data 提交的資料
     * @return JSONObject(通過JSONObject.get(key)的方式獲取json物件的屬性值)
     */
    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String data) {
        JSONObject jsonObject = null;
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        try {
            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 設定請求方式(GET/POST)
            conn.setRequestMethod(requestMethod);
            conn.connect();
            // 當data不為null時向輸出流寫資料
            if (null != data) {
                // getOutputStream方法隱藏了connect()方法
                OutputStream outputStream = conn.getOutputStream();
                // 注意編碼格式
                outputStream.write(data.getBytes("UTF-8"));
                outputStream.close();
            }
            // 從輸入流讀取返回內容
            inputStream = conn.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            conn.disconnect();
            jsonObject = JSONObject.fromObject(buffer.toString());
            return jsonObject;
        } catch (Exception e) {
        	loger.error("傳送https請求失敗,失敗", e);
            return null;
        } finally {
            // 釋放資源
            try {
                if(null != inputStream) {
                    inputStream.close();
                }
                if(null != inputStreamReader) {
                    inputStreamReader.close();
                }
                if(null != bufferedReader) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
            	loger.error("釋放資源失敗,失敗", e);
            }
        }
    }
}

注意:你可能會出現如下圖所示“org.apache.commons.lang.exception.NestableRuntimeException”的報錯
在這裡插入圖片描述
參考:https://blog.csdn.net/gu_gu_/article/details/50551775
解決:在pom.xml檔案中加入下面的配置

		<dependency>
			<groupId>net.sf.ezmorph</groupId>
			<artifactId>ezmorph</artifactId>
			<version>1.0.4</version>
		</dependency>
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.9.1</version>
		</dependency>

注意:我們需要現在微信公眾平臺設定 IP白名單,也就是本機的外網IP地址,否則無法獲取access_token
 

二、獲取微信公眾號二維碼

說明:可以和上一篇文章“事件推送”配合使用。為了滿足使用者渠道推廣分析的需要,公眾平臺提供了生成帶引數二維碼的介面。使用該介面可以獲得多個帶不同場景值的二維碼,使用者掃描後,公眾號可以接收到事件推送。
目前有2種類型的二維碼,分別是臨時二維碼和永久二維碼,前者有過期時間,最大為1800秒,但能夠生成較多數量,後者無過期時間,數量較少(目前引數只支援1–100000)。兩種二維碼分別適用於帳號繫結、使用者來源統計等場景。
使用者掃描帶場景值二維碼時,可能推送以下兩種事件:
如果使用者還未關注公眾號,則使用者可以關注公眾號,關注後微信會將帶場景值關注事件推送給開發者。
如果使用者已經關注公眾號,在使用者掃描後會自動進入會話,微信也會將帶場景值掃描事件推送給開發者。
獲取帶引數的二維碼的過程包括兩步,首先建立二維碼ticket,然後憑藉ticket到指定URL換取二維碼。
官方文件:

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433542

程式碼例項:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import net.sf.json.JSONObject;

public class xiaoqiang {
	
	public static final String appid = "xxxxxxxxxxxxxxxxxx";
	public static final String appsecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

	private static Logger loger = LoggerFactory.getLogger(xiaoqiang.class);
	
	public static void main(String args[]) throws UnsupportedEncodingException {
//		System.out.println(getWXAccessToken());
		getWXPublicQRCode("1",123,"hehe");
	}
    
	/**
     * 獲取微信公眾號二維碼
     * @param codeType 二維碼型別 "1": 臨時二維碼  "2": 永久二維碼
     * @param sceneId 場景值ID
     * 		scene_id	場景值ID,臨時二維碼時為32位非0整型,永久二維碼時最大值為100000(目前引數只支援1--100000)
     * 		scene_str	場景值ID(字串形式的ID),字串型別,長度限制為1到64
     * @param fileName 圖片名稱
	 * @throws UnsupportedEncodingException 
     */
    public static void getWXPublicQRCode(String codeType, Integer sceneId, String fileName) throws UnsupportedEncodingException {
        // String wxAccessToken = getWXAccessToken();  // 這裡為了省略程式碼,可參考第一步獲取access_token
        Map<String, Object> map = new HashMap<>();
        if ("1".equals(codeType)) { // 臨時二維碼
            map.put("expire_seconds", 604800);
            map.put("action_name", "QR_SCENE");
            Map<String, Object> sceneMap = new HashMap<>();
            Map<String, Object> sceneIdMap = new HashMap<>();
            sceneIdMap.put("scene_id", sceneId);
            sceneMap.put("scene", sceneIdMap);
            map.put("action_info", sceneMap);
        } else if ("2".equals(codeType)) { // 永久二維碼
            map.put("action_name", "QR_LIMIT_SCENE");
            Map<String, Object> sceneMap = new HashMap<>();
            Map<String, Object> sceneIdMap = new HashMap<>();
            sceneIdMap.put("scene_id", sceneId);
            sceneMap.put("scene", sceneIdMap);
            map.put("action_info", sceneMap);
        }
        String data = JSON.toJSONString(map);
        // 得到ticket票據,用於換取二維碼圖片
        JSONObject jsonObject = httpsRequest("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + wxAccessToken, "POST", data);
        String ticket = (String) jsonObject.get("ticket");
        // WXConstants.QRCODE_SAVE_URL: 填寫存放圖片的路徑
        httpsRequestPicture("https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + 
        	URLEncoder.encode(ticket, "UTF-8"), //URLEncoder.encode(ticket)已不建議使用
            "GET", null, "C:\\Users\\Administrator\\Desktop", fileName, "png");
    }
    
    /**
     * 傳送https請求,返回二維碼圖片
     * @param requestUrl 請求地址
     * @param requestMethod 請求方式(GET、POST)
     * @param data 提交的資料
     * @param savePath 圖片儲存路徑
     * @param fileName 圖片名稱
     * @param fileType 圖片型別
     */
    public static void httpsRequestPicture(String requestUrl, String requestMethod, String data, String savePath, String fileName, String fileType) {
        InputStream inputStream = null;
        try {
            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            //設定請求方式(GET/POST)
            conn.setRequestMethod(requestMethod);
            conn.connect();
            //當data不為null時向輸出流寫資料
            if (null != data) {
                //getOutputStream方法隱藏了connect()方法
                OutputStream outputStream = conn.getOutputStream();
                //注意編碼格式
                outputStream.write(data.getBytes("UTF-8"));
                outputStream.close();
            }
            // 從輸入流讀取返回內容
            inputStream = conn.getInputStream();
            loger.info("開始生成微信二維碼...");
            inputStreamToMedia(inputStream, savePath, fileName, fileType);
            loger.info("微信二維碼生成成功!!!");
            conn.disconnect();
        } catch (Exception e) {
            loger.error("傳送https請求失敗,失敗", e);
        }finally {
            //釋放資源
            try {
                if(null != inputStream) {
                    inputStream.close();
                }
            } catch (IOException e) {
                loger.error("釋放資源失敗,失敗", e);
            }
        }
    }
    
    /**
     * 將輸入流轉換為圖片
     * @param input 輸入流
     * @param savePath 圖片需要儲存的路徑
     * @param fileType 圖片型別
     */
    public static void inputStreamToMedia(InputStream input, String savePath, String fileName, String fileType) throws Exception {
        String filePath = savePath + "/" + fileName + "." + fileType;
        File file = new File(filePath);
        FileOutputStream outputStream = new FileOutputStream(file);
        int length;
        byte[] data = new byte[1024];
        while ((length = input.read(data)) != -1) {
            outputStream.write(data, 0, length);
        }
        outputStream.flush();
        outputStream.close();
    }
}

參考:
https://blog.csdn.net/goodbye_youth/article/details/80653132