微信开发学习总结(四)——自定义菜单(5)——个性化菜单接口

版权声明:本文为博主原创文章,请尊重原创,未经博主允许禁止转载,保留追究权 https://blog.csdn.net/qq_29914837/article/details/82948779

一、个性化菜单接口说明

为了帮助公众号实现灵活的业务运营,微信公众平台新增了个性化菜单接口,开发者可以通过该接口,让公众号的不同用户群体看到不一样的自定义菜单。该接口开放给已认证订阅号和已认证服务号。

开发者可以通过以下条件来设置用户看到的菜单:

1、用户标签(开发者的业务需求可以借助用户标签来完成)
2、性别
3、手机操作系统
4、地区(用户在微信客户端设置的地区)
5、语言(用户在微信客户端设置的语言)

个性化菜单接口说明:

1、个性化菜单要求用户的微信客户端版本在iPhone6.2.2,Android 6.2.4以上,暂时不支持其他版本微信
2、菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果
3、普通公众号的个性化菜单的新增接口每日限制次数为2000次,删除接口也是2000次,测试个性化菜单匹配结果接口为20000次
4、出于安全考虑,一个公众号的所有个性化菜单,最多只能设置为跳转到3个域名下的链接
5、创建个性化菜单之前必须先创建默认菜单(默认菜单是指使用普通自定义菜单创建接口创建的菜单)。如果删除默认菜单,个性化菜单也会全部删除
6、个性化菜单接口支持用户标签,请开发者注意,当用户身上的标签超过1个时,以最后打上的标签为匹配

个性化菜单匹配规则说明:

个性化菜单的更新是会被覆盖的。
例如公众号先后发布了默认菜单,个性化菜单1,个性化菜单2,个性化菜单3。那么当用户进入公众号页面时,将从个性化菜单3开始匹配,如果个性化菜单3匹配成功,则直接返回个性化菜单3,否则继续尝试匹配个性化菜单2,直到成功匹配到一个菜单。
根据上述匹配规则,为了避免菜单生效时间的混淆,决定不予提供个性化菜单编辑API,开发者需要更新菜单时,需将完整配置重新发布一轮。

二、目录

1 创建个性化菜单
2 删除个性化菜单
3 测试个性化菜单匹配结果
4 查询个性化菜单
5 删除所有菜单

三、创建个性化菜单

3.1创建个性化菜单接口说明
http请求方式:POST(请使用https协议)

https://api.weixin.qq.com/cgi-bin/menu/addconditional?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"
           }]
 }],
"matchrule":{
  "tag_id":"2",
  "sex":"1",
  "country":"中国",
  "province":"广东",
  "city":"广州",
  "client_platform_type":"2",
  "language":"zh_CN"
  }
}

参数说明

参数 是否必须 说明
button 一级菜单数组,个数应为1~3个
sub_button 二级菜单数组,个数应为1~5个
type 菜单的响应动作类型,view表示网页类型,click表示点击类型,miniprogram表示小程序类型
name 菜单标题,不超过16个字节,子菜单不超过40个字节
key click等点击类型必须 菜单KEY值,用于消息接口推送,不超过128字节
url view、miniprogram类型必须 网页链接,用户点击菜单可打开链接,不超过1024字节。当type为miniprogram时,不支持小程序的老版本客户端将打开本url
media_id media_id类型和view_limited类型必须 调用新增永久素材接口返回的合法media_id
appid miniprogram类型必须 小程序的appid
pagepath miniprogram类型必须 小程序的页面路径
matchrule 菜单匹配规则
tag_id 用户标签的id,可通过用户标签管理接口获取
sex 性别:男(1)女(2),不填则不做匹配
client_platform_type 客户端版本,当前只具体到系统型号:IOS(1), Android(2),Others(3),不填则不做匹配
country 国家信息,是用户在微信中设置的地区,具体请参考地区信息表
province 省份信息,是用户在微信中设置的地区,具体请参考地区信息表
city 城市信息,是用户在微信中设置的地区,具体请参考地区信息表
language 语言信息,是用户在微信中设置的语言,具体请参考语言表: 1、简体中文 “zh_CN” 2、繁体中文TW “zh_TW” 3、繁体中文HK “zh_HK” 4、英文 “en” 5、印尼 “id” 6、马来 “ms” 7、西班牙 “es” 8、韩国 “ko” 9、意大利 “it” 10、日本 “ja” 11、波兰 “pl” 12、葡萄牙 “pt” 13、俄国 “ru” 14、泰文 “th” 15、越南 “vi” 16、阿拉伯语 “ar” 17、北印度 “hi” 18、希伯来 “he” 19、土耳其 “tr” 20、德语 “de” 21、法语 “fr”

