springboot框架開發微信公衆號(四)之自定義菜單的使用

關於自定義菜單,微信爲我們提供了幾個接口分別是創建、查詢和刪除。我們平時使用最多的就是創建菜單了,往往我們執行了創建菜單的代碼後,菜單並不會當即在我們關注過的公衆號上顯示出來,我們可以通過重新關注的方法,來查看我們創建或更改後的菜單。下面就來跟筆者來學一學這些接口的使用方法吧

一、由於這幾個接口都是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爲空");
		}	
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章