首先說下業務場景
需要從某個頁面生成二維碼,用戶掃描二維碼,如果已關注公衆號,跳到公衆號頁面,推送小程序鏈接
如果還未關注公衆號,跳轉到關注頁面,關注公衆號後推送小程序鏈接。
當然從公衆號跳轉到小程序,多多少少是需要帶一點業務相關參數的。
本篇主要將二維碼生成,以及事件推送
一、二維碼生成
根據官方文檔介紹,目前公衆號二維碼主要有永久和臨時兩種,但是永久二維碼是有數量限制的,臨時二維碼攜帶參數又有限制。
所以我們一般都使用臨時二維碼
生成二維碼的動作主要有兩步,第一步根據參數拿到二維碼ticket,第二步根據ticket換取二維碼
首先看獲取二維碼的參數
拼接結構如下:{“action_name”: “QR_LIMIT_SCENE”, “action_info”: {“scene”: {“scene_id”: 123}}}
注意scene是在action_info 裏面的
請求URL爲 :https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN 類型爲POST
返回數據是這樣的
{“ticket”:“gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm
3sUw==”,“expire_seconds”:60,“url”:“http://weixin.qq.com/q/kZgfwMTm72WWPkovabbI”}
下面上具體代碼
/**
* 創建臨時帶參二維碼
*
* @param accessToken 接口訪問憑證
* @param expireSeconds 二維碼有效時間,單位爲秒,最大不超過1800
* @param sceneId 場景ID
* @return WeixinQRCode
*/
public WeixinQRCode createTemporaryQRCode(String accessToken, int expireSeconds, String sceneStr) {
QRCodeParMapping byMappingValue = qrCodeParamMappingUtil.getQrcodeParMappingByMappingValue(sceneStr);
Integer mappingID = null;
if (byMappingValue == null) {
byMappingValue = new QRCodeParMapping();
byMappingValue.setMappingValue(sceneStr);
qrCodeParamMappingUtil.save(byMappingValue);
}
mappingID = byMappingValue.getMappingID();
sceneStr = mappingID.toString();
System.out.println("二維碼攜帶參數爲" + sceneStr);
WeixinQRCode weixinQRCode = null;
// 拼接請求地址
String requestUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=ACCESS_TOKEN";
requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken);
// 需要提交的json數據
String jsonMsg = "{\"expire_seconds\": %d, \"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": %s}}}";
// 創建臨時帶參二維碼
JSONObject jsonObject = WechatUtil.httpsRequest(requestUrl, "POST",
String.format(jsonMsg, expireSeconds, sceneStr));
if (null != jsonObject) {
try {
weixinQRCode = new WeixinQRCode();
weixinQRCode.setTicket(jsonObject.getString("ticket"));
weixinQRCode.setExpireSeconds(jsonObject.getInt("expire_seconds"));
logger.info("創建臨時帶參二維碼成功 ticket:{} expire_seconds:{}", weixinQRCode.getTicket(),
weixinQRCode.getExpireSeconds());
} catch (Exception e) {
weixinQRCode = null;
int errorCode = jsonObject.getInt("errcode");
String errorMsg = jsonObject.getString("errmsg");
logger.error("創建臨時帶參二維碼失敗 errcode:{} errmsg:{}", errorCode, errorMsg);
}
}
return weixinQRCode;
}
/**
* 發起https請求並獲取結果
*
* @param requestUrl 請求地址
* @param requestMethod 請求方式(GET、POST)
* @param outputStr 提交的數據
* @return JSONObject(通過JSONObject.get ( key)的方式獲取json對象的屬性值)
*/
public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try {
// 創建SSLContext對象,並使用我們指定的信任管理器初始化
TrustManager[] tm = {new MyX509TrustManager()};
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 從上述SSLContext對象中得到SSLSocketFactory對象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 設置請求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);
if ("GET".equalsIgnoreCase(requestMethod))
httpUrlConn.connect();
// 當有數據需要提交時
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意編碼格式,防止中文亂碼
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 將返回的輸入流轉換成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 釋放資源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
log.error("Weixin server connection timed out.");
} catch (Exception e) {
log.error("https request error:{}", e);
}
return jsonObject;
}
/**
* 臨時二維碼信息
*
* @author liufeng
* @date 2013-11-10
*/
public class WeixinQRCode {
// 獲取的二維碼ticket
private String ticket;
// 二維碼的有效時間,單位爲秒,最大不超過1800
private int expireSeconds;
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public int getExpireSeconds() {
return expireSeconds;
}
public void setExpireSeconds(int expireSeconds) {
this.expireSeconds = expireSeconds;
}
}
一共兩個方法 一個類
第一個方法是生成二維碼的步驟,三個參數:1、accessToken 請自備2、過期時間 3、二維碼攜帶參數
第二個方法是訪問微信的GET請求
第三個二維碼實體類
這裏要額外說一個事情,
第一個查詢映射的方法,是幹什麼的
首先上面參數有說過,二維碼可攜帶參數有scene_id 和scene_str 但是臨時二維碼 只能用ID(關乎於後面的事件推送) 並且是32位非零整型,長度有限制,所以個人做了個參數映射,生成二維碼碼的參數在數據庫關聯一個ID,每次ID自增,每次傳參要查詢是否有對應的ID,沒有就生成一個新的
這部分邏輯很簡單先不上代碼了,如不需要,可自行註釋代碼,有需要可能後面會補。
這樣我們就拿到了二維碼的ticket
獲取二維碼就很簡單了
通過訪問鏈接就可以直接拿到二維碼
官方是這麼寫的:
HTTP GET請求(請使用https協議)https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
提醒:TICKET記得進行UrlEncode
ticket正確的情況下,狀態碼200,是一張圖片可以下載。錯誤的話可能是404
這裏額外再說一句,那個攜帶參數,即使是它不支持或者超出限制了,二維碼仍然會正常返回,但是參數不會正常攜帶到後面的事件裏面
二、事件接收以及消息推送
首先說事件接收,這個事件接收是一個很廣的概念,可以接收很多類型的事件,官方是這麼寫的
事件推送的URL需要在公衆號後臺自行配置,是一個URL哦~不同的事件按照分類進行區別開發
二維碼的推送參數如下:
這是我代碼中打印的 已關注用戶推送的
根據這個我們能拿到二維碼攜帶過來的參數 就是Eventkey。
未關注用戶推送的:
注意未關注用戶的參數前面帶一個qrscene_ 獲取時自行截取
事件到了 我們需要做處理
這裏返回的不是模版消息,是客服消息
看官方文檔
消息類型是這樣,我的需求是要跳轉到小程序 並沒有鏈接類型
所以就使用文本類型,裏面自己嵌入鏈接,官方給出了方法
發送文本消息時,支持插入跳小程序的文字鏈
文本內容<a href="http://www.qq.com" data-miniprogram-appid="appid" data-miniprogram-path="pages/index/index">點擊跳小程序</a>
說明: 1.data-miniprogram-appid 項,填寫小程序appid,則表示該鏈接跳小程序; 2.data-miniprogram-path項,填寫小程序路徑,路徑與app.json中保持一致,可帶參數; 3.對於不支持data-miniprogram-appid 項的客戶端版本,如果有herf項,則仍然保持跳href中的網頁鏈接; 4.data-miniprogram-appid對應的小程序必須與公衆號有綁定關係。
下一篇詳細介紹怎麼回消息以及代碼~