通过微信公众平台开发文档可以知道:
自定义菜单创建接口为:
http请求方式:POST(请使用https协议)https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
click和view的请求示例
{ "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" }] }] }
参数说明
参数 | 是否必须 | 说明 |
---|---|---|
button | 是 | 一级菜单数组,个数应为1~3个 |
sub_button | 否 | 二级菜单数组,个数应为1~5个 |
type | 是 | 菜单的响应动作类型 |
name | 是 | 菜单标题,不超过16个字节,子菜单不超过40个字节 |
key | click等点击类型必须 | 菜单KEY值,用于消息接口推送,不超过128字节 |
url | view类型必须 | 网页链接,用户点击菜单可打开链接,不超过256字节 |
media_id | media_id类型和view_limited类型必须 | 调用新增永久素材接口返回的合法media_id |
返回结果
正确时的返回JSON数据包如下:{"errcode":0,"errmsg":"ok"}
错误时的返回JSON数据包如下(示例为无效菜单名长度):{"errcode":40018,"errmsg":"invalid button name size"}
接下来进行对象的封装
微信返回的结果集:
/** * * @类名: WechatResultState * @描述: 微信返回值状态 * @作者: ljx * @时间: 2018年3月8日 上午10:27:25 */ public class WechatResultState { private int errcode; // 状态 private String errmsg; //信息 public int getErrcode() { return errcode; } public void setErrcode(int errcode) { this.errcode = errcode; } public String getErrmsg() { return errmsg; } public void setErrmsg(String errmsg) { this.errmsg = errmsg; } }
菜单的基类,所有一级菜单、二级菜单都共有一个相同的属性,那就是name
/** * * @类名: Botten * @描述: 菜单项的基类 * @作者: ljx * @时间: 2018年3月12日 上午10:02:54 */ public class Button { private String name;//所有一级,二级菜单的属性 public String getName() { return name; } public void setName(String name) { this.name = name; } }
一级菜单
/** * * @类名: FatherButton * @描述: 一级菜单栏 * @作者: ljx * @时间: 2018年3月12日 上午10:05:41 */ public class FatherButton extends Button{ private List<?> sub_button;//通过数组来包含子菜单栏 public List<?> getSub_button() { return sub_button; } public void setSub_button(List<?> sub_button) { this.sub_button = sub_button; } }
用来整合整个一级菜单和子菜单的实体
/** * * @类名: WeChatMenu * @描述: 微信菜单实体类 * @作者: ljx * @时间: 2018年3月12日 上午10:10:21 */ public class WeChatMenu { private List<?> button;//对整个菜单进行合并实体合并 public List<?> getButton() { return button; } public void setButton(List<?> button) { this.button = button; } }
创建数据表
表one_menu
menu_id | menu_name |
1 | 个人中心 |
2 | 设置 |
3 | 更多 |
id | menu_name | type | key | url | one_menu_Id |
01 | 个人详情 | click | 01 | 1 | |
02 | 个人设置 | click | 02 | 2 | |
03 | 模板 | click | 03 | 2 | |
04 | 搜索 | view | http://www.baidu.com | 3 |
创建表的实体类
/** * * @类名: OneMenu * @描述: 父菜单栏 * @作者: ljx * @时间: 2018年3月13日 上午9:15:58 */ public class OneMenu { private int menuId; private String menuname; public int getId() { return menuId; } public void setId(int menuId) { this.menuId = menuId; } public String getName() { return menuname; } public void setName(String menuname) { this.menuname = menuname; } }
/** * * @类名: TwoMenu * @描述: 子菜单栏 * @作者: ljx * @时间: 2018年3月13日 上午9:17:24 */ public class TwoMenu { private int id; private String name; private String type;//二级菜单属性 private String key;//二级菜单属性 private String url;//二级菜单属性 private int oneId; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } 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; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public int getOneId() { return oneId; } public void setOneId(int oneId) { this.oneId = oneId; } }
查出表的结果
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.leaflink.sitms.mapper.OneMenuMapper" > <select id="getAllOneMenu" resultType="com.leaflink.sitms.pojo.OneMenu"> SELECT menu_id,menu_name FROM `one_menu`; </select> </mapper>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.leaflink.sitms.mapper.TwoMenuMapper" > <resultMap type="java.util.TreeMap" id="twoMenu1"> <result property="name" column="menu_name"/> <result property="type" column="type"/> <result property="key" column="key"/> <result property="url" column="url"/> </resultMap> <select id="getTwoMenuByOneId" parameterType="int" resultMap="twoMenu1"> SELECT menu_name,type,`key`,url FROM `two_menu` WHERE one_menu_id=#{id}; </select> </mapper>
对数据进行包装
/** * * @类名: MenuServiceImpl * @描述: 微信菜单栏 * @作者: ljx * @时间: 2018年3月13日 上午10:58:41 */ @Service public class MenuServiceImpl implements MenuService { @Autowired OneMenuMapper oneMenuMapper; @Autowired TwoMenuMapper twoMenuMapper; /** * * @标题: getMenu * @描述: 获取菜单栏样式 * @return * @返回值: WeChatMenu */ public List<FatherButton> getMenu(){ //获取数据 List<OneMenu> list = getAllOneMenu(); List<FatherButton> menu = new ArrayList<FatherButton>(); for (OneMenu oneMenu : list) { //创建一级按钮 FatherButton fb = new FatherButton(); //存入一级按钮名称 fb.setName(oneMenu.getName()); //存入二级按钮样式 fb.setSub_button(getTwoMenuByOneId(oneMenu.getId())); menu.add(fb); } return menu; } /** * * @标题: getAllOneMenu * @描述: 获取所有父类菜单 * @return * @see com.leaflink.sitms.service.MenuService#getAllOneMenu() */ @Override public List<OneMenu> getAllOneMenu() { return oneMenuMapper.getAllOneMenu(); } /** * * @标题: getTwoMenuByOneId * @描述: 根据父类id获取子类菜单 * @param id * @return * @see com.leaflink.sitms.service.MenuService#getTwoMenuByOneId(java.lang.String) */ @Override public List<Map<String, String>> getTwoMenuByOneId(int id) { return twoMenuMapper.getTwoMenuByOneId(id); } }
输出样式
/** * * @类名: WeChatMenuController * @描述: TODO * @作者: ljx * @时间: 2018年3月13日 上午11:32:47 */ @Controller @RequestMapping("/wexinmenu") public class WeChatMenuController { @Autowired MenuService menuService; @RequestMapping("/getMenu") @ResponseBody public WeChatMenu getMenu(){ //整合整个菜单对象 WeChatMenu menu = new WeChatMenu(); menu.setButton(menuService.getMenu()); return menu; } }
{ "button": [ { "name": "个人中心", "sub_button": [ { "key": "01", "name": "个人详情", "type": "click" } ] }, { "name": "设置", "sub_button": [ { "key": "02", "name": "个人设置", "type": "click" }, { "key": "03", "name": "模板", "type": "click" } ] }, { "name": "更多", "sub_button": [ { "key": "04", "name": "搜索", "type": "view", "url":"http://www.baidu.com" } ] } ] }
以上是微信菜单栏样式数据接口,在portal层或其他地方调用获取数据并提交到微信中去
@Service public class WeChatMenuServiceImpl implements WeChatMenuService { @Autowired SessionByRest sessionByRest; public static String menuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN"; public static String removeMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN"; @Override public WechatResultState creatMenu(String token) { WechatResultState result = null; // 拼接token String url = menuUrl.replace("ACCESS_TOKEN", token); // 获取菜单样式并转换成json格式 String jsonMenu = JsonUtils.objectToJson(getMenu()); // 提交数据到微信端 try { String jsonObject = HttpClientUtil.doPostJson(url, jsonMenu); result = JsonUtils.jsonToPojo(jsonObject, WechatResultState.class); } catch (Exception e) { System.out.println("请求错误:" + e.getMessage()); } return result; } @Override public WechatResultState removeMenu(String token) { WechatResultState result = null; // 拼接token String url = removeMenuUrl.replace("ACCESS_TOKEN", token); // 移除菜单栏 try { String jsonObject = HttpClientUtil.doGet(url); result = JsonUtils.jsonToPojo(jsonObject, WechatResultState.class); } catch (Exception e) { System.out.println("请求错误:" + e.getMessage()); } return result; } @Value("${REST_URL}") String REST_URL; @Value("${REST_GETMENU}") String REST_GETMENU; /** * * @标题: getMenu * @描述: 获取微信菜单 * @return * @see com.leaflink.sitms.service.WeChatMenuService#getMenu() */ @Override public WeChatMenu getMenu() { //后台连接 String url = REST_URL + REST_GETMENU; //获取数据 String json = HttpClientUtil.doGet(url); WeChatMenu menu = JsonUtils.jsonToPojo(json, WeChatMenu.class); return menu; } }
下面贴一下httpCliectUtil工具类
import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.client.CookieStore; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; import org.apache.http.cookie.Cookie; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.springframework.web.multipart.MultipartFile; /** * * @类名: HttpClientUtil * @描述: HttpClient工具类 * @作者: ljx * @时间: 2017年12月18日 上午11:38:44 */ public class HttpClientUtil { private static CookieStore cookieStore= new BasicCookieStore(); public static String getCookie(String name){ List<Cookie> cookies = cookieStore.getCookies(); for(Cookie cookie : cookies){ if(cookie.getName().equalsIgnoreCase(name)){ return cookie.getValue(); } } return null; } public static String doGet(String url, Map<String, String> param) { // 创建Httpclient对象 CloseableHttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();; String resultString = ""; CloseableHttpResponse response = null; try { // 创建uri URIBuilder builder = new URIBuilder(url); if (param != null) { for (String key : param.keySet()) { builder.addParameter(key, param.get(key)); } } URI uri = builder.build(); // 创建http GET请求 HttpGet httpGet = new HttpGet(uri); // 执行请求 response = httpclient.execute(httpGet); // 判断返回状态是否为200 if (response.getStatusLine().getStatusCode() == 200) { resultString = EntityUtils.toString(response.getEntity(), "UTF-8"); } } catch (Exception e) { LoggerUtil.error(e); } finally { try { if (response != null) { response.close(); } httpclient.close(); } catch (IOException e) { LoggerUtil.error(e); } } return resultString; } public static String doGet(String url) { return doGet(url, null); } /** * * @标题: doPost * @描述: 接口用@RequestParam 单个,单个参数接收或者用javabean * @param url * @param param * @return * @返回值: String */ public static String doPost(String url, Map<String, String> param) { // 创建Httpclient对象 CloseableHttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();; CloseableHttpResponse response = null; String resultString = ""; try { // 创建Http Post请求 HttpPost httpPost = new HttpPost(url); // 创建参数列表 if (param != null) { List<NameValuePair> paramList = new ArrayList<NameValuePair>(); for (String key : param.keySet()) { paramList.add(new BasicNameValuePair(key, param.get(key))); } // 模拟表单 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"utf-8"); httpPost.setEntity(entity); } // 执行http请求 response = httpclient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "utf-8"); } catch (Exception e) { LoggerUtil.error(e); } finally { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block LoggerUtil.error(e); } } return resultString; } /** * * @标题: doPostbyFrom * @描述: 文件提交,接口用MultipartFile类,file为名接收 * @param url * @param file * @return * @返回值: String */ public static String doPostbyFrom(String url, MultipartFile file) { // 创建Httpclient对象 CloseableHttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();; CloseableHttpResponse response = null; String resultString = ""; try { String fileName = file.getOriginalFilename(); // 创建Http Post请求 HttpPost httpPost = new HttpPost(url); MultipartEntityBuilder meb = MultipartEntityBuilder.create(); meb.addBinaryBody("file", file.getInputStream(),ContentType.MULTIPART_FORM_DATA, fileName); meb.addTextBody("filename", fileName); HttpEntity httpentity = meb.build(); httpPost.setEntity(httpentity); // 执行http请求 response = httpclient.execute(httpPost); HttpEntity responseEntity = response.getEntity(); if (responseEntity != null) { resultString = EntityUtils.toString(response.getEntity(), "utf-8"); } } catch (Exception e) { LoggerUtil.error(e); } finally { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block LoggerUtil.error(e); } } return resultString; } /** * * @标题: doPostJson * @描述: 接口用@requestByod 的javabean或者Map接收 * @param url * @param json * @return * @返回值: String */ public static String doPostJson(String url, String json) { // 创建Httpclient对象 CloseableHttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();; CloseableHttpResponse response = null; String resultString = ""; try { // 创建Http Post请求 HttpPost httpPost = new HttpPost(url); // 创建请求内容 StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); httpPost.setEntity(entity); // 执行http请求 response = httpclient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "utf-8"); } catch (Exception e) { LoggerUtil.error(e); } finally { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block LoggerUtil.error(e); } } return resultString; } public static String doPost(String url) { return doPost(url, null); } public static String doPostJsonByCookie(String url, String json,List<String> cookies) { CloseableHttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();; CloseableHttpResponse response = null; String resultString = ""; try { // 创建Http Post请求 HttpPost httpPost = new HttpPost(url); // 创建请求内容 StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); httpPost.setEntity(entity); // 执行http请求 response = httpclient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "utf-8"); if (response!=null && !response.equals("")) { Header[] headers = response.getHeaders("Set-Cookie"); for (int i = 0; i < headers.length; i++) { cookies.add(headers[i].getValue()); } } } catch (Exception e) { LoggerUtil.error(e); } finally { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block LoggerUtil.error(e); } } return resultString; } }
以上是我个人对整个微信菜单自定义的实现,如果有什么错误的地方,欢迎指出。