新增media_idview_limited两种菜单类型

This commit is contained in:
jinyu 2015-04-30 19:56:07 +08:00
parent ce83591d35
commit 5de9ece244
9 changed files with 171 additions and 82 deletions

View File

@ -263,4 +263,8 @@
* 2015-04-29 * 2015-04-29
+ <font color="red">released 1.4</font> + <font color="red">released 1.4</font>
* 2015-04-30
+ 新增`media_id``view_limited`两种菜单类型

View File

@ -43,7 +43,7 @@ public class Button implements Serializable {
* <p> * <p>
* 使用API设置的自定义菜单</br> * 使用API设置的自定义菜单</br>
* clickscancode_pushscancode_waitmsgpic_sysphotopic_photo_or_album * clickscancode_pushscancode_waitmsgpic_sysphotopic_photo_or_album
* </br> pic_weixinlocation_select保存值到keyview保存链接到url * </br> pic_weixinlocation_select保存为keyview保存为url;media_idview_limited保存为media_id
* </p> * </p>
* </p> * </p>
*/ */

View File

@ -1,10 +1,11 @@
package com.foxinmy.weixin4j.type; package com.foxinmy.weixin4j.type;
/** /**
* 自定义菜单类型 </br> * 自定义菜单类型 </br> <font
* <font color="red">scancode_push location_selec * color="red">请注意scancode_push到location_select的所有事件仅支持微信iPhone5.4.1以上版本和Android5.4以上版本的微信用户
* 仅支持微信iPhone5.4.1以上版本和Android5 .4以上版本的微信用户 旧版本微信用户点击后将没有回应 * 旧版本微信用户点击后将没有回应
* 开发者也不能正常接收到事件推送</font> * 开发者也不能正常接收到事件推送media_id和view_limited是专门给第三方平台旗下未微信认证具体而言是资质认证未通过的订阅号准备的事件类型
* 它们是没有事件推送的能力相对受限其他类型的公众号不必使用</font>
* *
* @className ButtonType * @className ButtonType
* @author jy * @author jy
@ -51,5 +52,15 @@ public enum ButtonType {
* 弹出地理位置选择器用户点击按钮后微信客户端将调起地理位置选择工具完成选择操作后将选择的地理位置发送给开发者的服务器同时收起位置选择工具 * 弹出地理位置选择器用户点击按钮后微信客户端将调起地理位置选择工具完成选择操作后将选择的地理位置发送给开发者的服务器同时收起位置选择工具
* 随后可能会收到开发者下发的消息 * 随后可能会收到开发者下发的消息
*/ */
location_select; location_select,
/**
* 下发消息除文本消息:用户点击media_id类型按钮后微信服务器会将开发者填写的永久素材id对应的素材下发给用户永久素材类型可以是图片
* 音频视频图文消息 请注意永久素材id必须是在素材管理/新增永久素材接口上传后获得的合法id
*/
media_id,
/**
* 跳转图文消息URL:用户点击view_limited类型按钮后微信客户端将打开开发者在按钮中填写的永久素材id对应的图文消息URL
* 永久素材类型只支持图文消息 请注意永久素材id必须是在素材管理/新增永久素材接口上传后获得的合法id
*/
view_limited;
} }

View File

