导入jar包

首先是 菜单项的基类,所有一级菜单、二级菜单都共有一个相同的属性,那就是name。菜单项基类的封装代码如下:

package com.souvc.weixin.menu;/**
* 类名: Button </br>
* 包名: com.souvc.weixin.menu
* 描述: 菜单项的基类  </br>
* 开发人员: souvc  </br>
* 创建时间:  2015-12-1 </br>
* 发布版本:V1.0  </br>*/
public class Button {private String name;//所有一级菜单、二级菜单都共有一个相同的属性,那就是namepublic String getName() {return name;}public void setName(String name) {this.name = name;}
}

接着是子菜单项的封装。这里对子菜单是这样定义的:没有子菜单的菜单项,有可能是二级菜单项,也有可能是不含二级菜单的一级菜单。这类子菜单项一定会包含三个属性:type、name和key,封装的代码如下:

package com.souvc.weixin.menu;/**
* 类名: CommonButton </br>
* 包名: com.souvc.weixin.menu
* 描述: 子菜单项 :没有子菜单的菜单项,有可能是二级菜单项,也有可能是不含二级菜单的一级菜单。 </br>
* 开发人员: souvc  </br>
* 创建时间:  2015-12-1 </br>
* 发布版本:V1.0  </br>*/
public class CommonButton extends Button {private String type;private String key;public String getType() {return type;}public void setType(String type) {this.type = type;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}
}

再往下是父菜单项的封装。对父菜单项的定义:包含有二级菜单项的一级菜单。这类菜单项包含有二个属性:name和sub_button,而sub_button以是一个子菜单项数组。父菜单项的封装代码如下:

package com.souvc.weixin.menu;/**
* 类名: ComplexButton </br>
* 包名: com.souvc.weixin.menu
* 描述: 父菜单项 :包含有二级菜单项的一级菜单。这类菜单项包含有二个属性:name和sub_button,而sub_button以是一个子菜单项数组 </br>
* 开发人员: souvc  </br>
* 创建时间:  2015-12-1 </br>
* 发布版本:V1.0  </br>*/
public class ComplexButton extends Button {private Button[] sub_button;public Button[] getSub_button() {return sub_button;}public void setSub_button(Button[] sub_button) {this.sub_button = sub_button;}
}

最后是整个菜单对象的封装,菜单对象包含多个菜单项(最多只能有3个),这些菜单项即可以是子菜单项(不含二级菜单的一级菜单),也可以是父菜单项(包含二级菜单的菜单项),如果能明白上面所讲的,再来看封装后的代码就很容易理解了:

package com.souvc.weixin.menu;/**
* 类名: Menu </br>
* 包名: com.souvc.weixin.menu
* 描述: 整个菜单对象的封装 </br>
* 开发人员:souvc </br>
* 创建时间:  2015-12-1 </br>
* 发布版本:V1.0  </br>*/
public class Menu {private Button[] button;public Button[] getButton() {return button;}public void setButton(Button[] button) {this.button = button;}
}

关于菜单的POJO类的封装就介绍完了。

AccessToken 的POJO的封装:

package com.souvc.weixin.pojo;/**
* 类名: AccessToken </br>
* 包名: com.souvc.weixin.pojo
* 描述: 微信通用接口凭证  </br>
* 开发人员:souvc </br>
* 创建时间:  2015-12-1 </br>
* 发布版本:V1.0  </br>*/
public class AccessToken {// 获取到的凭证private String token;// 凭证有效时间,单位:秒private int expiresIn;public String getToken() {return token;}public void setToken(String token) {this.token = token;}public int getExpiresIn() {return expiresIn;}public void setExpiresIn(int expiresIn) {this.expiresIn = expiresIn;}
}

封装通用的请求方法

读到这里,就默认大家已经掌握了上面讲到的所有关于自定义菜单的理论知识,下面就进入代码实战讲解的部分。

先前我们了解到,创建菜单需要调用二个接口,并且都是https请求,而非http。如果要封装一个通用的请求方法,该方法至少需要具备以下能力:

1)支持HTTPS请求;

