您好,登錄后才能下訂單哦!
本文是 微信開發-素材/消息管理接口 的后續,主要介紹微信公眾平臺的自定義菜單接口開發。由于個人的訂閱號是沒有大多數接口的權限的,所以我們需要使用微信官方提供的測試號來進行開發。測試號的申請可參考下文:
本小節我們來開發一個自定義菜單,官方文檔地址如下:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013
自定義菜單接口可實現多種類型按鈕,如下:
1、click:點擊推事件用戶點擊click類型按鈕后,微信服務器會通過消息接口推送消息類型為event的結構給開發者(參考消息接口指南),并且帶上按鈕中開發者填寫的key值,開發者可以通過自定義的key值與用戶進行交互;
2、view:跳轉URL用戶點擊view類型按鈕后,微信客戶端將會打開開發者在按鈕中填寫的網頁URL,可與網頁授權獲取用戶基本信息接口結合,獲得用戶基本信息。
3、scancode_push:掃碼推事件用戶點擊按鈕后,微信客戶端將調起掃一掃工具,完成掃碼操作后顯示掃描結果(如果是URL,將進入URL),且會將掃碼的結果傳給開發者,開發者可以下發消息。
4、scancode_waitmsg:掃碼推事件且彈出“消息接收中”提示框用戶點擊按鈕后,微信客戶端將調起掃一掃工具,完成掃碼操作后,將掃碼的結果傳給開發者,同時收起掃一掃工具,然后彈出“消息接收中”提示框,隨后可能會收到開發者下發的消息。
5、pic_sysphoto:彈出系統拍照發圖用戶點擊按鈕后,微信客戶端將調起系統相機,完成拍照操作后,會將拍攝的相片發送給開發者,并推送事件給開發者,同時收起系統相機,隨后可能會收到開發者下發的消息。
6、pic_photo_or_album:彈出拍照或者相冊發圖用戶點擊按鈕后,微信客戶端將彈出選擇器供用戶選擇“拍照”或者“從手機相冊選擇”。用戶選擇后即走其他兩種流程。
7、pic_weixin:彈出微信相冊發圖器用戶點擊按鈕后,微信客戶端將調起微信相冊,完成選擇操作后,將選擇的相片發送給開發者的服務器,并推送事件給開發者,同時收起相冊,隨后可能會收到開發者下發的消息。
8、location_select:彈出地理位置選擇器用戶點擊按鈕后,微信客戶端將調起地理位置選擇工具,完成選擇操作后,將選擇的地理位置發送給開發者的服務器,同時收起位置選擇工具,隨后可能會收到開發者下發的消息。
9、media_id:下發消息(除文本消息)用戶點擊media_id類型按鈕后,微信服務器會將開發者填寫的永久素材id對應的素材下發給用戶,永久素材類型可以是圖片、音頻、視頻、圖文消息。請注意:永久素材id必須是在“素材管理/新增永久素材”接口上傳后獲得的合法id。
10、view_limited:跳轉圖文消息URL用戶點擊view_limited類型按鈕后,微信客戶端將打開開發者在按鈕中填寫的永久素材id對應的圖文消息URL,永久素材類型只支持圖文消息。請注意:永久素材id必須是在“素材管理/新增永久素材”接口上傳后獲得的合法id。
創建自定義菜單所需傳遞的參數如下:
click和view的請求體示例:
{
"button":[
{
"type":"click",
"name":"今日歌曲",
"key":"V1001_TODAY_MUSIC"
},
{
"name":"菜單",
"sub_button":[
{
"type":"view",
"name":"搜索",
"url":"http://www.soso.com/"
},
{
"type":"miniprogram",
"name":"wxa",
"url":"http://mp.weixin.qq.com",
"appid":"wx286b93c14bbf93aa",
"pagepath":"pages/lunar/index"
},
{
"type":"click",
"name":"贊一下我們",
"key":"V1001_GOOD"
}]
}]
}
其他新增按鈕類型的請求體示例:
{
"button": [
{
"name": "掃碼",
"sub_button": [
{
"type": "scancode_waitmsg",
"name": "掃碼帶提示",
"key": "rselfmenu_0_0",
"sub_button": [ ]
},
{
"type": "scancode_push",
"name": "掃碼推事件",
"key": "rselfmenu_0_1",
"sub_button": [ ]
}
]
},
{
"name": "發圖",
"sub_button": [
{
"type": "pic_sysphoto",
"name": "系統拍照發圖",
"key": "rselfmenu_1_0",
"sub_button": [ ]
},
{
"type": "pic_photo_or_album",
"name": "拍照或者相冊發圖",
"key": "rselfmenu_1_1",
"sub_button": [ ]
},
{
"type": "pic_weixin",
"name": "微信相冊發圖",
"key": "rselfmenu_1_2",
"sub_button": [ ]
}
]
},
{
"name": "發送位置",
"type": "location_select",
"key": "rselfmenu_2_0"
},
{
"type": "media_id",
"name": "圖片",
"media_id": "MEDIA_ID1"
},
{
"type": "view_limited",
"name": "圖文消息",
"media_id": "MEDIA_ID2"
}
]
}
本文主要介紹click和view類型的菜單按鈕的實現,只要成功實現了click和view類型的菜單按鈕,其他類型的實現起來都是差不多的。
首先,我們需要根據官方給出的click和view類型請求體示例中的json結構,封裝出各個實體類。第一個要創建的是菜單按鈕基類,封裝通用的字段,代碼如下:
package org.zero01.weixin.mqdemo.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @program: mq-demo
* @description: 菜單按鈕基類
* @author: 01
* @create: 2018-07-05 20:05
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Button {
private String name;
private String type;
private Button[] sub_button;
}
然后是click類型的按鈕,代碼如下:
package org.zero01.weixin.mqdemo.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @program: mq-demo
* @description: click類型的按鈕
* @author: 01
* @create: 2018-07-05 20:08
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ClickButton extends Button {
// click類型按鈕的唯一標識符
private String key;
}
view類型的按鈕,代碼如下:
package org.zero01.weixin.mqdemo.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @program: mq-demo
* @description: view類型的按鈕
* @author: 01
* @create: 2018-07-05 20:08
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ViewButton extends Button {
// view類型按鈕的點擊跳轉鏈接
private String url;
}
最外層的自定義菜單按鈕實體,代碼如下:
package org.zero01.weixin.mqdemo.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @program: mq-demo
* @description: 自定義菜單
* @author: 01
* @create: 2018-07-05 20:10
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Menu {
private Button[] button;
}
封裝完實體類之后,將創建菜單接口的url地址,配置到SpringBoot的配置文件中,如下:
wechat:
...
menuUrl: https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
然后在配置類里加上該配置信息的字段,如下:
...
public class WeXinConfig {
...
private String menuUrl;
}
完成配置后,接著在WeiXinUtil里加入如下兩個方法:
/**
* 組裝自定義菜單對象
*
* @return
*/
public static Menu initMenu() {
Menu menu = new Menu();
ClickButton clickButton = new ClickButton();
clickButton.setName("click菜單");
clickButton.setType("click");
// key可自定義
clickButton.setKey("click_001");
ViewButton viewButton = new ViewButton();
viewButton.setName("view菜單");
viewButton.setType("view");
// url需要帶http協議頭
viewButton.setUrl("http://www.baidu.com");
ClickButton clickButton2 = new ClickButton();
clickButton2.setName("掃碼事件");
clickButton2.setType("scancode_push");
clickButton2.setKey("click_002");
ClickButton clickButton3 = new ClickButton();
clickButton3.setName("發送地理位置");
clickButton3.setType("location_select");
clickButton3.setKey("click_003");
Button button = new Button();
button.setName("自定義菜單");
// 設置子菜單
button.setSub_button(new Button[]{clickButton2, clickButton3});
menu.setButton(new Button[]{clickButton, viewButton, button});
return menu;
}
/**
* 創建自定義菜單
*
* @param token
* @param menu
* @return
* @throws IOException
*/
public static JSONObject createMenu(String token, String menu) throws IOException {
String url = wxConfig.getMenuUrl().replace("ACCESS_TOKEN", token);
// 發送創建菜單請求
return doPost(url, menu);
}
由于將對象轉換成JSON數據的時候,需要用到 JSONObject.fromObject();
這個方法,所以我們需要在pom.xml文件中,添加以下依賴:
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
確保該依賴添加成功后,在WeiXinUtilTest測試類中,新增一個測試方法,用于測試創建自定義菜單。代碼如下:
@Test
public void createMenu() throws IOException {
// 獲取token
AccessToken accessToken = WeiXinUtil.getAccessToken();
// 組裝自定義菜單對象
Menu menu = WeiXinUtil.initMenu();
// 將對象轉換成json
String menuStr = JSONObject.fromObject(menu).toString();
// 調用接口,創建自定義菜單
org.json.JSONObject jsonObject = WeiXinUtil.createMenu(accessToken.getToken(), menuStr);
// 打印返回結果
System.out.println(jsonObject);
}
執行如上測試方法后,控制臺輸出如下:
{"errcode":0,"errmsg":"ok"}
從輸出的信息可以看到是創建成功的,那么就打開測試的公眾號,自定義菜單果然成功創建了,如下:
子菜單也能正常顯示,如下:
開發完自定義菜單的創建功能后,本小節我們來看看自定義菜單的事件推送,官方文檔地址如下:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141016
用戶點擊自定義菜單后,微信會把點擊事件推送給開發者,這樣開發者就可以對一些事件進行相應的邏輯處理。請注意,點擊菜單彈出子菜單,不會產生上報。請注意,第3個到第8個的所有事件,僅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用戶,舊版本微信用戶點擊后將沒有回應,開發者也不能正常接收到事件推送。
首先,我們來看看click類型的事件推送。當點擊click類型的菜單拉取消息時,會產生事件推送。推送XML數據包示例:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[CLICK]]></Event>
<EventKey><![CDATA[EVENTKEY]]></EventKey>
</xml>
參數的說明如下:
新增一個枚舉類,用于封裝菜單事件類型,代碼如下:
package org.zero01.weixin.mqdemo.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @program: mq-demo
* @description: 菜單事件類型
* @author: 01
* @create: 2018-06-24 14:09
**/
@Getter
@AllArgsConstructor
public enum MenuType {
// 菜單的click類型
MENU_CLICK("CLICK"),
// 菜單的view類型
MENU_VIEW("VIEW"),
MENU_SCANCODE("scancode_push"),
MENU_LOCATION("location"),
;
private String menuType;
}
那么我們就來實現一些簡單的菜單事件推送效果吧,在 WeChatMqController 的text方法里,增加一些判斷條件,雖然這樣比較low,但是demo嘛,懶得寫那么仔細了,粗暴的能實現就行,如下:
/**
* 接收微信公眾號消息的接口
*
* @param xmlStr
* @return
*/
@PostMapping("/common")
public String text(@RequestBody String xmlStr) {
// 將xml格式的數據,轉換為 AllMessage 對象
AllMessage allMessage = MessageUtil.xmlToAllMessage(xmlStr);
// 是否是文本消息類型
if (allMessage.getMsgType().equals(MessageTypeEnum.MSG_TEXT.getMsgType())) {
if ("1".equals(allMessage.getContent())) {
return MessageUtil.initNewsMessage(allMessage.getToUserName(), allMessage.getFromUserName());
} else if ("2".equals(allMessage.getContent())) {
return MessageUtil.initImageMessage(allMessage.getToUserName(), allMessage.getFromUserName());
} else if ("3".equals(allMessage.getContent())) {
return MessageUtil.initMusicMessage(allMessage.getToUserName(), allMessage.getFromUserName());
}
// 自動回復用戶所發送的文本消息
return MessageUtil.autoReply(allMessage, ContentEnum.CONTENT_PREFIX.getContent() + allMessage.getContent());
}
// 是否是事件推送類型
else if (allMessage.getMsgType().equals(MessageTypeEnum.MSG_EVENT.getMsgType())) {
// 是否為訂閱事件
if (EventType.EVENT_SUBSCRIBE.getEventType().equals(allMessage.getEvent())) {
// 自動回復歡迎語
return MessageUtil.autoReply(allMessage, ContentEnum.CONTENT_SUBSCRIBE.getContent());
} else if (MenuType.MENU_CLICK.getMenuType().equals(allMessage.getEvent())) {
return MessageUtil.autoReply(allMessage, "你點擊了click菜單");
} else if (MenuType.MENU_VIEW.getMenuType().equals(allMessage.getEvent())) {
String url = allMessage.getEventKey();
System.out.println("用戶點擊了view菜單, url: " + url);
} else if (MenuType.MENU_SCANCODE.getMenuType().equals(allMessage.getEvent())) {
String key = allMessage.getEventKey();
System.out.println("用戶點擊了掃碼菜單, key: " + key);
}
} else if (MenuType.MENU_LOCATION.getMenuType().equals(allMessage.getMsgType())) {
String label = allMessage.getLabel();
return MessageUtil.autoReply(allMessage, "你點擊了發送地理位置菜單, label: " + label);
} else {
// 暫不支持文本以外的消息回復
return MessageUtil.autoReply(allMessage, ContentEnum.CONTENT_NONSUPPORT.getContent());
}
return MessageUtil.autoReply(allMessage, ContentEnum.CONTENT_NONSUPPORT.getContent());
}
重啟SpringBoot工程,效果如下:
控制臺輸出信息如下:
用戶點擊了view菜單, url: http://www.baidu.com
用戶點擊了掃碼菜單, key: click_002
菜單的幾個基本事件也介紹完了,本小節我們來看看自定義菜單的查詢與刪除,官方文檔地址如下,自定義菜單查詢接口:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014
自定義菜單刪除接口:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015
由于查詢與刪除接口比較簡單,這里就不贅述了,直接開始開發吧。同樣的,我們需要先把這兩個接口的url地址配置到SpringBoot的配置文件當中,如下:
wechat:
...
queryMenuUrl: https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
delMenuUrl: https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
在配置類里加上這兩個配置項的字段,如下:
...
public class WeXinConfig {
...
private String queryMenuUrl;
private String delMenuUrl;
}
在WeiXinUtil類中,增加如下兩個方法:
/**
* 查詢自定義菜單
*
* @param token
* @return
* @throws IOException
*/
public static JSONObject queryMenu(String token) throws IOException {
String url = wxConfig.getQueryMenuUrl().replace("ACCESS_TOKEN", token);
return doGet(url);
}
/**
* 刪除當前使用的自定義菜單
*
* @param token
* @return
* @throws IOException
*/
public static JSONObject delMenu(String token) throws IOException {
String url = wxConfig.getDelMenuUrl().replace("ACCESS_TOKEN", token);
return doGet(url);
}
在WeiXinUtilTest測試類里,增加如下測試方法:
@Test
public void queryMenu() throws IOException {
AccessToken accessToken = WeiXinUtil.getAccessToken();
org.json.JSONObject jsonObject = WeiXinUtil.queryMenu(accessToken.getToken());
System.out.println(jsonObject);
}
執行測試方法后,正常情況會返回一段json格式的數據,將其格式化后,如下:
{
"menu": {
"button": [
{
"name": "click菜單",
"sub_button": [],
"type": "click",
"key": "click_001"
},
{
"name": "view菜單",
"sub_button": [],
"type": "view",
"url": "http:\/\/www.baidu.com"
},
{
"name": "自定義菜單",
"sub_button": [
{
"name": "掃碼事件",
"sub_button": [],
"type": "scancode_push",
"key": "click_002"
},
{
"name": "發送地理位置",
"sub_button": [],
"type": "location_select",
"key": "click_003"
}
]
}
]
}
}
查詢自定義菜單的方法測試成功后,再來測試一下刪除當前使用的自定義菜單的方法。在WeiXinUtilTest測試類里,增加如下測試方法:
@Test
public void delMenu() throws IOException {
AccessToken accessToken = WeiXinUtil.getAccessToken();
org.json.JSONObject jsonObject = WeiXinUtil.delMenu(accessToken.getToken());
System.out.println(jsonObject);
}
執行測試方法后,控制臺輸出如下:
{"errcode":0,"errmsg":"ok"}
可以看到,菜單已經刪除成功了,沒有之前的菜單按鈕了:
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。