連小白都能看懂的微信開發之自定義菜單以及自定義菜單推送事件

微信開發之自定義菜單以及自定義菜單推送事件

自定義菜單建立接口

微信提供2種機制生成菜單java

機制一

是在公衆平臺官網經過網站功能發佈菜單 ,這種方式接入後臺服務器以後菜單會失效。程序員

在這裏插入圖片描述

機制二

是經過API調用設置的菜單json

微信官方文檔是這樣子描述:小程序

一、自定義菜單最多包括3個一級菜單,每一個一級菜單最多包含5個二級菜單。
二、一級菜單最多4個漢字,二級菜單最多7個漢字,多出來的部分將會以「...」代替。
三、建立自定義菜單後,菜單的刷新策略是,在用戶進入公衆號會話頁或公衆號profile頁時,若是發現上一次拉取菜單的請求在5分鐘之前,就會拉取一下菜單,若是菜單有更新,就會刷新客戶端的菜單。測試時能夠嘗試取消關注公衆帳號後再次關注,則能夠看到建立後的效果。

自定義菜單接口類型按鈕,以下10種:api

一、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。

請注意,3到8的全部事件,僅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用戶,舊版本微信用戶點擊後將沒有迴應,開發者也不能正常接收到事件推送。9和10,是專門給第三方平臺旗下未微信認證(具體而言,是資質認證未經過)的訂閱號準備的事件類型,它們是沒有事件推送的,能力相對受限,其餘類型的公衆號沒必要使用。數組

接口調用請求說明服務器

http請求方式:POST(請使用https協議) https://api.weixin.qq.com/cgi...微信

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

其餘新增按鈕類型的請求示例app

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

參數說明

參數 是否必須 說明
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類型必須 小程序的頁面路徑

返回結果

正確時的返回JSON數據包以下:

{"errcode":0,"errmsg":"ok"}

錯誤時的返回JSON數據包以下(示例爲無效菜單名長度):

{"errcode":40018,"errmsg":"invalid button name size"}

代碼示例:

1 簡單的一級菜單能夠直接發送json字符串 ,調用接口便可。

能夠查看此博客 https://www.jianshu.com/p/6ee...

2 複雜的二級菜單

頂級菜單基類
@Data
public class BasicButton {
    private String name;

    private String type;

    /**
     * 二級菜單的數組標籤 爲 sub_button
     */
    private BasicButton []sub_button;

}
點擊事件菜單實體
@Data
public class ClickButton extends BasicButton {

    private String key;
}
跳轉連接菜單實體
@Data
public class ViewButton extends  BasicButton {
    private String url ;
}
設置菜單
public final static String CREAT_OPTION_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";
    public static void creatOption() {
        
        String url = CREAT_OPTION_URL + AccessTokenTool.getToken();
        String data = JSON.toJSONString(getMenu());
        log.info("發送的菜單json數據爲: " + data);
        String s = HttpUtil.sendHttpByPost(url, data);
        log.info("返回的菜單json數據爲: " + s);
        JSONObject jsonObject = JSONObject.parseObject(s);
        if (jsonObject.getInteger("errcode") == 0) {
            log.info("設置自定義菜單成功。");

        } else {
            log.error("設置自定義菜單失敗。");
        }
    }



    /**
     * 組裝菜單數據
     *
     * @return
     */
    private static Menu getMenu() {
        ClickButton btn11 = new ClickButton();
        btn11.setName("點擊事件11");
        btn11.setType("click");
        btn11.setKey("11");

        ClickButton btn12 = new ClickButton();
        btn12.setName("點擊事件12");
        btn12.setType("click");
        btn12.setKey("12");

        ClickButton btn13 = new ClickButton();
        btn13.setName("點擊事件13");
        btn13.setType("click");
        btn13.setKey("13");

        ViewButton btn14 = new ViewButton();
        btn14.setName("view類型事件14");
        btn14.setType("view");
        btn14.setUrl("https://www.baidu.com"); //須要跳轉的url

        ViewButton btn21 = new ViewButton();
        btn21.setName("view類型事件21");
        btn21.setType("view");
        btn21.setUrl("須要跳轉的url"); //須要跳轉的url

        ViewButton btn22 = new ViewButton();
        btn22.setName("view類型事件22");
        btn22.setType("view");
        btn22.setUrl("須要跳轉的url"); //須要跳轉的url

        ClickButton btn31 = new ClickButton();
        btn31.setName("點擊事件31");
        btn31.setType("click");
        btn31.setKey("31");

        ViewButton btn32 = new ViewButton();
        btn32.setName("view類型事件32");
        btn32.setType("view");
        btn32.setUrl("/find"); //須要跳轉的url

        ClickButton btn33 = new ClickButton();
        btn33.setName("點擊事件33");
        btn33.setType("click");
        btn33.setKey("33");

        ViewButton btn34 = new ViewButton();
        btn34.setName("view類型事件34");
        btn34.setType("view");
        btn34.setUrl( "https://www.baidu.com"); //須要跳轉的url

        BasicButton mainBtn1 = new BasicButton();
        mainBtn1.setName("一級菜單1");
        mainBtn1.setSub_button(new BasicButton[]{ btn11, btn12, btn13 ,btn14});

        BasicButton mainBtn2 = new BasicButton();
        mainBtn2.setName("一級菜單2");
        mainBtn2.setSub_button(new BasicButton[] { btn21, btn22});

        BasicButton mainBtn3 = new BasicButton();
        mainBtn3.setName("一級菜單3");
        mainBtn3.setSub_button(new BasicButton[] { btn31, btn32, btn33,btn34 });

        /**
         * 這是公衆號 「 程序員平常錦集 」 目前的菜單結構 ,每一個一級菜單都有二級菜單項<br>
         *
         * 在某個一級菜單下沒有二級菜單的狀況,menu該如何定義呢?<br>
         * 好比,第三個一級菜單項不是「點擊事件31」,而直接是「view類型事件32」,那麼menu應該這樣定義:<br>
         * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn32 });
         */
        Menu menu = new Menu();
        menu.setButton(new BasicButton[] { mainBtn1, mainBtn2, mainBtn3 });

        return menu;
    }

