之前申请了一个订阅号,当准备大张旗鼓的开始创建自定义菜单的时候发现自定义菜单不针对订阅号开放,没有办法,只好再申请服务号,问题又产生了,服务号不针对个人
开放,经过一系列的折腾,不能不说我最后还是申请到了一个服务号(xiaofeiyu_super),还是蛮感谢腾讯审核的那个人的,虽然不知道是哪位,并且之前也给我拒绝过一次。
废话少说,也不再扯些自定义菜单有什么好处,我想对于大多说我们来说,就只是为了好玩,发现有这么个东西,便想着去玩玩。还是开始今天的主题,怎样才能生成自己的
菜单吧。其实对于自定义菜单的生成也没有什么难点的,和微信公众号开发的其他功能一个样,也只是对某个接口的调用而已。
首先看看腾讯官方对自定义菜单生成的说明:
由此我们可以知道几件事情,首先是采用https协议的POST请求,其次是请求哪个接口,再就是我们在请求时需要获得ACCESS_TOKEN的值。那么下面的工作就是一步步的
完成上面的工作。
要使用HTTPS协议就必须先了解这种协议的工作原理,https协议即安全的超文本传输协议,采用ssl技术,确保web应用的安全性。java中的jsse技术使得我们可以很方便的
使用https协议。Java安全套接扩展 (Java Secure Socket Extension, JSSE)是实现Internet安全通信的一系列包的集合。它是一个SSL和TLS的纯Java实现,可以透明地提
供数据加密、服务器认证、信息完整性 等功能,可以使我们像使用普通的套接字一样使用JSSE建立的安全套接字。JSSE是一个开放的标准,不只是Sun公司才能实现一个JSSE
,事实上其他 公司有自己实现的JSSE。下面就直接给出实现代码,关于https协议与http协议的讲解会用专门的文章讲解。
首先我们要获得安全证书类,如下:
1 //实现自己的安全证书类,覆盖下面三个方法,什么也不做,即对所有的信任 2 public class MyX509TrustManager implements X509TrustManager { 3 4 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 5 } 6 7 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 8 } 9 10 public X509Certificate[] getAcceptedIssuers() { 11 return null; 12 } 13 }
获得此类后我们就可以采用https方式请求指定连接了。接下来我么就获得access_token。
1 //获取access_token 2 public class GetToken { 3 public static void main(String[] args) throws Exception { 4 get(); 5 } 6 public static void get() throws Exception{ 7 //获得SSLContext 8 TrustManager[] manager = {new MyX509TrustManager()}; 9 SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); 10 sslContext.init(null, manager, new SecureRandom()); 11 12 //获得SSLSocketFactory 13 SSLSocketFactory factory = sslContext.getSocketFactory(); 14 15 //获得连接 16 String path = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=youAPPID&secret=youSECRET";//此处填写自己的APPID和APPSECRET 17 URL url = new URL(path); 18 HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); 19 connection.setSSLSocketFactory(factory); 20 21 //对连接进行设置 22 connection.setDoInput(true); 23 connection.setDoOutput(true); 24 25 //获得输出流 26 InputStream inputStream = connection.getInputStream(); 27 InputStreamReader reader = new InputStreamReader(inputStream,"utf-8"); 28 BufferedReader bufferedReader = new BufferedReader(reader); 29 30 //开始读数据 31 StringBuffer sb = new StringBuffer(); 32 String str = null; 33 while((str = bufferedReader.readLine())!=null){ 34 sb.append(str); 35 } 36 37 System.out.println(sb.toString()); 38 } 39 }
在获得access_token后我们就可以对接口发送数据了,如下代码所示:
1 public class HttpsConn { 2 public static void getCon() throws Exception{ 3 //得到SSLContext 4 TrustManager[] trustManager = {new MyX509TrustManager()}; 5 SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE"); 6 sslContext.init(null, trustManager, new SecureRandom()); 7 8 //由SSLContext创建SSLSocketFactory 9 SSLSocketFactory factory = sslContext.getSocketFactory(); 10 11 //获得HttpsURLConnection 12 String path = " https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";//换成你自己上一步得到的access_token 13 URL url = new URL(path); 14 HttpsURLConnection connection = (HttpsURLConnection)url.openConnection(); 15 connection.setSSLSocketFactory(factory); 16 17 //对连接进行设置 18 connection.setDoInput(true); 19 connection.setDoOutput(true); 20 connection.setRequestMethod("POST"); 21 22 //创建向接口发送的数据 23 String jsonMenu = null; 24 //向接口发送数据 25 OutputStream outputStream = connection.getOutputStream(); 26 // 注意编码格式,防止中文乱码 27 outputStream.write(jsonMenu.getBytes("UTF-8")); 28 outputStream.close(); 29 } 30 }
在上面的想接口发送数据中,我们并没有写好数据,而只是用null代替,接下来我们就看看怎么创建自己的菜单类。
在微信菜单中的结构式3*5形式的,即只有三个主菜单,每个主菜单上面有5个子菜单。而每个子菜单都有自己的名字和id,以及点击该菜单后产生什么动作,每个主菜单
也有自己的名字,以及包含子菜单。具体的菜单说明可以看微信开发文档<a href="http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html">
微信开发文档</a>。因此我们的菜单结构可以如下:,其中Button类是其他类的父类,有一个成员变量name;commonButton类就是上面说的子
菜单;complexButton类就是父类了。menu就是创建好的菜单。
1 public class Button { 2 private String name; 3 4 public String getName() { 5 return name; 6 } 7 8 public void setName(String name) { 9 this.name = name; 10 } 11 }
1 public class ComplexButton extends Button { 2 private Button[] sub_button; 3 4 public Button[] getSub_button() { 5 return sub_button; 6 } 7 8 public void setSub_button(Button[] sub_button) { 9 this.sub_button = sub_button; 10 } 11 }
1 public class Menu { 2 private Button[] button; 3 4 public Button[] getButton() { 5 return button; 6 } 7 8 public void setButton(Button[] button) { 9 this.button = button; 10 } 11 }
1 public class Create { 2 public static void create(){ 3 Menu menu = getMenu(); 4 String jsonMenu = JSONObject.fromObject(menu).toString(); 5 } 6 7 private static Menu getMenu() { 8 CommonButton btn11 = new CommonButton(); 9 btn11.setName("天气预报"); 10 btn11.setType("click"); 11 btn11.setKey("11"); 12 13 14 CommonButton btn21 = new CommonButton(); 15 btn21.setName("经典游戏"); 16 btn21.setType("click"); 17 btn21.setKey("21"); 18 19 20 21 CommonButton btn31 = new CommonButton(); 22 btn31.setName("微社区"); 23 btn31.setType("click"); 24 btn31.setKey("31"); 25 26 ComplexButton mainBtn1 = new ComplexButton(); 27 mainBtn1.setName("生活助手"); 28 mainBtn1.setSub_button(new CommonButton[] { btn11 }); 29 30 ComplexButton mainBtn2 = new ComplexButton(); 31 mainBtn2.setName("娱乐休闲"); 32 mainBtn2.setSub_button(new CommonButton[] { btn21 }); 33 34 ComplexButton mainBtn3 = new ComplexButton(); 35 mainBtn3.setName("更多体验"); 36 mainBtn3.setSub_button(new CommonButton[] {btn31}); 37 38 /** 39 * 40 * 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?<br> 41 * 比如,第三个一级菜单项不是“更多体验”,而直接是“幽默笑话”,那么menu应该这样定义:<br> 42 * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 }); 43 */ 44 Menu menu = new Menu(); 45 menu.setButton(new Button[] { mainBtn1, mainBtn2 ,mainBtn3}); 46 47 return menu; 48 } 49 }
在上面创建好了菜单后,只需要将它传值给上面的“向指定接口发送数据”即可,我们创建的菜单就会显示在自己微信公众账号上面,不过需要先取消关注了再重新关注才会
出现。