matchrule共六个字段,均可为空,但不能全部为空,至少要有一个匹配信息是不为空的。 country、province、city组成地区信息,将按照country、province、city的顺序进行验证,要符合地区信息表的内容。地区信息从大到小验证,小的可以不填,即若填写了省份信息,则国家信息也必填并且匹配,城市信息可以不填。 例如 “中国 广东省 广州市”、“中国 广东省”都是合法的地域信息,而“中国 广州市”则不合法,因为填写了城市信息但没有填写省份信息。 地区信息表请点击下载。

返回结果

正确时的返回JSON数据包如下,错误时的返回码请见接口返回码说明。

{"menuid":"208379533"}

3.2创建个性化菜单接口代码实现

	/**
	 * 自定义个性化菜单-个性化菜单接口  http请求方式:POST(请使用https协议)
	 */
    public static final String MENU_MATCHRULE_CREATE="https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN";
    

创建个性化菜单试题类

package weixin.entity.menu;

/**
 * @所属类别:实体类_菜单匹配规则
 * @用途:微信公众号开发中自定义菜单-创建个性化菜单(个性化菜单属性)
 * @author yilei
 * @version:1.0
 */
public class Matchrule {

	private String tag_id;//用户标签的id,可通过用户标签管理接口获取
	private String sex;//性别:男(1)女(2),不填则不做匹配
	private String country;// 国家信息,是用户在微信中设置的地区,具体请参考地区信息表
	private String province;//省份信息,是用户在微信中设置的地区,具体请参考地区信息表
	private String city;//城市信息,是用户在微信中设置的地区,具体请参考地区信息表
	private String client_platform_type;//客户端版本,当前只具体到系统型号:IOS(1), Android(2),Others(3),不填则不做匹配
	private String language;//语言信息,是用户在微信中设置的语言,具体请参考语言表: 1、简体中文 "zh_CN" 2、繁体中文TW "zh_TW" 3、繁体中文HK "zh_HK" 4、英文 "en" 5、印尼 "id" 6、马来 "ms" 7、西班牙 "es" 8、韩国 "ko" 9、意大利 "it" 10、日本 "ja" 11、波兰 "pl" 12、葡萄牙 "pt" 13、俄国 "ru" 14、泰文 "th" 15、越南 "vi" 16、阿拉伯语 "ar" 17、北印度 "hi" 18、希伯来 "he" 19、土耳其 "tr" 20、德语 "de" 21、法语 "fr"
	public String getTag_id() {
		return tag_id;
	}
	public void setTag_id(String tag_id) {
		this.tag_id = tag_id;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public String getProvince() {
		return province;
	}
	public void setProvince(String province) {
		this.province = province;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public String getClient_platform_type() {
		return client_platform_type;
	}
	public void setClient_platform_type(String client_platform_type) {
		this.client_platform_type = client_platform_type;
	}
	public String getLanguage() {
		return language;
	}
	public void setLanguage(String language) {
		this.language = language;
	}
	
	 
}

创建菜单实体类

package weixin.entity.menu;

/**
 * @所属类别:实体类
 * @用途:微信公众号开发中自定义菜单-自定义菜单创建接口(Menu类代表整个微信公众号自定义菜单)
 * @author yilei
 * @version:1.0
 */
public class Menu {

	private Button[] button;//button	是	一级菜单数组,个数应为1~3个

	private Matchrule matchrule ;//个性化菜单-	菜单匹配规则
	
	public Matchrule getMatchrule() {
		return matchrule;
	}

	public void setMatchrule(Matchrule matchrule) {
		this.matchrule = matchrule;
	}

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

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

	/**
	 * @param button
	 */
	public Menu(Button[] button) {
		this.button = button;
	}
	
	public Menu(){
		
	}

	/**
	 * @param button
	 * @param matchrule
	 */
	public Menu(Button[] button, Matchrule matchrule) {
		this.button = button;
		this.matchrule = matchrule;
	}
	
	
}

第一个方法initMenu()是组装默认菜单,第二个方法initMatchruleMenu()是组装个性化菜单

    /**
     * 组装默认菜单
     * @return
     */
    public static Menu initMenu(){
    Menu menu = new Menu();
    
    //---------菜单1、点击类型菜单-------------------//
    TypeButton c1 = new TypeButton();
    c1.setName("点击类型菜单1");
    c1.setType("click");
    c1.setKey("1");

    Button b1 = new Button();
    b1.setName("菜单标题1");
    b1.setSub_button(new Button[]{c1}); 

    //---------菜单2,具有2个子菜单(一个点击类型、一个是网页类型)   -------------------//
    TypeButton c2 = new TypeButton();
    c2.setName("点击类型菜单2");
    c2.setType("click");
    c2.setKey("11");

    TypeButton v1 = new TypeButton();
    v1.setName("点击网页类型2");
    v1.setType("view");
    v1.setUrl("http://www.baidu.com");
    
    Button b2 = new Button();
    b2.setName("菜单标题2");
    
    b2.setSub_button(new Button[]{c2,v1}); 
    
    //---------菜单3,具有5个子菜单(scancode_push/scancode_waitmsg/pic_sysphoto/pic_photo_or_album/pic_weixin/location_select)   -------------------//   
    TypeButton t1 = new TypeButton();
    t1.setName("扫码推事件");
    t1.setType("scancode_push");
    t1.setKey("scancode_push");
 
    TypeButton t2 = new TypeButton();
    t2.setName("扫码带提示");
    t2.setType("scancode_waitmsg");
    t2.setKey("scancode_waitmsg");
    
    TypeButton t3 = new TypeButton();
    t3.setName("系统拍照发图");
    t3.setType("pic_sysphoto");
    t3.setKey("pic_sysphoto");
    
    TypeButton t4 = new TypeButton();
    t4.setName("拍照或者相册发图");
    t4.setType("pic_photo_or_album");
    t4.setKey("pic_photo_or_album");
    
    TypeButton t5 = new TypeButton();
    t5.setName("微信相册发图");
    t5.setType("pic_weixin");
    t5.setKey("pic_weixin");

    TypeButton t6 = new TypeButton();
    t6.setName("发送位置");
    t6.setType("location_select");
    t6.setKey("location_select");
    
    Button b3 = new Button();
    b3.setName("菜单标题3"); 
    b3.setSub_button(new Button[]{t1,t2,t3,t4,t5});
       
    menu.setButton(new Button[]{b1,b2,b3});// 
    return menu;

    }
 
    
    /**
     * 组装个性化菜单1
     * @return
     */
    public static Menu initMatchruleMenu(){
    Menu menu = new Menu();
    
    //---------菜单1、点击类型菜单-------------------//
    TypeButton c1 = new TypeButton();
    c1.setName("点击类型菜单1");
    c1.setType("click");
    c1.setKey("1");

    Button b1 = new Button();
    b1.setName("个性化标题1");
    b1.setSub_button(new Button[]{c1}); 

    //---------菜单2,具有2个子菜单(一个点击类型、一个是网页类型)   -------------------//
    TypeButton c2 = new TypeButton();
    c2.setName("点击类型菜单2");
    c2.setType("click");
    c2.setKey("11");

    TypeButton v1 = new TypeButton();
    v1.setName("点击网页类型2");
    v1.setType("view");
    v1.setUrl("http://www.baidu.com");
    
    Button b2 = new Button();
    b2.setName("个性化标题2");
    
    b2.setSub_button(new Button[]{c2,v1}); 
    
    //---------菜单3,具有5个子菜单(scancode_push/scancode_waitmsg/pic_sysphoto/pic_photo_or_album/pic_weixin/location_select)   -------------------//   
    TypeButton t1 = new TypeButton();
    t1.setName("扫码推事件");
    t1.setType("scancode_push");
    t1.setKey("scancode_push");
 
    TypeButton t2 = new TypeButton();
    t2.setName("扫码带提示");
    t2.setType("scancode_waitmsg");
    t2.setKey("scancode_waitmsg");
    
    TypeButton t3 = new TypeButton();
    t3.setName("系统拍照发图");
    t3.setType("pic_sysphoto");
    t3.setKey("pic_sysphoto");
    
    TypeButton t4 = new TypeButton();
    t4.setName("拍照或者相册发图");
    t4.setType("pic_photo_or_album");
    t4.setKey("pic_photo_or_album");
    
    TypeButton t5 = new TypeButton();
    t5.setName("微信相册发图");
    t5.setType("pic_weixin");
    t5.setKey("pic_weixin");

    TypeButton t6 = new TypeButton();
    t6.setName("发送位置");
    t6.setType("location_select");
    t6.setKey("location_select");
    
    Button b3 = new Button();
    b3.setName("个性化标题3"); 
    b3.setSub_button(new Button[]{t1,t2,t3,t4,t5});
       
    menu.setButton(new Button[]{b1,b2,b3});
    Matchrule matchrule = new Matchrule();
    matchrule.setSex("1");//过滤男性
    menu.setMatchrule(matchrule);
    return menu;

    }

createMenu()方法是创建默认菜单,createMatchruleMenu()方法创建个性化菜单

    /**
     * 创建默认菜单
     * @param token(ACCESS_TOKEN)
     * @param menu(已经转换为json格式的Meun类型的字符串)
     * @return result =0,表示创建成功,否则失败
     */
    public static int createMenu(String token,String menu){
    	int errcode = 0;
    	String url = WeiXin.MENU_CREATE.replace("ACCESS_TOKEN", token);
    	JSONObject jsonObject = doPostStr(url, menu);
    	if(jsonObject != null){
    		errcode = jsonObject.getInt("errcode");
    	}
    	return errcode;
    }
    
    /**
     * 创建个性化菜单
     * @param token(ACCESS_TOKEN)
     * @param menu(已经转换为json格式的Meun类型的字符串)
     * @return result =0,表示创建成功,否则失败
     */
    public static String createMatchruleMenu(String token,String menu){
    	String menuid ="";
    	String url = WeiXin.MENU_MATCHRULE_CREATE.replace("ACCESS_TOKEN", token);
    	JSONObject jsonObject = doPostStr(url, menu);
    	if(jsonObject != null){
    		menuid = jsonObject.getString("menuid");
    	}
    	return menuid;
    }

第一个doPost()是创建默认菜单,第二个doPost()是创建个性化菜单使用

	/**
	 * 处理微信服务器发post请求发来的xml格式消息--创建默认菜单
	 */
 /*    @Override
	public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
    	ServletContext context = getServletContext();
    	AccessToken accessToken = (AccessToken) context.getAttribute("access_token");
    	String menu = JSONObject.fromObject(WeiXinCheck.initMenu()).toString();
    	//创建菜单
    	int errcode = WeiXinCheck.createMenu(accessToken.getAccessToken() , menu);
    	if(errcode==0){
    		System.out.println("菜单创建成功!");
    		long startTime=System.currentTimeMillis();   //获取开始时间
            // TODO 接收、处理、响应由微信服务器转发的用户发送给公众帐号的消息
            // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            System.out.println("微信的post请求进入了本地服务器了");
            String result = "";
            try {
                Map<String,String> map = WeiXinCheck.parseXml(request);
                System.out.println("微信公众号要开始发送消息");
                result =  WeiXinCheck.buildResponseMessage(map);
                
                if(result.equals("")){
                    result = "未正确响应";
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("发生异常:"+ e.getMessage());
            }
            
            response.getWriter().println(result);
            System.out.println( result) ;
            long endTime=System.currentTimeMillis(); //获取结束时间
            System.out.println("程序运行时间: "+(endTime-startTime)+"ms");
    	}else{
    		System.out.println("菜单创建失败");
    	}
    	
    }
    */
	/**
	 * 处理微信服务器发post请求发来的xml格式消息----创建个性化菜单
	 */
  @Override
	public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
    	ServletContext context = getServletContext();
    	AccessToken accessToken = (AccessToken) context.getAttribute("access_token");
    	String menu = JSONObject.fromObject(WeiXinCheck.initMatchruleMenu()).toString();
    	//创建菜单
    	String menuid = WeiXinCheck.createMatchruleMenu(accessToken.getAccessToken() , menu);
    	if(!"".equals(menuid)){
    		System.out.println("菜单创建成功!");
    		long startTime=System.currentTimeMillis();   //获取开始时间
            // TODO 接收、处理、响应由微信服务器转发的用户发送给公众帐号的消息
            // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            System.out.println("微信的post请求进入了本地服务器了");
            String result = "";
            try {
                Map<String,String> map = WeiXinCheck.parseXml(request);
                System.out.println("微信公众号要开始发送消息");
                result =  WeiXinCheck.buildResponseMessage(map);
                
                if(result.equals("")){
                    result = "未正确响应";
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("发生异常:"+ e.getMessage());
            }
            
            response.getWriter().println(result);
            System.out.println( result) ;
            long endTime=System.currentTimeMillis(); //获取结束时间
            System.out.println("程序运行时间: "+(endTime-startTime)+"ms");
    	}else{
    		System.out.println("菜单创建失败");
    	}
    	
    }

启动项目,因为我个性化菜单中设置了sex=1,即sex=男
因此,首先设置微信号性别为女

在这里插入图片描述

重新关注微信公众号:发现展示的还是默认菜单
在这里插入图片描述

重新设置微信号性别为男
在这里插入图片描述

重新关注微信公众号,发现由默认菜单更新为个性化菜单
在这里插入图片描述

表明当个性化菜单中sex=1,表示微信号为男性的用户,使用个性化菜单展示,微信号为女的用户还是采用的默认菜单展示
注意:个性化菜单如果创建了,那么就会一直存在,只用使用微信公众号提供的删除个性化菜单接口才可以删除。并且如何有多个个性化菜单,那么会优先执行最后创建的一个


四、删除个性化菜单

删除个性化菜单

http请求方式:POST(请使用https协议)

https://api.weixin.qq.com/cgi-bin/menu/delconditional?access_token=ACCESS_TOKEN

请求示例

{"menuid":"208379533"}

menuid为菜单id,可以通过自定义菜单查询接口获取。

正确时的返回JSON数据包如下,错误时的返回码请见接口返回码说明。:

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

五、测试个性化菜单匹配结果

http请求方式:POST(请使用https协议)

https://api.weixin.qq.com/cgi-bin/menu/trymatch?access_token=ACCESS_TOKEN

请求示例

{"user_id":"weixin"}

user_id可以是粉丝的OpenID,也可以是粉丝的微信号。

返回结果 该接口将返回菜单配置,示例如下:

{
    "button": [
        {
            "type": "view", 
            "name": "tx", 
            "url": "http://www.qq.com/", 
            "sub_button": [ ]
        }, 
        {
            "type": "view", 
            "name": "tx", 
            "url": "http://www.qq.com/", 
            "sub_button": [ ]
        }, 
        {
            "type": "view", 
            "name": "tx", 
            "url": "http://www.qq.com/", 
            "sub_button": [ ]
        }
    ]
}

错误时的返回码请见接口返回码说明。

六、查询个性化菜单

使用普通自定义菜单查询接口可以获取默认菜单和全部个性化菜单信息,请见自定义菜单查询接口的说明。

参考博客:https://blog.csdn.net/qq_29914837/article/details/82928977

七、删除所有菜单

使用普通自定义菜单删除接口可以删除所有自定义菜单(包括默认菜单和全部个性化菜单),请见自定义菜单删除接口的说明。

参考博客:https://blog.csdn.net/qq_29914837/article/details/82948147


本节代码:
微信开发学习总结(四)——自定义菜单(5)——个性化菜单接口——项目源码
下载地址:
https://download.csdn.net/download/qq_29914837/10702945

猜你喜欢

转载自blog.csdn.net/qq_29914837/article/details/82948779