2)支持GET、POST两种方式;

3)支持参数提交,也支持无参数的情况;

对于https请求,我们需要一个证书信任管理器,这个管理器类需要自己定义,但需要实现X509TrustManager接口,代码如下:

package com.souvc.weixin.util;import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;import javax.net.ssl.X509TrustManager;/**
* 类名: MyX509TrustManager </br>
* 包名: com.souvc.weixin.util
* 描述: 证书信任管理器(用于https请求)  </br>
* 开发人员:souvc  </br>
* 创建时间:  2015-12-1 </br>
* 发布版本:V1.0  </br>*/
public class MyX509TrustManager implements X509TrustManager {public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}public X509Certificate[] getAcceptedIssuers() {return null;}
}

这个证书管理器的作用就是让它信任我们指定的证书,上面的代码意味着信任所有证书,不管是否权威机构颁发。

证书有了,通用的https请求方法就不难实现了,实现代码如下:

package com.souvc.weixin.util;import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;import net.sf.json.JSONException;
import net.sf.json.JSONObject;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.souvc.weixin.menu.Menu;
import com.souvc.weixin.pojo.AccessToken;/**
* 类名: WeixinUtil </br>
* 包名: com.souvc.weixin.util
* 描述: 公众平台通用接口工具类 </br>
* 开发人员: souvc  </br>
* 创建时间:  2015-12-1 </br>
* 发布版本:V1.0  </br>*/
public class WeixinUtil {private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);// 获取access_token的接口地址(GET) 限200(次/天)public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";// 菜单创建(POST) 限100(次/天)public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";/*** 创建菜单* * @param menu 菜单实例* @param accessToken 有效的access_token* @return 0表示成功,其他值表示失败*/public static int createMenu(Menu menu, String accessToken) {int result = 0;// 拼装创建菜单的urlString url = menu_create_url.replace("ACCESS_TOKEN", accessToken);// 将菜单对象转换成json字符串String jsonMenu = JSONObject.fromObject(menu).toString();// 调用接口创建菜单JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);if (null != jsonObject) {if (0 != jsonObject.getInt("errcode")) {result = jsonObject.getInt("errcode");log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return result;}/*** 获取access_token* * @param appid 凭证* @param appsecret 密钥* @return*/public static AccessToken getAccessToken(String appid, String appsecret) {AccessToken accessToken = null;String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);JSONObject jsonObject = httpRequest(requestUrl, "GET", null);// 如果请求成功if (null != jsonObject) {try {accessToken = new AccessToken();accessToken.setToken(jsonObject.getString("access_token"));accessToken.setExpiresIn(jsonObject.getInt("expires_in"));} catch (JSONException e) {accessToken = null;// 获取token失败log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return accessToken;}/*** 描述:  发起https请求并获取结果* @param requestUrl 请求地址* @param requestMethod 请求方式(GET、POST)* @param outputStr 提交的数据* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)*/public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {JSONObject jsonObject = null;StringBuffer buffer = new StringBuffer();try {// 创建SSLContext对象,并使用我们指定的信任管理器初始化TrustManager[] tm = { new MyX509TrustManager() };SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");sslContext.init(null, tm, new java.security.SecureRandom());// 从上述SSLContext对象中得到SSLSocketFactory对象SSLSocketFactory ssf = sslContext.getSocketFactory();URL url = new URL(requestUrl);HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();httpUrlConn.setSSLSocketFactory(ssf);httpUrlConn.setDoOutput(true);httpUrlConn.setDoInput(true);httpUrlConn.setUseCaches(false);// 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestMethod);if ("GET".equalsIgnoreCase(requestMethod))httpUrlConn.connect();// 当有数据需要提交时if (null != outputStr) {OutputStream outputStream = httpUrlConn.getOutputStream();// 注意编码格式,防止中文乱码outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 将返回的输入流转换成字符串InputStream inputStream = httpUrlConn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}bufferedReader.close();inputStreamReader.close();// 释放资源
            inputStream.close();inputStream = null;httpUrlConn.disconnect();jsonObject = JSONObject.fromObject(buffer.toString());} catch (ConnectException ce) {log.error("Weixin server connection timed out.");} catch (Exception e) {log.error("https request error:{}", e);}return jsonObject;}
}

