一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - java微信開發API第四步 微信自定義個性化菜單實現

java微信開發API第四步 微信自定義個性化菜單實現

2020-05-22 10:37wgyscsf JAVA教程

這篇文章主要為大家詳細介紹了java微信開發API第四步,自定義菜單以及個性化菜單實現 ,感興趣的小伙伴們可以參考一下

微信如何實現自定義個性化菜單,下面為大家介紹

一、全局說明
詳細說明請參考前兩篇文章。

二、本文說明
本文分為五部分:
    * 工具類AccessTokenUtils的封裝
    * 自定義菜單和個性化菜單文檔的閱讀解析
    * 菜單JSON的分析以及構建對應bean
    * 自定義菜單的實現
    * 個性化菜單的實現
微信自定義菜單所有類型菜單都給出演示
本文結束會給出包括本文前四篇文章的所有演示源碼

工具類AccessTokenUtils的封裝
在上文中關于AccessToken的獲取和定時保存已經詳細介紹過,此處直接給出處理過之后封裝的AccessTokenUtils,實現原理以及文檔閱讀不再給出。
AccessTokenUtils.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package com.gist.utils;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
 
import javax.net.ssl.HttpsURLConnection;
 
import com.gist.bean.Access_token;
import com.google.gson.Gson;
 
/**
 * @author 高遠</n> 郵箱:[email protected]</n> 博客 http://blog.csdn.net/wgyscsf</n>
 *  編寫時期 2016-4-7 下午5:44:33
 */
public class AccessTokenUtils {
 private static final long MAX_TIME = 7200 * 1000;// 微信允許最長Access_token有效時間(ms)
 private static final String TAG = "WeixinApiTest";// TAG
 private static final String APPID = "wx889b020b3666b0b8";// APPID
 private static final String SECERT = "6da7676bf394f0a9f15fbf06027856bb";// 秘鑰
 
 /*
 * 該方法實現獲取Access_token、保存并且只保存2小時Access_token。如果超過兩個小時重新獲取;如果沒有超過兩個小時,直接獲取。該方法依賴
 * :public static String getAccessToken();
 *
 * 思路:將獲取到的Access_token和當前時間存儲到file里,
 * 取出時判斷當前時間和存儲里面的記錄的時間的時間差,如果大于MAX_TIME,重新獲取,并且將獲取到的存儲到file替換原來的內容
 * ,如果小于MAX_TIME,直接獲取。
 */
 // 為了調用不拋異常,這里全部捕捉異常,代碼有點長
 public static String getSavedAccess_token() {
 Gson gson = new Gson();// 第三方jar,處理json和bean的轉換
 String mAccess_token = null;// 需要獲取的Access_token;
 FileOutputStream fos = null;// 輸出流
 FileInputStream fis = null;// 輸入流
 File file = new File("temp_access_token.temp");// Access_token保存的位置
 try {
  // 如果文件不存在,創建
  if (!file.exists()) {
  file.createNewFile();
  }
 } catch (Exception e1) {
  e1.printStackTrace();
 }
 // 如果文件大小等于0,說明第一次使用,存入Access_token
 if (file.length() == 0) {
  try {
  mAccess_token = getAccessToken();// 獲取AccessToken
  Access_token at = new Access_token();
  at.setAccess_token(mAccess_token);
  at.setExpires_in(System.currentTimeMillis() + "");// 設置存入時間
  String json = gson.toJson(at);
  fos = new FileOutputStream(file, false);// 不允許追加
  fos.write((json).getBytes());// 將AccessToken和當前時間存入文件
  fos.close();
  return mAccess_token;
  } catch (Exception e) {
  e.printStackTrace();
  }
 } else {
  // 讀取文件內容
  byte[] b = new byte[2048];
  int len = 0;
  try {
  fis = new FileInputStream(file);
  len = fis.read(b);
  } catch (IOException e1) {
  // TODO Auto-generated catch block
  e1.printStackTrace();
  }
  String mJsonAccess_token = new String(b, 0, len);// 讀取到的文件內容
  Access_token access_token = gson.fromJson(mJsonAccess_token,
   new Access_token().getClass());
  if (access_token.getExpires_in() != null) {
  long saveTime = Long.parseLong(access_token.getExpires_in());
  long nowTime = System.currentTimeMillis();
  long remianTime = nowTime - saveTime;
  // System.out.println(TAG + "時間差:" + remianTime + "ms");
  if (remianTime < MAX_TIME) {
   Access_token at = gson.fromJson(mJsonAccess_token,
    new Access_token().getClass());
   mAccess_token = at.getAccess_token();
   return mAccess_token;
  } else {
   mAccess_token = getAccessToken();
   Access_token at = new Access_token();
   at.setAccess_token(mAccess_token);
   at.setExpires_in(System.currentTimeMillis() + "");
   String json = gson.toJson(at);
   try {
   fos = new FileOutputStream(file, false);// 不允許追加
   fos.write((json).getBytes());
   fos.close();
   } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   }
   return mAccess_token;
  }
 
  } else {
  return null;
  }
 }
 
