@@ -1,5 +1,8 @@ | |||||
package me.chanjar.weixin.common.bean.menu; | package me.chanjar.weixin.common.bean.menu; | ||||
import me.chanjar.weixin.common.util.ToStringUtils; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.io.InputStreamReader; | import java.io.InputStreamReader; | ||||
import java.io.Serializable; | import java.io.Serializable; | ||||
@@ -7,11 +10,8 @@ import java.nio.charset.StandardCharsets; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import me.chanjar.weixin.common.bean.menu.WxMenuButton; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
/** | /** | ||||
* 企业号菜单 | |||||
* 菜单(公众号和企业号共用的) | |||||
* | * | ||||
* @author Daniel Qian | * @author Daniel Qian | ||||
*/ | */ | ||||
@@ -61,9 +61,7 @@ public class WxMenu implements Serializable { | |||||
@Override | @Override | ||||
public String toString() { | public String toString() { | ||||
return "WxMenu{" + | |||||
"buttons=" + this.buttons + | |||||
'}'; | |||||
return ToStringUtils.toSimpleString(this); | |||||
} | } | ||||
} | } |
@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.api; | |||||
import me.chanjar.weixin.common.bean.menu.WxMenu; | import me.chanjar.weixin.common.bean.menu.WxMenu; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult; | |||||
/** | /** | ||||
* 菜单相关操作接口 | * 菜单相关操作接口 | ||||
@@ -56,4 +57,20 @@ public interface WxMpMenuService { | |||||
*/ | */ | ||||
WxMenu menuTryMatch(String userid) throws WxErrorException; | WxMenu menuTryMatch(String userid) throws WxErrorException; | ||||
/** | |||||
* <pre> | |||||
* 获取自定义菜单配置接口 | |||||
* 本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过API调用设置的菜单,则返回菜单的开发配置,而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。 | |||||
请注意: | |||||
1、第三方平台开发者可以通过本接口,在旗下公众号将业务授权给你后,立即通过本接口检测公众号的自定义菜单配置,并通过接口再次给公众号设置好自动回复规则,以提升公众号运营者的业务体验。 | |||||
2、本接口与自定义菜单查询接口的不同之处在于,本接口无论公众号的接口是如何设置的,都能查询到接口,而自定义菜单查询接口则仅能查询到使用API设置的菜单配置。 | |||||
3、认证/未认证的服务号/订阅号,以及接口测试号,均拥有该接口权限。 | |||||
4、从第三方平台的公众号登录授权机制上来说,该接口从属于消息与菜单权限集。 | |||||
5、本接口中返回的图片/语音/视频为临时素材(临时素材每次获取都不同,3天内有效,通过素材管理-获取临时素材接口来获取这些素材),本接口返回的图文消息为永久素材素材(通过素材管理-获取永久素材接口来获取这些素材)。 | |||||
* 接口调用请求说明: | |||||
http请求方式: GET(请使用https协议) | |||||
https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN | |||||
*</pre> | |||||
*/ | |||||
WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException; | |||||
} | } |
@@ -1,12 +1,13 @@ | |||||
package me.chanjar.weixin.mp.api.impl; | package me.chanjar.weixin.mp.api.impl; | ||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import me.chanjar.weixin.common.bean.menu.WxMenu; | import me.chanjar.weixin.common.bean.menu.WxMenu; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import me.chanjar.weixin.mp.api.WxMpMenuService; | import me.chanjar.weixin.mp.api.WxMpMenuService; | ||||
import me.chanjar.weixin.mp.api.WxMpService; | import me.chanjar.weixin.mp.api.WxMpService; | ||||
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult; | |||||
import me.chanjar.weixin.mp.bean.menu.WxMpSelfMenuInfo; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
/** | /** | ||||
* Created by Binary Wang on 2016/7/21. | * Created by Binary Wang on 2016/7/21. | ||||
@@ -14,7 +15,7 @@ import me.chanjar.weixin.mp.api.WxMpService; | |||||
public class WxMpMenuServiceImpl implements WxMpMenuService { | public class WxMpMenuServiceImpl implements WxMpMenuService { | ||||
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/menu"; | private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/menu"; | ||||
private static Logger log = LoggerFactory | private static Logger log = LoggerFactory | ||||
.getLogger(WxMpMenuServiceImpl.class); | |||||
.getLogger(WxMpMenuServiceImpl.class); | |||||
private WxMpService wxMpService; | private WxMpService wxMpService; | ||||
@@ -74,10 +75,17 @@ public class WxMpMenuServiceImpl implements WxMpMenuService { | |||||
} catch (WxErrorException e) { | } catch (WxErrorException e) { | ||||
// 46003 不存在的菜单数据 46002 不存在的菜单版本 | // 46003 不存在的菜单数据 46002 不存在的菜单版本 | ||||
if (e.getError().getErrorCode() == 46003 | if (e.getError().getErrorCode() == 46003 | ||||
|| e.getError().getErrorCode() == 46002) { | |||||
|| e.getError().getErrorCode() == 46002) { | |||||
return null; | return null; | ||||
} | } | ||||
throw e; | throw e; | ||||
} | } | ||||
} | } | ||||
@Override | |||||
public WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException { | |||||
String url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info"; | |||||
String resultContent = this.wxMpService.get(url, null); | |||||
return WxMpGetSelfMenuInfoResult.fromJson(resultContent); | |||||
} | |||||
} | } |
@@ -0,0 +1,44 @@ | |||||
package me.chanjar.weixin.mp.bean.menu; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import me.chanjar.weixin.common.util.ToStringUtils; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
/** | |||||
* <pre> | |||||
* Created by Binary Wang on 2016-11-25. | |||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||||
* </pre> | |||||
*/ | |||||
public class WxMpGetSelfMenuInfoResult { | |||||
@SerializedName("selfmenu_info") | |||||
private WxMpSelfMenuInfo selfMenuInfo; | |||||
@SerializedName("is_menu_open") | |||||
private Integer isMenuOpen; | |||||
public static WxMpGetSelfMenuInfoResult fromJson(String json) { | |||||
return WxGsonBuilder.create().fromJson(json, WxMpGetSelfMenuInfoResult.class); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return ToStringUtils.toSimpleString(this); | |||||
} | |||||
public WxMpSelfMenuInfo getSelfMenuInfo() { | |||||
return selfMenuInfo; | |||||
} | |||||
public void setSelfMenuInfo(WxMpSelfMenuInfo selfMenuInfo) { | |||||
this.selfMenuInfo = selfMenuInfo; | |||||
} | |||||
public Integer getIsMenuOpen() { | |||||
return isMenuOpen; | |||||
} | |||||
public void setIsMenuOpen(Integer isMenuOpen) { | |||||
this.isMenuOpen = isMenuOpen; | |||||
} | |||||
} |
@@ -0,0 +1,288 @@ | |||||
package me.chanjar.weixin.mp.bean.menu; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import me.chanjar.weixin.common.util.ToStringUtils; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | |||||
* <pre> | |||||
* Created by Binary Wang on 2016-11-25. | |||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||||
* </pre> | |||||
*/ | |||||
public class WxMpSelfMenuInfo { | |||||
/** | |||||
* 菜单按钮 | |||||
*/ | |||||
@SerializedName("button") | |||||
private List<WxMpSelfMenuButton> buttons; | |||||
@Override | |||||
public String toString() { | |||||
return ToStringUtils.toSimpleString(this); | |||||
} | |||||
public static class WxMpSelfMenuButton { | |||||
@Override | |||||
public String toString() { | |||||
return ToStringUtils.toSimpleString(this); | |||||
} | |||||
/** | |||||
* <pre> | |||||
* 菜单的类型,公众平台官网上能够设置的菜单类型有view(跳转网页)、text(返回文本,下同)、img、photo、video、voice。 | |||||
* 使用API设置的则有8种,详见<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN">《自定义菜单创建接口》</a> | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("type") | |||||
private String type; | |||||
/** | |||||
* 菜单名称 | |||||
*/ | |||||
@SerializedName("name") | |||||
private String name; | |||||
/** | |||||
* <pre> | |||||
* 对于不同的菜单类型,value的值意义不同。 | |||||
* 官网上设置的自定义菜单: | |||||
* <li>Text:保存文字到value; | |||||
* <li>Img、voice:保存mediaID到value; | |||||
* <li>Video:保存视频下载链接到value; | |||||
* <li>News:保存图文消息到news_info,同时保存mediaID到value; | |||||
* <li>View:保存链接到url。</li> | |||||
* | |||||
* 使用API设置的自定义菜单: | |||||
* <li>click、scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album、 pic_weixin、location_select:保存值到key; | |||||
* <li>view:保存链接到url | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("key") | |||||
private String key; | |||||
/** | |||||
* @see #key | |||||
*/ | |||||
@SerializedName("url") | |||||
private String url; | |||||
/** | |||||
* @see #key | |||||
*/ | |||||
@SerializedName("value") | |||||
private String value; | |||||
/** | |||||
* 子菜单信息 | |||||
*/ | |||||
@SerializedName("sub_button") | |||||
private SubButtons subButtons; | |||||
public SubButtons getSubButtons() { | |||||
return subButtons; | |||||
} | |||||
public void setSubButtons(SubButtons subButtons) { | |||||
this.subButtons = subButtons; | |||||
} | |||||
public static class SubButtons { | |||||
@Override | |||||
public String toString() { | |||||
return ToStringUtils.toSimpleString(this); | |||||
} | |||||
@SerializedName("list") | |||||
private List<WxMpSelfMenuButton> subButtons = new ArrayList<>(); | |||||
public List<WxMpSelfMenuButton> getSubButtons() { | |||||
return subButtons; | |||||
} | |||||
public void setSubButtons(List<WxMpSelfMenuButton> subButtons) { | |||||
this.subButtons = subButtons; | |||||
} | |||||
} | |||||
/** | |||||
* 图文消息的信息 | |||||
*/ | |||||
@SerializedName("news_info") | |||||
private NewsInfo newsInfo; | |||||
public String getType() { | |||||
return type; | |||||
} | |||||
public void setType(String type) { | |||||
this.type = type; | |||||
} | |||||
public String getName() { | |||||
return name; | |||||
} | |||||
public void setName(String name) { | |||||
this.name = name; | |||||
} | |||||
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 String getValue() { | |||||
return value; | |||||
} | |||||
public void setValue(String value) { | |||||
this.value = value; | |||||
} | |||||
public NewsInfo getNewsInfo() { | |||||
return newsInfo; | |||||
} | |||||
public void setNewsInfo(NewsInfo newsInfo) { | |||||
this.newsInfo = newsInfo; | |||||
} | |||||
public static class NewsInfo { | |||||
@Override | |||||
public String toString() { | |||||
return ToStringUtils.toSimpleString(this); | |||||
} | |||||
@SerializedName("list") | |||||
private List<NewsInButton> news = new ArrayList<>(); | |||||
public List<NewsInButton> getNews() { | |||||
return news; | |||||
} | |||||
public void setNews(List<NewsInButton> news) { | |||||
this.news = news; | |||||
} | |||||
public static class NewsInButton { | |||||
@Override | |||||
public String toString() { | |||||
return ToStringUtils.toSimpleString(this); | |||||
} | |||||
/** | |||||
* 图文消息的标题 | |||||
*/ | |||||
@SerializedName("title") | |||||
private String title; | |||||
/** | |||||
* 摘要 | |||||
*/ | |||||
@SerializedName("digest") | |||||
private String digest; | |||||
/** | |||||
* 作者 | |||||
*/ | |||||
@SerializedName("author") | |||||
private String author; | |||||
/** | |||||
* show_cover | |||||
* 是否显示封面,0为不显示,1为显示 | |||||
*/ | |||||
@SerializedName("show_cover") | |||||
private Integer showCover; | |||||
/** | |||||
* 封面图片的URL | |||||
*/ | |||||
@SerializedName("cover_url") | |||||
private String coverUrl; | |||||
/** | |||||
* 正文的URL | |||||
*/ | |||||
@SerializedName("content_url") | |||||
private String contentUrl; | |||||
/** | |||||
* 原文的URL,若置空则无查看原文入口 | |||||
*/ | |||||
@SerializedName("source_url") | |||||
private String sourceUrl; | |||||
public String getTitle() { | |||||
return title; | |||||
} | |||||
public void setTitle(String title) { | |||||
this.title = title; | |||||
} | |||||
public String getDigest() { | |||||
return digest; | |||||
} | |||||
public void setDigest(String digest) { | |||||
this.digest = digest; | |||||
} | |||||
public String getAuthor() { | |||||
return author; | |||||
} | |||||
public void setAuthor(String author) { | |||||
this.author = author; | |||||
} | |||||
public Integer getShowCover() { | |||||
return showCover; | |||||
} | |||||
public void setShowCover(Integer showCover) { | |||||
this.showCover = showCover; | |||||
} | |||||
public String getCoverUrl() { | |||||
return coverUrl; | |||||
} | |||||
public void setCoverUrl(String coverUrl) { | |||||
this.coverUrl = coverUrl; | |||||
} | |||||
public String getContentUrl() { | |||||
return contentUrl; | |||||
} | |||||
public void setContentUrl(String contentUrl) { | |||||
this.contentUrl = contentUrl; | |||||
} | |||||
public String getSourceUrl() { | |||||
return sourceUrl; | |||||
} | |||||
public void setSourceUrl(String sourceUrl) { | |||||
this.sourceUrl = sourceUrl; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,18 +1,17 @@ | |||||
package me.chanjar.weixin.mp.api.impl; | package me.chanjar.weixin.mp.api.impl; | ||||
import me.chanjar.weixin.mp.api.WxMpService; | |||||
import org.testng.Assert; | |||||
import org.testng.annotations.DataProvider; | |||||
import org.testng.annotations.Guice; | |||||
import org.testng.annotations.Test; | |||||
import com.google.inject.Inject; | import com.google.inject.Inject; | ||||
import me.chanjar.weixin.common.api.WxConsts; | import me.chanjar.weixin.common.api.WxConsts; | ||||
import me.chanjar.weixin.common.bean.menu.WxMenu; | import me.chanjar.weixin.common.bean.menu.WxMenu; | ||||
import me.chanjar.weixin.common.bean.menu.WxMenuButton; | import me.chanjar.weixin.common.bean.menu.WxMenuButton; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import me.chanjar.weixin.mp.api.ApiTestModule; | import me.chanjar.weixin.mp.api.ApiTestModule; | ||||
import me.chanjar.weixin.mp.api.WxMpService; | |||||
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult; | |||||
import org.testng.Assert; | |||||
import org.testng.annotations.DataProvider; | |||||
import org.testng.annotations.Guice; | |||||
import org.testng.annotations.Test; | |||||
/** | /** | ||||
* 测试菜单 | * 测试菜单 | ||||
@@ -28,11 +27,22 @@ public class WxMpMenuServiceImplTest { | |||||
protected WxMpService wxService; | protected WxMpService wxService; | ||||
@Test(dataProvider = "menu") | @Test(dataProvider = "menu") | ||||
public void testCreateMenu(WxMenu wxMenu) throws WxErrorException { | |||||
public void testMenuCreate(WxMenu wxMenu) throws WxErrorException { | |||||
System.out.println(wxMenu.toJson()); | System.out.println(wxMenu.toJson()); | ||||
this.wxService.getMenuService().menuCreate(wxMenu); | this.wxService.getMenuService().menuCreate(wxMenu); | ||||
} | } | ||||
@Test | |||||
public void testMenuTryMatch() throws Exception { | |||||
//TODO | |||||
} | |||||
@Test | |||||
public void testGetSelfMenuInfo() throws Exception { | |||||
WxMpGetSelfMenuInfoResult selfMenuInfo = this.wxService.getMenuService().getSelfMenuInfo(); | |||||
System.out.println(selfMenuInfo); | |||||
} | |||||
@Test | @Test | ||||
public void testCreateMenu2() throws WxErrorException { | public void testCreateMenu2() throws WxErrorException { | ||||
String a = "{\n" | String a = "{\n" | ||||
@@ -77,15 +87,15 @@ public class WxMpMenuServiceImplTest { | |||||
this.wxService.getMenuService().menuCreate(menu); | this.wxService.getMenuService().menuCreate(menu); | ||||
} | } | ||||
@Test(dependsOnMethods = { "testCreateMenu"}) | |||||
public void testGetMenu() throws WxErrorException { | |||||
@Test(dependsOnMethods = { "testMenuCreate"}) | |||||
public void testMenuGet() throws WxErrorException { | |||||
WxMenu wxMenu = this.wxService.getMenuService().menuGet(); | WxMenu wxMenu = this.wxService.getMenuService().menuGet(); | ||||
Assert.assertNotNull(wxMenu); | Assert.assertNotNull(wxMenu); | ||||
System.out.println(wxMenu.toJson()); | System.out.println(wxMenu.toJson()); | ||||
} | } | ||||
@Test(dependsOnMethods = { "testGetMenu"}) | |||||
public void testDeleteMenu() throws WxErrorException { | |||||
@Test(dependsOnMethods = { "testMenuGet"}) | |||||
public void testMenuDelete() throws WxErrorException { | |||||
this.wxService.getMenuService().menuDelete(); | this.wxService.getMenuService().menuDelete(); | ||||
} | } | ||||