Java微信公众平台之自定义菜单

一、自定义菜单的说明和按钮类型

1、菜单说明

1)自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。

2)一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。
3)创建自定义菜单后,菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。

2、自定义菜单接口可实现多种类型按钮

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。

说明:3到8的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。9和10,是专门给第三方平台旗下未微信认证(具体而言,是资质认证未通过)的订阅号准备的事件类型,它们是没有事件推送的,能力相对受限,其他类型的公众号不必使用。

二、菜单的创建/查询/删除

官方的click和view事件demo

{
 "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"
   }]
  }]
}

其他类型(包括9、10)

{
 "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"
  }
 ]
} 

1、根据实例开始封装实体类

菜单按钮基类BasicButton.java

public class BasicButton { 

 private String name; 

 public String getName() {
  return name;
 } 

 public void setName(String name) {
  this.name = name;
 }
}

菜单Menu.java

public class Menu { 

 public final static String CLICK = "click"; // click菜单
 public final static String VIEW = "view"; // url菜单
 public final static String SCANCODE_WAITMSG = "scancode_waitmsg"; // 扫码带提示
 public final static String SCANCODE_PUSH = "scancode_push"; // 扫码推事件
 public final static String PIC_SYSPHOTO = "pic_sysphoto"; // 系统拍照发图
 public final static String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; // 拍照或者相册发图
 public final static String PIC_WEIXIN = "pic_weixin"; // 微信相册发图
 public final static String LOCATION_SELECT = "location_select"; // 发送位置 

 private BasicButton[] button; 

 public BasicButton[] getButton() {
  return button;
 } 

 public void setButton(BasicButton[] button) {
  this.button = button;
 }
} 

view类型按钮类ViewButton.java,其他的类型可以照此一一封装

public class ViewButton extends BasicButton { 

 private String type = Menu.VIEW;
 private 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;
 }
}

一级菜单包含二级菜单的封装ComplexMenu.java

public class ComplexMenu extends BasicButton { 

 private BasicButton[] sub_button; 

 public BasicButton[] getSub_button() {
  return sub_button;
 } 

 public void setSub_button(BasicButton[] sub_button) {
  this.sub_button = sub_button;
 }
}

2.封装完毕,组装菜单

private static Menu getMenu() { 

 ViewButton btn11 = new ViewButton();
 btn11.setName("测试11");
 btn11.setUrl("http://www.qq.com"); 

 ClickButton btn21 = new ClickButton();
 btn21.setName("测试21");
 btn21.setKey("21"); 

 ClickButton btn22 = new ClickButton();
 btn22.setName("测试22");
 btn22.setKey("22"); 

 //一级菜单(没有二级菜单)
 ComplexMenu mainBtn1 = new ComplexMenu();
 mainBtn1.setName("测试1");
 mainBtn1.setSub_button(new BasicButton[] { btn11}); 

 //一级菜单(有二级菜单)
 ComplexMenu mainBtn2 = new ComplexMenu();
 mainBtn2.setName("测试2");
 mainBtn2.setSub_button(new BasicButton[] { btn21, btn22 }); 

 Menu menu = new Menu();
 menu.setButton(new BasicButton[] { mainBtn1, mainBtn2 });
 return menu;
}

3.自定义菜单的创建

/**
 * 创建的菜单
 *
 * @param menu 菜单项
 * @param token 授权token
 * @return {"errcode":0,"errmsg":"ok"}
 */
public ResultState createMenu(Menu menu, String token) {
 TreeMap<String, String> map = new TreeMap<String, String>();
 map.put("access_token", token);
 String jsonData = JsonUtil.toJson(menu).toString();
 String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.POST_METHOD, WechatConfig.MENU_CREATE_URL, map, jsonData);
 return JsonUtil.fromJson(result, ResultState.class);
}

4、自定义菜单的查询

返回的实例

对应创建接口,正确的Json返回结果:

