diff --git a/CHANGE.md b/CHANGE.md index 7c08f55a..0bc21e83 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -547,3 +547,7 @@ * 2015-12-15 + weixin4j-[mp|qy]:version upgrade to 1.6.5 + +* 2015-12-18 + + + weixin4j-mp:新增个性化菜单接口 diff --git a/README.md b/README.md index d7651ddf..740306cb 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ weixin4j ------------- > `weixin4j`是一个用java编写针对微信开发的工具包,包含[weixin4j-mp](./weixin4j-mp)(微信公众平台API)、[weixin4j-qy](./weixin4j-qy)(微信企业号API)以及[weixin4j-server](./weixin4j-server)(微信回调消息服务器)三个工程. -功能列表 +模块说明 ------- * **weixin4j-base** diff --git a/weixin4j-mp/CHANGE.md b/weixin4j-mp/CHANGE.md index c2081eb8..97e43f5a 100644 --- a/weixin4j-mp/CHANGE.md +++ b/weixin4j-mp/CHANGE.md @@ -179,3 +179,7 @@ * 2015-12-15 + version upgrade to 1.6.5 + +* 2015-12-18 + + + 新增个性化菜单接口 diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java index c0646c6e..dd2d0a90 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java @@ -35,6 +35,7 @@ import com.foxinmy.weixin4j.mp.model.Following; import com.foxinmy.weixin4j.mp.model.Group; import com.foxinmy.weixin4j.mp.model.KfAccount; import com.foxinmy.weixin4j.mp.model.KfSession; +import com.foxinmy.weixin4j.mp.model.Menu; import com.foxinmy.weixin4j.mp.model.MenuSetting; import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.QRResult; @@ -1084,7 +1085,7 @@ public class WeixinProxy { /** * 自定义菜单 * - * @param btnList + * @param buttons * 菜单列表 * @throws WeixinException * @see btnList) throws WeixinException { - return menuApi.createMenu(btnList); + public JsonResult createMenu(List buttons) throws WeixinException { + return menuApi.createMenu(buttons); } /** @@ -1111,19 +1112,64 @@ public class WeixinProxy { return menuApi.getMenu(); } + /** + * 查询全部菜单(包含个性化菜单) + * + * @return 菜单集合 + * @throws WeixinException + * @see 查询菜单 + * @see 个性化菜单 + * @see com.foxinmy.weixin4j.model.Button + * @see com.foxinmy.weixin4j.mp.model.Menu + * @see com.foxinmy.weixin4j.mp.api.MenuApi + */ + public List getAllMenu() throws WeixinException { + return menuApi.getAllMenu(); + } + /** * 删除菜单 * * @throws WeixinException * @see 删除菜单 - * @see com.foxinmy.weixin4j.model.Button * @see com.foxinmy.weixin4j.mp.api.MenuApi */ public JsonResult deleteMenu() throws WeixinException { return menuApi.deleteMenu(); } + /** + * 删除个性化菜单 + * + * @throws WeixinException + * @see 删除个性化菜单 + * @see com.foxinmy.weixin4j.mp.api.MenuApi + * @return 处理结果 + */ + public JsonResult deleteCustomMenu(String menuId) throws WeixinException { + return menuApi.deleteCustomMenu(menuId); + } + + /** + * 测试个性化菜单匹配结果 + * + * @param userId + * 可以是粉丝的OpenID,也可以是粉丝的微信号。 + * @return 匹配到的菜单配置 + * @see 测试个性化菜单 + * @see com.foxinmy.weixin4j.model.Button + * @see com.foxinmy.weixin4j.mp.api.MenuApi + * @throws WeixinException + */ + public List matchCustomMenu(String userId) throws WeixinException { + return menuApi.matchCustomMenu(userId); + } + /** * 生成带参数的二维码 * diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MenuApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MenuApi.java index b956f89d..20d3a8b2 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MenuApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MenuApi.java @@ -15,6 +15,8 @@ import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Button; import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.mp.model.Menu; +import com.foxinmy.weixin4j.mp.model.MenuMatchRule; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.type.ButtonType; @@ -26,6 +28,7 @@ import com.foxinmy.weixin4j.type.ButtonType; * @date 2014年9月25日 * @since JDK 1.6 * @see com.foxinmy.weixin4j.model.Button + * @see http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html */ public class MenuApi extends MpApi { @@ -38,21 +41,25 @@ public class MenuApi extends MpApi { /** * 自定义菜单 * - * @param btnList + * @param buttons * 菜单列表 * @throws WeixinException * @see 创建自定义菜单 * @see com.foxinmy.weixin4j.model.Button */ - public JsonResult createMenu(List btnList) throws WeixinException { + public JsonResult createMenu(List buttons) throws WeixinException { String menu_create_uri = getRequestUri("menu_create_uri"); - Token token = tokenHolder.getToken(); JSONObject obj = new JSONObject(); - obj.put("button", btnList); + obj.put("button", buttons); + return createMenu0(menu_create_uri, obj); + } + + private JsonResult createMenu0(String url, JSONObject data) + throws WeixinException { WeixinResponse response = weixinExecutor.post( - String.format(menu_create_uri, token.getAccessToken()), - JSON.toJSONString(obj, new NameFilter() { + String.format(url, tokenHolder.getAccessToken()), + JSON.toJSONString(data, new NameFilter() { @Override public String process(Object object, String name, Object value) { @@ -86,25 +93,47 @@ public class MenuApi extends MpApi { * @see com.foxinmy.weixin4j.model.Button */ public List getMenu() throws WeixinException { + return buttonsConvertor(getMenu0().getJSONObject("menu")); + } + + private JSONObject getMenu0() throws WeixinException { String menu_get_uri = getRequestUri("menu_get_uri"); Token token = tokenHolder.getToken(); WeixinResponse response = weixinExecutor.get(String.format( menu_get_uri, token.getAccessToken())); + return response.getAsJson(); + } - JSONArray buttons = response.getAsJson().getJSONObject("menu") - .getJSONArray("button"); - List buttonList = new ArrayList(buttons.size()); - ParseProcess processor = new ExtraProcessor() { - @Override - public void processExtra(Object object, String key, Object value) { - JSONPath.set(object, "$.content", value); + /** + * 查询全部菜单(包含个性化菜单) + * + * @return 菜单集合 + * @throws WeixinException + * @see 查询菜单 + * @see 个性化菜单 + * @see com.foxinmy.weixin4j.model.Button + * @see com.foxinmy.weixin4j.mp.model.Menu + */ + public List getAllMenu() throws WeixinException { + JSONObject response = getMenu0(); + List menus = new ArrayList(); + // 普通菜单 + JSONObject menuObj = response.getJSONObject("menu"); + menus.add(new Menu(menuObj.getString("menuid"), + buttonsConvertor(menuObj), null)); + // 个性化菜单 + JSONArray menuObjs = response.getJSONArray("conditionalmenu"); + if (menuObjs != null && !menuObjs.isEmpty()) { + for (int i = 0; i < menuObjs.size(); i++) { + menuObj = menuObjs.getJSONObject(i); + menus.add(new Menu(menuObj.getString("menuid"), + buttonsConvertor(menuObj), + menuObj.getObject("matchrule", MenuMatchRule.class))); } - }; - for (int i = 0; i < buttons.size(); i++) { - buttonList.add(JSON.parseObject(buttons.getString(i), Button.class, - processor)); } - return buttonList; + return menus; } /** @@ -123,4 +152,85 @@ public class MenuApi extends MpApi { return response.getAsJsonResult(); } + + /** + * 创建个性化菜单 + * + * @param buttons + * 菜单列表 + * @param matchRule + * 匹配规则 至少要有一个匹配信息是不为空 + * @throws WeixinException + * @see 创建个性化菜单 + * @see com.foxinmy.weixin4j.model.Button + */ + public JsonResult createCustomMenu(List buttons, + MenuMatchRule matchRule) throws WeixinException { + String menu_create_uri = getRequestUri("menu_custom_create_uri"); + JSONObject obj = new JSONObject(); + obj.put("button", buttons); + obj.put("matchrule", matchRule.getRule()); + return createMenu0(menu_create_uri, obj); + } + + /** + * 删除个性化菜单 + * + * @throws WeixinException + * @see 删除个性化菜单 + * @return 处理结果 + */ + public JsonResult deleteCustomMenu(String menuId) throws WeixinException { + String menu_delete_uri = getRequestUri("menu_delete_custom_uri"); + Token token = tokenHolder.getToken(); + JSONObject obj = new JSONObject(); + obj.put("menuid", menuId); + WeixinResponse response = weixinExecutor.post( + String.format(menu_delete_uri, token.getAccessToken()), + obj.toJSONString()); + + return response.getAsJsonResult(); + } + + /** + * 测试个性化菜单匹配结果 + * + * @param userId + * 可以是粉丝的OpenID,也可以是粉丝的微信号。 + * @return 匹配到的菜单配置 + * @see 测试个性化菜单 + * @see com.foxinmy.weixin4j.model.Button + * @throws WeixinException + */ + public List matchCustomMenu(String userId) throws WeixinException { + String menu_trymatch_uri = getRequestUri("menu_trymatch_uri"); + Token token = tokenHolder.getToken(); + JSONObject obj = new JSONObject(); + obj.put("user_id", userId); + WeixinResponse response = weixinExecutor.post( + String.format(menu_trymatch_uri, token.getAccessToken()), + obj.toJSONString()); + + return buttonsConvertor(response.getAsJson().getJSONObject("menu")); + } + + private final ParseProcess buttonProcess = new ExtraProcessor() { + @Override + public void processExtra(Object object, String key, Object value) { + JSONPath.set(object, "$.content", value); + } + }; + + private List buttonsConvertor(JSONObject menu) { + JSONArray buttons = menu.getJSONArray("button"); + List buttonList = new ArrayList(buttons.size()); + for (int i = 0; i < buttons.size(); i++) { + buttonList.add(JSON.parseObject(buttons.getString(i), Button.class, + buttonProcess)); + } + return buttonList; + } } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties index 123d1086..841afdc6 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties @@ -56,12 +56,18 @@ group_delete_uri={api_cgi_url}/groups/delete?access_token=%s following_uri={api_cgi_url}/user/get?access_token=%s&next_openid=%s # \u81ea\u5b9a\u4e49\u83dc\u5355 menu_create_uri={api_cgi_url}/menu/create?access_token=%s +# \u521b\u5efa\u4e2a\u6027\u5316\u83dc\u5355 +menu_custom_create_uri={api_cgi_url}/menu/addconditional?access_token=%s # \u67e5\u8be2\u83dc\u5355 menu_get_uri={api_cgi_url}/menu/get?access_token=%s # \u67e5\u8be2\u901a\u8fc7\u63a5\u53e3\u6216\u8005\u5728\u516c\u4f17\u5e73\u53f0\u4e0a\u8bbe\u7f6e\u7684\u83dc\u5355\u914d\u7f6e\u4fe1\u606f menu_get_selfmenu_uri={api_cgi_url}/get_current_selfmenu_info?access_token=%s # \u5220\u9664\u83dc\u5355 menu_delete_uri={api_cgi_url}/menu/delete?access_token=%s +# \u5220\u9664\u4e2a\u6027\u5316\u83dc\u5355 +menu_delete_custom_uri={api_cgi_url}/menu/delconditional?access_token=%s +# \u6d4b\u8bd5\u4e2a\u6027\u5316\u83dc\u5355\u5339\u914d\u7ed3\u679c +menu_trymatch_uri={api_cgi_url}/menu/trymatch?access_token=%s # \u4e0a\u4f20\u56fe\u6587 article_upload_uri={api_cgi_url}/media/uploadnews?access_token=%s # \u4e0a\u4f20\u89c6\u9891 diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/Menu.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/Menu.java new file mode 100644 index 00000000..a832b9ef --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/Menu.java @@ -0,0 +1,48 @@ +package com.foxinmy.weixin4j.mp.model; + +import java.io.Serializable; +import java.util.List; + +import com.foxinmy.weixin4j.model.Button; + +/** + * 底部菜单 + * + * @className Menu + * @author jy + * @date 2015年12月18日 + * @since JDK 1.7 + * @see + */ +public class Menu implements Serializable { + + private static final long serialVersionUID = -915139819768888593L; + + private String menuId; + private List buttons; + private MenuMatchRule matchRule; + + public Menu(String menuId, List buttons, MenuMatchRule matchRule) { + this.menuId = menuId; + this.buttons = buttons; + this.matchRule = matchRule; + } + + public String getMenuId() { + return menuId; + } + + public List getButtons() { + return buttons; + } + + public MenuMatchRule getMatchRule() { + return matchRule; + } + + @Override + public String toString() { + return "Menu [menuId=" + menuId + ", buttons=" + buttons + + ", matchRule=" + matchRule + "]"; + } +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MenuMatchRule.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MenuMatchRule.java new file mode 100644 index 00000000..28b1b8e5 --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MenuMatchRule.java @@ -0,0 +1,174 @@ +package com.foxinmy.weixin4j.mp.model; + +import java.io.Serializable; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.model.Gender; +import com.foxinmy.weixin4j.mp.type.ClientPlatformType; + +/** + * 个性化菜单匹配规则 + * + * @className MenuMatchRule + * @author jy + * @date 2015年12月17日 + * @since JDK 1.6 + * @see + */ +public class MenuMatchRule implements Serializable { + + private static final long serialVersionUID = 8115117407710728580L; + + private JSONObject matchRule; + + public MenuMatchRule() { + this.matchRule = new JSONObject(); + } + + /** + * 用户分组id,可通过用户分组管理接口获取 + */ + private Integer groupId; + + @JSONField(name = "group_id") + public MenuMatchRule group(int groupId) { + matchRule.put("group_id", groupId); + this.groupId = groupId; + return this; + } + + /** + * 性别 + */ + private Gender gender; + + @JSONField(name = "sex") + public void gender0(int sex) { + this.gender = Gender.values().length >= sex ? Gender.values()[sex - 1] + : null; + } + + public MenuMatchRule gender(Gender gender) { + if (gender != null && gender != Gender.unknown) { + matchRule.put("sex", gender.ordinal() + 1); + } + this.gender = gender; + return this; + } + + /** + * 客户端版本 + */ + private ClientPlatformType platformType; + + @JSONField(name = "client_platform_type") + public void platform0(int platform) { + this.platformType = ClientPlatformType.values().length >= platform ? ClientPlatformType + .values()[platform - 1] : null; + } + + public MenuMatchRule platform(ClientPlatformType platformType) { + if (platformType != null) { + matchRule.put("client_platform_type", platformType.ordinal() + 1); + } + this.platformType = platformType; + return this; + } + + private String country; + + /** + * 国家信息,是用户在微信中设置的地区 + * + * country、province、city组成地区信息,将按照country、province、city的顺序进行验证 + * ,要符合地区信息表的内容。地区信息从大到小验证,小的可以不填,即若填写了省份信息,则国家信息也必填并且匹配,城市信息可以不填。 例如 “中国 + * 广东省 广州市”、“中国 广东省”都是合法的地域信息,而“中国 广州市”则不合法,因为填写了城市信息但没有填写省份信息 + * + * @param country + * @return + */ + @JSONField(name = "country") + public MenuMatchRule country(String country) { + matchRule.put("country", country); + this.country = country; + return this; + } + + private String province; + + /** + * 省份信息,是用户在微信中设置的地区 + * + * country、province、city组成地区信息,将按照country、province、city的顺序进行验证,要符合地区信息表的内容。 + * 地区信息从大到小验证,小的可以不填,即若填写了省份信息,则国家信息也必填并且匹配,城市信息可以不填。 例如 “中国 广东省 广州市”、“中国 + * 广东省”都是合法的地域信息,而“中国 广州市”则不合法,因为填写了城市信息但没有填写省份信息 + * + * @param country + * @return + */ + @JSONField(name = "province") + public MenuMatchRule province(String province) { + matchRule.put("province", province); + this.province = province; + return this; + } + + private String city; + + /** + * 城市信息,是用户在微信中设置的地区 + * + * country、province、city组成地区信息,将按照country、province、city的顺序进行验证,要符合地区信息表的内容。 + * 地区信息从大到小验证,小的可以不填,即若填写了省份信息,则国家信息也必填并且匹配,城市信息可以不填。 例如 “中国 广东省 广州市”、“中国 + * 广东省”都是合法的地域信息,而“中国 广州市”则不合法,因为填写了城市信息但没有填写省份信息 + * + * @param city + * @return + */ + @JSONField(name = "city") + public MenuMatchRule city(String city) { + matchRule.put("city", city); + this.city = city; + return this; + } + + public ClientPlatformType getPlatformType() { + return platformType; + } + + public Integer getGroupId() { + return groupId; + } + + public Gender getGender() { + return gender; + } + + public String getCountry() { + return country; + } + + public String getProvince() { + return province; + } + + public String getCity() { + return city; + } + + public boolean hasRule() { + return !matchRule.isEmpty(); + } + + public JSONObject getRule() { + return this.matchRule; + } + + @Override + public String toString() { + return "MenuMatchRule [groupId=" + groupId + ", gender=" + gender + + ", platformType=" + platformType + ", country=" + country + + ", province=" + province + ", city=" + city + "]"; + } +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/ClientPlatformType.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/ClientPlatformType.java new file mode 100644 index 00000000..3f65c891 --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/ClientPlatformType.java @@ -0,0 +1,14 @@ +package com.foxinmy.weixin4j.mp.type; + +/** + * 平台类型 + * + * @className ClientPlatformType + * @author jy + * @date 2015年12月17日 + * @since JDK 1.7 + * @see + */ +public enum ClientPlatformType { + IOS, Android, Others +} diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java index 871c8cb6..d3325bbf 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java @@ -55,7 +55,7 @@ public class MediaTest extends TokenTest { @Test public void download1() throws WeixinException, IOException { MediaDownloadResult content = mediaApi.downloadMedia( - "nD05mhmkW-SHVS8NfWSxdzJi-6VnVF5YSP5hmMWnKJUxLK5czAWtN4NhVmgEfVoe", false); + "BmzcrM2jaJXZCjBqxLwyC03kh5pge3CbrBqXP4XbYBCeKr7xz-rHuwPf4vYLVdL1", false); Assert.assertTrue(content != null); System.err.println(content); } diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java index bdc06a18..792ce9d6 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java @@ -11,6 +11,9 @@ import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.model.Button; import com.foxinmy.weixin4j.mp.api.MenuApi; +import com.foxinmy.weixin4j.mp.model.Menu; +import com.foxinmy.weixin4j.mp.model.MenuMatchRule; +import com.foxinmy.weixin4j.mp.type.ClientPlatformType; import com.foxinmy.weixin4j.type.ButtonType; /** @@ -24,7 +27,7 @@ import com.foxinmy.weixin4j.type.ButtonType; public class MenuTest extends TokenTest { private MenuApi menuApi; - private List btnList; + private List buttons; @Before public void init() { @@ -33,44 +36,47 @@ public class MenuTest extends TokenTest { @Test public void create() throws WeixinException { - btnList = new ArrayList(); + buttons = new ArrayList(); String domain = "http://wx.jdxg.doubimeizhi.com"; - btnList.add(new Button("立即下单", domain, ButtonType.view)); + buttons.add(new Button("立即下单", domain, ButtonType.view)); - btnList.add(new Button("个人中心", domain + "/user", ButtonType.view)); + buttons.add(new Button("个人中心", domain + "/user", ButtonType.view)); Button button = new Button("小哥介绍", domain, ButtonType.view); - button.pushSub(new Button("小哥介绍", "http://mp.weixin.qq.com/s?__biz=MzI2MTA5OTM4OQ==&mid=400990970&idx=1&sn=5c7fd72e782c49f7c933b91c63eddc80#rd", ButtonType.view)); + button.pushSub(new Button( + "小哥介绍", + "http://mp.weixin.qq.com/s?__biz=MzI2MTA5OTM4OQ==&mid=400990970&idx=1&sn=5c7fd72e782c49f7c933b91c63eddc80#rd", + ButtonType.view)); button.pushSub(new Button("服务流程", "FLOW", ButtonType.click)); button.pushSub(new Button("在线客服", "KF", ButtonType.click)); - btnList.add(button); + buttons.add(button); - JsonResult result = menuApi.createMenu(btnList); + JsonResult result = menuApi.createMenu(buttons); Assert.assertEquals(0, result.getCode()); } @Test public void create1() throws WeixinException { - btnList = new ArrayList(); + buttons = new ArrayList(); Button b1 = new Button("我要订餐", "ORDERING", ButtonType.click); - btnList.add(b1); + buttons.add(b1); Button b2 = new Button("查询订单", "http://www.lendocean.com/order/list", ButtonType.view); - btnList.add(b2); + buttons.add(b2); Button b3 = new Button("最新资讯", "NEWS", ButtonType.click); - btnList.add(b3); - JsonResult result = menuApi.createMenu(btnList); + buttons.add(b3); + JsonResult result = menuApi.createMenu(buttons); Assert.assertEquals(0, result.getCode()); } @Test public void get() throws WeixinException { - btnList = menuApi.getMenu(); - for (Button btn : btnList) { + buttons = menuApi.getMenu(); + for (Button btn : buttons) { System.out.println(btn); } - Assert.assertEquals(3, btnList.size()); + Assert.assertEquals(3, buttons.size()); // Button [name=我的门店, type=view, // content=http://dianzhang.canyi.net/setting/index, subs=[]] // Button [name=每日签到, type=click, content=CHECKIN, subs=[]] @@ -86,4 +92,26 @@ public class MenuTest extends TokenTest { JsonResult result = menuApi.deleteMenu(); Assert.assertEquals(0, result.getCode()); } + + @Test + public void testCustom() throws WeixinException { + buttons = new ArrayList(); + buttons.add(new Button("only for iphone", "iphone", ButtonType.click)); + MenuMatchRule matchRule = new MenuMatchRule(); + matchRule.platform(ClientPlatformType.IOS); + JsonResult result = menuApi.createCustomMenu(buttons, matchRule); + Assert.assertEquals(0, result.getCode()); + } + + @Test + public void testGetAllMenus() throws WeixinException { + List menus = menuApi.getAllMenu(); + System.err.println(menus); + } + + @Test + public void testMatchMenu()throws WeixinException{ + List buttons = menuApi.matchCustomMenu("paihuaing"); + System.err.println(buttons); + } } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java index dff73862..dd9c8740 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java @@ -199,7 +199,7 @@ public class WeixinProxy { /** * 自定义菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式) * - * @param btnList + * @param buttons * 菜单列表 * @param agentid * 应用ID @@ -210,9 +210,9 @@ public class WeixinProxy { * 创建自定义菜单 * @see com.foxinmy.weixin4j.model.Button */ - public JsonResult createMenu(List btnList, int agentid) + public JsonResult createMenu(List buttons, int agentid) throws WeixinException { - return menuApi.createMenu(btnList, agentid); + return menuApi.createMenu(buttons, agentid); } /** diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MenuApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MenuApi.java index 672b1be7..35db54f5 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MenuApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MenuApi.java @@ -38,7 +38,7 @@ public class MenuApi extends QyApi { /** * 自定义菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式) * - * @param btnList + * @param buttons * 菜单列表 * @param agentid * 应用ID @@ -47,12 +47,12 @@ public class MenuApi extends QyApi { * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%88%9B%E5%BB%BA%E5%BA%94%E7%94%A8%E8%8F%9C%E5%8D%95">创建自定义菜单 * @see com.foxinmy.weixin4j.model.Button */ - public JsonResult createMenu(List btnList, int agentid) + public JsonResult createMenu(List buttons, int agentid) throws WeixinException { String menu_create_uri = getRequestUri("menu_create_uri"); Token token = tokenHolder.getToken(); JSONObject obj = new JSONObject(); - obj.put("button", btnList); + obj.put("button", buttons); WeixinResponse response = weixinExecutor .post(String.format(menu_create_uri, token.getAccessToken(), agentid), JSON.toJSONString(obj, new NameFilter() { diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/ClassUtil.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/ClassUtil.java index ff61fc6d..a98a7b35 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/ClassUtil.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/ClassUtil.java @@ -205,7 +205,6 @@ public final class ClassUtil { public static void main(String[] args) { System.err - .println(getClasses(com.foxinmy.weixin4j.handler.WeixinMessageHandler.class - .getPackage().getName())); + .println(getClasses("com.foxinmy.weixin4j.qy.event")); } }
+ * country、province、city组成地区信息,将按照country、province、city的顺序进行验证 + * ,要符合地区信息表的内容。地区信息从大到小验证,小的可以不填,即若填写了省份信息,则国家信息也必填并且匹配,城市信息可以不填。 例如 “中国 + * 广东省 广州市”、“中国 广东省”都是合法的地域信息,而“中国 广州市”则不合法,因为填写了城市信息但没有填写省份信息 + * + * @param country + * @return + */ + @JSONField(name = "country") + public MenuMatchRule country(String country) { + matchRule.put("country", country); + this.country = country; + return this; + } + + private String province; + + /** + * 省份信息,是用户在微信中设置的地区 + *
+ * country、province、city组成地区信息,将按照country、province、city的顺序进行验证,要符合地区信息表的内容。 + * 地区信息从大到小验证,小的可以不填,即若填写了省份信息,则国家信息也必填并且匹配,城市信息可以不填。 例如 “中国 广东省 广州市”、“中国 + * 广东省”都是合法的地域信息,而“中国 广州市”则不合法,因为填写了城市信息但没有填写省份信息 + * + * @param country + * @return + */ + @JSONField(name = "province") + public MenuMatchRule province(String province) { + matchRule.put("province", province); + this.province = province; + return this; + } + + private String city; + + /** + * 城市信息,是用户在微信中设置的地区 + *
+ * country、province、city组成地区信息,将按照country、province、city的顺序进行验证,要符合地区信息表的内容。 + * 地区信息从大到小验证,小的可以不填,即若填写了省份信息,则国家信息也必填并且匹配,城市信息可以不填。 例如 “中国 广东省 广州市”、“中国 + * 广东省”都是合法的地域信息,而“中国 广州市”则不合法,因为填写了城市信息但没有填写省份信息 + * + * @param city + * @return + */ + @JSONField(name = "city") + public MenuMatchRule city(String city) { + matchRule.put("city", city); + this.city = city; + return this; + } + + public ClientPlatformType getPlatformType() { + return platformType; + } + + public Integer getGroupId() { + return groupId; + } + + public Gender getGender() { + return gender; + } + + public String getCountry() { + return country; + } + + public String getProvince() { + return province; + } + + public String getCity() { + return city; + } + + public boolean hasRule() { + return !matchRule.isEmpty(); + } + + public JSONObject getRule() { + return this.matchRule; + } + + @Override + public String toString() { + return "MenuMatchRule [groupId=" + groupId + ", gender=" + gender + + ", platformType=" + platformType + ", country=" + country + + ", province=" + province + ", city=" + city + "]"; + } +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/ClientPlatformType.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/ClientPlatformType.java new file mode 100644 index 00000000..3f65c891 --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/ClientPlatformType.java @@ -0,0 +1,14 @@ +package com.foxinmy.weixin4j.mp.type; + +/** + * 平台类型 + * + * @className ClientPlatformType + * @author jy + * @date 2015年12月17日 + * @since JDK 1.7 + * @see + */ +public enum ClientPlatformType { + IOS, Android, Others +} diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java index 871c8cb6..d3325bbf 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java @@ -55,7 +55,7 @@ public class MediaTest extends TokenTest { @Test public void download1() throws WeixinException, IOException { MediaDownloadResult content = mediaApi.downloadMedia( - "nD05mhmkW-SHVS8NfWSxdzJi-6VnVF5YSP5hmMWnKJUxLK5czAWtN4NhVmgEfVoe", false); + "BmzcrM2jaJXZCjBqxLwyC03kh5pge3CbrBqXP4XbYBCeKr7xz-rHuwPf4vYLVdL1", false); Assert.assertTrue(content != null); System.err.println(content); } diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java index bdc06a18..792ce9d6 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java @@ -11,6 +11,9 @@ import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.model.Button; import com.foxinmy.weixin4j.mp.api.MenuApi; +import com.foxinmy.weixin4j.mp.model.Menu; +import com.foxinmy.weixin4j.mp.model.MenuMatchRule; +import com.foxinmy.weixin4j.mp.type.ClientPlatformType; import com.foxinmy.weixin4j.type.ButtonType; /** @@ -24,7 +27,7 @@ import com.foxinmy.weixin4j.type.ButtonType; public class MenuTest extends TokenTest { private MenuApi menuApi; - private List btnList; + private List buttons; @Before public void init() { @@ -33,44 +36,47 @@ public class MenuTest extends TokenTest { @Test public void create() throws WeixinException { - btnList = new ArrayList(); + buttons = new ArrayList(); String domain = "http://wx.jdxg.doubimeizhi.com"; - btnList.add(new Button("立即下单", domain, ButtonType.view)); + buttons.add(new Button("立即下单", domain, ButtonType.view)); - btnList.add(new Button("个人中心", domain + "/user", ButtonType.view)); + buttons.add(new Button("个人中心", domain + "/user", ButtonType.view)); Button button = new Button("小哥介绍", domain, ButtonType.view); - button.pushSub(new Button("小哥介绍", "http://mp.weixin.qq.com/s?__biz=MzI2MTA5OTM4OQ==&mid=400990970&idx=1&sn=5c7fd72e782c49f7c933b91c63eddc80#rd", ButtonType.view)); + button.pushSub(new Button( + "小哥介绍", + "http://mp.weixin.qq.com/s?__biz=MzI2MTA5OTM4OQ==&mid=400990970&idx=1&sn=5c7fd72e782c49f7c933b91c63eddc80#rd", + ButtonType.view)); button.pushSub(new Button("服务流程", "FLOW", ButtonType.click)); button.pushSub(new Button("在线客服", "KF", ButtonType.click)); - btnList.add(button); + buttons.add(button); - JsonResult result = menuApi.createMenu(btnList); + JsonResult result = menuApi.createMenu(buttons); Assert.assertEquals(0, result.getCode()); } @Test public void create1() throws WeixinException { - btnList = new ArrayList(); + buttons = new ArrayList(); Button b1 = new Button("我要订餐", "ORDERING", ButtonType.click); - btnList.add(b1); + buttons.add(b1); Button b2 = new Button("查询订单", "http://www.lendocean.com/order/list", ButtonType.view); - btnList.add(b2); + buttons.add(b2); Button b3 = new Button("最新资讯", "NEWS", ButtonType.click); - btnList.add(b3); - JsonResult result = menuApi.createMenu(btnList); + buttons.add(b3); + JsonResult result = menuApi.createMenu(buttons); Assert.assertEquals(0, result.getCode()); } @Test public void get() throws WeixinException { - btnList = menuApi.getMenu(); - for (Button btn : btnList) { + buttons = menuApi.getMenu(); + for (Button btn : buttons) { System.out.println(btn); } - Assert.assertEquals(3, btnList.size()); + Assert.assertEquals(3, buttons.size()); // Button [name=我的门店, type=view, // content=http://dianzhang.canyi.net/setting/index, subs=[]] // Button [name=每日签到, type=click, content=CHECKIN, subs=[]] @@ -86,4 +92,26 @@ public class MenuTest extends TokenTest { JsonResult result = menuApi.deleteMenu(); Assert.assertEquals(0, result.getCode()); } + + @Test + public void testCustom() throws WeixinException { + buttons = new ArrayList(); + buttons.add(new Button("only for iphone", "iphone", ButtonType.click)); + MenuMatchRule matchRule = new MenuMatchRule(); + matchRule.platform(ClientPlatformType.IOS); + JsonResult result = menuApi.createCustomMenu(buttons, matchRule); + Assert.assertEquals(0, result.getCode()); + } + + @Test + public void testGetAllMenus() throws WeixinException { + List menus = menuApi.getAllMenu(); + System.err.println(menus); + } + + @Test + public void testMatchMenu()throws WeixinException{ + List buttons = menuApi.matchCustomMenu("paihuaing"); + System.err.println(buttons); + } } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java index dff73862..dd9c8740 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java @@ -199,7 +199,7 @@ public class WeixinProxy { /** * 自定义菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式) * - * @param btnList + * @param buttons * 菜单列表 * @param agentid * 应用ID @@ -210,9 +210,9 @@ public class WeixinProxy { * 创建自定义菜单