5.3.4 案例:创建菜单

接下来,我们以图5-2所示的菜单为例,演示通过以上封装类定义菜单的结构,并最终得到JSON格式的菜单数据。案例代码如下:

  1. 1 public static void main(String[] args) {
  2. 2  ClickButton btn1 = new ClickButton();
  3. 3  btn1.setName("今日歌曲");
  4. 4  btn1.setType("click");
  5. 5  btn1.setKey("V1001_TODAY_MUSIC");
  6. 6
  7. 7  ViewButton btn2 = new ViewButton();
  8. 8  btn2.setName("歌手简介");
  9. 9  btn2.setType("view");
  10. 10  btn2.setUrl("http:// www.qq.com/");
  11. 11 
  12. 12  ClickButton btn31 = new ClickButton();
  13. 13  btn31.setName("hello word");
  14. 14  btn31.setType("click");
  15. 15  btn31.setKey("V1001_HELLO_WORLD");
  16. 16
  17. 17  ClickButton btn32 = new ClickButton();
  18. 18  btn32.setName("赞一下我们");
  19. 19  btn32.setType("click");
  20. 20  btn32.setKey("V1001_GOOD");
  21. 21
  22. 22  // 复合按钮包含2个click类型的按钮
  23. 23  ComplexButton btn3 = new ComplexButton();
  24. 24  btn3.setName("菜单");
  25. 25  btn3.setSub_button(new Button[] { btn31, btn32 });
  26. 26
  27. 27  // 创建菜单对象
  28. 28  Menu menu = new Menu();
  29. 29  menu.setButton(new Button[] { btn1, btn2, btn3 });
  30. 30
  31. 31  // 将菜单对象转换成JSON字符串
  32. 32  String jsonMenu = JSONObject.fromObject(menu).toString();
  33. 33  System.out.println(jsonMenu);
  34. 34 }

第23~25行代码创建了一个复合按钮,它包含了两个click类型的子按钮。再来看第32行代码,在得到菜单对象menu后仍然是使用JSON-lib将menu对象转换成JSON字符串。上面代码的运行结果与本节开头给出的JSON菜单数据完全相同。显然,这种通过操作对象获取菜单数据的方式要比直接在程序中拼接JSON数据更简便,而且不容易出错。

在得到JSON格式的菜单结构之后,我们需要发起HTTPS POST请求将菜单结构提交到https://api.weixin.qq.com/cgi-bin/menu/createaccess_token=ACCESS_TOKEN,菜单创建代码如下所示。

  1. 1 // 菜单创建接口地址
  2. 2 String menuCreateUrl =
  3. 3  "https:// api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
  4. 4 // 建立连接
  5. 5 URL url = new URL(menuCreateUrl);
  6. 6 HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
  7. 7 // 使用自定义的信任管理器
  8. 8 TrustManager[] tm = { new MyX509TrustManager() };
  9. 9 SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
  10. 10 sslContext.init(null, tm, new java.security.SecureRandom());
  11. 11 SSLSocketFactory ssf = sslContext.getSocketFactory();
  12. 12 conn.setSSLSocketFactory(ssf);
  13. 13 httpUrlConn.setDoOutput(true);
  14. 14 httpUrlConn.setDoInput(true);
  15. 15 // 设置请求方式
  16. 16 httpUrlConn.setRequestMethod("POST");
  17. 17 
  18. 18 // 向输出流写菜单结构
  19. 19 OutputStream outputStream = httpUrlConn.getOutputStream();
  20. 20 outputStream.write(jsonMenu.getBytes("UTF-8"));
  21. 21 outputStream.close();
  22. 22 
  23. 23 // 取得输入流
  24. 24 InputStream inputStream = httpUrlConn.getInputStream();
  25. 25 InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
  26. 26 BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
  27. 27 // 读取响应内容
  28. 28 StringBuffer buffer = new StringBuffer();
  29. 29 String str = null;
  30. 30 while ((str = bufferedReader.readLine()) != null) {
  31. 31  buffer.append(str);
  32. 32 }
  33. 33 // 关闭/释放资源
  34. 34 bufferedReader.close();
  35. 35 inputStreamReader.close();
  36. 36 inputStream.close();
  37. 37 httpUrlConn.disconnect();
  38. 38 // 输出菜单创建结果
  39. 39 System.out.println(buffer);

代码中的第16行将请求方式设置为POST,第19~21行是将菜单结构jsonMenu写到输出流,第23~32行是从输入流中读取响应内容(菜单创建结果)并保存在buffer变量中,第39行代码是将buffer输出到控制台。在运行上面的代码前,需要先获取凭证,然后将接口地址中的ACCESS_TOKEN替换为获取到的凭证。

自定义菜单创建完成后,由于微信客户端缓存的原因,需要24小时后才会在公众账号上展现出来。开发者在测试时可以通过取消关注公众账号后再次关注的方式立即看到最新的菜单效果。


说明 如果要修改公众账号的菜单,那么不需要将原有的菜单删除,再次创建菜单便会自动覆盖原有的菜单。