添加菜单管理器:

package com.souvc.weixin.main;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.souvc.weixin.menu.Button;
import com.souvc.weixin.menu.CommonButton;
import com.souvc.weixin.menu.ComplexButton;
import com.souvc.weixin.menu.Menu;
import com.souvc.weixin.pojo.AccessToken;
import com.souvc.weixin.util.WeixinUtil;/**
* 类名: MenuManager </br>
* 包名: com.souvc.weixin.main
* 描述:菜单管理器类 </br>
* 开发人员: liuhf </br>
* 创建时间:  2015-12-1 </br>
* 发布版本:V1.0  </br>*/
public class MenuManager {private static Logger log = LoggerFactory.getLogger(MenuManager.class);public static void main(String[] args) {// 第三方用户唯一凭证String appId = "000000000000000000";// 第三方用户唯一凭证密钥String appSecret = "00000000000000000000000000000000";// 调用接口获取access_tokenAccessToken at = WeixinUtil.getAccessToken(appId, appSecret);if (null != at) {// 调用接口创建菜单int result = WeixinUtil.createMenu(getMenu(), at.getToken());// 判断菜单创建结果if (0 == result)log.info("菜单创建成功!");elselog.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 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 btn32 = new CommonButton();btn32.setName("电影排行榜");btn32.setType("click");btn32.setKey("32");CommonButton btn33 = new CommonButton();btn33.setName("幽默笑话");btn33.setType("click");btn33.setKey("33");/*** 微信:  mainBtn1,mainBtn2,mainBtn3底部的三个一级菜单。*/ComplexButton mainBtn1 = new ComplexButton();mainBtn1.setName("生活助手");//一级下有4个子菜单mainBtn1.setSub_button(new CommonButton[] { btn11, btn12, btn13, btn14 });ComplexButton mainBtn2 = new ComplexButton();mainBtn2.setName("休闲驿站");mainBtn2.setSub_button(new CommonButton[] { btn21, btn22, btn23, btn24, btn25 });ComplexButton mainBtn3 = new ComplexButton();mainBtn3.setName("更多体验");mainBtn3.setSub_button(new CommonButton[] { btn31, btn32, btn33 });/*** 封装整个菜单*/Menu menu = new Menu();menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });return menu;}
}

注意替换称自己的appId和appSecret。

添加log4j.properties

    log4j.rootLogger=info,console,file  log4j.appender.console=org.apache.log4j.ConsoleAppender  log4j.appender.console.layout=org.apache.log4j.PatternLayout  log4j.appender.console.layout.ConversionPattern=[%-5p] %m%n  log4j.appender.file=org.apache.log4j.DailyRollingFileAppender  log4j.appender.file.DatePattern='-'yyyy-MM-dd  log4j.appender.file.File=./logs/weixinmpmenu.log  log4j.appender.file.Append=true  log4j.appender.file.layout=org.apache.log4j.PatternLayout  log4j.appender.file.layout.ConversionPattern=[%-5p] %d %37c %3x - %m%n  

直接执行MenuManager 的main 方法即可。

效果如下:

注意由于我们没有写处理事件,点击这些按钮是没有反应的。


微信公众号后台配置菜单代码相关推荐

  1. vue开发微信公众号可视化配置菜单

    vue开发微信公众号可视化配置菜单 其实一开始我也是懵逼的,我搞不懂微信公众号后台其实已经很好用了,为什么还需要开发一个模仿微信公众号后台的系统呢?而且微信公众号可以绑定多个运营者,都可以和管理员一样 ...

  2. 深入探索微信公众号开发:Java代码实现与最佳实践

    微信公众号是一种基于微信生态的社交工具,它可以帮助企业和个人实现信息传播.客户互动和营销推广等目标.本文将深入探讨微信公众号的开发流程.核心功能和Java代码实现,同时提供一些最佳实践,帮助你更好地应 ...

