[15] 微信公众帐号开发教程第15篇-自定义菜单的view类型(访问网页)

2019-03-02 00:11|来源: 网路

引言及内容概要

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

view(访问网页):

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

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


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


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

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

{	
	"type":"click",
	"name":"今日歌曲",
	"key":"V1001_TODAY_MUSIC"
},
{
	"type":"view",
	"name":"歌手简介",
	"url":"http://www.qq.com/"
}

从上面可以看出,两种类型的菜单除了type值不同之外,属性也有差别。click类型的菜单有key属性,而view类型的菜单没有key属性,与之对应的是url属性。通过上一篇的学习我们知道,key值是用于判断用户点击了哪个click类型的菜单项。而 view类型的菜单没有key属性,目前无法在公众账号后台判断是否有用户点击了view类型的菜单项,也就没办法知道哪个用户点击了view类型的菜单项。


建立view类型的菜单对象

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

package org.liufeng.weixin.pojo;

/**
 * view类型的菜单
 * 
 * @author liuyq
 * @date 2013-04-10
 */
public class ViewButton extends Button {
	private String type;
	private String url;

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}
}


创建带view类型的菜单示例

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

package org.liufeng.weixin.main;

import org.liufeng.weixin.pojo.AccessToken;
import org.liufeng.weixin.pojo.Button;
import org.liufeng.weixin.pojo.CommonButton;
import org.liufeng.weixin.pojo.ComplexButton;
import org.liufeng.weixin.pojo.Menu;
import org.liufeng.weixin.pojo.ViewButton;
import org.liufeng.weixin.util.WeixinUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 菜单管理器类
 * 
 * @author liufeng
 * @date 2013-08-08
 */
public class MenuManager {
	private static Logger log = LoggerFactory.getLogger(MenuManager.class);

	public static void main(String[] args) {
		// 第三方用户唯一凭证
		String appId = "000000000000000000";
		// 第三方用户唯一凭证密钥
		String appSecret = "00000000000000000000000000000000";

		// 调用接口获取access_token
		AccessToken at = WeixinUtil.getAccessToken(appId, appSecret);

		if (null != at) {
			// 调用接口创建菜单
			int result = WeixinUtil.createMenu(getMenu(), at.getToken());

			// 判断菜单创建结果
			if (0 == result)
				log.info("菜单创建成功!");
			else
				log.info("菜单创建失败,错误码:" + result);
		}
	}