{
 "menu": {
  "button": [
   {
    "type": "click",
    "name": "今日歌曲",
    "key": "V1001_TODAY_MUSIC",
    "sub_button": [ ]
   },
   {
    "type": "click",
    "name": "歌手简介",
    "key": "V1001_TODAY_SINGER",
    "sub_button": [ ]
   },
   {
    "name": "菜单",
    "sub_button": [
     {
      "type": "view",
      "name": "搜索",
      "url": "http://www.soso.com/",
      "sub_button": [ ]
     },
     {
      "type": "view",
      "name": "视频",
      "url": "http://v.qq.com/",
      "sub_button": [ ]
     },
     {
      "type": "click",
      "name": "赞一下我们",
      "key": "V1001_GOOD",
      "sub_button": [ ]
     }
    ]
   }
  ]
 }
}
/**
  * 获取自定义菜单
  *
  * @param token
  * @return
  */
 public String getMenu(String token) {
  TreeMap<String, String> map = new TreeMap<String, String>();
  map.put("access_token", token);
  String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, WechatConfig.MENU_GET_URL, map, "");
  return result;
 }

菜单所有属性MenuAttr.java

/**
 * 菜单所有属性
 * @author phil
 *
 */
public class MenuAttr extends BasicMenu { 

 private String type;
 private String url;
 private String key;
 private String sub_button; 

 get/set方法
}

返回的菜单类MenuReturn.java

/**
 * 返回的菜单类
 * @author phil
 *
 */
public class MenuReturn extends BasicMenu{ 

 private MenuAttr[] sub_button; 

 public MenuAttr[] getSub_button() {
  return sub_button;
 } 

 public void setSub_button(MenuAttr[] subButton) {
  sub_button = subButton;
 }
} 

将json格式的字符串转换为Menu对象

/**
 * 将json格式的字符串转换为Menu对象
 * @param json
 * @return
 */
public List<MenuReturn> converMenu(String json) {
 List<MenuReturn> list = new ArrayList<MenuReturn>();
 if (json!= null && !"".equals(json)) {
  JSONObject object = JSONObject.parseObject(json);
  JSONArray array = object.getJSONObject("menu").getJSONArray("button");
  for (int i = 0; i < array.size(); i++) {
   MenuReturn mr= new MenuReturn();
   mr= array.getObject(i, MenuReturn.class);
   list.add(mr);
  }
 }
 return list;
}

注:此处用的fastjson

此处方法待改进,有更好的请指教一二

5、自定义菜单的删除

 /**
 * 删除自定义菜单
 *
 * @param token
 * @return
 */
public boolean deleteMenu(String token) {
 boolean falg = true;
 TreeMap<String, String> map = new TreeMap<String, String>();
 map.put("access_token", token);
 String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, WechatConfig.MENU_DELTE_URL, map, "");
 ResultState state = JsonUtil.fromJson(result, ResultState.class);
 if (state.getErrcode()!= 0|| state.getErrmsg() != "ok") {
  falg = false;
 }
 return falg;
}

三、自定义菜单事件推送

用户点击自定义菜单后,微信会把点击事件推送给开发者,请注意,点击菜单弹出子菜单,不会产生上报。请注意,第3个到第8个的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。

1、解析微信推送的xml数据包

/**
 * 解析微信发来的请求(XML)
 * 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>
 * @param request
 * @return
 * @throws Exception
 */
public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
 // 将解析结果存储在HashMap中
 Map<String, String> map = new HashMap<String, String>();
 // 从request中取得输入流
 InputStream inputStream = request.getInputStream();
 // 读取输入流
 SAXReader reader = new SAXReader();
 Document document = reader.read(inputStream);
 // 得到xml根元素
 Element root = document.getRootElement();
 // 得到根元素的所有子节点
 List<Element> elementList = root.elements(); 

 // 遍历所有子节点
 for (Element e : elementList)
  map.put(e.getName(), e.getText()); 

 // 释放资源
 inputStream.close();
 inputStream = null;
 return map;
} 

