日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自定义菜单用例

發(fā)布時間:2023/12/31 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自定义菜单用例 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2013年8月5日,伴隨著微信5.0 iPhone版的發(fā)布,公眾平臺也進(jìn)行了重要的更新,主要包括:

  • 運營主體為組織,可選擇成為服務(wù)號或者訂閱號;
  • 服務(wù)號可以申請自定義菜單;
  • 使用QQ登錄的公眾號,可以升級為郵箱登錄;
  • 使用郵箱登錄的公眾號,可以修改登錄郵箱;
  • 編輯圖文消息可選填作者;
  • 群發(fā)消息可以同步到騰訊微博。
  • 其中,大家議論最多的當(dāng)屬前兩條,就是關(guān)于帳號類型和自定義菜單的更新,我這里做幾點補充說明:

  • 目前公眾號類型分為兩種:服務(wù)號和訂閱號,8月5日平臺更新后所有的帳號默認(rèn)為訂閱號,有一次轉(zhuǎn)換成服務(wù)號的機會;
  • 服務(wù)號主要面向企業(yè)、政府和其他組織,而訂閱號主要面向媒體和個人;
  • 只有服務(wù)號可以申請自定義菜單,訂閱號不能申請;
  • 服務(wù)號每月只能群發(fā)一條消息,而訂閱號每天能群發(fā)一條消息。
  • 平臺更新后,讓很多人糾結(jié)的是自定義菜單和每天群發(fā)一條消息不可兼得,對此,我不想過多評論。

    引言及內(nèi)容概要

    在微信5.0以前,自定義菜單是作為一種內(nèi)測資格使用的,只有少數(shù)公眾帳號擁有菜單,因此出現(xiàn)很多企業(yè)為了弄到菜單不惜重金求購。現(xiàn)如今,一大批帳號從訂閱號轉(zhuǎn)為服務(wù)號,很多都是奔著自定義菜單去的。而且,經(jīng)測試發(fā)現(xiàn),微信最近的審核放松很多,只要申請服務(wù)號、自定義菜單的基本都成功了,根本不管填寫的資料真?zhèn)巍2恢酪院笪⑿艜粫?#xff0c;要求補全企業(yè)資料,那將會是一種給小孩一顆糖吃再把他打哭的感覺。。。

    自定義菜單是申請到了,到底該怎么創(chuàng)建、怎么使用呢?最近幾天不管是微信官方交流群,還是在我博客留言里,都能夠看到不少開發(fā)者都在為這個發(fā)愁。本篇文章就為大家解決這個難題。

    自定義菜單的創(chuàng)建步驟

  • 找到AppId和AppSecret。自定義菜單申請成功后,在"高級功能"-"開發(fā)模式"-"接口配置信息"的最后兩項就是;
  • 根據(jù)AppId和AppSecret,以https get方式獲取訪問特殊接口所必須的憑證access_token;
  • 根據(jù)access_token,將json格式的菜單數(shù)據(jù)通過https post方式提交。
  • 分析創(chuàng)建菜單的難點

    原來創(chuàng)建菜單這么簡單,三步就能搞定?跟把大象放冰箱差不多。呵呵,當(dāng)然沒有這么簡單,那我們一步步來看,到底難在哪里?

    首先,第1步肯定都沒有問題,只要成功申請了自定義菜單,一定能拿到AppId和AppSecret這兩個值。

    再來看第2步,由于是get方式獲取access_token,很多人直接把拼好的url放在瀏覽器里執(zhí)行,access_token就拿到了。拋開是不是用編程方式實現(xiàn)的來說,這真是個好辦法,顯然大家在第二步上也沒有問題。

    最后再看第3步,拼裝json格式的菜單數(shù)據(jù),雖然繁鎖一點,但基本上也都沒有什么問題的,因為官方給了個例子,照貓畫虎就行了。那問題一定就出現(xiàn)在https post提交上了。

    結(jié)論:不知道如何創(chuàng)建自定義菜單的朋友,大都可以歸為以下三種情況:

  • 根本不看或者沒看懂公眾平臺API文檔中關(guān)于"通用接口"、"自定義菜單接口"和"使用限制"部分的說明;
  • 不知道如何發(fā)起HTTPS請求(平時的http請求,直接使用HttpUrlConnection就可以輕松搞定,但https請求要復(fù)雜一點);
  • 不知道如何通過POST方式提交json格式的菜單數(shù)據(jù)。
  • 正在看文章的你,不知道是屬于哪一種,或者幾種情況都有,不妨留言說出來,也可以做個調(diào)查。不管屬于哪一種情況,既然看到了這篇文章,相信一定會讓你弄明白的。

    解讀通用接口文檔---憑證的獲取

    我們先來看通用接口文檔的簡介部分,如下圖所示。

    通俗點講,這段簡介可以這么理解:公眾平臺還有很多特殊的接口,像自定義菜單的創(chuàng)建、語音文件的獲取、主動發(fā)送消息等,如果開發(fā)者想通過HTTP請求訪問這些特殊接口,就必須要有訪問憑證,也就是access_token。

    那么,又該如何獲取接口訪問憑證access_token呢?讓我們繼續(xù)往下看。

    圖中已經(jīng)表達(dá)的很清楚了,獲取access_token是通過GET方式訪問如下鏈接:

    https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

    鏈接中有三個參數(shù),分別是grant_type、appid和secret。根據(jù)圖中的參數(shù)說明,grant_type傳固定值client_credential,而appid和secret就是申請完自定義菜單后微信分配給我們的。

    請求發(fā)送成功后,微信服務(wù)器會返回一個json串,包含access_token和expires_in兩個元素。其中,access_token就是我們最終需要的憑證,而expires_in是憑證的有效期,單位是秒,7200秒也就是2個小時。這就意味著,不是每次訪問特殊接口,都需要重新獲取一次access_token,只要access_token還在有效期內(nèi),就一直可以使用。

    解讀自定義菜單接口文檔

    還是一樣,先來看看自定義菜單接口的簡介部分,如下圖所示。

    從圖中我們能夠獲取到以下信息:

  • 拿到憑證access_token后,我們能對菜單執(zhí)行三種操作:創(chuàng)建、查詢和刪除;
  • 自定義菜單目前只支持click一種事件,即用戶點擊后回復(fù)某種類型的消息;不能夠?qū)崿F(xiàn)點擊菜單項直接打開頁面(type=view未開放,目前只是微生活有);
  • 由于微信客戶端緩存的原因,菜單創(chuàng)建后并不會立即在微信上顯示出來,需要過24小時。在測試菜單創(chuàng)建時,可以通過取消關(guān)注后,再關(guān)注的方式達(dá)到立即看菜單的目的。
  • 繼續(xù)往下看,就是關(guān)于菜單怎么創(chuàng)建的介紹了,如下圖所示。

    其實就是向地址https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN以POST方式提交一個JSON格式的菜單字符串。

    后面,關(guān)于參數(shù)說明的部分我就不一一貼圖說明了,把重點說一下:

  • 自定義菜單是一個3x5結(jié)構(gòu)的,即菜單最多只能有二級,一級菜單最多只能有3個,每個一級菜單下最多可以有5個二級菜單項;
  • 菜單項都有一個key值。當(dāng)用戶點擊某個菜單項時,微信會將該菜單項的key值以事件推送的方式發(fā)送給我們的后臺處理程序。
  • 關(guān)于菜單的查詢、創(chuàng)建我就不提了,這兩個接口使用的頻率非常小,一般都用不上。如果需要,再按照我上面提供的思路也不難理解。

    解讀API文檔之使用限制

    很多小伙伴看到這張圖就開始疑惑了:怎么菜單還限制使用次數(shù),用戶量越來越大的時候,根本不夠用啊。看清楚,這個限制是針對接口調(diào)用的,也就是針對開發(fā)者的,和用戶數(shù)、使用次數(shù)半點關(guān)系也沒有。

    就先拿獲取憑證接口來說吧,限制一天只能調(diào)用200次。還記得前面提到過access_token是有有效期的,并且有效期為兩小時,也就是獲取一次access_token后的兩小時內(nèi),都可以繼續(xù)使用,那么理想情況一天24小時內(nèi),是不是只需要獲取12次就夠了?難道200次還不夠用?

    再來看下菜單創(chuàng)建接口限制一天只能調(diào)用100次。我就這么解釋吧,菜單創(chuàng)建一次后,只要你不切換模式(指的是在編輯模式和開發(fā)模式間切換)、不調(diào)用刪除接口,這個菜單會永遠(yuǎn)存在的。誰沒事干,一天要創(chuàng)建100次菜單,就算是測試,測個10次8次足夠了吧?

    菜單的查詢和刪除接口的限制我就不解釋了,至今為止這二個接口我都沒使用過一次。就算有這樣的使用需求,一天這么多次的調(diào)用,完全足夠了。

    封裝通用的請求方法

    讀到這里,就默認(rèn)大家已經(jīng)掌握了上面講到的所有關(guān)于自定義菜單的理論知識,下面就進(jìn)入代碼實戰(zhàn)講解的部分。

    先前我們了解到,創(chuàng)建菜單需要調(diào)用二個接口,并且都是https請求,而非http。如果要封裝一個通用的請求方法,該方法至少需要具備以下能力:

  • 支持HTTPS請求;
  • 支持GET、POST兩種方式;
  • 支持參數(shù)提交,也支持無參數(shù)的情況;
  • 對于https請求,我們需要一個證書信任管理器,這個管理器類需要自己定義,但需要實現(xiàn)X509TrustManager接口,代碼如下:

    package org.liufeng.weixin.util;import java.security.cert.CertificateException; import java.security.cert.X509Certificate;import javax.net.ssl.X509TrustManager;/*** 證書信任管理器(用于https請求)* * @author liufeng* @date 2013-08-08*/ public class MyX509TrustManager implements X509TrustManager {public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}public X509Certificate[] getAcceptedIssuers() {return null;} }

    這個證書管理器的作用就是讓它信任我們指定的證書,上面的代碼意味著信任所有證書,不管是否權(quán)威機構(gòu)頒發(fā)。

    證書有了,通用的https請求方法就不難實現(xiàn)了,實現(xiàn)代碼如下:

    package org.liufeng.weixin.util;import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ConnectException; import java.net.URL;import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager;import net.sf.json.JSONObject;import org.slf4j.Logger; import org.slf4j.LoggerFactory;/*** 公眾平臺通用接口工具類* * @author liuyq* @date 2013-08-09*/ public class WeixinUtil {private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);/*** 發(fā)起https請求并獲取結(jié)果* * @param requestUrl 請求地址* @param requestMethod 請求方式(GET、POST)* @param outputStr 提交的數(shù)據(jù)* @return JSONObject(通過JSONObject.get(key)的方式獲取json對象的屬性值)*/public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {JSONObject jsonObject = null;StringBuffer buffer = new StringBuffer();try {// 創(chuàng)建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);// 設(shè)置請求方式(GET/POST)httpUrlConn.setRequestMethod(requestMethod);if ("GET".equalsIgnoreCase(requestMethod))httpUrlConn.connect();// 當(dāng)有數(shù)據(jù)需要提交時if (null != outputStr) {OutputStream outputStream = httpUrlConn.getOutputStream();// 注意編碼格式,防止中文亂碼outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 將返回的輸入流轉(zhuǎn)換成字符串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;} }

    代碼說明:

  • 41~50行:解決https請求的問題,很多人問題就出在這里;
  • 55~59行:兼容GET、POST兩種方式;
  • 61~67行:兼容有數(shù)據(jù)提交、無數(shù)據(jù)提交兩種情況,也有相當(dāng)一部分人不知道如何POST提交數(shù)據(jù);
  • Pojo類的封裝

    在獲取憑證創(chuàng)建菜單前,我們還需要封裝一些pojo,這會讓我們的代碼更美觀,有條理。

    首先是調(diào)用獲取憑證接口后,微信服務(wù)器會返回json格式的數(shù)據(jù):{"access_token":"ACCESS_TOKEN","expires_in":7200},我們將其封裝為一個AccessToken對象,對象有二個屬性:token和expiresIn,代碼如下:

    package org.liufeng.weixin.pojo;/*** 微信通用接口憑證* * @author liufeng* @date 2013-08-08*/ public class AccessToken {// 獲取到的憑證private String token;// 憑證有效時間,單位:秒private int expiresIn;public String getToken() {return token;}public void setToken(String token) {this.token = token;}public int getExpiresIn() {return expiresIn;}public void setExpiresIn(int expiresIn) {this.expiresIn = expiresIn;} }

    接下來是對菜單結(jié)構(gòu)的封裝。因為我們是采用面向?qū)ο蟮木幊谭绞?#xff0c;最終提交的json格式菜單數(shù)據(jù)就應(yīng)該是由對象直接轉(zhuǎn)換得到,而不是在程序代碼中拼一大堆json數(shù)據(jù)。菜單結(jié)構(gòu)封裝的依據(jù)是公眾平臺API文檔中給出的那一段json格式的菜單結(jié)構(gòu),如下所示:

    {"button":[{ "type":"click","name":"今日歌曲","key":"V1001_TODAY_MUSIC"},{"type":"click","name":"歌手簡介","key":"V1001_TODAY_SINGER"},{"name":"菜單","sub_button":[{"type":"click","name":"hello word","key":"V1001_HELLO_WORLD"},{"type":"click","name":"贊一下我們","key":"V1001_GOOD"}]}]}

    首先是菜單項的基類,所有一級菜單、二級菜單都共有一個相同的屬性,那就是name。菜單項基類的封裝代碼如下:

    package org.liufeng.weixin.pojo;/*** 按鈕的基類* * @author liufeng* @date 2013-08-08*/ public class Button {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;} }

    接著是子菜單項的封裝。這里對子菜單是這樣定義的:沒有子菜單的菜單項,有可能是二級菜單項,也有可能是不含二級菜單的一級菜單。這類子菜單項一定會包含三個屬性:type、name和key,封裝的代碼如下:

    package org.liufeng.weixin.pojo;/*** 普通按鈕(子按鈕)* * @author liufeng* @date 2013-08-08*/ public class CommonButton 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;} }

    再往下是父菜單項的封裝。對父菜單項的定義:包含有二級菜單項的一級菜單。這類菜單項包含有二個屬性:name和sub_button,而sub_button以是一個子菜單項數(shù)組。父菜單項的封裝代碼如下:

    package org.liufeng.weixin.pojo;/*** 復(fù)雜按鈕(父按鈕)* * @author liufeng* @date 2013-08-08*/ 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;} }

    最后是整個菜單對象的封裝,菜單對象包含多個菜單項(最多只能有3個),這些菜單項即可以是子菜單項(不含二級菜單的一級菜單),也可以是父菜單項(包含二級菜單的菜單項),如果能明白上面所講的,再來看封裝后的代碼就很容易理解了:

    package org.liufeng.weixin.pojo;/*** 菜單* * @author liufeng* @date 2013-08-08*/ public class Menu {private Button[] button;public Button[] getButton() {return button;}public void setButton(Button[] button) {this.button = button;} }

    關(guān)于POJO類的封裝就介紹完了。

    憑證access_token的獲取方法

    繼續(xù)在先前通用請求方法的類WeixinUtil.java中加入以下代碼,用于獲取接口訪問憑證:

    // 獲取access_token的接口地址(GET) 限200(次/天) public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";/*** 獲取access_token* * @param appid 憑證* @param appsecret 密鑰* @return*/ public static AccessToken getAccessToken(String appid, String appsecret) {AccessToken accessToken = null;String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);JSONObject jsonObject = httpRequest(requestUrl, "GET", null);// 如果請求成功if (null != jsonObject) {try {accessToken = new AccessToken();accessToken.setToken(jsonObject.getString("access_token"));accessToken.setExpiresIn(jsonObject.getInt("expires_in"));} catch (JSONException e) {accessToken = null;// 獲取token失敗log.error("獲取token失敗 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return accessToken; }

    自定義菜單的創(chuàng)建方法

    繼續(xù)在先前通用請求方法的類WeixinUtil.java中加入以下代碼,用于創(chuàng)建自定義菜單:

    // 菜單創(chuàng)建(POST) 限100(次/天)public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";/*** 創(chuàng)建菜單* * @param menu 菜單實例* @param accessToken 有效的access_token* @return 0表示成功,其他值表示失敗*/ public static int createMenu(Menu menu, String accessToken) {int result = 0;// 拼裝創(chuàng)建菜單的urlString url = menu_create_url.replace("ACCESS_TOKEN", accessToken);// 將菜單對象轉(zhuǎn)換成json字符串String jsonMenu = JSONObject.fromObject(menu).toString();// 調(diào)用接口創(chuàng)建菜單JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);if (null != jsonObject) {if (0 != jsonObject.getInt("errcode")) {result = jsonObject.getInt("errcode");log.error("創(chuàng)建菜單失敗 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return result; }

    調(diào)用封裝的方法創(chuàng)建自定義菜單

    package org.liufeng.weixin.main;import org.liufeng.weixin.pojo.AccessToken; import org.liufeng.weixin.pojo.Button; import org.liufeng.weixin.pojo.CommonButton; import org.liufeng.weixin.pojo.ComplexButton; import org.liufeng.weixin.pojo.Menu; import org.liufeng.weixin.util.WeixinUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory;/*** 菜單管理器類* * @author liufeng* @date 2013-08-08*/ public class MenuManager {private static Logger log = LoggerFactory.getLogger(MenuManager.class);public static void main(String[] args) {// 第三方用戶唯一憑證String appId = "000000000000000000";// 第三方用戶唯一憑證密鑰String appSecret = "00000000000000000000000000000000";// 調(diào)用接口獲取access_tokenAccessToken at = WeixinUtil.getAccessToken(appId, appSecret);if (null != at) {// 調(diào)用接口創(chuàng)建菜單int result = WeixinUtil.createMenu(getMenu(), at.getToken());// 判斷菜單創(chuàng)建結(jié)果if (0 == result)log.info("菜單創(chuàng)建成功!");elselog.info("菜單創(chuàng)建失敗,錯誤碼:" + result);}}/*** 組裝菜單數(shù)據(jù)* * @return*/private static Menu getMenu() {CommonButton btn11 = new CommonButton();btn11.setName("天氣預(yù)報");btn11.setType("click");btn11.setKey("11");CommonButton btn12 = new CommonButton();btn12.setName("公交查詢");btn12.setType("click");btn12.setKey("12");CommonButton btn13 = new CommonButton();btn13.setName("周邊搜索");btn13.setType("click");btn13.setKey("13");CommonButton btn14 = new CommonButton();btn14.setName("歷史上的今天");btn14.setType("click");btn14.setKey("14");CommonButton btn21 = new CommonButton();btn21.setName("歌曲點播");btn21.setType("click");btn21.setKey("21");CommonButton btn22 = new CommonButton();btn22.setName("經(jīng)典游戲");btn22.setType("click");btn22.setKey("22");CommonButton btn23 = new CommonButton();btn23.setName("美女電臺");btn23.setType("click");btn23.setKey("23");CommonButton btn24 = new CommonButton();btn24.setName("人臉識別");btn24.setType("click");btn24.setKey("24");CommonButton btn25 = new CommonButton();btn25.setName("聊天嘮嗑");btn25.setType("click");btn25.setKey("25");CommonButton btn31 = new CommonButton();btn31.setName("Q友圈");btn31.setType("click");btn31.setKey("31");CommonButton btn32 = new CommonButton();btn32.setName("電影排行榜");btn32.setType("click");btn32.setKey("32");CommonButton btn33 = new CommonButton();btn33.setName("幽默笑話");btn33.setType("click");btn33.setKey("33");ComplexButton mainBtn1 = new ComplexButton();mainBtn1.setName("生活助手");mainBtn1.setSub_button(new CommonButton[] { btn11, btn12, btn13, btn14 });ComplexButton mainBtn2 = new ComplexButton();mainBtn2.setName("休閑驛站");mainBtn2.setSub_button(new CommonButton[] { btn21, btn22, btn23, btn24, btn25 });ComplexButton mainBtn3 = new ComplexButton();mainBtn3.setName("更多體驗");mainBtn3.setSub_button(new CommonButton[] { btn31, btn32, btn33 });/*** 這是公眾號xiaoqrobot目前的菜單結(jié)構(gòu),每個一級菜單都有二級菜單項<br>* * 在某個一級菜單下沒有二級菜單的情況,menu該如何定義呢?<br>* 比如,第三個一級菜單項不是"更多體驗",而直接是"幽默笑話",那么menu應(yīng)該這樣定義:<br>* menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 });*/Menu menu = new Menu();menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });return menu;} }

    注意:在運行以上代碼時,需要將appId和appSecret換成你自己公眾號的。

    ?

    為了保證文章的完整獨立性和可讀性,我是新建了一個Java?Project(Java web工程也可以,沒有太大關(guān)系),沒有在前幾篇文章所講到的weixinCourse工程中添加代碼。如果需要,讀者可以自己實現(xiàn)將菜單創(chuàng)建的代碼移到自己已有的工程中去。

    圖中所有Java文件的源代碼都在文章中貼出并進(jìn)行了說明,圖中使用到的jar也是Java開發(fā)中通用的jar包,很容易在網(wǎng)上下載到。

    工程中引入的jar包主要分為兩類:

  • 第一類是json開發(fā)工具包,用于Java對象和Json字符串之間的轉(zhuǎn)換;json開發(fā)工具包一共有3個jar:ezmorph-1.0.6.jar,json-lib-2.2.3-jdk13.jar和morph-1.1.1.jar。
  • 第二類是slf4j日志工具包,用于記錄系統(tǒng)運行所產(chǎn)生的日志,日志可以輸出到控制臺或文件中。
  • 整個工程中,唯一沒有講到的是src下的log4j.properties的配置,也把它貼出來,方便大家參考,這樣才是一個完整的工程源碼。log4j.properties文件的內(nèi)容如下:

    log4j.rootLogger=info,console,filelog4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%-5p] %m%nlog4j.appender.file=org.apache.log4j.DailyRollingFileAppender log4j.appender.file.DatePattern='-'yyyy-MM-dd log4j.appender.file.File=./logs/weixinmpmenu.log log4j.appender.file.Append=true log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%-5p] %d %37c %3x - %m%n

    響應(yīng)時間參考代碼如下:

    <?phpdefine("TOKEN", "weixin"); $wechatObj = new wechatCallbackapiTest(); if (isset($_GET['echostr'])) {$wechatObj->valid(); }else{$wechatObj->responseMsg(); }class wechatCallbackapiTest {public function valid(){$echoStr = $_GET["echostr"];if($this->checkSignature()){echo $echoStr;exit;}}private function checkSignature(){$signature = $_GET["signature"];$timestamp = $_GET["timestamp"];$nonce = $_GET["nonce"];$token = TOKEN;$tmpArr = array($token, $timestamp, $nonce);sort($tmpArr);$tmpStr = implode( $tmpArr );$tmpStr = sha1( $tmpStr );if( $tmpStr == $signature ){return true;}else{return false;}}public function responseMsg(){$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];if (!empty($postStr)){$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);$RX_TYPE=trim($postObj->MsgType);$fromUsername = $postObj->FromUserName;$toUsername = $postObj->ToUserName;$time = time();$msgType = "text";$textTpl = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[%s]]></MsgType><Content><![CDATA[%s]]></Content><FuncFlag>0</FuncFlag></xml>";switch($RX_TYPE){case "text":$keyword = trim($postObj->Content);$url = "http://apix.sinaapp.com/weather/?appkey=".$postObj->ToUserName."&city=".urlencode($keyword);$output = file_get_contents($url);$content = json_decode($output, true);$itemTpl = " <item><Title><![CDATA[%s]]></Title><Description><![CDATA[%s]]></Description><PicUrl><![CDATA[%s]]></PicUrl><Url><![CDATA[%s]]></Url></item>";$item_str = "";if(!is_array($content)){$resultStr = sprintf($textTpl, $postObj->FromUserName, $postObj->ToUserName, time(), "text", "無法找到該地址");}else{foreach ($content as $item){$item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);}$newsTpl = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[news]]></MsgType><Content><![CDATA[]]></Content><ArticleCount>%s</ArticleCount><Articles>%s</Articles></xml>";$resultStr = sprintf($newsTpl, $postObj->FromUserName, $postObj->ToUserName, time(), count($content), $item_str);}echo $resultStr;break;case "event":switch ($postObj->Event){case "subscribe":$contentStr = "歡迎關(guān)注";$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);echo $resultStr;break;case "LOCATION":$contentStr = "緯度 ".$postObj->Latitude." 經(jīng)度".$postObj->Longitude;$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);echo $resultStr;break;case "CLICK":$contentStr = "";switch($postObj->EventKey){case "11":$contentStr = "自己去外面看看天氣唄~";break;case "12":$contentStr = "站牌那里有~";break;case "13":$contentStr = "扭個頭就都看見了~";break;case "14":$contentStr = "歷史上的今天啊,我想想哦~";break;case "21":$contentStr = "我今天嗓子啞了,你就別聽了~";break;case "22":$contentStr = "石頭剪刀布?";break;case "23":$contentStr = "我是美女你是電臺~";break;case "24":$contentStr = "你太丑識別不出來~";break;case "31":$contentStr = "你只有我一個好友~";break;case "32":$contentStr = "我的電影還沒出呢~";break;case "33":$contentStr = "你自己就是個笑話~";break;case "25":$contentStr = "咱倆是一個年代的嗎?沒話聊~";break;default:$contentStr = "CLICK: ".$postObj->EventKey;break;}$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);echo $resultStr;break;default:break;}break;case "image":$textTpl = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[news]]></MsgType><Content><![CDATA[]]></Content><ArticleCount>1</ArticleCount><Articles><item><Title><![CDATA[hello]]></Title><Description><![CDATA[hello]]></Description><PicUrl><![CDATA[%s]]></PicUrl><Url><![CDATA[]]></Url></item></Articles><FuncFlag>0</FuncFlag></xml>";$resultStr = sprintf($textTpl, $postObj->FromUserName, $postObj->ToUserName,time(), $postObj->PicUrl); echo $resultStr;break;default:break;}}else{echo "";exit;}}public function transmitNews($object, $newsArray){if(!is_array($newsArray)){return "";}return $result;} } ?>

    總結(jié)

    以上是生活随笔為你收集整理的自定义菜单用例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。