@ -9,7 +9,6 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath; import com.alibaba.fastjson.JSONPath;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor; import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import com.alibaba.fastjson.serializer.NameFilter;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Button; import com.foxinmy.weixin4j.model.Button;
@ -118,65 +117,63 @@ public class HelperApi extends MpApi {
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
Response response = request.get(String.format(menu_get_selfmenu_uri, Response response = request.get(String.format(menu_get_selfmenu_uri,
token.getAccessToken())); token.getAccessToken()));
JSONObject result = response.getAsJson(); JSONObject result = response.getAsJson();
JSONArray buttons = result.getJSONObject("selfmenu_info").getJSONArray( JSONArray buttons = result.getJSONObject("selfmenu_info").getJSONArray(
"button"); "button");
List<Button> _buttons = new ArrayList<Button>(); List<Button> buttonList = new ArrayList<Button>(buttons.size());
JSONObject buttonObj = null; JSONObject buttonObj = null;
Object subButton = null;
for (int i = 0; i < buttons.size(); i++) { for (int i = 0; i < buttons.size(); i++) {
buttonObj = buttons.getJSONObject(i); buttonObj = buttons.getJSONObject(i);
subButton = buttonObj.remove("sub_button"); if (buttonObj.containsKey("sub_button")) {
if (subButton != null) { JSONPath.set(buttonObj, "$.sub_button", buttonObj
buttonObj.put("sub_button", .getJSONObject("sub_button").getJSONArray("list"));
((JSONObject) subButton).getJSONArray("list"));
} }
Button button = JSON.parseObject( buttonList.add(JSON.parseObject(buttonObj.toJSONString(),
JSON.toJSONString(buttonObj, ArticleNameFilter.global), Button.class, ButtonExtraProcessor.global));
Button.class, NewsExtraProcessor.global);
_buttons.add(button);
} }
return new MenuSetting(result.getBooleanValue("is_menu_open"), _buttons); return new MenuSetting(result.getBooleanValue("is_menu_open"),
buttonList);
} }
private static final class NewsExtraProcessor implements ExtraProcessor { private static final class ButtonExtraProcessor implements ExtraProcessor {
private static NewsExtraProcessor global = new NewsExtraProcessor(); private static ButtonExtraProcessor global = new ButtonExtraProcessor();
private NewsExtraProcessor() { private ButtonExtraProcessor() {
} }
@Override @Override
public void processExtra(Object object, String key, Object value) { public void processExtra(Object object, String key, Object value) {
if (key.equals("news_info")) { if (key.equals("news_info")) {
List<MpArticle> news = JSON JSONArray news = ((JSONObject) value).getJSONArray("list");
.parseArray(((JSONObject) value).getString("list"), List<MpArticle> newsList = new ArrayList<MpArticle>(news.size());
MpArticle.class); for (int i = 0; i < news.size(); i++) {
JSONPath.set(object, "$.content", news); newsList.add(JSON.parseObject(news.getString(i),
MpArticle.class, ArticleExtraProcessor.global));
}
JSONPath.set(object, "$.content", newsList);
} else {
JSONPath.set(object, "$.content", value);
} }
} }
}; };
private static final class ArticleNameFilter implements NameFilter { private static final class ArticleExtraProcessor implements ExtraProcessor {
private static final ArticleNameFilter global = new ArticleNameFilter(); private static final ArticleExtraProcessor global = new ArticleExtraProcessor();
private ArticleNameFilter() { private ArticleExtraProcessor() {
} }
@Override @Override
public String process(Object object, String name, Object value) { public void processExtra(Object object, String key, Object value) {
if (name.equals("url") || name.equals("key")) { MpArticle mpArticle = (MpArticle) object;
return "content"; if (key.equals("show_cover")) {
mpArticle.setShowCoverPic(value.equals("1"));
} }
if (name.equals("show_cover")) { if (key.equals("source_url")) {
return "show_cover_pic"; mpArticle.setSourceUrl(value.toString());
} }
if (name.equals("source_url")) {
return "content_source_url";
}
return name;
} }
} }
@ -194,13 +191,13 @@ public class HelperApi extends MpApi {
Response response = request.get(String.format( Response response = request.get(String.format(
autoreply_setting_get_uri, token.getAccessToken())); autoreply_setting_get_uri, token.getAccessToken()));
JSONObject obj = response.getAsJson(); JSONObject result = response.getAsJson();
AutoReplySetting replySetting = JSON.toJavaObject(obj, AutoReplySetting replySetting = JSON.toJavaObject(result,
AutoReplySetting.class); AutoReplySetting.class);
List<AutoReplySetting.Rule> ruleList = null; List<AutoReplySetting.Rule> ruleList = null;
if (obj.containsKey("keyword_autoreply_info")) { if (result.containsKey("keyword_autoreply_info")) {
JSONArray keywordList = obj.getJSONObject("keyword_autoreply_info") JSONArray keywordList = result.getJSONObject(
.getJSONArray("list"); "keyword_autoreply_info").getJSONArray("list");
ruleList = new ArrayList<AutoReplySetting.Rule>(keywordList.size()); ruleList = new ArrayList<AutoReplySetting.Rule>(keywordList.size());
JSONObject keywordObj = null; JSONObject keywordObj = null;
JSONArray replyList = null; JSONArray replyList = null;
@ -215,10 +212,9 @@ public class HelperApi extends MpApi {
for (int j = 0; j < replyList.size(); j++) { for (int j = 0; j < replyList.size(); j++) {
replyObj = replyList.getJSONObject(j); replyObj = replyList.getJSONObject(j);
if (replyObj.getString("type").equals("news")) { if (replyObj.getString("type").equals("news")) {
entryList.add(JSON.parseObject(JSON.toJSONString( entryList.add(JSON.parseObject(replyObj.toJSONString(),
replyObj, ArticleNameFilter.global),
AutoReplySetting.Entry.class, AutoReplySetting.Entry.class,
NewsExtraProcessor.global)); ButtonExtraProcessor.global));
} else { } else {
entryList.add(JSON.toJavaObject(replyObj, entryList.add(JSON.toJavaObject(replyObj,
AutoReplySetting.Entry.class)); AutoReplySetting.Entry.class));

View File

@ -1,9 +1,14 @@
package com.foxinmy.weixin4j.mp.api; package com.foxinmy.weixin4j.mp.api;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import com.alibaba.fastjson.parser.deserializer.ParseProcess;
import com.alibaba.fastjson.serializer.NameFilter; import com.alibaba.fastjson.serializer.NameFilter;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
@ -52,8 +57,13 @@ public class MenuApi extends MpApi {
public String process(Object object, String name, public String process(Object object, String name,
Object value) { Object value) {
if (object instanceof Button && name.equals("content")) { if (object instanceof Button && name.equals("content")) {
if (((Button) object).getFormatType() == ButtonType.view) { ButtonType buttonType = ((Button) object)
.getFormatType();
if (buttonType == ButtonType.view) {
return "url"; return "url";
} else if (buttonType == ButtonType.media_id
|| buttonType == ButtonType.view_limited) {
return "media_id";
} else { } else {
return "key"; return "key";
} }
@ -80,19 +90,20 @@ public class MenuApi extends MpApi {
Response response = request.get(String.format(menu_get_uri, Response response = request.get(String.format(menu_get_uri,
token.getAccessToken())); token.getAccessToken()));
String text = JSON.toJSONString( JSONArray buttons = response.getAsJson().getJSONObject("menu")
response.getAsJson().getJSONObject("menu") .getJSONArray("button");
.getJSONArray("button"), new NameFilter() { List<Button> buttonList = new ArrayList<Button>(buttons.size());
@Override ParseProcess processor = new ExtraProcessor() {
public String process(Object object, String name, @Override
Object value) { public void processExtra(Object object, String key, Object value) {
if (name.equals("url") || name.equals("key")) { JSONPath.set(object, "$.content", value);
return "content"; }
} };
return name; for (int i = 0; i < buttons.size(); i++) {
} buttonList.add(JSON.parseObject(buttons.getString(i), Button.class,
}); processor));
return JSON.parseArray(text, Button.class); }
return buttonList;
} }
/** /**

View File

@ -18,9 +18,13 @@ public class OauthToken extends Token {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 用户的openi * 用户的openid
*/ */
private String openid; private String openid;
/**
* 只有在用户将公众号绑定到微信开放平台帐号后才会出现该字段
*/
private String unionid;
/** /**
* 刷新token时的凭证 * 刷新token时的凭证
@ -38,6 +42,14 @@ public class OauthToken extends Token {
this.openid = openid; this.openid = openid;
} }
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public String getRefreshToken() { public String getRefreshToken() {
return refreshToken; return refreshToken;
} }
@ -56,9 +68,10 @@ public class OauthToken extends Token {
@Override @Override
public String toString() { public String toString() {
return "OauthToken [openid=" + openid + ", refreshToken=" return "OauthToken [openid=" + openid + ", unionid=" + unionid
+ refreshToken + ", scope=" + scope + ", getAccessToken()=" + ", refreshToken=" + refreshToken + ", scope=" + scope
+ getAccessToken() + ", getExpiresIn()=" + getExpiresIn() + ", getAccessToken()=" + getAccessToken()
+ ", getTime()=" + getTime() + "]"; + ", getExpiresIn()=" + getExpiresIn() + ", getTime()="
+ getTime() + "]";
} }
} }

View File

@ -402,9 +402,11 @@ public class WeixinProxy {
* 通过员工授权获取到的code每次员工授权带上的code将不一样code只能使用一次5分钟未被使用自动过期 * 通过员工授权获取到的code每次员工授权带上的code将不一样code只能使用一次5分钟未被使用自动过期
* @param agentid * @param agentid
* 跳转链接时所在的企业应用ID * 跳转链接时所在的企业应用ID
* @see com.foxinmy.weixin4j.qy.model.User
* @see com.foxinmy.weixin4j.qy.api.UserApi * @see com.foxinmy.weixin4j.qy.api.UserApi
* @return 成员对象 * @return 成员对象
* @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#getUser(String)} * @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#getUser(String)}
* @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#getUserIdByCode(String,int)}
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E8%8E%B7%E5%8F%96code">企业获取code</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E8%8E%B7%E5%8F%96code">企业获取code</a>
* @see <a * @see <a
@ -415,6 +417,26 @@ public class WeixinProxy {
return userApi.getUserByCode(code, agentid); return userApi.getUserByCode(code, agentid);
} }
/**
* 根据code获取成员信息
*
* @param code
* 通过员工授权获取到的code每次员工授权带上的code将不一样code只能使用一次5分钟未被使用自动过期
* @param agentid
* 跳转链接时所在的企业应用ID
* @return { "UserId":"USERID", "DeviceId":"DEVICEID" }
* @see com.foxinmy.weixin4j.qy.api.UserApi
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E8%8E%B7%E5%8F%96code">企业获取code</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%A0%B9%E6%8D%AEcode%E8%8E%B7%E5%8F%96%E6%88%90%E5%91%98%E4%BF%A1%E6%81%AF">根据code获取成员信息</a>
* @throws WeixinException
*/
public JSONObject getUserIdByCode(String code, int agentid)
throws WeixinException {
return userApi.getUserIdByCode(code, agentid);
}
/** /**
* 获取部门成员 * 获取部门成员
* *

View File

@ -1,9 +1,14 @@
package com.foxinmy.weixin4j.qy.api; package com.foxinmy.weixin4j.qy.api;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import com.alibaba.fastjson.parser.deserializer.ParseProcess;
import com.alibaba.fastjson.serializer.NameFilter; import com.alibaba.fastjson.serializer.NameFilter;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
@ -55,8 +60,13 @@ public class MenuApi extends QyApi {
public String process(Object object, String name, public String process(Object object, String name,
Object value) { Object value) {
if (object instanceof Button && name.equals("content")) { if (object instanceof Button && name.equals("content")) {
if (((Button) object).getFormatType() == ButtonType.view) { ButtonType buttonType = ((Button) object)
.getFormatType();
if (buttonType == ButtonType.view) {
return "url"; return "url";
} else if (buttonType == ButtonType.media_id
|| buttonType == ButtonType.view_limited) {
return "media_id";
} else { } else {
return "key"; return "key";
} }
@ -85,19 +95,20 @@ public class MenuApi extends QyApi {
Response response = request.get(String.format(menu_get_uri, Response response = request.get(String.format(menu_get_uri,
token.getAccessToken(), agentid)); token.getAccessToken(), agentid));
String text = JSON.toJSONString( JSONArray buttons = response.getAsJson().getJSONObject("menu")
response.getAsJson().getJSONObject("menu") .getJSONArray("button");
.getJSONArray("button"), new NameFilter() { List<Button> buttonList = new ArrayList<Button>(buttons.size());
@Override ParseProcess processor = new ExtraProcessor() {
public String process(Object object, String name, @Override
Object value) { public void processExtra(Object object, String key, Object value) {
if (name.equals("url") || name.equals("key")) { JSONPath.set(object, "$.content", value);
return "content"; }
} };
return name; for (int i = 0; i < buttons.size(); i++) {
} buttonList.add(JSON.parseObject(buttons.getString(i), Button.class,
}); processor));
return JSON.parseArray(text, Button.class); }
return buttonList;
} }
/** /**

View File

@ -112,9 +112,11 @@ public class UserApi extends QyApi {
* 通过员工授权获取到的code每次员工授权带上的code将不一样code只能使用一次5分钟未被使用自动过期 * 通过员工授权获取到的code每次员工授权带上的code将不一样code只能使用一次5分钟未被使用自动过期
* @param agentid * @param agentid
* 跳转链接时所在的企业应用ID * 跳转链接时所在的企业应用ID
* @see com.foxinmy.weixin4j.qy.model.User
* @see com.foxinmy.weixin4j.qy.api.UserApi * @see com.foxinmy.weixin4j.qy.api.UserApi
* @return 成员对象 * @return 成员对象
* @see {@link com.foxinmy.weixin4j.qy.api.UserApi#getUser(String)} * @see {@link com.foxinmy.weixin4j.qy.api.UserApi#getUser(String)}
* @see {@link com.foxinmy.weixin4j.qy.api.UserApi#getUserIdByCode(String,int)}
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E8%8E%B7%E5%8F%96code">企业获取code</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E8%8E%B7%E5%8F%96code">企业获取code</a>
* @see <a * @see <a
@ -122,11 +124,30 @@ public class UserApi extends QyApi {
* @throws WeixinException * @throws WeixinException
*/ */
public User getUserByCode(String code, int agentid) throws WeixinException { public User getUserByCode(String code, int agentid) throws WeixinException {
return getUser(getUserIdByCode(code, agentid).getString("UserId"));
}
/**
* 根据code获取成员信息
*
* @param code
* 通过员工授权获取到的code每次员工授权带上的code将不一样code只能使用一次5分钟未被使用自动过期
* @param agentid
* 跳转链接时所在的企业应用ID
* @return { "UserId":"USERID", "DeviceId":"DEVICEID" }
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E8%8E%B7%E5%8F%96code">企业获取code</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%A0%B9%E6%8D%AEcode%E8%8E%B7%E5%8F%96%E6%88%90%E5%91%98%E4%BF%A1%E6%81%AF">根据code获取成员信息</a>
* @throws WeixinException
*/
public JSONObject getUserIdByCode(String code, int agentid)
throws WeixinException {
String user_getid_uri = getRequestUri("user_getid_uri"); String user_getid_uri = getRequestUri("user_getid_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
Response response = request.post(String.format(user_getid_uri, Response response = request.post(String.format(user_getid_uri,
token.getAccessToken(), code, agentid)); token.getAccessToken(), code, agentid));
return getUser(response.getAsJson().getString("UserId")); return response.getAsJson();
} }
/** /**