2、利用map的get(key)获取value

MsgType 消息类型,event
Event          事件类型,CLICK
EventKey 事件KEY值,与自定义菜单接口中KEY值对应

注:key是参数名

附:WechatConfig.java

// 创建菜单
public static final String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create";
// 查询自定义菜单
public static final String MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get";
// 删除自定义菜单
public static final String MENU_DELTE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete"; 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java实现微信公众平台自定义菜单的创建示例

    复制代码 代码如下: import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL; import org.json.JSONObject; public class MenuUtil { /**  * 获得ACC

  • Java微信公众平台开发(10) 微信自定义菜单的创建实现

    自定义菜单这个功能在我们普通的编辑模式下是可以直接在后台编辑的,但是一旦我们进入开发模式之后我们的自定义菜单就需要自己用代码实现,所以对于刚开始接触的人来说可能存在一定的疑惑,这里我说下平时我们在开发模式下常用的两种自定义菜单的实现方式:①不用写实现代码,直接用网页测试工具Post json字符串生成菜单:②就是在我们的开发中用代码实现菜单生成!(参考文档:http://mp.weixin.qq.com/wiki/10/0234e39a2025342c17a7d23595c6b40a.html 

  • java微信开发API第四步 微信自定义个性化菜单实现

    微信如何实现自定义个性化菜单,下面为大家介绍 一.全局说明 详细说明请参考前两篇文章. 二.本文说明 本文分为五部分:     * 工具类AccessTokenUtils的封装     * 自定义菜单和个性化菜单文档的阅读解析     * 菜单JSON的分析以及构建对应bean     * 自定义菜单的实现     * 个性化菜单的实现 微信自定义菜单所有类型菜单都给出演示 本文结束会给出包括本文前四篇文章的所有演示源码 工具类AccessTokenUtils的封装 在上文中关于AccessTo

  • Android仿微信菜单(Menu)(使用C#和Java分别实现)

    本篇是对安卓菜单使用编程方式实现,当然可以使用XML的方式完成同样的功能,基本Java和C#写法都是一致的,所以使用XML的方式在本篇中使用Java演示,需要注意的是,对于如果不是VS开发的话,那么资源文件名称必须以小写开头,否则会报错. 运行效果 C#实现 using Android.App; using Android.OS; using Android.Views; using Android.Widget; namespace MenuDemo { [Activity(Label = "

  • Java微信公众平台之自定义菜单

    一.自定义菜单的说明和按钮类型 1.菜单说明 1)自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单. 2)一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以"..."代替. 3)创建自定义菜单后,菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单.测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果. 2.自定义菜单接口可实现多种类型

  • php实现微信公众平台账号自定义菜单类

    微信公众平台服务号可申请自定义菜单了,其它的号暂时不支持自定义菜单了,这个不但可以使用api来操作,还可以直接在后台定义菜单与参数哦. 服务号可以申请自定义菜单:使用QQ登录的公众号,可以升级为邮箱登录:使用邮箱登录的公众号,可以修改登录邮箱:群发消息可以同步到腾讯微博.微信公众平台升级:服务号可申请自定义菜单 wx_menu.php <?php //define your token define("TOKEN", "chenxiang");//改成自己的T

  • PHP实现微信公众号企业号自定义菜单接口示例

    本文实例讲述了PHP实现微信公众号企业号自定义菜单接口.分享给大家供大家参考,具体如下: define(AppId, "wx666cae44xxxxxx2");//定义AppId,需要在微信公众平台申请自定义菜单后会得到 define(AppSecret, "d77026a714d443a01d0229xxxxxxxx");//定义AppSecret,需要在微信公众平台申请自定义菜单后会得到 include("menu.php");//引入微信类

  • Java微信公众平台之群发接口(高级群发)

    再次吐槽下,微信素材管理和群发这块文档对Java很不友好,此文需要结合我前文和官方文档. 测试号调试群发只需看是否群发消息是否能组装成功,不需要看结果如何(反正不会发送成功的),因为微信还没开放这个功能(估计也不会开放的). 一.群发说明 在公众平台网站上,为订阅号提供了每天一条的群发权限,为服务号提供每月(自然月)4条的群发权限. 1.对于认证订阅号,群发接口每天可成功调用1次,此次群发可选择发送给全部用户或某个标签: 2.对于认证服务号虽然开发者使用高级群发接口的每日调用限制为100次,但是

  • Java微信公众平台之素材管理

    微信素材管理和群发这块文档对Java很不友好.本文只对新增临时素材,新增永久素材做介绍,其余获取.删除.修改自行补充 公众号经常有需要用到一些临时性的多媒体素材的场景,例如在使用接口特别是发送消息时,对多媒体文件.多媒体消息的获取和调用等操作,是通过media_id来进行的.素材管理接口对所有认证的订阅号和服务号开放. 素材的限制 图片(image): 2M,支持PNG\JPEG\JPG\GIF格式 语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式 视频(video):10

  • Java微信公众平台之获取地理位置

    本部分需要用到微信的JS-SDK,微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统的能力,同时可以直接使用微信分享.扫一扫.卡券.支付等微信特有的能力,为微信用户提供更优质的网页体验. 官方文档 一.JS-SDK引入 1.先登录微信公众平台进入"公众号设置"的"功能设置"里填写"JS接口安全域名",和网页授权一样只是个域名. 2

  • 微信公众号开发 自定义菜单跳转页面并获取用户信息实例详解

    微信公众号开发 自定义菜单 请先读完本文再进行配置开发 请先前往微信平台开发者文档阅读"网页授权获取用户基本信息"的接口说明 在微信公众账号开发中,往往有定义一个菜单,然后用户点击该菜单就进入用户个人中心的功能,通常应用于各个公众账号中的会员服务. 如何在微信自定义菜单中将用户导航到个人中心页面呢? 首选需要通过用户点击获取用户openid,而通过用户的点击跳转获取用户openid就必须在菜单中动态绑定用户的openid,或者在菜单的跳转URL中填写微信提供的链接,官方给了两个链接类型

  • Java微信公众平台开发(12) 微信用户信息的获取

    前面的文章有讲到微信的一系列开发文章,包括token获取.菜单创建等,在这一篇将讲述在微信公众平台开发中如何获取微信用户的信息,在上一篇我们有说道微信用户和微信公众账号之间的联系可以通过Openid关联,所以在这里我们就采用openid去获取用户微信信息,并实现一个简单场景应用:当微信新用户关注我们的微信公众平台的时候我们自动回复一篇图文消息,然后在图文消息中标题为:[尊敬的:XXX,你好!],而且在图文消息中的图片就是用户的微信头像,如下图: 有关获取微信用户信息的文档我们可以参照:http:

  • Java微信公众平台开发(1) 接入微信公众平台

    前面几篇文章一直都在说微信公众平台的开发准备工作,那么从这篇开始我们就将正式的进入JAVA微信公众平台开发的整个流程,那么这篇我们开始聊聊如何将我们的服务端和微信公众平台对接! (一)接入流程解析 在我们的开发过程中无论如何最好的参考工具当然是我们的官方文档了:http://mp.weixin.qq.com/wiki/8/f9a0b8382e0b77d87b3bcc1ce6fbc104.html 通过上面我们可以看出其中接入微信公众平台开发,开发者需要按照如下步骤完成: 填写服务器配置 验证服务

  • Java微信公众平台之消息管理

    Java微信公众平台开发之消息管理,一定要先看下官方文档 微信消息管理分为接收普通消息.接收事件推送.发送消息(被动回复).客服消息.群发消息.模板消息这几部分 一.接收普通消息 当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上. 关于MsgId,官方给出解释,相当于每个消息ID,关于重试的消息排重,推荐使用msgid排重.微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次. 比如文本消息的Xml示例 <xml> <ToU

随机推荐