通过微信公众平台开发文档可以知道:
自定义菜单创建接口为:
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;
}
}
以上是我个人对整个微信菜单自定义的实现,如果有什么错误的地方,欢迎指出。