微信公眾號關注二維碼開發
ps:微信相關開發部落格地址:https://www.cnblogs.com/txw1958/p/
本文介紹在微信公眾平臺上如何使用高階介面開發生成帶引數二維碼的功能。
一、場景二維碼
為了滿足使用者渠道推廣分析的需要,公眾平臺提供了生成帶引數二維碼的介面。使用該介面可以獲得多個帶不同場景值的二維碼,使用者掃描後,公眾號可以接收到事件推送。
目前有2種類型的二維碼,分別是臨時二維碼和永久二維碼,前者有過期時間,最大為1800秒,但能夠生成較多數量,後者無過期時間,數量較少(目前引數只支援1--100000)。兩種二維碼分別適用於帳號繫結、使用者來源統計等場景。
使用者掃描帶場景值二維碼時,可能推送以下兩種事件:
如果使用者還未關注公眾號,則使用者可以關注公眾號,關注後微信會將帶場景值關注事件推送給開發者。
如果使用者已經關注公眾號,在使用者掃描後會自動進入會話,微信也會將帶場景值掃描事件推送給開發者。
獲取帶引數的二維碼的過程包括兩步,首先建立二維碼ticket,然後憑藉ticket到指定URL換取二維碼。
// 臨時二維碼
private final static String QR_SCENE = "QR_SCENE";
// 永久二維碼
private final static String QR_LIMIT_SCENE = "QR_LIMIT_SCENE";
// 永久二維碼(字串)
private final static String QR_LIMIT_STR_SCENE = "QR_LIMIT_STR_SCENE";
// 建立二維碼
private String create_ticket_path = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
// 通過ticket換取二維碼
private static String showqrcode_path = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";
/**
* 建立永久二維碼(字串)
* @param sceneStr 場景值
* @param accessToken
* @return
*/
public static Map createForeverStrQr(String sceneStr,String accessToken ) {
RestTemplate rest = new RestTemplate();
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+accessToken ;
// 引數:{"action_name": "QR_LIMIT_STR_SCENE", "action_info": {"scene": {"scene_str": sceneStr}}}
Map<String,Object> param = new HashMap<String, Object>();
param.put("action_name", "QR_LIMIT_STR_SCENE");
Map<String,Object> action = new HashMap<String, Object>();
action.put("pId", "");
Map<String,Object> scene = new HashMap<String, Object>();
scene.put("scene_str", sceneStr);
action.put("scene", scene);
param.put("action_info", action);
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
HttpEntity requestEntity = new HttpEntity(param, headers);
Map result = null;
try {
ResponseEntity<Map> entity = rest.exchange(url, HttpMethod.POST, requestEntity,Map.class, new Object[0]);
System.out.println("呼叫生成微信永久二維碼URL介面返回結果:" + entity.getBody());
result = (Map) entity.getBody();
} catch (Exception e) {
System.out.println("呼叫生成微信永久二維碼URL介面異常"+e);
}
if(result!=null){
return result;
}
return null;
}
/**
* 建立臨時帶引數二維碼
* @param accessToken
* @expireSeconds 該二維碼有效時間,以秒為單位。 最大不超過2592000(即30天),此欄位如果不填,則預設有效期為30秒。
* @param sceneId 場景Id
* @return
*/
public static String createTempQr(String accessToken, String expireSeconds, String sceneStr) {
RestTemplate rest = new RestTemplate();
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+accessToken ;
// 引數:{"expire_seconds": 604800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": 123}}}
Map<String,String> intMap = new HashMap<String,String>();
intMap.put("scene_str",sceneStr);
Map<String,Map<String,String>> mapMap = new HashMap<String,Map<String,String>>();
mapMap.put("scene", intMap);
Map<String,Object> paramsMap = new HashMap<String,Object>();
paramsMap.put("expire_seconds", expireSeconds);
paramsMap.put("action_name", QR_SCENE);
paramsMap.put("action_info", mapMap);
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
HttpEntity requestEntity = new HttpEntity(paramsMap, headers);
Map result = null;
try {
ResponseEntity<Map> entity = rest.exchange(url, HttpMethod.POST, requestEntity,Map.class, new Object[0]);
System.out.println("呼叫生成微信臨時二維碼URL介面返回結果:" + entity.getBody());
result = (Map) entity.getBody();
} catch (Exception e) {
System.out.println("呼叫生成微信臨時二維碼URL介面異常"+e);
}
if(result!=null){
return (String) result.get("ticket");
}
return null;
}
/**
* 獲取access_token
* @param appid 憑證
* @param appsecret 金鑰
* @return
*/
public static String getAccessToken() {
String result = HttpRequestUtil.getAccessToken(WhParamesAPI.WX_APPID,WhParamesAPI.WX_SECRET);
try {
JSONObject jsonObject = JSONObject.parseObject(result);
String accessToken = (String) jsonObject.get("access_token");
return accessToken;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
//列印二維碼地址
System.out.println(showqrcode_path+createTempQr(getAccessToken(),"2592000","o3Y6l1As68lzErl8jmOxhta8uhLg"));
}
/**
* HttpRequestUtil 工具類
*
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import com.thinkgem.jeesite.common.utils.StringUtils;
import com.thinkgem.jeesite.common.utils.wechat.MyX509TrustManager;
public class HttpRequestUtil {
//private static Logger logger = Logger.getLogger(HttpRequestUtil.class);
public static final String GET_METHOD = "GET";
public static final String POST_METHOD = "POST";
public static final String DEFAULT_CHARSET = "utf-8";
private static int DEFAULT_CONNTIME = 5000;
private static int DEFAULT_READTIME = 5000;
// 獲取access_token的路徑
private static String token_path = "https://api.weixin.qq.com/cgi-bin/token";
/**
* http請求
*
* @param method
* 請求方法GET/POST
* @param path
* 請求路徑
* @param timeout
* 連線超時時間 預設為5000
* @param readTimeout
* 讀取超時時間 預設為5000
* @param data 資料
* @return
*/
public static String defaultConnection(String method, String path, int timeout, int readTimeout, String data)
throws Exception {
String result = "";
URL url = new URL(path);
if (url != null) {
HttpURLConnection conn = getConnection(method, url);
conn.setConnectTimeout(timeout == 0 ? DEFAULT_CONNTIME : timeout);
conn.setReadTimeout(readTimeout == 0 ? DEFAULT_READTIME : readTimeout);
if (data != null && !"".equals(data)) {
OutputStream output = conn.getOutputStream();
output.write(data.getBytes(DEFAULT_CHARSET));
output.flush();
output.close();
}
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
InputStream input = conn.getInputStream();
result = inputToStr(input);
input.close();
conn.disconnect();
}
}
return result;
}
/**
* 根據url的協議選擇對應的請求方式 例如 http://www.baidu.com 則使用http請求,https://www.baidu.com
* 則使用https請求
*
* @param method
* 請求的方法
* @return
* @throws IOException
*/
private static HttpURLConnection getConnection(String method, URL url) throws IOException {
HttpURLConnection conn = null;
if ("https".equals(url.getProtocol())) {
SSLContext context = null;
try {
context = SSLContext.getInstance("SSL", "SunJSSE");
context.init(new KeyManager[0], new TrustManager[] { new MyX509TrustManager() },
new java.security.SecureRandom());
} catch (Exception e) {
throw new IOException(e);
}
HttpsURLConnection connHttps = (HttpsURLConnection) url.openConnection();
connHttps.setSSLSocketFactory(context.getSocketFactory());
connHttps.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
conn = connHttps;
} else {
conn = (HttpURLConnection) url.openConnection();
}
conn.setRequestMethod(method);
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
return conn;
}
/**
* 將輸入流轉換為字串
*
* @param input
* 輸入流
* @return 轉換後的字串
*/
public static String inputToStr(InputStream input) {
String result = "";
if (input != null) {
byte[] array = new byte[1024];
StringBuffer buffer = new StringBuffer();
try {
for (int index; (index = (input.read(array))) > -1;) {
buffer.append(new String(array, 0, index, DEFAULT_CHARSET));
}
result = buffer.toString();
} catch (IOException e) {
e.printStackTrace();
result = "";
}
}
return result;
}
/**
* 設定引數
*
* @param map
* 引數map
* @param path
* 需要賦值的path
* @param charset
* 編碼格式 預設編碼為utf-8(取消預設)
* @return 已經賦值好的url 只需要訪問即可
*/
public static String setParmas(Map<String, String> map, String path, String charset) throws Exception {
String result = "";
boolean hasParams = false;
if (path != null && !"".equals(path)) {
if (map != null && map.size() > 0) {
StringBuilder builder = new StringBuilder();
Set<Entry<String, String>> params = map.entrySet();
for (Entry<String, String> entry : params) {
String key = entry.getKey().trim();
String value = entry.getValue().trim();
if (hasParams) {
builder.append("&");
} else {
hasParams = true;
}
if(charset != null && !"".equals(charset)){
//builder.append(key).append("=").append(URLDecoder.(value, charset));
builder.append(key).append("=").append(urlEncode(value, charset));
}else{
builder.append(key).append("=").append(value);
}
}
result = builder.toString();
}
}
return doUrlPath(path, result).toString();
}
/**
* 設定連線引數
*
* @param path
* 路徑
* @return
*/
private static URL doUrlPath(String path, String query) throws Exception {
URL url = new URL(path);
if (StringUtils.isEmpty(path)) {
return url;
}
if (StringUtils.isEmpty(url.getQuery())) {
if (path.endsWith("?")) {
path += query;
} else {
path = path + "?" + query;
}
} else {
if (path.endsWith("&")) {
path += query;
} else {
path = path + "&" + query;
}
}
return new URL(path);
}
/**
* 預設的http請求執行方法,返回
*
* @param method
* 請求的方法 POST/GET
* @param path
* 請求path 路徑
* @param map
* 請求引數集合
* @param data
* 輸入的資料 允許為空
* @return
*/
public static String HttpDefaultExecute(String method, String path, Map<String, String> map, String data) {
String result = "";
try {
String url = setParmas((TreeMap<String, String>) map, path, "");
result = defaultConnection(method, url, DEFAULT_CONNTIME, DEFAULT_READTIME, data);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 預設的https執行方法,返回
*
* @param method
* 請求的方法 POST/GET
* @param path
* 請求path 路徑
* @param map
* 請求引數集合
* @param data
* 輸入的資料 允許為空
* @return
*/
public static String HttpsDefaultExecute(String method, String path, Map<String, String> map, String data) {
String result = "";
try {
String url = setParmas((TreeMap<String, String>) map, path, "");
result = defaultConnection(method, url, DEFAULT_CONNTIME, DEFAULT_READTIME, data);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 獲取授權token
*
* @param key 應用key
* @param secret 應用密匙
* @return json格式的字串
*/
public static String getAccessToken(String key, String secret) {
TreeMap<String, String> map = new TreeMap<String, String>();
map.put("grant_type", "client_credential");
map.put("appid", key);
map.put("secret", secret);
String result = HttpDefaultExecute(GET_METHOD, token_path, map, "");
return result;
}
public static String urlEncode(String source, String encode) {
String result = source;
try {
result = URLEncoder.encode(source, encode);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
}