微信开发将自定义菜单_微信自定义菜单开发 - CSDN
  • 一、自定义菜单概述 自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能。开启自定义菜单后,公众号界面如图所示: 二、申请自定义菜单 个人订阅号使用微博认证、企业订阅号通过...

    一、自定义菜单概述

    自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能。开启自定义菜单后,公众号界面如图所示:


    二、申请自定义菜单

    个人订阅号使用微博认证、企业订阅号通过微信认证;可以申请到自定义菜单资格

    服务号默认有菜单权限。

    三、获得AppId 和AppSecert

    AppId和AppSecret在开发者中心-开发者ID中,可以找到。



    四、获得Access Token

    appid和appsecert获得access token,接口为

    https://api.weixin.qq.com/cgi-bi ... mp;secret=APPSECRET

    程序实现如下

    $appid = "";
    $appsecret = "";
    $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appid&secret=$appsecret";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $output = curl_exec($ch);
    curl_close($ch);
    $jsoninfo = json_decode($output, true);
    $access_token = $jsoninfo["access_token"];

    复制代码

    你也可以直接在浏览器地址栏中,拼接出地址,执行后,获得如下数据

    {"access_token":"N2L7KXa084WvelONYjkJ_traBMCCvy_UKmpUUzlrQ0EA2yNp3Iz6eSUrRG0bhaR_viswd50vDuPkY5nG43d1gbm-olT2KRMxOsVE08RfeD9lvK9lMguNG9kpIkKGZEjIf8Jv2m9fFhf8bnNa-yQH3g",
    "expires_in":7200}


    复制代码

    参数说明如下


    其中的

    N2L7KXa084WvelONYjkJ_traBMCCvy_UKmpUUzlrQ0EA2yNp3Iz6eSUrRG0bhaR_viswd50vDuPkY5nG43d1gbm-olT2KRMxOsVE08RfeD9lvK9lMguNG9kpIkKGZEjIf8Jv2m9fFhf8bnNa-yQH3g
    就是access token。

    或者使用官方的接口调试工具,地址为:

    https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index&type=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95&form=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3%20/menu/create

    使用网页调试工具调试自定义菜单接口


    点击检查问题得,得到


    这样也获得了access token

    五、组织菜单内容

    目前自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代 替。请注意,创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来。建议测试时可以尝试取消关注公众账号后再次关注,则可以看到创 建后的效果。

    目前自定义菜单接口可实现两种类型按钮,如下:

    click:
    用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event        的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;
    view:
    用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的url值        (即网页链接),达到打开网页的目的,建议与网页授权获取用户基本信息接口结合,获得用户的登入个人信息。


    接口调用请求说明

    http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bi ... _token=ACCESS_TOKEN

    请求示例

    1.{
    2.     "button":[
    3.     {    
    4.          "type":"click",
    5.          "name":"今日歌曲",
    6.          "key":"V1001_TODAY_MUSIC"
    7.      },
    8.      {
    9.           "type":"click",
    10.           "name":"歌手简介",
    11.           "key":"V1001_TODAY_SINGER"
    12.      },
    13.      {
    14.           "name":"菜单",
    15.           "sub_button":[
    16.           {    
    17.               "type":"view",
    18.               "name":"搜索",
    19.               "url":"http://www.soso.com/"
    20.            },
    21.            {
    22.               "type":"view",
    23.               "name":"视频",
    24.               "url":"http://v.qq.com/"
    25.            },
    26.            {
    27.               "type":"click",
    28.               "name":"赞一下我们",
    29.               "key":"V1001_GOOD"
    30.            }]
    31.       }]
    32.}

    复制代码

    参数说明


    返回结果

    正确时的返回JSON数据包如下:

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

    错误时的返回JSON数据包如下(示例为无效菜单名长度):

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

    六、提交菜单内容给服务器

    菜单的JSON结构为

    {"button": [{"name":"天气预报","sub_button":[{"type":"click","name":"北京天气","key":"天气北 京"},
    {"type":"click","name":"上海天气","key":"天气上海"},
    {"type":"click","name":" 广州天气","key":"天气广州"},{"type":"click","name":"深圳天气","key":"天气深圳"}, 
    {"type":"view","name":"本地天气","url":"http://m.hao123.com/a/tianqi"}]},
     {"name":"方倍工作室","sub_button":[{"type":"click","name":"公司简 介","key":"company"},
    {"type":"click","name":"趣味游戏","key":"游戏"}, {"type":"click","name":"讲个笑话","key":"笑话"}]}]}

    复制代码

    将以下代码保存为menu.php,并且在浏览器中运行该文件(比如 http://127.0.0.1/menu.php),将直接向微信服务器提交菜单,

    1.?php
    2.
    3.$access_token = "";
    4.
    5.$jsonmenu = '{
    6.      "button":[
    7.      {
    8.            "name":"天气预报",
    9.           "sub_button":[
    10.            {
    11.               "type":"click",
    12.               "name":"北京天气",
    13.               "key":"天气北京"
    14.            },
    15.            {
    16.               "type":"click",
    17.               "name":"上海天气",
    18.               "key":"天气上海"
    19.            },
    20.            {
    21.               "type":"click",
    22.               "name":"广州天气",
    23.               "key":"天气广州"
    24.            },
    25.            {
    26.               "type":"click",
    27.               "name":"深圳天气",
    28.               "key":"天气深圳"
    29.            },
    30.            {
    31.                "type":"view",
    32.                "name":"本地天气",
    33.                "url":"http://m.hao123.com/a/tianqi"
    34.            }]
    35.      
    36.
    37.       },
    38.       {
    39.           "name":"瑞雪",
    40.           "sub_button":[
    41.            {
    42.               "type":"click",
    43.               "name":"公司简介",
    44.               "key":"company"
    45.            },
    46.            {
    47.               "type":"click",
    48.               "name":"趣味游戏",
    49.               "key":"游戏"
    50.            },
    51.            {
    52.                "type":"click",
    53.                "name":"讲个笑话",
    54.                "key":"笑话"
    55.            }]
    56.       
    57.
    58.       }]
    59.}';
    60.
    61.
    62.$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$access_token;
    63.$result = https_request($url, $jsonmenu);
    64.var_dump($result);
    65.
    66.function https_request($url,$data = null){
    67.    $curl = curl_init();
    68.    curl_setopt($curl, CURLOPT_URL, $url);
    69.    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    70.    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    71.    if (!empty($data)){
    72.        curl_setopt($curl, CURLOPT_POST, 1);
    73.        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    74.    }
    75.    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    76.    $output = curl_exec($curl);
    77.    curl_close($curl);
    78.    return $output;
    79.}
    80.
    81.?>


    复制代码

    或者使用官方的调试接口 使用网页调试工具调试该接口



    提交成功后,重新关注后即可看到菜单。菜单效果类似如下:


    七、响应菜单点击事件

    在消息接口中处理event事件,其中的click代表菜单点击,通过响应菜单结构中的key值回应消息,view事件无须响应,将直接跳转过去

    define("TOKEN", "weixin");
    
    $wechatObj = new wechatCallbackapiTest();
    if (!isset($_GET['echostr'])) {
        $wechatObj->responseMsg();
    }else{
       $wechatObj->valid();
    }
    
    class wechatCallbackapiTest
    {
       public function valid()
       {
            $echoStr = $_GET["echostr"];
           if($this->checkSignature()){
                echo $echoStr;
               exit;
           }
      }
    
       private function checkSignature()
       {
            $signature = $_GET["signature"];
          $timestamp = $_GET["timestamp"];
           $nonce = $_GET["nonce"];
    
          $token = TOKEN;
            $tmpArr = array($token, $timestamp, $nonce);
           sort($tmpArr);
           $tmpStr = implode( $tmpArr );
            $tmpStr = sha1( $tmpStr );
    
            if( $tmpStr == $signature ){
                return true;
            }else{
                return false;
            }
       }
    
        public function responseMsg()
        {
            $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
            if (!empty($postStr)){
               $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            $RX_TYPE = trim($postObj->MsgType);
    
              switch ($RX_TYPE)
               {
                    case "text":
                        $resultStr = $this->receiveText($postObj);
                        break;
                    case "event":
                      $resultStr = $this->receiveEvent($postObj);
                        break;
                   default:
                        $resultStr = "";
                      break;
               }
                echo $resultStr;
            }else {
               echo "";
              exit;
            }
       }
    
        private function receiveText($object)
       {
           $funcFlag = 0;
           $contentStr = "你发送的内容为:".$object->Content;
           $resultStr = $this->transmitText($object, $contentStr, $funcFlag);
            return $resultStr;
       }
        
       private function receiveEvent($object)
       {
           $contentStr = "";
            switch ($object->Event)
           {
                case "subscribe":
                    $contentStr = "欢迎洋洋博客";
               case "unsubscribe":
                    break;
                case "CLICK":
                   switch ($object->EventKey)
                   {
                        case "company":
                           $contentStr[] = array("Title" =>"公司简介", 
                            "Description" =>"洋洋的博客", 
                           "PicUrl" =>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", 
                           "Url" =>"weixin://addfriend/pondbaystudio");
                           break;
                        default:
                           $contentStr[] = array("Title" =>"默认菜单回复", 
                            "Description" =>"您正在使用的是<span style="font-family: Arial, Helvetica, sans-serif;">洋洋的博客</span><span style="font-family: Arial, Helvetica, sans-serif;">", </span>
                           "PicUrl" =>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", 
                            "Url" =>"weixin://addfriend/pondbaystudio");
                            break;
                    }
                    break;
                default:
                   break;      
    
           }
            if (is_array($contentStr)){
               $resultStr = $this->transmitNews($object, $contentStr);
           }else{
               $resultStr = $this->transmitText($object, $contentStr);
          }
           return $resultStr;
       }
    
        private function transmitText($object, $content, $funcFlag = 0)
        {
           $textTpl = "<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[%s]]></Content>
    <FuncFlag>%d</FuncFlag>
    </xml>";
            $resultStr = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(), $content, $funcFlag);
            return $resultStr;
        }
    
       private function transmitNews($object, $arr_item, $funcFlag = 0)
        {
           //首条标题28字,其他标题39字
            if(!is_array($arr_item))
               return;
    
            $itemTpl = "    <item>
            <Title><![CDATA[%s]]></Title>
           <Description><![CDATA[%s]]></Description>
           <PicUrl><![CDATA[%s]]></PicUrl>
           <Url><![CDATA[%s]]></Url>
       </item>
    ";
            $item_str = "";
           foreach ($arr_item as $item)
               $item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
    
            $newsTpl = "<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[news]]></MsgType>
    <Content><![CDATA[]]></Content>
    <ArticleCount>%s</ArticleCount>
    <Articles>
    $item_str</Articles>
    <FuncFlag>%s</FuncFlag>
    </xml>";
    
          $resultStr = sprintf($newsTpl, $object->FromUserName, $object->ToUserName, time(), count($arr_item), $funcFlag);
            return $resultStr;
        }
    }
    ?> 

    复制代码

    八、菜单中获取OpenID

    由于菜单中只能填写固定的url地址,对于想要菜单中获取用户的OpenID的情况,可以使用OAuth2.0授权的方式来实现。

    URL中填写的地址为一个固定的回调地址。原理方法可以参考  微信公众平台开发(99) 自定义菜单获取OpenID

    <?php
    /*
        洋洋的博客
    */
    
    define("TOKEN", "weixin");
    $wechatObj = new wechatCallbackapiTest();
    if (isset($_GET['echostr'])) {
        $wechatObj->valid();
    }else{
        $wechatObj->responseMsg();
    }
    
    class wechatCallbackapiTest
    {
        public function valid()
        {
            $echoStr = $_GET["echostr"];
            if($this->checkSignature()){
                header('content-type:text');
                echo $echoStr;
                exit;
            }
        }
    
        private function checkSignature()
        {
            $signature = $_GET["signature"];
            $timestamp = $_GET["timestamp"];
            $nonce = $_GET["nonce"];
    
            $token = TOKEN;
            $tmpArr = array($token, $timestamp, $nonce);
            sort($tmpArr, SORT_STRING);
            $tmpStr = implode( $tmpArr );
            $tmpStr = sha1( $tmpStr );
    
            if( $tmpStr == $signature ){
                return true;
            }else{
                return false;
            }
        }
    
        public function responseMsg()
        {
            $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
    
            if (!empty($postStr)){
                $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $fromUsername = $postObj->FromUserName;
                $toUsername = $postObj->ToUserName;
                $keyword = trim($postObj->Content);
                $time = time();
                $textTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[%s]]></MsgType>
                            <Content><![CDATA[%s]]></Content>
                            <FuncFlag>0</FuncFlag>
                            </xml>";
                if($keyword == "?" || $keyword == "?")
                {
                    $msgType = "text";
                    $contentStr = '当前时间是:'.date("Y-m-d H:i:s",time());
                    $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                    echo $resultStr;
                }
            }else{
                echo "";
                exit;
            }
        }
    }
    ?>

    展开全文
  • 微信开发交流群:148540125系列文章参考地址 极速开发微信公众号欢迎留言、转发 项目源码参考地址 点我点我–欢迎Start 前几篇文章已讲完如何导入项目,如何启动配置项目,如何成为开发者,重源码分析消息是如何...

    微信开发交流群:148540125

    系列文章参考地址 极速开发微信公众号

    欢迎留言、转发
    项目源码参考地址 点我点我–欢迎Start

    前几篇文章已讲完如何导入项目,如何启动配置项目,如何成为开发者,重源码分析消息是如何交互(如果前四项不是很清楚可以看这里 极速开发微信公众号。这篇文章就来讲讲如果实现自定义菜单

    实现自定义菜单有两种方式
    1、编辑模式
    2、开发模式

    编辑模式就很简单了就不赘述了……

    开发模式实现自定义菜单

    1、使用微信公众平台接口调试工具实现
    2、使用官方提供的接口实现

    前期准备

    注意:
    1、目前订阅号 只能使用编辑模式而且不能添加超链接,微信认证之后才可以使用开发模式。
    2、编辑模式与开发模式不能同时开启
    3、生成的菜单不会立即显示(隔天),如果想立即看到效果可以取消关注再关注

    添加插件

    K8WTIEI86W9W5XERD`MRD{6.png

    使用微信公众平台接口调试工具实现

    自定义菜单-接口调试工具.png

    可以看到需要两个参数而且都是必填 access_token body

    有人要问,这两个参数如何获取呢?

    body 其实就是要生成菜单的JSON对象 官方有提供一个栗子可以参考

     {
         "button":[
         {  
              "type":"click",
              "name":"今日歌曲",
              "key":"V1001_TODAY_MUSIC"
          },
          {
               "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"
                }]
           }]
     }
    

    access_token 的获取如下图
    自定义菜单-获取access_token.png

    使用官方提供的接口实现

    初次了解微信自定义菜单的同学建议先看看官方的文档3遍

    Jfinal-weixin中有封装菜单的创建、查询、删除、以及个性化菜单的创建、查询、删除、测试个性化菜单匹配结果

    自定义菜单-菜单封装的接口.png

    那么问题来了,封装好了如何使用呢?
    以下是提供封装的接口

        //查询自定义菜单
        public static ApiResult getMenu() {
            String jsonResult = HttpUtils.get(getMenu + AccessTokenApi.getAccessTokenStr());
            return new ApiResult(jsonResult);
        }
        //创建自定义菜单
        public static ApiResult createMenu(String jsonStr) {
            String jsonResult = HttpUtils.post(createMenu + AccessTokenApi.getAccessTokenStr(), jsonStr);
            return new ApiResult(jsonResult);
        }
        //删除自定义菜单
        public static ApiResult deleteMenu() {
            String jsonResult = HttpUtils.get(deleteMenuUrl + AccessTokenApi.getAccessTokenStr());
            return new ApiResult(jsonResult);
        }
        //创建个性化自定义菜单
        public static ApiResult addConditional(String jsonStr) {
            String jsonResult = HttpUtils.post(addConditionalUrl + AccessTokenApi.getAccessTokenStr(), jsonStr);
            return new ApiResult(jsonResult);
        }
        //删除个性化自定义菜单
        public static ApiResult delConditional(String menuid) {
            HashMap params = new HashMap();
            params.put("menuid", menuid);
            String url = delConditionalUrl + AccessTokenApi.getAccessTokenStr();
            String jsonResult = HttpUtils.post(url, JsonUtils.toJson(params));
            return new ApiResult(jsonResult);
        }
        //测试个性化菜单匹配结果
        public static ApiResult tryMatch(String userId) {
            HashMap params = new HashMap();
            params.put("user_id", userId);
            String url = tryMatchUrl + AccessTokenApi.getAccessTokenStr();
            String jsonResult = HttpUtils.post(url, JsonUtils.toJson(params));
            return new ApiResult(jsonResult);
        }
    
        public static ApiResult getCurrentSelfMenuInfo() {
            String jsonResult = HttpUtils.get(getCurrentSelfMenuInfoUrl + AccessTokenApi.getAccessTokenStr());
            return new ApiResult(jsonResult);
        }

    开源项目weixin_guidecom.javen.weixin.menu.MenuManager类中提供了详细使用的Demo

    public static void main(String[] args) { 
    
               // 将菜单对象转换成json字符串
               String jsonMenu = JsonKit.toJson(getTestMenu()).toString();
               System.out.println(jsonMenu);
               ApiConfig ac = new ApiConfig();
    
                // 配置微信 API 相关常量 请使用你自己公众号的
                ac.setAppId("wx614c453e0d1dcd12");
                ac.setAppSecret("19a02e4927d346484fc70327970457f9");
    //          ac.setAppId(PropKit.get("appId"));
    //          ac.setAppSecret(PropKit.get("appSecret"));
                ApiConfigKit.setThreadLocalApiConfig(ac);
    
               //创建菜单
               ApiResult apiResult=MenuApi.createMenu(jsonMenu);
               System.out.println(apiResult.getJson());
         }  

    可以看到main方法中调用了MenuApi.createMenu(jsonMenu)
    jsonMenu 从何而来呢?

    其实这里是将自定义菜单的实体对象转化为了JSON

    String jsonMenu = JsonKit.toJson(getTestMenu()).toString();

    菜单的封装

     
                 *  
                 * 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?
    * 比如,第三个一级菜单项不是“更多体验”,而直接是“幽默笑话”,那么menu应该这样定义:
    * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 }); */ Menu menu = new Menu(); menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 }); return menu; }" data-snippet-id="ext.c263135461e9345e2fb1fe96fc2d9c0c" data-snippet-saved="false" data-codota-status="done">/** * 组装菜单数据 * * @return */ private static Menu getTestMenu() { ClickButton btn11 = new ClickButton(); btn11.setName("微信相册发图"); btn11.setType("pic_weixin"); btn11.setKey("rselfmenu_1_1"); ClickButton btn12 = new ClickButton(); btn12.setName("拍照或者相册发图"); btn12.setType("pic_photo_or_album"); btn12.setKey("rselfmenu_1_2");; ClickButton btn13 = new ClickButton(); btn13.setName("系统拍照发图"); btn13.setType("pic_sysphoto"); btn13.setKey("rselfmenu_1_3"); ClickButton btn21 = new ClickButton(); btn21.setName("扫码带提示"); btn21.setType("scancode_waitmsg"); btn21.setKey("rselfmenu_2_1");; ClickButton btn22 = new ClickButton(); btn22.setName("扫码推事件"); btn22.setType("scancode_push"); btn22.setKey("rselfmenu_2_2");; ViewButton btn23 = new ViewButton(); btn23.setName("我的设备"); btn23.setType("view"); btn23.setUrl("https://hw.weixin.qq.com/devicectrl/panel/device-list.html?appid=wx614c453e0d1dcd12"); ViewButton btn31 = new ViewButton(); btn31.setName("微社区"); btn31.setType("view"); btn31.setUrl("http://whsf.tunnel.mobi/whsf/msg/wsq"); ClickButton btn32 = new ClickButton(); btn32.setName("发送位置"); btn32.setType("location_select"); btn32.setKey("rselfmenu_3_2"); //http://tencent://message/?uin=572839485&Site=在线咨询&Menu=yes //http://wpa.qq.com/msgrd?v=3&uin=572839485&site=qq&menu=yes ViewButton btn33 = new ViewButton(); btn33.setName("在线咨询"); btn33.setType("view"); btn33.setUrl("http://wpa.qq.com/msgrd?v=3&uin=572839485&site=qq&menu=yes"); ViewButton btn34 = new ViewButton(); btn34.setName("我的博客"); btn34.setType("view"); btn34.setUrl("http://www.cnblogs.com/zyw-205520"); ClickButton btn35 = new ClickButton(); btn35.setName("点击事件"); btn35.setType("click"); btn35.setKey("rselfmenu_3_5"); ComButton mainBtn1 = new ComButton(); mainBtn1.setName("发图"); mainBtn1.setSub_button(new Button[] { btn11, btn12, btn13}); ComButton mainBtn2 = new ComButton(); mainBtn2.setName("扫码"); mainBtn2.setSub_button(new Button[] { btn21, btn22 ,btn23}); ComButton mainBtn3 = new ComButton(); mainBtn3.setName("个人中心"); mainBtn3.setSub_button(new Button[] { btn31, btn32, btn33, btn34 ,btn35 }); /** * 这是公众号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; }

    执行main方法会输出生成菜单的JSON以及响应的状态

    生成菜单的JSON:{"button":[{"sub_button":[{"name":"微信相册发图","type":"pic_weixin","key":"rselfmenu_1_1"},{"name":"拍照或者相册发图","type":"pic_photo_or_album","key":"rselfmenu_1_2"},{"name":"系统拍照发图","type":"pic_sysphoto","key":"rselfmenu_1_3"}],"name":"发图","type":null},{"sub_button":[{"name":"扫码带提示","type":"scancode_waitmsg","key":"rselfmenu_2_1"},{"name":"扫码推事件","type":"scancode_push","key":"rselfmenu_2_2"},{"name":"我的设备","type":"view","url":"https://hw.weixin.qq.com/devicectrl/panel/device-list.html?appid=wx614c453e0d1dcd12"}],"name":"扫码","type":null},{"sub_button":[{"name":"微社区","type":"view","url":"http://whsf.tunnel.mobi/whsf/msg/wsq"},{"name":"发送位置","type":"location_select","key":"rselfmenu_3_2"},{"name":"在线咨询","type":"view","url":"http://wpa.qq.com/msgrd?v=3&uin=572839485&site=qq&menu=yes"},{"name":"我的博客","type":"view","url":"http://www.cnblogs.com/zyw-205520"},{"name":"点击事件","type":"click","key":"rselfmenu_3_5"}],"name":"个人中心","type":null}],"matchrule":null}
    
    响应的状态: {"errcode":0,"errmsg":"ok"}

    以上是生成自定义菜单的全过程。

    欢迎留言、转发
    项目源码参考地址 点我点我–欢迎Start

    展开全文
  • 在上篇文章实现微信扫码获取带指定参数时,微信公众号后台启用了服务器配置,导致之前设置好的微信自定义菜单失效。 开启了服务器配置,就无法用之前的方式在微信公众平台配置自定义菜单 此时,我们要通过接口来...

    在上篇文章实现微信扫码获取带指定参数时,微信公众号后台启用了服务器配置,导致之前设置好的微信自定义菜单失效。
    这里写图片描述
    开启了服务器配置,就无法用之前的方式在微信公众平台配置自定义菜单
    此时,我们要通过接口来配置微信自定义菜单,微信自定义菜单接口链接

    这里写图片描述

    首先,我们打开微信公众平台接口调试工具 接口调试工具
    1.通过appid以及secret来获取access_token,
    这里写图片描述

    2.组织创建菜单内容。微信提供了许多不同功能的按钮类型,可根据实际需求组织创建。
    这里简单的创建两个1级view类型按钮:即用户点击按钮实现跳转URL。

    {
        "button": [
            {
                "type": "view", 
                "name": "百度", 
                "url": "http://www.baidu.com"
            }, 
            {
                "type": "view", 
                "name": "淘宝", 
                "url": "http://www.taobao.com"
            }
        ]
    }

    3.在接口调试工具- - -选择 ‘自定义菜单’的接口类型,填入access_token,以及刚刚构建好的菜单内容。

    这里写图片描述

    点击检查问题,如果填写参数正确,则请求成功。
    这里写图片描述

    此时,重新打开或重新关注公众号,即能看到刚刚构建的自定义菜单已经生效。

    展开全文
  • 微信公众平台自定义菜单PHP开发
                   

    转自:http://www.cnblogs.com/GmrBrian/p/3593070.html

    微信公众平台自定义菜单PHP开发,微信公众平台自定义菜单是如何实现的呢?其实很简单,首先在微信公众平台升级为服务号,获取appid和appsecret,然后根据这2个参数获取access_token,在根据access_token,post一串字符到微信服务器就可以了。代码如下:

    回调URL(config.php)代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    define(AppId,"wx1234567890abcdef");//定义AppId,需要在微信公众平台申请自定义菜单后会得到
     
    define(AppSecret,"1234567890abcdefghijklmnopqrstuv");//定义AppSecret,需要在微信公众平台申请自定义菜单后会得到
     
    include("wechat.class.php");//引入微信类
     
    $wechatObj =new Wechat();//实例化微信类
     
    $creatMenu =$wechatObj->creatMenu();//创建菜单

    微信类(wechat.class.php)代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    展开全文
  • 首先要了解,在做微信开发项目的时候,都是需要进行一个token验证的,微信服务端去验证你传来的token,校验通过之后,才能给你开放一些借口以便于你进行一些详细的读写操作,所以我们在做开发之前都是需要先通过微信...

    首先要了解,在做微信开发项目的时候,都是需要进行一个token验证的,微信服务端去验证你传来的token,校验通过之后,才能给你开放一些借口以便于你进行一些详细的读写操作,所以我们在做开发之前都是需要先通过微信端的接口来获取到access_token来进行接下来的一些操作,具体看代码
    这是微信提供的获取access_token的地址
    https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    这其中有三个参数:

    • grant_type——获取access_token填写client_credential
    • appid——第三方用户唯一凭证
    • secret——第三方用户唯一凭证密钥,即appsecret
      通过你传来的appid和secret来识别唯一的用户,就是判断你是否是开发者并且你的账号没有异常,校验通过以后
      正常情况下,微信会返回下述JSON数据包:{“access_token”:“ACCESS_TOKEN”,“expires_in”:7200}
      这里的access_token就是你获取到的token,expires_in就是这个token的过期时间2个小时,当我们获取到这个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”
    }]
    }]
    }

    这样模块的一个菜单,通过一些json拼接数组的操作就可以得到这样的数据

    //根据pid去数据库查询一级菜单
    List<WeChatMenu> menuList = wechatMapper.findById(0);
    JSONObject parentjson = new JSONObject();
    
    JSONArray parentarray = new JSONArray();
    
    //循环集合,拼接第一级菜单
    for (int i = 0; i < menuList.size() ; i++) {
        WeChatMenu weChatMenu = menuList.get(i);//获取第一级菜单
    
        JSONObject jsonObject = new JSONObject();
    
        JSONArray jsonArray = new JSONArray();
        //判断同级菜单中是否存在type为null的情况
        if(!StringUtils.isBlank(weChatMenu.getM_type())){//type不为空,添加type类型,否则不添加
            jsonObject.put("type",weChatMenu.getM_type());
            jsonObject.put("name",weChatMenu.getM_name());
            //根据获取到的type类型判断增加的是key还是url
            if(weChatMenu.getM_type().equals("click")){
                jsonObject.put("key",weChatMenu.getM_key());
            }
            if(weChatMenu.getM_type().equals("view")){
                jsonObject.put("url",weChatMenu.getM_url());
            }
        }else{
            jsonObject.put("name",weChatMenu.getM_name());
            List<WeChatMenu> list = wechatMapper.findById(weChatMenu.getId());//根据一级菜单的id查询对应的子菜单
            for (int j = 0; j < list.size(); j++) {
                WeChatMenu menu = list.get(j);
                JSONObject childrenjson = new JSONObject();
                childrenjson.put("type",menu.getM_type());
                childrenjson.put("name",menu.getM_name());
    
                if(menu.getM_type().equals("click")){
                    childrenjson.put("key",menu.getM_key());
                }
    
                if(menu.getM_type().equals("view")){
                    childrenjson.put("url",menu.getM_url());
                }
                jsonArray.add(childrenjson);
            }
            jsonObject.put("sub_button",jsonArray);
        }
    
        parentarray.add(jsonObject);
    }
    //拼接一级菜单
    parentjson.put("button", parentarray);//{"button":[]}
    

    这是我的数据库的表结构,展示一下
    在这里插入图片描述
    这是嵌套循环的方式获取到的数据的代码,也可以通过递归的方法来获取,具体看个人喜好,在这里关于菜单的type类型我只判断了click和view,因为开发中基本上用的最多的就是这两种,如果还需要其他的那么久自行添加。拼接完这些数据之后,就需要通过调用微信提供的接口把我们的数据和获取到的access_token传过去,等微信端校验完成之后就可以看到新建好的菜单了。
    那么怎么在项目中通过java代码来实现操作呢,就需要用到httpclient post请求方式

    public static String postMethod(String url,String param){
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost post = new HttpPost(url);
        String result = null;
        try {
            StringEntity entity = new StringEntity(param,Charset.forName("UTF-8"));
            post.setEntity(entity);
            HttpResponse execute = httpClient.execute(post);
            result = EntityUtils.toString(execute.getEntity());//将返回来的实体对象转换成字符串
    
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
    

    这里我自定义了一个工具类,只需要把拼接好的数据放入进来就可以了

    //将拼接好的字符串和地址通过httputils发送请求
    String result = HttpClientUtils.postMethod(change_menulist_url, parentjson.toString());
    

    如果校验成功并且拼接的数据没有错的话就会返回来{“errcode”:0,“errmsg”:“ok”}这样的result

    这是关于返回来的状态码的详细解释

    展开全文
  • 最近在做一个基于微信公众号的资源回收系统,由于与队长的想法发生冲突的原因,就打算自己自学一下微信公众号的自定义菜单。 ▍概述 由于目前只是在大学阶段,没有企业身份,不能进行企业注册,也就无法使用...
  • 微信公众号开发5-自定义菜单-微信开发php讲师介绍: 秦子恒,CEO/董事长/总经理,大秦电商创始人,专注网络技术的电商应用。已经出品《1小时快速建站》《微博营销实战》《PHP采集》《网络招商系统》课程介绍: ...
  • 在这里介绍微信公众号的自定义菜单开发 先恭迎我们的TX文档 微信公众号——自定义菜单栏 官方文档里说明了一些需要注意的事项 在这里 我只使用了几个我业务中用到的类型 哈哈哈 本来在考虑要不要加在后台上...
  • java微信开发自定义菜单,点击事件,授权等模板,使用mvc模式,
  • 本来想 把那个 5分的 给大家改成免费的 结果CSDN改不了 从新上传一个免费的 也完善了一下
  • 微信接口自定义菜单在线客服微信支付
  • 三、去获取 access_token,应用 id 在 微信企业号开发平台《应用中心》的对应应用里。但是获取 access_token 还需要 corpid 和 corpsecret。四、获取 access_token 还需要 corpid 和 corpsecret。要去权限管理创建
  • 微信公众号:自定义菜单的实现说明文档实现创建菜单接口参数说明注意事项 说明 自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能。 1.自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个...
  • 最近想学习下微信公众号的开发,所以从自定义菜单功能开始开发自定义菜单功能的开发需要完成微信认证之后才能拥有权限,否则会报错:40081, 没有微信认证可以申请微信接口测试公众号。 自定义菜单能够帮助公众号...
  • 使用JAVA后端去自定义创建菜单微信公众号开发文档中提供了API: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013,请大家认真的观看文档的中的信息, 创建菜单中有一些要注意的地方: 1、...
  • 创建自定义菜单,实现菜单事件。 首先获取Access_Token 接口: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET 然后配置菜单的事件,caidan.php <...
  • 自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能。 1、自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。 2、一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分会以...
  • 1,调用微信开发测试工具,检查菜单是否正确。 2,正确的情况下,浏览器调用一下菜单查询接口,重新关注公众号,很快生效。 转载于:https://www.cnblogs.com/code-Officer/p/8366197.html...
  • 微信公众号的自定义菜单微信开发基础课程之一,不论是订阅号还是服务号都必须学会和精通自定义菜单
  • 微信自定义菜单开发
1 2 3 4 5 ... 20
收藏数 15,720
精华内容 6,288
关键字:

微信开发将自定义菜单