自定义菜单基本介绍:
目前自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。请注意,创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来。建议测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。
目前自定义菜单接口可实现两种类型按钮,如下:
click: 用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event 的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互; view: 用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的url值 (即网页链接),达到打开网页的目的,建议与网页授权获取用户基本信息接口结合,获得用户的登入个人信息。
接口调用请求说明
http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
自定义菜单的请求是一个json格式的请求内容
官网的请求示例
{ "button":[ { "type":"click", "name":"今日歌曲", "key":"V1001_TODAY_MUSIC" }, { "type":"click", "name":"歌手简介", "key":"V1001_TODAY_SINGER" }, { "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数据包如下:
{"errcode":0,"errmsg":"ok"}
错误时的返回JSON数据包如下(示例为无效菜单名长度):
{"errcode":40018,"errmsg":"invalid button name size"}
首先是菜单项的基类,所有一级菜单、二级菜单都共有一个相同的属性,那就是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以是一个子菜单项数组。父菜单项的封装代码如下:
package org.liufeng.weixin.pojo; /** * 复杂按钮(父按钮) * * @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; } }
关于POJO类的封装就介绍完了
/** * 组装菜单数据 * * @return */ private static Menu getMenu() { CommonButton btn11 = new CommonButton(); btn11.setName("天气预报"); 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("经典游戏"); 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目前的菜单结构,每个一级菜单都有二级菜单项<br> * * 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?<br> * 比如,第三个一级菜单项不是"更多体验",而直接是"幽默笑话",那么menu应该这样定义:<br> * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 }); */ Menu menu = new Menu(); menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 }); return menu; } }
通过json格式创建菜单
package controllers;
import org.apache.log4j.Logger;
import com.star.wxservice.MenuService;
import com.star.wxservice.baseservice;
import com.star.wxservice.impl.MenuServiceImpl;
public class WXMenuController extends ApplicationController {
baseservice baseservice = new baseservice();
MenuService menuService = new MenuServiceImpl();
private static Logger logger = Logger.getLogger(DrpController.class);
/**
* 微信菜单
*
* @return
*/
public static String getJsonMenu() {
// baseservice.BuildAuthCallbackUrl("需要授权的URL地址",EnumScopeType.snsapi_userinfo);
StringBuilder jsonMenu = new StringBuilder();
jsonMenu.append("{\"button\":[");
jsonMenu.append("{\"name\":\"主菜单一\",\"sub_button\":[");
jsonMenu.append("{\"type\":\"click\",\"name\":\"输入1\",\"key\":\"M1001\"},");
jsonMenu.append("{\"type\":\"view\",\"name\":\"搜搜\",\"url\":\"http://www.soso.com/\"}]},");
jsonMenu.append("{\"type\":\"click\",\"name\":\"主菜单二\",\"key\":\"M2001\"},");
jsonMenu.append("{\"type\":\"click\",\"name\":\"主菜单三\",\"key\":\"M3001\"}");
jsonMenu.append("]}");
return jsonMenu.toString();
}
/**
* 自定义微信菜单
*
* 1、自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。
* 2、一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。
* 3、创建自定义菜单后,菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。
*
* @return
* @throws Exception
*/
public String CreateMenu() throws Exception {
String jsonMenu = getJsonMenu();
String strjson = "";
try {
strjson = menuService.CreateMenu(jsonMenu);
} catch (Exception e) {
logger.error("创建菜单失败" + e);
e.printStackTrace();
}
return strjson;
}
/**
* 使用接口创建自定义菜单后,开发者还可使用接口删除当前使用的自定义菜单。另请注意,在个性化菜单时,调用此接口会删除默认菜单及全部个性化菜单。
*
* @return
*/
public String DeleteMenu() {
String strjson = menuService.DeleteMenu();
return strjson;
}
}
package com.star.wxservice.impl;
import org.apache.log4j.Logger;
import com.star.utils.HttpRequestUtil;
import com.star.wxservice.MenuService;
import com.star.wxservice.baseservice;
import controllers.DrpController;
import net.sf.json.JSONObject;
public class MenuServiceImpl implements MenuService {
baseservice baseservice = new baseservice();
private static Logger logger = Logger.getLogger(DrpController.class);
// 菜单创建(POST) 限100(次/天)
public static String MENU_CREATE = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
// 删除当前使用的自定义菜单
public static String MENU_DELETE = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
public String CreateMenu(String jsonMenu) {
String resultStr = "";
// 调用接口获取token
String token = null;
try {
token = baseservice.GetAccessToken();
} catch (Exception e) {
logger.error("菜单创建获取token异常");
// TODO Auto-generated catch block
e.printStackTrace();
}
if (token != null) {
// 调用接口创建菜单
int result = createMenu(jsonMenu, token);
// 判断菜单创建结果
if (0 == result) {
resultStr = "菜单创建成功";
logger.info(resultStr);
} else {
resultStr = "菜单创建失败,错误码:" + result;
logger.error(resultStr);
}
}
return resultStr;
}
/**
* 创建菜单
*
* @param jsonMenu
* 菜单的json格式
* @param accessToken
* 有效的access_token
* @return 0表示成功,其他值表示失败
*/
public static int createMenu(String jsonMenu, String accessToken) {
int result = 0;
// 拼装创建菜单的url
String url = MENU_CREATE.replace("ACCESS_TOKEN", accessToken);
// 调用接口创建菜单
String strjson = HttpRequestUtil.httpRequest(url, jsonMenu, "POST");
JSONObject jsonObject = JSONObject.fromObject(strjson);
if (null != jsonObject) {
if (0 != jsonObject.getInt("errcode")) {
result = jsonObject.getInt("errcode");
logger.error(
"创建菜单失败 errcode:" + jsonObject.getInt("errcode") + ",errmsg:" + jsonObject.getString("errmsg"));
}
}
return result;
}
/**
* 删除默认菜单及全部个性化菜单。
*
* @return
*/
public String DeleteMenu() {
String token = null;
try {
token = baseservice.GetAccessToken();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String url = MENU_DELETE.replace("ACCESS_TOKEN", token);
String strjson = HttpRequestUtil.httpRequest(url, "", "GET");
return strjson;
}
}
部分转载于:http://www.5icool.org/a/201308/a2152_2.html