 return mAccess_token;
 }
 
 /*
 * 獲取微信服務器AccessToken。該部分和getAccess_token() 一致,不再加注釋
 */
 public static String getAccessToken() {
 String urlString = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
  + APPID + "&secret=" + SECERT;
 String reslut = null;
 try {
  URL reqURL = new URL(urlString);
  HttpsURLConnection httpsConn = (HttpsURLConnection) reqURL
   .openConnection();
  InputStreamReader isr = new InputStreamReader(
   httpsConn.getInputStream());
  char[] chars = new char[1024];
  reslut = "";
  int len;
  while ((len = isr.read(chars)) != -1) {
  reslut += new String(chars, 0, len);
  }
  isr.close();
 } catch (IOException e) {
 
  e.printStackTrace();
 }
 Gson gson = new Gson();
 Access_token access_token = gson.fromJson(reslut,
  new Access_token().getClass());
 if (access_token.getAccess_token() != null) {
  return access_token.getAccess_token();
 } else {
  return null;
 }
 }
}

自定義菜單和個性化菜單文檔的閱讀解析
•自定義菜單
?自定義菜單創建接口
 ?自定義菜單查詢接口
 ?自定義菜單刪除接口
 ?自定義菜單事件推送
 ?個性化菜單接口
 ?獲取公眾號的菜單配置

 •文檔地址:http://mp.weixin.qq.com/wiki/10/0234e39a2025342c17a7d23595c6b40a.html
 •官網文檔給出這樣解釋:
* 自定義菜單接口可實現多種類型按鈕,如下:1、click:點擊事件...;2、view:跳轉事件...;3、...(關于自定義菜單)
* 接口調用請求說明 http請求方式:POST(請使用https協議) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN(關于自定義菜單)
* click和view的請求示例 {"button":[...]}  (關于自定義菜單)
* 參數說明...(關于自定義菜單)
* 創建個性化菜單http請求方式:POST(請使用https協議)https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN(關于個性化菜單)
* 請求示例: {"button":[...],"matchrule":{...}}(關于個性化菜單)
* 參數說明...(關于個性化菜單)
* 開發者可以通過以下條件來設置用戶看到的菜單(關于個性化菜單):
    1、用戶分組(開發者的業務需求可以借助用戶分組來完成)
    2、性別
    3、手機操作系統
    4、地區(用戶在微信客戶端設置的地區)
    5、語言(用戶在微信客戶端設置的語言)

 •理解:
?又是熟悉的POST請求,但是,關于調用貌似說的含糊其辭,不太明白。只是知道我們需要使用“?access_token=ACCESS_TOKEN”這個參數,這個參數我們在上篇文章已經獲取到了。假如我們將微信文檔給的那個請求地址中“ACCESS_TOKEN”換成我們獲取到的自己的ACCESS_TOKEN,訪問該網址,會看到“{“errcode”:44002,”errmsg”:”empty post data hint: [Gdveda0984vr23]”}”。大概意思是,空的post請求數據。所以,我們要通過POST請求的形式傳遞參數給微信服務器,在文檔下面還給出了參數的格式:{“button”:[…]},所以,我們要按照該格式給微信服務器進行傳遞參數。
 ?關于參數說明,我們可以看到在自定義菜單創建中有七個參數。在個性化菜單接口中除去這七個參數之外,另外多個八個參數。簡單查看此部分文檔,我們可以了解到這個八個參數是為了個性化菜單做匹配篩選用的。
 ?現在,我們需要按照微信文檔的要求構造json通過post的請求向微信服務器發送這一串json數據,json里面就包括我們創建的各種類型的按鈕事件。