  3. Yii2.0实现微信公众号后台开发

    2019独角兽企业重金招聘Python工程师标准>>> 研读 微信公众平台开发者文档 ,然后再阅读本文,效果更佳! 接入微信 Yii2后台配置 1.在app/config/param ...

  4. php创建菜单_php实现微信公众号创建自定义菜单功能的实例代码

    目的 创建自定义菜单,实现菜单事件. 首先获取Access_Token 接口: 我用的是测试号,修改APPID和APPSECRET,然后浏览器访问上面这个Url即可生成Access_Token 然后配 ...

  5. 微信公众号 接口配置信息 URL 配置失败(能进入后台方法,无返回信息)

    微信公众号 接口配置信息 URL 配置失败(能进入后台方法,无返回信息) 操作步骤:1.微信公众号输入url.token点提交,提示配置失败. 后台代码: @ResponseBody@RequestM ...

  6. python 公众号菜单_Python微信公众号后台开发003:自定义菜单

    有同学问道微信公众号后台开发的自定义菜单怎么实现? 这个问题本来想放到后面的,因为的确对公众号的影响挺明显的, 因为开启后台服务,公众号的自定义菜单就不见了,很影响使用, 也有同学问这个问题,就提前了 ...

  7. Python微信公众号后台开发003:自定义菜单

    有同学问道微信公众号后台开发的自定义菜单怎么实现? 这个问题本来想放到后面的,因为的确对公众号的影响挺明显的, 因为开启后台服务,公众号的自定义菜单就不见了,很影响使用, 也有同学问这个问题,就提前了 ...

  8. html仿微信公众号底部菜单代码,模仿微信公众号底部导航菜单

    模仿微信公众号底部导航菜单 demo *{ margin:0; padding:0; box-sizing: border-box; } body{ background: #fff; font-si ...

  9. 云服务器有token_配置node服务器并且链接微信公众号接口配置

    配置node服务器并且链接微信公众号接口配置 配置node服务器 在购买好服务器后,用Xshell链接到服务器. 1.安装nvm curl -o- https://raw.githubusercont ...

最新文章

  1. java mvc view_对Springmvc view层的理解
  2. Git 看这一篇就够了
  3. 实验六 快速生成树配置
  4. RabbitMQ-c在Linux上编译
  5. 开源软件 许可证密钥_自由和开源软件-1中的重要许可证
  6. 批量文件替换_让你效率翻倍的15个Word批量操作小技巧
  7. Django - Xadmin (四) Filter
  8. Linux学习总结(6)——CenterOS7安装mysql5.5的方法
  9. Sentinel服务熔断配置exceptionsToIgnore_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0053
  10. python xlutils教程_python xlutils复制表格使用方法
  11. 地球轨道计算方法,开普勒三大定律的证明,补充-解析几何之椭圆
  12. 实验3:利用SVM实现线性高斯分类
  13. jxt - 强结构文档数据表示协议
  14. PEST分析顺丰服务需求_顺丰内外部环境分析.doc
  15. 免密钥登录脚本(转载)
  16. cpu与主板的区别、独立显卡与集成显卡
  17. [java]深入剖析Java性能监控调优视频教程
  18. 图解图库JanusGraph系列-一文知晓“图数据“底层存储结构(JanusGraph data model)
  19. 用手机计算机计算三次根号,手机自带计算器不行求推荐一个能开3次根号的 – 手机爱问...
  20. 接下来或许是一年中跳槽的最佳时间

热门文章

  1. linux ubuntu麒麟下安装playframework和Intellij2016
  2. Windows sever DNS 中创建主机A记录
  3. 那杯社会责任的咖啡千滋百味
  4. 分配算法:Kuhn-Munkres 算法
  5. Mysql 8.0修改密码
  6. 拯救者14OpenCore0.6.8黑苹果Big Sur 2021年4月12日
  7. Git:解决Your branch is ahead of ‘origin/master‘ by N commits问题
  8. 混合(Blending)
  9. 富文本解析 wxParse 解析数据造成页面假死
  10. 外部存储之SDcard