springboot框架開發微信公眾號(四)之自定義選單的使用
阿新 • • 發佈:2018-11-30
關於自定義選單,微信為我們提供了幾個介面分別是建立、查詢和刪除。我們平時使用最多的就是建立選單了,往往我們執行了建立選單的程式碼後,選單並不會當即在我們關注過的公眾號上顯示出來,我們可以通過重新關注的方法,來檢視我們建立或更改後的選單。下面就來跟筆者來學一學這些介面的使用方法吧
一、由於這幾個介面都是https協議,所以我們首先要能讓我們的程式可以請求https。
對於https請求,我們需要一個證書信任管理器, 這個管理器類需要自己定義,但需要實現X509TrustManager介面程式碼如下:
public class MyX509TrustManager implements X509TrustManager{ /** * 該方法用於檢查客戶端的證書,若不信則丟擲異常 * 由於我們不需要對客戶端進行認證,可以不做任何處理 */ @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateEncodingException{ } /** * 該方法用於檢驗伺服器端的證書,若不信任則丟擲異常 * 通過自己實現該方法,可以使之信任我們指定的任何證書 * 在實現該方法時,也可以不做任何處理,即一個空的方法實現 * 由於不會丟擲異常,它就會信任任何證書 */ @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateEncodingException{ } /** * 返回收信任的X509證書陣列 */ @Override public X509Certificate[] getAcceptedIssuers(){ return null; }
發起https請求工具類
/** * * @Description: 發起https請求並獲取結果 * @Parameters: requestUrl 請求地址。 需要寫全地址,即前邊的http必須寫上,不能只寫www.baidu.com這樣的。 * requestMethod 請求方式(GET、POST) * outputStr 我們在發起請求的時候傳遞引數到所要請求的伺服器, * 要傳遞的引數也要看介面文件確定格式,一般是封裝成json或xml. * @Return: JSONObject(通過JSONObject.get(key)的方式獲取json物件的屬性值) * @Create Date: 2018年9月19日上午8:20:33 * @Version: V1.00 * @author: 來日可期 */ @Component public class HttpRequestUtil { Logger logger = LoggerFactory.getLogger(HttpRequestUtil.class); public JSONObject httpsRequest(String requestUrl,String requestMethod,String outputStr){ //初始化一個json物件 JSONObject jsonObject = null; try { //建立SSLContext物件,並使用我們指定的信任管理器初始化 TrustManager[] tmManagers = {new MyX509TrustManager()}; SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE"); sslContext.init(null, tmManagers, new java.security.SecureRandom()); //從上述SSLContext物件中得到SSLSocketFactory物件 SSLSocketFactory sslSocket = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection httpsURLConnection = (HttpsURLConnection)url.openConnection(); httpsURLConnection.setSSLSocketFactory(sslSocket); httpsURLConnection.setDoOutput(true); /*httpUrlConnection.setDoOutput(true);以後就可以使用conn.getOutputStream().write() httpUrlConnection.setDoInput(true);以後就可以使用conn.getInputStream().read(); get請求用不到conn.getOutputStream(),因為引數直接追加在地址後面,因此預設是false。 post請求(比如:檔案上傳)需要往服務區傳輸大量的資料,這些資料是放在http的body裡面的,因此需要在建立連線以後,往服務端寫資料。 因為總是使用conn.getInputStream()獲取服務端的響應,因此預設值是true。 */ httpsURLConnection.setDoInput(true); httpsURLConnection.setUseCaches(false); //設定請求方式 GET/POST httpsURLConnection.setRequestMethod(requestMethod); if ("GET".equalsIgnoreCase(requestMethod)) { //不考慮大小寫。如果兩個字串的長度相等,並且兩個字串中的相應字元都相等(忽略大小寫),則認為這兩個字串是相等的。 httpsURLConnection.connect(); } //當有資料需要提交時,往伺服器端寫內容 也就是發起http請求需要帶的引數 if (null != outputStr) { OutputStream outputStream = httpsURLConnection.getOutputStream(); //注意編碼格式,防止中文亂碼 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } //獲得輸入流 讀取伺服器端返回的內容 InputStream inputStream = httpsURLConnection.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer stringBuffer = new StringBuffer(); while((str = bufferedReader.readLine()) != null){ stringBuffer.append(str); } //釋放資源 bufferedReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; httpsURLConnection.disconnect(); //將字串轉換為json物件 jsonObject = JSONObject.fromObject(stringBuffer.toString()); System.out.println("JSONObject---------------------->"+jsonObject); } catch (ConnectException ce) { logger.error("Weixin server connection timed out."); } catch(Exception e){ logger.error("https request error:{}",e); } return jsonObject; } }
二、封裝選單類,共有五種,將它們放到一個包下
/** * @Description: 按鈕的基類(每個按鈕物件都有一個共同的name屬性, * 因此需要定義一個按鈕物件的基類,所有按鈕物件都需要繼承該類) * @Parameters: * @Return: * @Create Date: 2018年3月10日上午9:30:27 * @Version: V1.00 * @author: 來日可期 */ public class Button { private String name; public void setName(String name){ this.name = name; } public String getName(){ return name; } } /** * @Description: click型別的按鈕(有type、name和key3個屬性) * @Parameters: * @Return: * @Create Date: 2018年3月10日上午9:35:30 * @Version: V1.00 * @author: 來日可期 */ public class ClickButton extends Button { private String type; private String key; public String getType() { return type; } public void setType(String type) { this.type = type; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } } /** * @Description: view型別的按鈕(有type、name、url三個屬性) * @Parameters: * @Return: * @Create Date: 2018年3月10日上午9:39:06 * @Version: V1.00 * @author: 來日可期 */ public class ViewButton extends Button{ public String type; public String url; public String getType() { return type; } public void setType(String type) { this.type = type; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } /** * @Description: 複合型別的按鈕(也就是含有子選單的一級選單) * @Parameters: * @Return: * @Create Date: 2018年3月10日上午9:43:13 * @Version: V1.00 * @author: 來日可期 */ public class ComplexButton extends Button{ private Button[] sub_button; public Button[] getSub_button() { return sub_button; } public void setSub_button(Button[] sub_button) { this.sub_button = sub_button; } } /** * @Description: 選單 * @Parameters: * @Return: * @Create Date: 2018年3月10日上午9:47:20 * @Version: V1.00 * @author: 來日可期 */ public class Menu { private Button[] button; public Button[] getButton() { return button; } public void setButton(Button[] button) { this.button = button; } }
三、利用封裝的選單類和按鈕類,編輯自己的自定義選單
click型別的按鈕,key值對應微信請求訊息中MsgType(請求訊息的型別)中Event(事件)的EventKey(事件的key值)
package com.b505.weixin.util;
import com.b505.weixin.menu.Button;
import com.b505.weixin.menu.ClickButton;
import com.b505.weixin.menu.Menu;
import com.b505.weixin.menu.ViewButton;
/**
* @Description: 選單管理器類
* @Parameters:
* @Return:
* @Create Date: 2018年9月28日下午4:33:24
* @Version: V1.00
* @author: 來日可期
*/
public class WechatMenuManagerUtil {
/**
* @Description: 定義選單結構
* @Parameters:
* @Return:
* @Create Date: 2018年9月28日下午5:36:08
* @Version: V1.00
* @author: 來日可期
*/
public Menu getMenu(){
ClickButton firstClickButton = new ClickButton();
firstClickButton.setName("功能圖文");
firstClickButton.setKey("function");
firstClickButton.setType("click");
ViewButton firstViewButton = new ViewButton();
firstViewButton.setName("聯絡我們");
firstViewButton.setType("view");
firstViewButton.setUrl("");
Menu menu = new Menu();
Button[] boButtons = {firstClickButton,firstViewButton};
menu.setButton(boButtons);
return menu;
}
}
四、編寫自定義選單工具類,呼叫微信介面,實現選單的建立,查詢與刪除
如果是建立選單,則需要將第三步中編輯好的選單一併請求給建立自定義選單介面
package com.b505.weixin.util;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.b505.util.HttpRequestUtil;
import com.b505.weixin.menu.Menu;
/**
* @Description: 自定義選單工具類,包括選單的建立、查詢、刪除
* @Parameters:
* @Return:
* @Create Date: 2018年9月19日下午7:46:27
* @Version: V1.00
* @author: 來日可期
*/
@Component
public class WechatMenuUtil {
Logger logger = LoggerFactory.getLogger(WechatMenuUtil.class);
@Autowired
private HttpRequestUtil httpRequestUtil;
/**
* @Parameters: menu 選單例項
* accessToken 憑證
* @Return: true false
* @Return:
* @Create Date: 2018年9月22日上午7:45:53
* @Version: V1.00
* @author: 來日可期
*/
public boolean creatMenu(Menu menu,String accessToken){
boolean result = false;
String url = WechatConstants.MENU_CREATE_URL.replace("ACCESS_TOKEN", accessToken);
//將選單物件轉換成JSON字串
String jsonMenu = JSONObject.fromObject(menu).toString();
//發起POST請求建立選單
JSONObject jsonObject = httpRequestUtil.httpsRequest(url, "POST", jsonMenu);
if (null != jsonObject) {
int errorCode = jsonObject.getInt("errcode");
String errorMsg = jsonObject.getString("errmsg");
if (0== errorCode) {
result = true;
} else {
result = false;
logger.error("建立選單失敗 errcode:{} errmsg:{} ",errorCode,errorMsg);
}
}
return result;
}
/**
*
* @Description: 查詢選單
* @Parameters:
* @Return:
* @Create Date: 2018年3月13日下午2:24:02
* @Version: V1.00
* @author: 來日可期
*/
public String getMenu(String accessToken){
String result = null;
String requestUrl = WechatConstants.MENU_GET_URL.replace("ACCESS_TOKEN", accessToken);
//發起GET請求查詢選單
JSONObject jsonObject = httpRequestUtil.httpsRequest(requestUrl, "GET", null);
if (null != jsonObject) {
result = jsonObject.toString();
}
return result;
}
/**
*
* @Description: 刪除選單
* @Parameters:
* @Return:
* @Create Date: 2018年3月13日下午2:31:15
* @Version: V1.00
* @author: 來日可期
*/
public boolean deleteMenu(String accessToken){
boolean result = false;
String requestUrl = WechatConstants.MENU_DELETE_URL.replace("ACCESS_TOKEN", accessToken);
//發起GET請求刪除選單
JSONObject jsonObject = httpRequestUtil.httpsRequest(requestUrl, "GET", null);
if (null != jsonObject) {
int errorCode = jsonObject.getInt("errcode");
String errorMsg = jsonObject.getString("errmsg");
if (0== errorCode) {
result = true;
} else {
result = false;
logger.error("建立選單失敗 errcode:{} errmsg:{} ",errorCode,errorMsg);
}
}
return result;
}
}
五、編寫獲取access_token的工具類
呼叫微信高階介面需要憑證access_token,所以在這之前我們需要獲取access_token.
package com.b505.weixin.util;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.b505.util.HttpRequestUtil;
import com.b505.weixin.pojo.AccessToken;
@Component
public class WechatCommonUtil {
Logger logger = LoggerFactory.getLogger(WechatCommonUtil.class);
//獲取access_token介面
private static String token_url = WechatConstants.ACCESS_TOKEN_URL;
@Autowired
HttpRequestUtil httpRequestUtil;
/**
* @Description: 獲取微信呼叫高階介面的憑證(access_token)
* @Parameters:
* @Return:
* @Create Date: 2018年9月28日下午12:22:55
* @Version: V1.00
* @author: 來日可期
*/
public AccessToken getAccessToken(String appid,String appsecret){
//將公眾號的appid和appsecret替換進url
String url = token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
AccessToken accessToken = new AccessToken();
//發起get請求獲取憑證
JSONObject jsonObject = httpRequestUtil.httpsRequest(url,"GET",null);
logger.info("獲取到的json格式的Token為:"+jsonObject);
if (jsonObject!=null) {
try {
accessToken.setAccess_token(jsonObject.getString("access_token"));
accessToken.setExpires_in(jsonObject.getInt("expires_in"));
} catch (Exception e) {
accessToken = null;
//獲取token失敗
logger.error("獲取token失敗 errcode:{} errmsg:{}",
jsonObject.getInt("errcode"),
jsonObject.getString("errmsg"));
}
}
return accessToken;
}
}
六、編寫主方法,進行自定義選單建立
package com.b505.weixin.main;
import com.b505.weixin.menu.Menu;
import com.b505.weixin.util.WechatCommonUtil;
import com.b505.weixin.util.WechatConstants;
import com.b505.weixin.util.WechatMenuManagerUtil;
import com.b505.weixin.util.WechatMenuUtil;
/**
* @Description: 建立自定義選單主方法
* @Parameters:
* @Return:
* @Create Date: 2018年9月28日下午2:25:33
* @Version: V1.00
* @author: 來日可期
*/
public class WechatCreatDefaultMenu {
public static void main(String[] args){
WechatCommonUtil wechatCommonUtil = new WechatCommonUtil();
WechatMenuUtil wechatMenuUtil = new WechatMenuUtil();
WechatMenuManagerUtil wechatMenuManagerUtil = new WechatMenuManagerUtil();
String appid = "公眾號的appid";
String appsecret = "公眾號的appsecret";
//獲取access_token
String accessToken = wechatCommonUtil.getAccessToken(appid, appsecret).getAccess_token();
//獲取選單結構
Menu menu = wechatMenuManagerUtil.getMenu();
if (accessToken!=null) {
//生成選單
boolean result = wechatMenuUtil.creatMenu(menu, accessToken);
if (result) {
System.out.println("選單建立成功");
}else {
System.out.println("選單建立失敗");
}
}else {
System.out.println("token為空");
}
}
}