菜單JSON的分析以及構建對應bean
 自定義菜單json分析(不包括個性化菜單)。下面這段代碼是微信文檔給的示例。
click和view的請求示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"button":[
{
 "type":"click",
 "name":"今日歌曲",
 "key":"V1001_TODAY_MUSIC"
},
{
 "name":"菜單",
 "sub_button":[
 {
 "type":"view",
 "name":"搜索",
 "url":"http://www.soso.com/"
 },
 {
 "type":"view",
 "name":"視頻",
 "url":"http://v.qq.com/"
 },
 {
 "type":"click",
 "name":"贊一下我們",
 "key":"V1001_GOOD"
 }]
}]
}

經過分析我們可以看到這串json數據分為三層:“”button”:[{…},{…}]”、“[{…},{{“name”:菜單,”sub_button”:[{},{}]}]”、“{“type”:”view”,”name:”:”視頻”,”url”:”…”},{},{}”,可能看起來比較暈。
但是,如果我們能夠聯想起來現實中看到的微信菜單,就會好理解一點:一級:菜單(一個菜單),下包括一到三個父按鈕;二級:父按鈕(1~3個父按鈕),下包括一到五個子按鈕;三級:子按鈕(1~5個子按鈕)。
 現在,我們可以看到json和我們理解的“菜單”可以一一對應起來了。現在重點是如何確認每一級的“級名”,在java中也就是對應的javabean對象。
 同時,因為一級菜單下會有多個父按鈕,所以是一個List<父菜單>的形式。父按鈕下可能有多個子菜單,也是一個 List<子菜單>;但是,父按鈕也有可能也是一個單獨的可以響應的按鈕。是一個單獨的父按鈕對象。子按鈕就是一個單獨的子按鈕對象。
 查看關于自定義菜單的參數說明,我們可以看到按鈕分為一級按鈕(“button”)和二級按鈕(“sub_button”)。還有一些公用的數據類型,例如:菜單響應類型(“type”)、菜單標題(“name”)、click類型的參數(“key”)、view類型的參數(“url”)、media_id類型和view_limited類型的參數(“media_id”)。
 •數據抽象(沒有寫setter,getter):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//按鈕基類
public class BaseButton {
 private String type;
 private String name;
 private String key;
 private String url;
 private String media_id;
}
//子按鈕
public class SonButton extends BaseButton {
 private String sub_button;
}
//父按鈕
public class FatherButton extends BaseButton {
private String button;//可能直接一個父按鈕做響應
@SerializedName("sub_button")//為了保證Gson解析后子按鈕的名字是“sub_button”,具體用法請搜索
private List<SonButton> sonButtons;//可能有多個子按鈕
}
 
public class Menu {
@SerializedName("button")
private List<FatherButton> fatherButtons;
}

 以上是完整的自定義菜單的分析以及對應javabean的構建。

 對于個性化菜單,如果查看該部分的文檔,會發現和自定義菜單大致相同,只是多個一個“配置”的json,格式是這樣的:{“button”:[…],”matchrule”:{…}}。
 我們發現,“匹配”這段json和“button”是同級的,分析和實現和上面基本等同,直接給出實現的javabean。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//匹配的json對應的json
public class MatchRule {
private String group_id;
private String sex;
private String client_platform_type;
private String country;
private String province;
private String city;
private String language;
}
 
//修改Menu.java
public class Menu {
@SerializedName("button")
private List<FatherButton> fatherButtons;
private MatchRule matchrule;
}

 自定義菜單的實現
 任務,我們實現所有微信按鈕響應類型:
 任務(注釋:“m-0”表示父按鈕;“m-n”表示第m個父按鈕,第n個子按鈕(m,n≠0)):1-0:名字:click,響應點擊事件:點擊推事件 。2-0:名字:父按鈕2。2-1:名字:view,響應事件:跳轉網頁;2-2:名字:scancode_push,響應事件:掃碼推事件;2-3:名字:scancode_waitmsg,響應事件:掃碼推事件且彈出“消息接收中”提示框;2-4:名字:pic_sysphoto,響應事件
 :彈出系統拍照發圖。2-5:名字:pic_photo_or_album,響應事件:彈出拍照或者相冊發圖。3-0:名字:父按鈕3。3-1:名字
 :pic_weixin,響應事件:彈出微信相冊發圖器;3-2:名字:location_select,響應事件:彈出地理位置選擇器;3-3:名字:media_id,響應事件:下發消息(除文本消息);3-4:名字:view_limited,響應事件:跳轉圖文消息url。

實現源碼(引用的AccessTokenUtils.java在第一部分:工具類AccessTokenUtils的封裝)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
* 創建自定義菜單。
*/
@Test
public void createCommMenu() {
String ACCESS_TOKEN = AccessTokenUtils.getAccessToken();// 獲取AccessToken,AccessTokenUtils是封裝好的類
// 拼接api要求的httpsurl鏈接
String urlString = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="
 + ACCESS_TOKEN;
try {
 // 創建一個url
 URL reqURL = new URL(urlString);
 // 拿取鏈接
 HttpsURLConnection httpsConn = (HttpsURLConnection) reqURL
  .openConnection();
 httpsConn.setDoOutput(true);
 // 取得該連接的輸出流,以讀取響應內容
 OutputStreamWriter osr = new OutputStreamWriter(
  httpsConn.getOutputStream());
 osr.write(getMenuJson());// 使用本類外部方法getMenuJson()
 osr.close();
 
 // 返回結果
 InputStreamReader isr = new InputStreamReader(
  httpsConn.getInputStream());
 // 讀取服務器的響應內容并顯示
 char[] chars = new char[1024];
 String reslut = "";
 int len;
 while ((len = isr.read(chars)) != -1) {
 reslut += new String(chars, 0, len);
 }
 System.out.println("返回結果:" + reslut);
 isr.close();
} catch (IOException e) {
 e.printStackTrace();
}
}
 
public String getMenuJson() {
Gson gson = new Gson();// json處理工具
 
Menu menu = new Menu();// 菜單類
List<FatherButton> fatherButtons = new ArrayList<FatherButton>();// 菜單中的父按鈕集合
// -----------
// 父按鈕1
FatherButton fb1 = new FatherButton();
fb1.setName("click");
fb1.setType("click");
fb1.setKey("10");
// -------------
// 父按鈕2
FatherButton fb2 = new FatherButton();
fb2.setName("父按鈕2");
List<SonButton> sonButtons2 = new ArrayList<SonButton>();// 子按鈕的集合
 
// 子按鈕2-1
SonButton sb21 = new SonButton();
sb21.setName("view");
sb21.setUrl("http://www.baidu.com");
sb21.setType("view");
// 子按鈕2-2
SonButton sb22 = new SonButton();
sb22.setName("scancode_push");
sb22.setType("scancode_push");
sb22.setKey("22");
// 子按鈕2-3
SonButton sb23 = new SonButton();
sb23.setName("scancode_waitmsg");
sb23.setType("scancode_waitmsg");
sb23.setKey("23");
// 子按鈕2-4
SonButton sb24 = new SonButton();
sb24.setName("pic_sysphoto");
sb24.setType("pic_sysphoto");
sb24.setKey("24");
// 子按鈕2-5
SonButton sb25 = new SonButton();
sb25.setName("pic_photo_or_album");
sb25.setType("pic_photo_or_album");
sb25.setKey("25");
 
// 添加子按鈕到子按鈕集合
sonButtons2.add(sb21);
sonButtons2.add(sb22);
sonButtons2.add(sb23);
sonButtons2.add(sb24);
sonButtons2.add(sb25);
 
// 將子按鈕放到2-0父按鈕集合
fb2.setSonButtons(sonButtons2);
 
// ------------------
// 父按鈕3
FatherButton fb3 = new FatherButton();
fb3.setName("父按鈕3");
List<SonButton> sonButtons3 = new ArrayList<SonButton>();
 
// 子按鈕3-1
SonButton sb31 = new SonButton();
sb31.setName("pic_weixin");
sb31.setType("pic_weixin");
sb31.setKey("31");
// 子按鈕3-2
SonButton sb32 = new SonButton();
sb32.setName("locatselect");
sb32.setType("location_select");
sb32.setKey("32");
// // 子按鈕3-3-->測試不了,因為要media_id。這需要調用素材id.
// SonButton sb33 = new SonButton();
// sb33.setName("media_id");
// sb33.setType("media_id");
// sb33.setMedia_id("???");
// // 子按鈕3-4-->測試不了,因為要media_id。這需要調用素材id.
// SonButton sb34 = new SonButton();
// sb34.setName("view_limited");
// sb34.setType("view_limited");
// sb34.setMedia_id("???");
 
// 添加子按鈕到子按鈕隊列
sonButtons3.add(sb31);
sonButtons3.add(sb32);
// sonButtons3.add(sb33);
// sonButtons3.add(sb34);
 
// 將子按鈕放到3-0父按鈕隊列
fb3.setSonButtons(sonButtons3);
// ---------------------
 
// 將父按鈕加入到父按鈕集合
fatherButtons.add(fb1);
fatherButtons.add(fb2);
fatherButtons.add(fb3);
 
// 將父按鈕隊列加入到菜單欄
menu.setFatherButtons(fatherButtons);
String json = gson.toJson(menu);
System.out.println(json);// 測試輸出
return json;
 
}

 個性化菜單的實現
 •任務:根據性別展示不同的按鈕顯示(可以根據性別、地區、分組手機操作系統等)
 •修改代碼一,因為是不同的微信后臺實現,所以接口也不一樣,不過還是POST請求,代碼不用改,只要替換原來urlString即可。

?
1
2
3
// 拼接api要求的httpsurl鏈接
String urlString = "https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token="
  + ACCESS_TOKEN;

 •修改代碼二,只要創建一個MatchRule,設置匹配規則,然后將matchrule加入到menu便可以完成匹配規則。

?
1
2
3
4
5
6
// -----
// 從此處開始設置個性菜單
MatchRule matchrule = new MatchRule();
matchrule.setSex("2");// 男生
menu.setMatchrule(matchrule);
// ----

源碼下載:WeixinApi.rar

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://blog.csdn.net/wgyscsf/article/details/51104855

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 精品在线免费观看 | 成人18视频在线观看 | 5g影院天天5g爽天天看 | 亚洲精品福利一区二区在线观看 | 日本激情小说 | 成人福利网 | 国产人成精品午夜在线观看 | 欧美男男gaysgays | 亚洲国产99 | 无耻之徒第十一季在线观看 | 青草午夜精品视频在线观看 | 美女被网站 | a毛片免费观看完整 | 国产一区二区三区欧美 | 成人精品第一区二区三区 | 国产精品福利在线观看入口 | 色小妹在线 | 欧美日韩一级视频 | 免费波多野结衣庭教师 | 美女扒开腿让男人桶爽动态图片 | 国产一区二区免费在线 | 超碰97 | 风间由美被义子中文字幕 | 欧美一级久久久久久久大片 | 成年美女黄网站色视频大全免费 | 欧美午夜视频一区二区三区 | 成在线人免费 | 国产大神91一区二区三区 | 果冻传媒九一制片厂 | 国产成人精品999在线 | 99热影院 | 水多多www视频在线观看高清 | 国产女乱淫真高清免费视频 | 国产欧美久久久精品影院 | 久久久无码精品无码国产人妻丝瓜 | 人生路不在线观看完整版 | 非洲黑人gay巨大 | 国产麻豆在线观看网站 | 性bbbbwwbbbb | 乳环贵妇堕落开发调教番号 | 好男人好资源在线观看 |