精华内容
下载资源
问答
  • 距离写上一篇文章《自定义菜单的创建及菜单事件响应》整整过了两个月的时间,那时公众平台还没有开放view类型的菜单。在不久前,微信公众平台悄悄开放了view类型... 用户点击view类型按钮后,会直接跳转到开发者指定的

    距离写上一篇文章《自定义菜单的创建及菜单事件响应》整整过了两个月的时间,那时公众平台还没有开放view类型的菜单。在不久前,微信公众平台悄悄开放了view类型的菜单,却没有在首页发布任何通知,貌似微信团队很喜欢这么干。一个偶然的机会,我留意到API文档的自定义菜单接口发生了变化,增加了对菜单view类型的说明:

    view(访问网页):

     用户点击view类型按钮后,会直接跳转到开发者指定的url中。

    于是我在第一时间更新了小q机器人(微信号:xiaoqrobot)的菜单,在一级菜单“更多”下增加了二级菜单“使用帮助”,点击该菜单项会直接跳转到网页,如下图所示。


    最近也有不少网友问起这种类型的菜单是如何创建的,本篇文章就为大家介绍下view类型的自定义菜单该如何创建。


    自定义菜单的两种类型(click和view)

    公众平台API文档中给出了自定义菜单的json结构示例,我从中截取两个菜单项的json代码,一个是click类型,另一个是view类型,如下所示。

    [html] view plaincopy
    1. {     
    2.     "type":"click",  
    3.     "name":"今日歌曲",  
    4.     "key":"V1001_TODAY_MUSIC"  
    5. },  
    6. {  
    7.     "type":"view",  
    8.     "name":"歌手简介",  
    9.     "url":"http://www.qq.com/"  
    10. }  
    从上面可以看出,两种类型的菜单除了type值不同之外,属性也有差别。click类型的菜单有key属性,而view类型的菜单没有key属性,与之对应的是url属性。通过上一篇的学习我们知道,key值是用于判断用户点击了哪个click类型的菜单项。而view类型的菜单没有key属性,目前无法在公众账号后台判断是否有用户点击了view类型的菜单项,也就没办法知道哪个用户点击了view类型的菜单项。


    建立view类型的菜单对象

    View类型的菜单有3个属性:type、name和url。在上一篇文章中,我们创建了菜单项的基类Button,Button类只有一个属性name。View类型的菜单对象也需要继承Button类,代码如下:

    [java] view plaincopy
    1. package org.liufeng.weixin.pojo;  
    2.   
    3. /** 
    4.  * view类型的菜单 
    5.  *  
    6.  * @author liuyq 
    7.  * @date 2013-04-10 
    8.  */  
    9. public class ViewButton extends Button {  
    10.     private String type;  
    11.     private String url;  
    12.   
    13.     public String getType() {  
    14.         return type;  
    15.     }  
    16.   
    17.     public void setType(String type) {  
    18.         this.type = type;  
    19.     }  
    20.   
    21.     public String getUrl() {  
    22.         return url;  
    23.     }  
    24.   
    25.     public void setUrl(String url) {  
    26.         this.url = url;  
    27.     }  
    28. }  


    创建带view类型的菜单示例

    我们对前一篇文章中给出的菜单创建代码进行调整,增加view类型的菜单项,完整的菜单创建代码如下:

    [java] view plaincopy
    1. package org.liufeng.weixin.main;  
    2.   
    3. import org.liufeng.weixin.pojo.AccessToken;  
    4. import org.liufeng.weixin.pojo.Button;  
    5. import org.liufeng.weixin.pojo.CommonButton;  
    6. import org.liufeng.weixin.pojo.ComplexButton;  
    7. import org.liufeng.weixin.pojo.Menu;  
    8. import org.liufeng.weixin.pojo.ViewButton;  
    9. import org.liufeng.weixin.util.WeixinUtil;  
    10. import org.slf4j.Logger;  
    11. import org.slf4j.LoggerFactory;  
    12.   
    13. /** 
    14.  * 菜单管理器类 
    15.  *  
    16.  * @author liufeng 
    17.  * @date 2013-08-08 
    18.  */  
    19. public class MenuManager {  
    20.     private static Logger log = LoggerFactory.getLogger(MenuManager.class);  
    21.   
    22.     public static void main(String[] args) {  
    23.         // 第三方用户唯一凭证  
    24.         String appId = "000000000000000000";  
    25.         // 第三方用户唯一凭证密钥  
    26.         String appSecret = "00000000000000000000000000000000";  
    27.   
    28.         // 调用接口获取access_token  
    29.         AccessToken at = WeixinUtil.getAccessToken(appId, appSecret);  
    30.   
    31.         if (null != at) {  
    32.             // 调用接口创建菜单  
    33.             int result = WeixinUtil.createMenu(getMenu(), at.getToken());  
    34.   
    35.             // 判断菜单创建结果  
    36.             if (0 == result)  
    37.                 log.info("菜单创建成功!");  
    38.             else  
    39.                 log.info("菜单创建失败,错误码:" + result);  
    40.         }  
    41.     }  
    42.   
    43.     /** 
    44.      * 组装菜单数据 
    45.      *  
    46.      * @return 
    47.      */  
    48.     private static Menu getMenu() {  
    49.         CommonButton btn11 = new CommonButton();  
    50.         btn11.setName("天气预报");  
    51.         btn11.setType("click");  
    52.         btn11.setKey("11");  
    53.   
    54.         CommonButton btn12 = new CommonButton();  
    55.         btn12.setName("公交查询");  
    56.         btn12.setType("click");  
    57.         btn12.setKey("12");  
    58.   
    59.         CommonButton btn13 = new CommonButton();  
    60.         btn13.setName("周边搜索");  
    61.         btn13.setType("click");  
    62.         btn13.setKey("13");  
    63.   
    64.         CommonButton btn14 = new CommonButton();  
    65.         btn14.setName("历史上的今天");  
    66.         btn14.setType("click");  
    67.         btn14.setKey("14");  
    68.           
    69.         CommonButton btn15 = new CommonButton();  
    70.         btn15.setName("电影排行榜");  
    71.         btn15.setType("click");  
    72.         btn15.setKey("32");  
    73.   
    74.         CommonButton btn21 = new CommonButton();  
    75.         btn21.setName("歌曲点播");  
    76.         btn21.setType("click");  
    77.         btn21.setKey("21");  
    78.   
    79.         CommonButton btn22 = new CommonButton();  
    80.         btn22.setName("经典游戏");  
    81.         btn22.setType("click");  
    82.         btn22.setKey("22");  
    83.   
    84.         CommonButton btn23 = new CommonButton();  
    85.         btn23.setName("美女电台");  
    86.         btn23.setType("click");  
    87.         btn23.setKey("23");  
    88.   
    89.         CommonButton btn24 = new CommonButton();  
    90.         btn24.setName("人脸识别");  
    91.         btn24.setType("click");  
    92.         btn24.setKey("24");  
    93.   
    94.         CommonButton btn25 = new CommonButton();  
    95.         btn25.setName("聊天唠嗑");  
    96.         btn25.setType("click");  
    97.         btn25.setKey("25");  
    98.   
    99.         CommonButton btn31 = new CommonButton();  
    100.         btn31.setName("Q友圈");  
    101.         btn31.setType("click");  
    102.         btn31.setKey("31");  
    103.   
    104.         CommonButton btn33 = new CommonButton();  
    105.         btn33.setName("幽默笑话");  
    106.         btn33.setType("click");  
    107.         btn33.setKey("33");  
    108.           
    109.         CommonButton btn34 = new CommonButton();  
    110.         btn34.setName("用户反馈");  
    111.         btn34.setType("click");  
    112.         btn34.setKey("34");  
    113.           
    114.         CommonButton btn35 = new CommonButton();  
    115.         btn35.setName("关于我们");  
    116.         btn35.setType("click");  
    117.         btn35.setKey("35");  
    118.           
    119.         ViewButton btn32 = new ViewButton();  
    120.         btn32.setName("使用帮助");  
    121.         btn32.setType("view");  
    122.         btn32.setUrl("http://liufeng.gotoip2.com/xiaoqrobot/help.jsp");  
    123.   
    124.         ComplexButton mainBtn1 = new ComplexButton();  
    125.         mainBtn1.setName("生活助手");  
    126.         mainBtn1.setSub_button(new Button[] { btn11, btn12, btn13, btn14, btn15 });  
    127.   
    128.         ComplexButton mainBtn2 = new ComplexButton();  
    129.         mainBtn2.setName("休闲驿站");  
    130.         mainBtn2.setSub_button(new Button[] { btn21, btn22, btn23, btn24, btn25 });  
    131.   
    132.         ComplexButton mainBtn3 = new ComplexButton();  
    133.         mainBtn3.setName("更多");  
    134.         mainBtn3.setSub_button(new Button[] { btn31, btn33, btn34, btn35, btn32 });  
    135.   
    136.         /** 
    137.          * 这是公众号xiaoqrobot目前的菜单结构,每个一级菜单都有二级菜单项<br> 
    138.          *  
    139.          * 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?<br> 
    140.          * 比如,第三个一级菜单项不是“更多体验”,而直接是“幽默笑话”,那么menu应该这样定义:<br> 
    141.          * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 }); 
    142.          */  
    143.         Menu menu = new Menu();  
    144.         menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });  
    145.   
    146.         return menu;  
    147.     }  
    148. }  

    119~122行代码就是用于创建view类型菜单项的。上面的菜单结构也是小q机器人(微信号:xiaoqrobot)目前在使用的,读者可以对照着理解。

    补充:居然还有些网友问我上面的自定义菜单创建代码在哪里调用,问我为什么不把调用的代码也公开?搞的我都有点不好意思了。上面的菜单创建代码是写在main方法中,直接在开发工具中运行一下就可以了,这应该是最最基础的Java知识了。另外,菜单只要创建一次,会一直存在的,不需要每次启动应用程序都去创建菜单。当然,你也可以把菜单的创建代码集成到项目中,并非一定要放在main方法中。程序是死的,人是活的,解决方法往往有很多种,怎么方便实用就怎么来!

    展开全文
  • 一、自定义菜单的说明和按钮类型 1、菜单说明 1)自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。 2)一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。 3)创建...

     

     

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

    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

    
     
    1. {

    2. "button":[

    3. {

    4. "type":"click",

    5. "name":"今日歌曲",

    6. "key":"V1001_TODAY_MUSIC"

    7. },

    8. {

    9. "name":"菜单",

    10. "sub_button":[

    11. {

    12. "type":"view",

    13. "name":"搜索",

    14. "url":"http://www.soso.com/"

    15. },

    16. {

    17. "type":"miniprogram",

    18. "name":"wxa",

    19. "url":"http://mp.weixin.qq.com",

    20. "appid":"wx286b93c14bbf93aa",

    21. "pagepath":"pages/lunar/index"

    22. },

    23. {

    24. "type":"click",

    25. "name":"赞一下我们",

    26. "key":"V1001_GOOD"

    27. }]

    28. }]

    29. }

    其他类型(包括9、10)

     

    
     
    1. {

    2. "button": [

    3. {

    4. "name": "扫码",

    5. "sub_button": [

    6. {

    7. "type": "scancode_waitmsg",

    8. "name": "扫码带提示",

    9. "key": "rselfmenu_0_0",

    10. "sub_button": [ ]

    11. },

    12. {

    13. "type": "scancode_push",

    14. "name": "扫码推事件",

    15. "key": "rselfmenu_0_1",

    16. "sub_button": [ ]

    17. }

    18. ]

    19. },

    20. {

    21. "name": "发图",

    22. "sub_button": [

    23. {

    24. "type": "pic_sysphoto",

    25. "name": "系统拍照发图",

    26. "key": "rselfmenu_1_0",

    27. "sub_button": [ ]

    28. },

    29. {

    30. "type": "pic_photo_or_album",

    31. "name": "拍照或者相册发图",

    32. "key": "rselfmenu_1_1",

    33. "sub_button": [ ]

    34. },

    35. {

    36. "type": "pic_weixin",

    37. "name": "微信相册发图",

    38. "key": "rselfmenu_1_2",

    39. "sub_button": [ ]

    40. }

    41. ]

    42. },

    43. {

    44. "name": "发送位置",

    45. "type": "location_select",

    46. "key": "rselfmenu_2_0"

    47. },

    48. {

    49. "type": "media_id",

    50. "name": "图片",

    51. "media_id": "MEDIA_ID1"

    52. },

    53. {

    54. "type": "view_limited",

    55. "name": "图文消息",

    56. "media_id": "MEDIA_ID2"

    57. }

    58. ]

    59. }

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

    菜单按钮基类BasicButton.java

    
     
    1. public class BasicButton {

    2.  
    3. private String name;

    4.  
    5. public String getName() {

    6. return name;

    7. }

    8.  
    9. public void setName(String name) {

    10. this.name = name;

    11. }

    12. }

    菜单Menu.java

    
     
    1. public class Menu {

    2.  
    3. public final static String CLICK = "click"; // click菜单

    4. public final static String VIEW = "view"; // url菜单

    5. public final static String SCANCODE_WAITMSG = "scancode_waitmsg"; // 扫码带提示

    6. public final static String SCANCODE_PUSH = "scancode_push"; // 扫码推事件

    7. public final static String PIC_SYSPHOTO = "pic_sysphoto"; // 系统拍照发图

    8. public final static String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; // 拍照或者相册发图

    9. public final static String PIC_WEIXIN = "pic_weixin"; // 微信相册发图

    10. public final static String LOCATION_SELECT = "location_select"; // 发送位置

    11.  
    12. private BasicButton[] button;

    13.  
    14. public BasicButton[] getButton() {

    15. return button;

    16. }

    17.  
    18. public void setButton(BasicButton[] button) {

    19. this.button = button;

    20. }

    21. }

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

     

    
     
    1. public class ViewButton extends BasicButton {

    2.  
    3. private String type = Menu.VIEW;

    4. private String url;

    5.  
    6. public String getType() {

    7. return type;

    8. }

    9. public void setType(String type) {

    10. this.type = type;

    11. }

    12. public String getUrl() {

    13. return url;

    14. }

    15. public void setUrl(String url) {

    16. this.url = url;

    17. }

    18. }

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

    
     
    1. public class ComplexMenu extends BasicButton {

    2.  
    3. private BasicButton[] sub_button;

    4.  
    5. public BasicButton[] getSub_button() {

    6. return sub_button;

    7. }

    8.  
    9. public void setSub_button(BasicButton[] sub_button) {

    10. this.sub_button = sub_button;

    11. }

    12. }

    2.封装完毕,组装菜单

    
     
    1. private static Menu getMenu() {

    2.  
    3. ViewButton btn11 = new ViewButton();

    4. btn11.setName("测试11");

    5. btn11.setUrl("http://www.qq.com");

    6.  
    7. ClickButton btn21 = new ClickButton();

    8. btn21.setName("测试21");

    9. btn21.setKey("21");

    10.  
    11. ClickButton btn22 = new ClickButton();

    12. btn22.setName("测试22");

    13. btn22.setKey("22");

    14.  
    15. //一级菜单(没有二级菜单)

    16. ComplexMenu mainBtn1 = new ComplexMenu();

    17. mainBtn1.setName("测试1");

    18. mainBtn1.setSub_button(new BasicButton[] { btn11});

    19.  
    20. //一级菜单(有二级菜单)

    21. ComplexMenu mainBtn2 = new ComplexMenu();

    22. mainBtn2.setName("测试2");

    23. mainBtn2.setSub_button(new BasicButton[] { btn21, btn22 });

    24.  
    25. Menu menu = new Menu();

    26. menu.setButton(new BasicButton[] { mainBtn1, mainBtn2 });

    27. return menu;

    28. }

    3.自定义菜单的创建

     

    
     
    1. /**

    2. * 创建的菜单

    3. *

    4. * @param menu 菜单项

    5. * @param token 授权token

    6. * @return {"errcode":0,"errmsg":"ok"}

    7. */

    8. public ResultState createMenu(Menu menu, String token) {

    9. TreeMap<String, String> map = new TreeMap<String, String>();

    10. map.put("access_token", token);

    11. String jsonData = JsonUtil.toJson(menu).toString();

    12. String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.POST_METHOD, WechatConfig.MENU_CREATE_URL, map, jsonData);

    13. return JsonUtil.fromJson(result, ResultState.class);

    14. }

     

    4、自定义菜单的查询

    返回的实例

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

    2. {

    3. "menu": {

    4. "button": [

    5. {

    6. "type": "click",

    7. "name": "今日歌曲",

    8. "key": "V1001_TODAY_MUSIC",

    9. "sub_button": [ ]

    10. },

    11. {

    12. "type": "click",

    13. "name": "歌手简介",

    14. "key": "V1001_TODAY_SINGER",

    15. "sub_button": [ ]

    16. },

    17. {

    18. "name": "菜单",

    19. "sub_button": [

    20. {

    21. "type": "view",

    22. "name": "搜索",

    23. "url": "http://www.soso.com/",

    24. "sub_button": [ ]

    25. },

    26. {

    27. "type": "view",

    28. "name": "视频",

    29. "url": "http://v.qq.com/",

    30. "sub_button": [ ]

    31. },

    32. {

    33. "type": "click",

    34. "name": "赞一下我们",

    35. "key": "V1001_GOOD",

    36. "sub_button": [ ]

    37. }

    38. ]

    39. }

    40. ]

    41. }

    42. }

    
     
    1. /**

    2. * 获取自定义菜单

    3. *

    4. * @param token

    5. * @return

    6. */

    7. public String getMenu(String token) {

    8. TreeMap<String, String> map = new TreeMap<String, String>();

    9. map.put("access_token", token);

    10. String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, WechatConfig.MENU_GET_URL, map, "");

    11. return result;

    12. }

    菜单所有属性MenuAttr.java

    
     
    1. /**

    2. * 菜单所有属性

    3. * @author phil

    4. *

    5. */

    6. public class MenuAttr extends BasicMenu {

    7.  
    8. private String type;

    9. private String url;

    10. private String key;

    11. private String sub_button;

    12.  
    13. get/set方法

    14. }

    返回的菜单类MenuReturn.java

    
     
    1. /**

    2. * 返回的菜单类

    3. * @author phil

    4. *

    5. */

    6. public class MenuReturn extends BasicMenu{

    7.  
    8. private MenuAttr[] sub_button;

    9.  
    10. public MenuAttr[] getSub_button() {

    11. return sub_button;

    12. }

    13.  
    14. public void setSub_button(MenuAttr[] subButton) {

    15. sub_button = subButton;

    16. }

    17. }

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

    
     
    1. /**

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

    3. * @param json

    4. * @return

    5. */

    6. public List<MenuReturn> converMenu(String json) {

    7. List<MenuReturn> list = new ArrayList<MenuReturn>();

    8. if (json!= null && !"".equals(json)) {

    9. JSONObject object = JSONObject.parseObject(json);

    10. JSONArray array = object.getJSONObject("menu").getJSONArray("button");

    11. for (int i = 0; i < array.size(); i++) {

    12. MenuReturn mr= new MenuReturn();

    13. mr= array.getObject(i, MenuReturn.class);

    14. list.add(mr);

    15. }

    16. }

    17. return list;

    18. }

    注:此处用的fastjson

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

    5、自定义菜单的删除

    
     
    1. /**

    2. * 删除自定义菜单

    3. *

    4. * @param token

    5. * @return

    6. */

    7. public boolean deleteMenu(String token) {

    8. boolean falg = true;

    9. TreeMap<String, String> map = new TreeMap<String, String>();

    10. map.put("access_token", token);

    11. String result = HttpReqUtil.HttpsDefaultExecute(HttpReqUtil.GET_METHOD, WechatConfig.MENU_DELTE_URL, map, "");

    12. ResultState state = JsonUtil.fromJson(result, ResultState.class);

    13. if (state.getErrcode()!= 0|| state.getErrmsg() != "ok") {

    14. falg = false;

    15. }

    16. return falg;

    17. }

    三、自定义菜单事件推送

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

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

    
     
    1. /**

    2. * 解析微信发来的请求(XML)

    3. * xml示例

    4. * <xml>

    5. <ToUserName><![CDATA[toUser]]></ToUserName>

    6. <FromUserName><![CDATA[FromUser]]></FromUserName>

    7. <CreateTime>123456789</CreateTime>

    8. <MsgType><![CDATA[event]]></MsgType>

    9. <Event><![CDATA[CLICK]]></Event>

    10. <EventKey><![CDATA[EVENTKEY]]></EventKey>

    11. </xml>

    12. * @param request

    13. * @return

    14. * @throws Exception

    15. */

    16. public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {

    17. // 将解析结果存储在HashMap中

    18. Map<String, String> map = new HashMap<String, String>();

    19. // 从request中取得输入流

    20. InputStream inputStream = request.getInputStream();

    21. // 读取输入流

    22. SAXReader reader = new SAXReader();

    23. Document document = reader.read(inputStream);

    24. // 得到xml根元素

    25. Element root = document.getRootElement();

    26. // 得到根元素的所有子节点

    27. List<Element> elementList = root.elements();

    28.  
    29. // 遍历所有子节点

    30. for (Element e : elementList)

    31. map.put(e.getName(), e.getText());

    32.  
    33. // 释放资源

    34. inputStream.close();

    35. inputStream = null;

    36. return map;

    37. }

     

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

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

    注:key是参数名

    附:WechatConfig.java

     

    
     
    1. // 创建菜单

    2. public static final String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create";

    3. // 查询自定义菜单

    4. public static final String MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get";

    5. // 删除自定义菜单

    6. public static final String MENU_DELTE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete";

     

    展开全文
  • 自定义菜单接口可实现多种类型按钮,如下: click:点击推事件用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,...

    自定义菜单接口可实现多种类型按钮,如下:
    click:点击推事件用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;
    view:跳转URL用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的网页URL,可与网页授权获取用户基本信息接口结合,获得用户基本信息。
    scancode_push:扫码推事件用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后显示扫描结果(如果是URL,将进入URL),且会将扫码的结果传给开发者,开发者可以下发消息。
    scancode_waitmsg:扫码推事件且弹出“消息接收中”提示框用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后,将扫码的结果传给开发者,同时收起扫一扫工具,然后弹出“消息接收中”提示框,随后可能会收到开发者下发的消息。
    pic_sysphoto:弹出系统拍照发图用户点击按钮后,微信客户端将调起系统相机,完成拍照操作后,会将拍摄的相片发送给开发者,并推送事件给开发者,同时收起系统相机,随后可能会收到开发者下发的消息。
    pic_photo_or_album:弹出拍照或者相册发图用户点击按钮后,微信客户端将弹出选择器供用户选择“拍照”或者“从手机相册选择”。用户选择后即走其他两种流程。
    pic_weixin:弹出微信相册发图器用户点击按钮后,微信客户端将调起微信相册,完成选择操作后,将选择的相片发送给开发者的服务器,并推送事件给开发者,同时收起相册,随后可能会收到开发者下发的消息。
    location_select:弹出地理位置选择器用户点击按钮后,微信客户端将调起地理位置选择工具,完成选择操作后,将选择的地理位置发送给开发者的服务器,同时收起位置选择工具,随后可能会收到开发者下发的消息。
    media_id:下发消息(除文本消息)用户点击media_id类型按钮后,微信服务器会将开发者填写的永久素材id对应的素材下发给用户,永久素材类型可以是图片、音频、视频、图文消息。请注意:永久素材id必须是在“素材管理/新增永久素材”接口上传后获得的合法id。
    view_limited:跳转图文消息URL用户点击view_limited类型按钮后,微信客户端将打开开发者在按钮中填写的永久素材id对应的图文消息URL,永久素材类型只支持图文消息。请注意:永久素材id必须是在“素材管理/新增永久素材”接口上传后获得的合法id。​

    一、自定义菜单

    接口调用请求说明

    http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN

    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”
    }]
    }]
    }

    使用对象封装,通过JSONObject.fromObject(button)我们直接将对象转化成josn。

    @Data
    public class Button {
        private List<AbstractButton> button =  new ArrayList<>();
    
    }
    
    @Data
    public class AbstractButton {
        private String name;
    
        public AbstractButton(String name){
            this.name = name;
        }
    }
    

    注意
    使用JSONObject jsonObject = JSONObject.fromObject(button);方法需要导入依赖,并不是阿里巴巴的fastjson的方法。

      <!-- 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>
    

    在这里插入图片描述
    将AbstractButton类修改为抽象类,其他按钮继承它即可。

    @Data
    public abstract class AbstractButton {
        private String name;
    
        public AbstractButton(String name){
            this.name = name;
        }
    }
    
    

    新建按钮对象

    @Data
    public class ClickButten extends AbstractButton {
        private String type = "click";
        private String key;
    
        public ClickButten(String name,String key){
            super(name);
            this.key = key;
    
        }
    }
    
    
    
    @Data
    public class ViewButton extends AbstractButton {
        private String type = "view";
        private String url;
        public ViewButton(String name,String url){
            super(name);
            this.url=url;
        }
    }
    
    
    
    package com.wx.model.button;
    
    import lombok.Data;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author :LiuShihao
     * @date :Created in 2020/10/10 10:52 上午
     * @desc :
     *  {
     *             "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": [ ]
     *                 }
     *             ]
     *         }
     */
    @Data
    public class PhotoAlbumButton extends AbstractButton {
        private String type;
        private String key;
        private List<AbstractButton> sub_button = new ArrayList<>();
    
        public PhotoAlbumButton(String name,String type,String key){
            super(name);
            this.key = key;
            this.type = type;
        }
    
    
    }
    
    
    
    @Data
    public class SubButton extends AbstractButton {
        private List<AbstractButton> sub_button = new ArrayList<>();
    
        public SubButton(String name ){
            super(name);
        }
    }
    

    将对象解析成Json

    在这里插入图片描述

    
         @Test
        public void test2(){
            Button button = new Button();
            button.getButton().add(new ClickButten("一级菜单_点击","1"));
            button.getButton().add(new ViewButton("一级跳转","http://baidu.com"));
            SubButton subButton = new SubButton("子菜单");
            subButton.getSub_button().add(new PhotoAlbumButton("系统拍照发图","pic_sysphoto","rselfmenu_1_0"));
            subButton.getSub_button().add(new ClickButten("二级菜单_点击","2"));
            subButton.getSub_button().add(new ViewButton("二级跳转","http://news.163.com"));
            button.getButton().add(subButton);
            JSONObject jsonObject = JSONObject.fromObject(button);
            System.out.println(jsonObject);
    
        }
    
    
    {"button":[{"key":"1","name":"一级菜单_点击","type":"click"},{"name":"一级跳转","type":"view","url":"http://baidu.com"},{"name":"子菜单","sub_button":[{"key":"rselfmenu_1_0","name":"系统拍照发图","sub_button":[],"type":"pic_sysphoto"},{"key":"2","name":"二级菜单_点击","type":"click"},{"name":"二级跳转","type":"view","url":"http://news.163.com"}]}]}
    
    
    
    {
        "button":[
            {
                "key":"1",
                "name":"一级菜单_点击",
                "type":"click"
            },
            {
                "name":"一级跳转",
                "type":"view",
                "url":"http://baidu.com"
            },
            {
                "name":"子菜单",
                "sub_button":[
                    {
                        "key":"rselfmenu_1_0",
                        "name":"系统拍照发图",
                        "sub_button":[
    
                        ],
                        "type":"pic_sysphoto"
                    },
                    {
                        "key":"2",
                        "name":"二级菜单_点击",
                        "type":"click"
                    },
                    {
                        "name":"二级跳转",
                        "type":"view",
                        "url":"http://news.163.com"
                    }
                ]
            }
        ]
    }
    

    二、创建自定义菜单

    package com.wx.util;
    
    import com.wx.model.button.*;
    import com.wx.service.Impl.WXServiceImpl;
    import net.sf.json.JSONObject;
    import org.springframework.beans.factory.annotation.Autowired;
    
    /**
     * @author :LiuShihao
     * @date :Created in 2020/10/10 12:32 下午
     * @desc :
     */
    public class CreateMenu {
        @Autowired
        WXServiceImpl wxService;
        public static void main(String[] args) {
            Button button = new Button();
            button.getButton().add(new ClickButten("一级菜单_点击","1"));
            button.getButton().add(new ViewButton("一级跳转","http://baidu.com"));
            SubButton subButton = new SubButton("子菜单");
            subButton.getSub_button().add(new PhotoAlbumButton("系统拍照发图","pic_sysphoto","rselfmenu_1_0"));
            subButton.getSub_button().add(new ClickButten("二级菜单_点击","2"));
            subButton.getSub_button().add(new ViewButton("二级跳转","http://news.163.com"));
            button.getButton().add(subButton);
            JSONObject jsonObject = JSONObject.fromObject(button);
            System.out.println(jsonObject);
            String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
            String token = WXServiceImpl.getToken();
            url = url.replace("ACCESS_TOKEN",token);
            com.alibaba.fastjson.JSONObject post = CommonUtil.httpsRequest(url, "POST", jsonObject.toString());
            System.out.println("post:"+post);
        }
    }
    
    

    在这里插入图片描述
    在这里插入图片描述

    处理图片信息(识别图片文字)调用百度AI开放平台的API

    当用户发送一个图片时,会发送到微信服务器,我们服务器接收的微信服务器发送过来的xml数据包,进行解析

     /**
         * 处理消息和事件推送
         * @param request
         * @throws IOException
         */
        @PostMapping
        public String method2(HttpServletRequest request) throws IOException {
    
            Map<String,String> map = wxService.parseRequest(request.getInputStream());
            System.out.println("处理消息和事件推送:"+map);
            return wxService.getRespose(map);
        }
    

    将xml数据包解析成map形式

        /**
         * 使用dom4j包     解析xml数据包  成Map形式
         * @param inputStream
         * @return
         */
        @Override
        public Map<String, String> parseRequest(ServletInputStream inputStream) {
            HashMap<String, String> hashMap = new HashMap<>();
            SAXReader reader = new SAXReader();
            try {
                //读取输入流 回去文档对象
                Document document = reader.read(inputStream);
                //根据文档对象 回去根节点
                Element rootElement = document.getRootElement();
                //根据根节点获取所有的子节点
                List<Element> elements = rootElement.elements();
                for (Element element : elements) {
                    hashMap.put(element.getName(), element.getStringValue());
                }
            } catch (DocumentException e) {
                e.printStackTrace();
            }
            return hashMap;
        }
    

    然后对不同的消息类型进行相应的处理:

    /**
         * 用于处理所有的事件和消息de 回复
         * 将Map解析成xml数据包  回复消息
         * @param map
         * @return  返回的是xml数据包
         */
        @Override
        public String getRespose(Map<String, String> map) {
            String msgType = map.get("MsgType");
            BaseMessage msg = null;
            switch (msgType){
                case "text":
                    msg = dealText(map);
                    break;
                case "image":
                    msg = dealImage(map);
                    break;
                case "voice":
                    msg = dealVoice(map);
                    break;
                case "video":
                    break;
                case "shortvideo":
                    break;
                case "location":
                    break;
                case "link":
                    break;
                case "event":
                    msg = dealEvent(map);
                    break;
                default:
                    break;
            }
            if (msg != null){
                String xml = beanToXml(msg);
                System.out.println(xml);
                log.info(xml);
                return xml;
            }else {
                return "success";
            }
        }
    

    msgType类型如果为image,就调用百度API;

    /**
         * 处理图片消息
         * @param map
         * @return
         */
        private BaseMessage dealImage(Map<String, String> map) {
            String url = map.get("PicUrl");
            String toText = bdUtil.imageToText(url);
            return new TextMessage(map,toText);
        }
    
    package com.wx.util;
    
    import com.baidu.aip.ocr.AipOcr;
    import com.wx.model.weather.*;
    import lombok.extern.slf4j.Slf4j;
    import net.sf.json.JSONArray;
    import net.sf.json.JSONObject;
    import org.json.JSONException;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    
    /**
     * @author :LiuShihao
     * @date :Created in 2020/10/10 3:24 下午
     * @desc :
     */
    @Slf4j
    @Component
    public class BDUtil {
    	//你的对应信息
        public static final String APP_ID = "228****23";
        public static final String API_KEY = "2D0gCVQP***********gGdjgUCs";
        public static final String SECRET_KEY = "UXL0pNYD***********ZO357kmXBa";
        public static AipOcr client;
    
        static {
            // 初始化一个AipOcr
             client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
        }
    
        /**
         * 识别 图片  文字
         * @param picUrl
         * @return
         * @throws JSONException
         */
        public String imageToText(String picUrl) throws JSONException {
            String totext = null;
            // 传入可选参数调用接口
            HashMap<String, String> options = new HashMap<String, String>();
            options.put("language_type", "CHN_ENG");
            options.put("detect_direction", "true");
            options.put("detect_language", "true");
            options.put("probability", "true");
    
    //        // 参数为本地路径
    //        String image = "test.jpg";
    //        JSONObject res = client.basicGeneral(image, options);
    //        System.out.println(res.toString(2));
    //
    //        // 参数为二进制数组
    //        byte[] file = readFile("test.jpg");
    //        res = client.basicGeneral(file, options);
    //        System.out.println(res.toString(2));
    
            // 通用文字识别, 图片参数为远程url图片
            org.json.JSONObject res = client.basicGeneralUrl(picUrl, options);
            /**
             * 返回成功:
             * {
             *   "words_result": [{
             *     "probability": {
             *       "average": 0.950565,
             *       "min": 0.74773,
             *       "variance": 0.005733
             *     },
             *     "words": "该公众号提供的服务出现故障,请稍后再试"
             *   }],
             *   "log_id": 1314882863493021696,
             *   "words_result_num": 1,
             *   "language": 3,
             *   "direction": 0
             * }
             *
             * 返回失败:
             *
             */
            System.out.println(res.toString(2));
            String s = res.toString(2);
            //将 字符创 转化成 JSONObject   package net.sf.json;
            JSONObject jsonObject = JSONObject.fromObject(s);
            System.out.println("jsonObject:"+jsonObject);
            try{
                String error_code = jsonObject.getString("error_code");
    
                if(!StringUtils.isEmpty(error_code)){
                    if ("216202".equals(error_code)){
                        totext = "上传的图片大小错误,现阶段我们支持的图片大小为:base64编码后小于4M,分辨率不高于4096*4096,请重新上传图片";
                    }
                    if ("216201".equals(error_code)){
                        totext = "上传的图片格式错误,现阶段我们支持的图片格式为:PNG、JPG、JPEG、BMP,请进行转码或更换图片";
                    }
                }
            }catch (net.sf.json.JSONException e){
                e.printStackTrace();
                JSONArray words_result = jsonObject.getJSONArray("words_result");
                StringBuilder stringBuilder = new StringBuilder();
                Iterator it = words_result.iterator();
                while (it.hasNext()){
                    JSONObject next = (JSONObject)it.next();
                    stringBuilder.append(next.getString("words"));
                }
                log.info("imageToText:"+stringBuilder);
                totext= stringBuilder.toString();
            }
            return totext;
        }
    }
    

    打开百度AI开放平台网站,选择文字识别服务,如果没有应用,创建一个应用

    在这里插入图片描述
    在这里插入图片描述

    删除菜单

    使用接口创建自定义菜单后,开发者还可使用接口删除当前使用的自定义菜单。另请注意,在个性化菜单时,调用此接口会删除默认菜单及全部个性化菜单。

    请求说明

    http请求方式:GET https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN

    返回说明

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

    {“errcode”:0,“errmsg”:“ok”}

    package com.wx.util;
    
    import com.wx.model.button.*;
    import com.wx.service.Impl.WXServiceImpl;
    import net.sf.json.JSONObject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    /**
     * @author :LiuShihao
     * @date :Created in 2020/10/10 12:32 下午
     * @desc :
     */
    @Component
    public class CreateMenu {
        @Autowired
        WXServiceImpl wxService;
    
    
        public static void main(String[] args) {
    
        }
        public void createMenu(){
            Button button = new Button();
            button.getButton().add(new ClickButten("一级菜单_点击","1"));
            button.getButton().add(new ViewButton("一级跳转","http://baidu.com"));
            SubButton subButton = new SubButton("子菜单");
            subButton.getSub_button().add(new PhotoAlbumButton("拍照或者相册发图","pic_photo_or_album","rselfmenu_1_0"));
            subButton.getSub_button().add(new ClickButten("二级菜单_点击","2"));
            subButton.getSub_button().add(new ViewButton("二级跳转","http://news.163.com"));
            subButton.getSub_button().add(new ViewButton("我的博客","http://116.62.13.104:8090/"));
            subButton.getSub_button().add(new ViewButton("我的网盘","http://116.62.13.104:8081/"));
            button.getButton().add(subButton);
            JSONObject jsonObject = JSONObject.fromObject(button);
            System.out.println(jsonObject);
            String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
            String token = WXServiceImpl.getToken();
            url = url.replace("ACCESS_TOKEN",token);
            com.alibaba.fastjson.JSONObject post = CommonUtil.httpsRequest(url, "POST", jsonObject.toString());
            System.out.println("post:"+post);
        }
    
        /**
         * http请求方式:GET https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
         */
        public void delMenu(){
            String url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
            String token = wxService.getRedisToken();
            url = url.replace("ACCESS_TOKEN",token);
            com.alibaba.fastjson.JSONObject post = CommonUtil.httpsRequest(url, "GET", null);
            System.out.println("post:"+post);
    
        }
    
        /**
         * http请求方式: GET(请使用https协议)https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
         */
        public void findMenu(){
            String url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN";
            String token = wxService.getRedisToken();
            url = url.replace("ACCESS_TOKEN",token);
            com.alibaba.fastjson.JSONObject post = CommonUtil.httpsRequest(url, "GET", null);
            System.out.println("post:"+post);
    
        }
    }
    
    
    
     @Test
        public void test3(){
    //        menu.delMenu();
            menu.createMenu();
            menu.findMenu();
        }
    
    展开全文
  • JAVA微信公众号开发之自定义菜单

    千次阅读 2017-07-27 23:20:31
    微信上文档说明: 1、click:点击推事件用户点击click类型按钮后...2、view:跳转URL用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的网页URL,可与网页授权获取用户基本信息接口结合,获得用户...

    微信上文档说明:

     

    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,是专门给第三方平台旗下未微信认证(具体而言,是资质认证未通过)的订阅号准备的事件类型,它们是没有事件推送的,能力相对受限,其他类型的公众号不必使用。

    接口调用请求说明

    http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN

    然后是自定义菜单的构造与参数:

     

     

    {
         "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 一级菜单数组,个数应为1~3个
    sub_button 二级菜单数组,个数应为1~5个
    type 菜单的响应动作类型,view表示网页类型,click表示点击类型,miniprogram表示小程序类型
    name 菜单标题,不超过16个字节,子菜单不超过60个字节
    key click等点击类型必须 菜单KEY值,用于消息接口推送,不超过128字节
    url view、miniprogram类型必须 网页链接,用户点击菜单可打开链接,不超过1024字节。type为miniprogram时,不支持小程序的老版本客户端将打开本url。
    media_id media_id类型和view_limited类型必须 调用新增永久素材接口返回的合法media_id
    appid miniprogram类型必须 小程序的appid(仅认证公众号可配置)

    pagepath

    miniprogram类型必须 小程序的页面路径

     

     

     

    1、首先组装实体类,创建主菜单与子菜单属性。这个就不介绍了,很简单。

    组装完一个菜单后然后创建菜单。

     

    public static int createMenu(String menu) throws ClientProtocolException, IOException{
    		int result=0;
    		String access_token = GetMapSign.getTicket().get("access_token");//获取access_token
    		String url = ConfigUtil.MENU_CREATE_URL.replace("ACCESS_TOKEN",access_token);
    		JSONObject jsonObject = doPostStr(url, menu);
    		if(jsonObject!=null){
    			 result = jsonObject.getInt("errcode");
    		}
    		return result;
    	}
    /**
    	 * post请求
    	 */
    	public static JSONObject doPostStr(String url,String outStr){
    
    		DefaultHttpClient httpClient = new DefaultHttpClient();
    		HttpPost httpPost = new HttpPost(url);
    		JSONObject jsonObject = null;
    		String result="";
    		try {
    			httpPost.setEntity(new StringEntity(outStr,"utf-8"));
    			HttpResponse response = httpClient.execute(httpPost);
    			result = EntityUtils.toString(response.getEntity(),"utf-8");
    		} catch (Exception e) {
    		} 
    		jsonObject = JSONObject.fromObject(result);
    		return jsonObject;
    	}	


    然后创建一个测试类,直接运行就好了,这里成功后errcode会返回0,发布后微信公众号就不用管了,以后一直就是这样了,以后想改的时候再改再运行就好了。

     

     

    public static void main(String[] args) throws Exception {
    		//创建自定义菜单
    		String menu = JSONObject.fromObject(SignUtil.initMenu()).toString();
    		int result = SignUtil.createMenu(menu);
    		
    		if(result==0){
    			System.out.println("菜单创建成功!");
    		}else{
    			System.out.println("菜单创建失败!");
    
    		}
    }

     

    最近在整理一些资源工具,放在网站分享 http://tools.maqway.com
    欢迎关注公众号:麻雀唯伊 , 不定时更新资源文章,生活优惠,或许有你想看的

     

     

     

     

     

    展开全文
  • 菜单实际上就是按钮,自定义菜单接口可实现多种类型按钮: 1.click:点击推事件用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者...
  • Java事件类型小结

    2015-09-19 19:30:19
    ActionEvent动作事件类ActionListener接口 actionPerformed(ActionEvent e)单击按钮、选择菜单项或在文本框中按回车时 AdjustmentEvent调整事件类AdjustmentListener接口 adjustmentValueChanged(AdjustmentEvent e...
  • 微信自定义菜单的创建与使用微信自定义菜单的创建与使用 需求 菜单类介绍 场景 代码 总结需求当微信公众号设置...由于新版微信添加的挺多按钮类型,目前只实现click(点击推事件)和view(跳转URL),其他类型的大致相同。
  •  1、click:点击推事件用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行...
  • 一、了解自定义菜单  自定义菜单是微信公众平台最常用也是最重要... 而自定义菜单可以实现的功能也是多种多样的,根据实现功能的不同,微信自定义菜单按钮共分为10种类型:  请注意,3到8的所有事件,仅支持...
  • 引用观察代码框下方的布局,可以看到两个按钮之下还有三个下拉菜单,依次点击之后本酱发现了一个神奇的选项:render all objects on the heap (Python/Java)。即图中红框处下拉菜单的第三个选项:这个...
  • 用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event 的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互; 2、view:跳转URL ...
  • 文章目录简介接口权限编辑模式开发模式TNW 中具体实现读取配置文件来创建菜单动态创建自定义菜单Java 版本自定义菜单开源推荐 简介 TNW: TypeScript(The) + Node.js...菜单规则以及按钮类型说明 实现自定义菜单有...
  • java界面编程(5) ------ 按钮按钮

    千次阅读 2014-11-16 00:31:37
     了解了布局管理器和Swing事件模型,那么剩下的就是Swing 的各个组件了,下面就开始逐个学习Swing的各个组件的用法及功能,本节... Swing提供了许多类型按钮,有普通的按钮,复选框,单选等按钮,甚至菜单项,所
  • 了解了布局管理器和Swing事件模型,...1. buttonSwing提供了很多类型的button,有普通的button,复选框,单选等button,甚至菜单项,全部的这些button都是从AbstractButton继承而来。例如以下图的继承关系:能够看...
  • Swing 菜单JMenu

    千次阅读 2012-08-19 21:25:25
    Swing菜单菜单项是按钮,因为JMenuItem扩展AbstractButton,JMenu扩展JMenuItem。因此,Swing菜单菜单项继承了如下功能,即包含文本和(或)图标、显示光标进入时的图标和助记符等。   JMenuItem和JMenu的父...
  • java源码包---java 源码 大量 实例

    千次下载 热门讨论 2013-04-18 23:15:26
    Java右键弹出菜单源码 简单 Java圆形按钮实例代码,含注释 两个目标文件,自绘button。 Java圆形电子时钟源代码 1个目标文件 内容索引:JAVA源码,系统相关,电子钟  用JAVA编写的指针式圆形电子钟,效果图如下所示...
  • 有三种类型按钮:click类、复合类、view类 - 由上面对Json文件的分析,我们可以用Java类的方式来封装,因为类是具有相同特性和行为的对象的集合,Json文件实际上需要很小心才可以写得好,所以为了简化操作,就...
  • java源码包

    2015-12-01 16:29:37
    Java右键弹出菜单源码 简单 Java圆形按钮实例代码,含注释 两个目标文件,自绘button。 Java圆形电子时钟源代码 1个目标文件 内容索引:JAVA源码,系统相关,电子钟  用JAVA编写的指针式圆形电子钟,效果图如下所示...
  • java源码包2

    千次下载 热门讨论 2013-04-20 11:28:17
    Java右键弹出菜单源码 简单 Java圆形按钮实例代码,含注释 两个目标文件,自绘button。 Java圆形电子时钟源代码 1个目标文件 内容索引:JAVA源码,系统相关,电子钟  用JAVA编写的指针式圆形电子钟,效果图如下...
  • java源码包3

    千次下载 热门讨论 2013-04-20 11:30:13
    Java右键弹出菜单源码 简单 Java圆形按钮实例代码,含注释 两个目标文件,自绘button。 Java圆形电子时钟源代码 1个目标文件 内容索引:JAVA源码,系统相关,电子钟  用JAVA编写的指针式圆形电子钟,效果图如下...
  • Java开发微信公众号

    2017-03-08 11:21:20
    也就是说,你开发后台接口按照微信规定的格式提供数据,不管你点菜单上哪个按钮,微信会调用你提供的唯一接口并告诉你是哪个按钮调的接口,你根据按钮类型返回数据,微信就会自动处理并显示你返回的数据。...
  • Java Web中表单数据的获取

    万次阅读 2016-05-12 19:28:30
    分为单一表单数据和捆绑表单数据,其中单一表单数据是指表单元素的值送给服务器端时,仅仅是一个变量,这种类型的表单元素主要有:文本框、密码框、多行文本框、多选按钮、下拉菜单等,对于捆绑表单就是指多个同名...
  • 按钮(Button)

    2013-08-31 17:45:03
    Swing提供了许多类型按钮。所有的按钮,包括检查框,单选按钮,甚至菜单项都是从 AbstractButton(因为包含了菜单项,所以将其命名为“AbstractSelector” 或者其它 概括的名字,似乎更恰当一些)继承而来。...
  • 疯狂JAVA讲义

    2014-10-17 13:35:01
    学生提问:图11.15和图11.16显示的所有按钮都紧挨在一起,如果希望像FlowLayout、GridLayout等布局管理器指定组件的间距该怎么办? 397 11.4 AWT 常用组件 398 11.4.1 基本组件 398 11.4.2 对话框 400 11.5 事件...
  • Java典型模块

    2012-02-25 18:27:40
    第1篇 Java开发必备基础 第1章 搭建Java开发环境 1.1 Java的过去、现在和未来 1.1.1 Java的历史 1.1.2 Java的语言特点 1.1.3 Java API简介 1.1.4 Java未来发展 1.2 Java程序设计环境 1.2.1 命令行工具——JDK 6.0 ...
  • Java2游戏编程.pdf

    热门讨论 2013-01-31 15:20:46
    2.2.7 Java数据类型、数组和标识符需要记忆的要点 2.3 Java中的运算符 2.3.1 赋值运算符 2.3.2 比较运算符 2.3.3 算术运算符 2.3.4 自增和自减运算符 2.3.5 更多的整数运算符 2.3.6 使用点运算符 2.3.7 instanceof...
  • Java代码实例

    2016-06-21 22:44:51
    第2章 基本数据类型——构建Java 大厦的基础 12 2.1 源代码注释 12 2.1.1 单行注释 12 2.1.2 区域注释 12 2.1.3 文档注释 13 2.2 基本数据类型 14 2.2.1 整型 15 2.2.2 浮点型 17 2.2.3 char型 17...
  • Java开发详解.zip

    2019-09-02 17:46:13
    010301_【第3章:Java基础程序设计】_Java数据类型笔记.pdf 010302_【第3章:Java基础程序设计】_运算符、表达式与语句笔记.pdf 010303_【第3章:Java基础程序设计】_判断与循环语句笔记.pdf 010401_【第4章:数组与...
  • Java开发技术大全(500个源代码).

    热门讨论 2012-12-02 19:55:48
    代码范例列表 第1章 示例描述:本章演示如何开始使用JDK进行程序的开发。 HelloWorldApp.java 第一个用Java开发的应用程序。 firstApplet.java 第一个用... demoForceChange.java 演示强制类型转换 demoGeneric.java ...

空空如也

空空如也

1 2 3 4 5 ... 10
收藏数 185
精华内容 74
关键字:

java菜单类型按钮菜单

java 订阅