自定義菜單事件推送

微信會將點擊事件推送給開發者,也就是咱們填寫的服務器地址!

這裏請注意:

請注意,點擊菜單彈出子菜單,不會產生上報。 請注意,第3個到第8個的全部事件,僅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用戶,舊版本微信用戶點擊後將沒有迴應,開發者也不能正常接收到事件推送。

點擊菜單拉取消息時的事件推送

推送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>

參數說明:

事件類型Event爲:CLICK

EventKey 就是咱們自定義菜單時候所填寫的key值,根據這個key值區分不一樣的菜單。

點擊菜單,解析微信推送給咱們的xml數據:

判斷菜單:
//這裏xml轉爲 map類型了 
    public static BaseMsg handleClick(Map<String, String> xmlData) {
        String eventKey = xmlData.get("EventKey");
        BaseMsg bm = null;

        switch (eventKey) {

            case "11":
                bm = new TextMsg(xmlData, "菜單11");
                break;

            case "12":

                bm = new TextMsg(xmlData,"菜單11" );;
                break;

            case "13":
                bm = new TextMsg(xmlData, "");
                break;

            case "31":
                bm =  new TextMsg(xmlData, "更多信息,敬請期待!");
                break;

            case "33":
                //返回圖文消息
                bm =  ArticlesMessageTool.getAiticlesMessage(xmlData, "url")

                    //其餘的消息類型本身定義便可
                break;

            default:
                bm = new TextMsg(xmlData, " 歡迎。。。。 ");
        }

        return bm;
    }
消息基類
@XStreamAlias("xml") //設置根節點名
@Data
public class BaseMsg {

    //置頂別名首字母大寫
    @XStreamAlias("ToUserName")
    private String toUserName;//開發者微信號
    private String FromUserName;//發送方賬號(一個OpenID)
    private String CreateTime;//消息建立時間 (整型)
    private String MsgType;//MsgType 文本類型


    public BaseMsg(Map<String, String> map) {
        this.CreateTime = System.currentTimeMillis() / 1000 + "";
        this.FromUserName = map.get("ToUserName");
        this.toUserName = map.get("FromUserName");
    }

}
文本消息類:
@XStreamAlias("xml")
@Data
public class TextMsg extends BaseMsg {

    private String Content;//文本消息內容

    public TextMsg(Map<String, String> map, String Content) {
        super(map);
        this.Content = Content;
        this.setMsgType("text");
    }

}
圖文消息類:
@XStreamAlias("xml") //設置根節點名
@Data
public class ImageMsg extends BaseMsg {


    private String ArticleCount;// 是  圖文消息個數;當用戶發送文本、圖片、視頻、圖文、地理位置這五種消息時,開發者只能回覆1條圖文消息;其他場景最多可回覆8條圖文消息
    private List<ArticlesItem> Articles;// 是  圖文消息信息,注意,若是圖文數超過限制,則將只發限制內的


    public ImageMsg() {
    }

    public ImageMsg(Map<String, String> map) {
        super(map);
        this.setMsgType("news");
    }
獲取圖文消息工具:
/**
     * 獲取圖文消息
     *
     * @param custermName
     * @param serverName
     * @param createTime
     * @param xmlData
     * @return
     */
    public static ImageMsg getAiticlesMessage(Map<String, String> xmlData, String url) {
        ImageMsg imageMsg = new ImageMsg(xmlData);
        List<ArticlesItem> list = new ArrayList<ArticlesItem>();
        ArticlesItem item = new ArticlesItem();
        String title = "歡迎使用公衆號!";
        String description = "點擊圖文進入";
        //圖片路徑
        String picurl = "本身的服務器地址" + "/img/008.jpg";

        item.setDescription(AirPortConfig.description);
        item.setTitle(AirPortConfig.title);
        item.setPicUrl(picurl);
        item.setUrl(url);
        list.add(item);
        
        // 多個能夠繼續設置.....

        imageMsg.setArticleCount("1");
        imageMsg.setMsgType("news");

        imageMsg.setArticles(list);

        return imageMsg;
    }
xml轉爲map
public static Map<String, String> getXmlData(InputStream inputStream) {
    Map<String, String> map = new HashMap<>();
    //截取xml
    SAXReader reader = new SAXReader();
    try {

        Document document = reader.read(inputStream);
        Element rootElement = document.getRootElement(); //獲取根節點
        List<Element> elements = rootElement.elements(); // h獲取全部的節點
        for (Element e : elements) {
            map.put(e.getName(), e.getStringValue());
        }

    } catch (DocumentException e) {
        e.printStackTrace();
    }
    return map;
}
實體對象輸出xml
public static String bean2Xml(BaseMsg baseMsg) {
        XStream xStream = new XStream();
        //若沒有這句,xml中的根元素會是<包.類名>;或者說:註解根本就沒生效,因此的元素名就是類的屬性
        xStream.processAnnotations(BaseMsg.class);
        xStream.processAnnotations(TextMsg.class);
        xStream.processAnnotations(ImageMsg.class);
        String xml = xStream.toXML(baseMsg);
        log.info("返回的xml = " + xml);
        return xml;
    }
maven依賴
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.11.1</version>
        </dependency>

更多信息關注微信公衆號

公衆號

!

相關文章
相關標籤/搜索