	/**
	 * 组装菜单数据
	 * 
	 * @return
	 */
	private static Menu getMenu() {
		CommonButton btn11 = new CommonButton();
		btn11.setName("天气预报");
		btn11.setType("click");
		btn11.setKey("11");

		CommonButton btn12 = new CommonButton();
		btn12.setName("公交查询");
		btn12.setType("click");
		btn12.setKey("12");

		CommonButton btn13 = new CommonButton();
		btn13.setName("周边搜索");
		btn13.setType("click");
		btn13.setKey("13");

		CommonButton btn14 = new CommonButton();
		btn14.setName("历史上的今天");
		btn14.setType("click");
		btn14.setKey("14");
		
		CommonButton btn15 = new CommonButton();
		btn15.setName("电影排行榜");
		btn15.setType("click");
		btn15.setKey("32");

		CommonButton btn21 = new CommonButton();
		btn21.setName("歌曲点播");
		btn21.setType("click");
		btn21.setKey("21");

		CommonButton btn22 = new CommonButton();
		btn22.setName("经典游戏");
		btn22.setType("click");
		btn22.setKey("22");

		CommonButton btn23 = new CommonButton();
		btn23.setName("美女电台");
		btn23.setType("click");
		btn23.setKey("23");

		CommonButton btn24 = new CommonButton();
		btn24.setName("人脸识别");
		btn24.setType("click");
		btn24.setKey("24");

		CommonButton btn25 = new CommonButton();
		btn25.setName("聊天唠嗑");
		btn25.setType("click");
		btn25.setKey("25");

		CommonButton btn31 = new CommonButton();
		btn31.setName("Q友圈");
		btn31.setType("click");
		btn31.setKey("31");

		CommonButton btn33 = new CommonButton();
		btn33.setName("幽默笑话");
		btn33.setType("click");
		btn33.setKey("33");
		
		CommonButton btn34 = new CommonButton();
		btn34.setName("用户反馈");
		btn34.setType("click");
		btn34.setKey("34");
		
		CommonButton btn35 = new CommonButton();
		btn35.setName("关于我们");
		btn35.setType("click");
		btn35.setKey("35");
		
		ViewButton btn32 = new ViewButton();
		btn32.setName("使用帮助");
		btn32.setType("view");
		btn32.setUrl("http://liufeng.gotoip2.com/xiaoqrobot/help.jsp");

		ComplexButton mainBtn1 = new ComplexButton();
		mainBtn1.setName("生活助手");
		mainBtn1.setSub_button(new Button[] { btn11, btn12, btn13, btn14, btn15 });

		ComplexButton mainBtn2 = new ComplexButton();
		mainBtn2.setName("休闲驿站");
		mainBtn2.setSub_button(new Button[] { btn21, btn22, btn23, btn24, btn25 });

		ComplexButton mainBtn3 = new ComplexButton();
		mainBtn3.setName("更多");
		mainBtn3.setSub_button(new Button[] { btn31, btn33, btn34, btn35, btn32 });

		/**
		 * 这是公众号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;
	}
}

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

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


如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号xiaoqrobot来支持柳峰!

转帖请注明本文出自柳峰的博客(http://blog.csdn.net/lyq8479),请尊重他人的辛勤劳动成果,谢谢!



转自:http://my.oschina.net/crossbell/blog/277760

相关问答

更多
  • 教程不一定要 PD 15的.其他的也一样,只要版本不是很老都可以. 比如说比较普遍的 PD 12.它的教程就很多. CSDN里面有很多下载资源. 建议你去淘一淘. 有不少值得下载的.
  • str.split(/;[,;]/)的意思是以正则表达式[,]来分割str字符串。 比如定义一个str为: var str = ;aaa[,]bbbb[,]cccccc;; 那么分割后的结果就是:aaa bbbb cccccc
  • List list2 = new ArrayList(); for(int i=0;i<50;i++) { try { list2.add(list1.get(i)); } catch(Exception rr) { list2.add(new ViewGridObject("blank","blank"); } } List list2 ...
  • 如果您使用动态编程 (存储子问题的结果,而不是重新计算它们),这可以快得多。 动态规划可以应用于显示最优子结构的问题 - 这意味着可以从最优解决方案到子问题(信用维基百科 )构建最优解。 我宁愿不要放弃答案,但请考虑右下角路径的数量可能与相邻广场路径的数量有关。 另外 - 如果你要手工工作,你该怎么办? This can be done much faster if you use dynamic programming (storing the results of subproblems rather ...
  • 如果您只是将参数类型更改为[int[]]那么这可能是最简单的,那么您的ValidateRange属性可以完成大部分工作。 但它不处理重复。 事实证明你不能像@PetSerAl指出的那样使用[ValidateScript()]。 因此,在开始块中以旧方式检查参数: Function Test-Something { [cmdletbinding()] Param( [Parameter(Position=0, Mandatory)] [ValidateRange ...
  • 克朗只允许你每分钟运行一次。 我会做的是在你的脚本中做15秒钟的时间。 每分钟执行一次父脚本。 在该脚本存在之前每15秒执行一次儿童脚本并开始一个新的循环。 Cron only lets you run things as fast as once a minute. What I would do is do the 15 second timings inside your script. Execute a parent script once a minute. Execute children s ...
  • 由于错误消息中的链接会告诉你: Highcharts预计数据将被排序 当您尝试创建线序列或股票图表时,会发生这种情况,其中数据未按升序X顺序排序。 出于性能原因,Highcharts不会对数据进行排序,而是需要实施者预先对数据进行排序。 在你的情况下,你的第一个系列中的x值是: -52587360000000 -52590038400000 -52611724800000 -52622611200000 -52655184000000 -52663392000000 -52855545600000 只要看 ...
  • 不。那个表是错误的或误导性的(多行,否则没有意义,可能反映了给定一些兼容性选项的行为变化,但如果是这样,我不知道它是什么选项)。 在标准Fortran中,INT泛型内在函数的结果类型仅取决于KIND参数的存在和值。 如果不存在KIND参数,则结果具有默认整数种类,否则KIND参数指定结果的KIND。 在没有更改默认整数类型的编译选项的情况下,示例程序中第二次调用INT的参数值不能用该编译器的默认整数表示。 您的代码不符合要求。 虽然文本没有实质性改变(除了可能变得更加混乱),我注意到你链接到的文档是古老的。 ...
  • CASE结构有两种形式。 要么你有 CASE expression WHEN value THEN result WHEN value THEN result ... ELSE END 或者你有 CASE WHEN boolean-expression THEN result WHEN boolean-expression THEN result ELSE END 在您的问题中,您需要第二个表单。 这是你想要的: SELECT @st ...
  • 这是一个按位和操作。 它正在做的是执行按位并使用值15和$value包含的任何$value 。 结果值是十进制值,对应于按位的结果和值的低4位。 例如: $value = 21 which has a binary representation of: 0b10101 执行bitwise and使用15意味着$value中的任何位将被置零,如果它们在低4位范围之外,或者在低4位中不包含1。 结果是: 0b10101 & 0b 1111 ------- 0b00101 = 5 查找用于执行按位运算的 ...