From d45cd6b8ee11de550426b19bf886388d5154e984 Mon Sep 17 00:00:00 2001 From: jinyu Date: Tue, 22 Nov 2016 18:24:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=BB=91=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGE.md | 6 +- weixin4j-mp/CHANGE.md | 6 +- .../com/foxinmy/weixin4j/mp/WeixinProxy.java | 92 ++++++++++++++++++- .../com/foxinmy/weixin4j/mp/api/GroupApi.java | 1 + .../com/foxinmy/weixin4j/mp/api/MassApi.java | 86 ++++++++++++++++- .../com/foxinmy/weixin4j/mp/api/TagApi.java | 88 +++++++++++++++++- .../src/main/resources/weixin4j.properties | 2 +- 7 files changed, 274 insertions(+), 7 deletions(-) diff --git a/CHANGE.md b/CHANGE.md index 681f10be..bd42b3e2 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -766,4 +766,8 @@ * 2016-10-10 - + version upgrade to 1.7.2 \ No newline at end of file + + version upgrade to 1.7.2 + +* 2016-11-22 + + + weixin4j-mp:新增黑名单接口 \ No newline at end of file diff --git a/weixin4j-mp/CHANGE.md b/weixin4j-mp/CHANGE.md index 0bfa360f..6178cb46 100644 --- a/weixin4j-mp/CHANGE.md +++ b/weixin4j-mp/CHANGE.md @@ -252,4 +252,8 @@ * 2016-10-10 - + version upgrade to 1.7.2 \ No newline at end of file + + version upgrade to 1.7.2 + +* 2016-11-22 + + + 新增黑名单接口 \ No newline at end of file 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 802ac368..bd2f2de6 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 @@ -213,7 +213,8 @@ public class WeixinProxy { private WeixinProxy(WeixinAccount weixinAccount, TokenCreator tokenCreator, CacheStorager cacheStorager) { if (weixinAccount == null) { - throw new IllegalArgumentException("weixinAccount must not be empty"); + throw new IllegalArgumentException( + "weixinAccount must not be empty"); } if (tokenCreator == null) { throw new IllegalArgumentException("tokenCreator must not be empty"); @@ -886,6 +887,58 @@ public class WeixinProxy { return massApi.massArticleByGroupId(articles, groupId); } + /** + * 标签群发 + *

+ * 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息, + * 如消息有时会进行审核、服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕 + *

+ * + * @param tuple + * 消息元件 + * @param isToAll + * 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户, + * 选择false可根据group_id发送给指定群组的用户 + * @param tagId + * 标签ID + * @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID,该字段只有在群发图文消息时,才会出现,可以用于在图文分析数据接口中 + * @throws WeixinException + * @see Tag + * @see com.foxinmy.weixin4j.tuple.Text + * @see com.foxinmy.weixin4j.tuple.Image + * @see com.foxinmy.weixin4j.tuple.Voice + * @see com.foxinmy.weixin4j.tuple.MpVideo + * @see com.foxinmy.weixin4j.tuple.MpNews + * @see com.foxinmy.weixin4j.tuple.Card + * @see com.foxinmy.weixin4j.tuple.MassTuple + * @see {@link TagApi#listTags()} + * @see 根据标签群发 + */ + public String[] massByTagId(MassTuple tuple, boolean isToAll, int tagId) + throws WeixinException { + return massApi.massByTagId(tuple, isToAll, tagId); + } + + /** + * 标签群发图文消息 + * + * @param articles + * 图文列表 + * @param tagId + * 标签ID + * @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID,该字段只有在群发图文消息时,才会出现。 + * @see 根据标签群发 + * @see {@link #massByTagId(Tuple,int)} + * @see com.foxinmy.weixin4j.tuple.MpArticle + * @throws WeixinException + */ + public String[] massArticleByTagId(List articles, int tagId) + throws WeixinException { + return massApi.massArticleByTagId(articles, tagId); + } + /** * openId群发 * @@ -1891,6 +1944,43 @@ public class WeixinProxy { return tagApi.getUserTags(openId); } + /** + * 获取公众号的黑名单列表 + * + * @param nextOpenId + * 下一次拉取数据的openid 不填写则默认从头开始拉取 + * @return 拉黑用户列表 不包含用户的详细信息 + * @see 获取黑名单列表 + * @see com.foxinmy.weixin4j.mp.api.TagApi + * @see com.foxinmy.weixin4j.mp.model.Following + * @throws WeixinException + */ + public Following getBalcklistOpenIds(String nextOpenId) + throws WeixinException { + return tagApi.getBalcklistOpenIds(nextOpenId); + } + + /** + * 获取公众号全部的黑名单列表 请慎重使用 + *

+ * 当公众号关注者数量超过10000时,可通过填写next_openid的值,从而多次拉取列表的方式来满足需求, + * 将上一次调用得到的返回中的next_openid值,作为下一次调用中的next_openid值 + *

+ * + * @return 用户openid集合 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.TagApi + * @see + * 获取黑名单列表 + * @see #getFollowingOpenIds(String) + */ + public List getAllBalcklistOpenIds() throws WeixinException { + return tagApi.getAllBalcklistOpenIds(); + } + /** * 创建卡券:创建卡券接口是微信卡券的基础接口,用于创建一类新的卡券,获取card_id,创建成功并通过审核后, * 商家可以通过文档提供的其他接口将卡券下发给用户,每次成功领取,库存数量相应扣除。 diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/GroupApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/GroupApi.java index 355d3b5c..aa42918b 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/GroupApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/GroupApi.java @@ -20,6 +20,7 @@ import com.foxinmy.weixin4j.token.TokenManager; * @since JDK 1.6 * @see com.foxinmy.weixin4j.mp.model.Group */ +@Deprecated public class GroupApi extends MpApi { private final TokenManager tokenManager; diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java index 6cd44b54..154cdeb4 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java @@ -86,6 +86,7 @@ public class MassApi extends MpApi { * @see 根据分组群发 */ + @Deprecated public String[] massByGroupId(MassTuple tuple, boolean isToAll, int groupId) throws WeixinException { if (tuple instanceof MpNews) { @@ -134,12 +135,95 @@ public class MassApi extends MpApi { * @see com.foxinmy.weixin4j.tuple.MpArticle * @throws WeixinException */ + @Deprecated public String[] massArticleByGroupId(List articles, int groupId) throws WeixinException { String mediaId = uploadArticle(articles); return massByGroupId(new MpNews(mediaId), false, groupId); } + /** + * 标签群发 + *

+ * 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息, + * 如消息有时会进行审核、服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕 + *

+ * + * @param tuple + * 消息元件 + * @param isToAll + * 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户, + * 选择false可根据group_id发送给指定群组的用户 + * @param tagId + * 标签ID + * @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID,该字段只有在群发图文消息时,才会出现,可以用于在图文分析数据接口中 + * @throws WeixinException + * @see Tag + * @see com.foxinmy.weixin4j.tuple.Text + * @see com.foxinmy.weixin4j.tuple.Image + * @see com.foxinmy.weixin4j.tuple.Voice + * @see com.foxinmy.weixin4j.tuple.MpVideo + * @see com.foxinmy.weixin4j.tuple.MpNews + * @see com.foxinmy.weixin4j.tuple.Card + * @see com.foxinmy.weixin4j.tuple.MassTuple + * @see {@link TagApi#listTags()} + * @see 根据标签群发 + */ + public String[] massByTagId(MassTuple tuple, boolean isToAll, int tagId) + throws WeixinException { + if (tuple instanceof MpNews) { + MpNews _news = (MpNews) tuple; + List _articles = _news.getArticles(); + if (StringUtil.isBlank(_news.getMediaId())) { + if (_articles.isEmpty()) { + throw new WeixinException( + "mass fail:mediaId or articles is required"); + } + tuple = new MpNews(uploadArticle(_articles)); + } + } + String msgtype = tuple.getMessageType(); + JSONObject obj = new JSONObject(); + JSONObject item = new JSONObject(); + item.put("is_to_all", isToAll); + if (!isToAll) { + item.put("tag_id", tagId); + } + obj.put("filter", item); + obj.put(msgtype, JSON.toJSON(tuple)); + obj.put("msgtype", msgtype); + String mass_group_uri = getRequestUri("mass_group_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor.post( + String.format(mass_group_uri, token.getAccessToken()), + obj.toJSONString()); + + obj = response.getAsJson(); + return new String[] { obj.getString("msg_id"), + obj.getString("msg_data_id") }; + } + + /** + * 标签群发图文消息 + * + * @param articles + * 图文列表 + * @param tagId + * 标签ID + * @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID,该字段只有在群发图文消息时,才会出现。 + * @see 根据标签群发 + * @see {@link #massByTagId(Tuple,int)} + * @see com.foxinmy.weixin4j.tuple.MpArticle + * @throws WeixinException + */ + public String[] massArticleByTagId(List articles, int tagId) + throws WeixinException { + String mediaId = uploadArticle(articles); + return massByTagId(new MpNews(mediaId), false, tagId); + } + /** * openId群发 * @@ -221,7 +305,7 @@ public class MassApi extends MpApi { * @throws WeixinException * @see 删除群发 - * @see {@link #massByGroupId(Tuple, int)} + * @see {@link #massByTagId(Tuple, int)} * @see {@link #massByOpenIds(Tuple, String...) */ public ApiResult deleteMassNews(String msgid) throws WeixinException { diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TagApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TagApi.java index 64d151a3..5e2f6ac2 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TagApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TagApi.java @@ -8,6 +8,7 @@ import com.alibaba.fastjson.JSONObject; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.ApiResult; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.mp.model.Following; import com.foxinmy.weixin4j.mp.model.Tag; import com.foxinmy.weixin4j.mp.model.User; @@ -126,8 +127,8 @@ public class TagApi extends MpApi { return batchUsers("tag_tagging_uri", tagId, openIds); } - private ApiResult batchUsers(String batchType, int tagId, - String... openIds) throws WeixinException { + private ApiResult batchUsers(String batchType, int tagId, String... openIds) + throws WeixinException { String tag_batch_uri = getRequestUri(batchType); JSONObject obj = new JSONObject(); obj.put("openid_list", openIds); @@ -290,4 +291,87 @@ public class TagApi extends MpApi { return response.getAsJson().getJSONArray("tagid_list") .toArray(new Integer[] {}); } + + /** + * 获取公众号的黑名单列表 + * + * @param nextOpenId + * 下一次拉取数据的openid 不填写则默认从头开始拉取 + * @return 拉黑用户列表 不包含用户的详细信息 + * @see 获取黑名单列表 + * @see com.foxinmy.weixin4j.mp.model.Following + * @throws WeixinException + */ + public Following getBalcklistOpenIds(String nextOpenId) + throws WeixinException { + JSONObject obj = new JSONObject(); + obj.put("begin_openid", nextOpenId == null ? "" : nextOpenId); + String getblacklist_uri = getRequestUri("getblacklist_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor.post(String.format( + getblacklist_uri, token.getAccessToken(), obj.toJSONString())); + JSONObject result = response.getAsJson(); + Following following = JSON.toJavaObject(result, Following.class); + if (following.getCount() > 0) { + following.setOpenIds(JSON.parseArray(result.getJSONObject("data") + .getString("openid"), String.class)); + } + return following; + } + + /** + * 获取公众号全部的黑名单列表 请慎重使用 + *

+ * 当公众号关注者数量超过10000时,可通过填写next_openid的值,从而多次拉取列表的方式来满足需求, + * 将上一次调用得到的返回中的next_openid值,作为下一次调用中的next_openid值 + *

+ * + * @return 用户openid集合 + * @throws WeixinException + * @see + * 获取黑名单列表 + * @see #getFollowingOpenIds(String) + */ + public List getAllBalcklistOpenIds() throws WeixinException { + List openIds = new ArrayList(); + String nextOpenId = null; + Following f = null; + for (;;) { + f = getBalcklistOpenIds(nextOpenId); + if (f.hasContent()) { + openIds.addAll(f.getOpenIds()); + nextOpenId = f.getNextOpenId(); + continue; + } + break; + } + return openIds; + } + + /** + * 黑名单操作 + * + * @param blacklist + * true=拉黑用户,false=取消拉黑用户 + * @param openIds + * 用户ID列表 + * @return 操作结果 + * @see 黑名单操作 + * @throws WeixinException + */ + public ApiResult batchBlacklist(boolean blacklist, String... openIds) + throws WeixinException { + JSONObject obj = new JSONObject(); + obj.put("openid_list", openIds); + String blacklist_url = blacklist ? getRequestUri("batchblacklist_uri") + : getRequestUri("batchunblacklist_uri"); + WeixinResponse response = weixinExecutor.post( + String.format(blacklist_url, tokenManager.getAccessToken()), + obj.toJSONString()); + return response.getAsResult(); + } } diff --git a/weixin4j-mp/src/main/resources/weixin4j.properties b/weixin4j-mp/src/main/resources/weixin4j.properties index 90213cd9..64c00099 100644 --- a/weixin4j-mp/src/main/resources/weixin4j.properties +++ b/weixin4j-mp/src/main/resources/weixin4j.properties @@ -1,7 +1,7 @@ # weixin4j\u7684\u914d\u7f6e\u6587\u4ef6:\u5982\u679c\u6ca1\u6709\u8bf7\u6784\u9020\u76f8\u5e94\u53c2\u6570\u4f20\u5165 \u5982\u679c\u6709\u8bf7\u4fdd\u8bc1\u5728classpath\u7684\u6839\u76ee\u5f55\u4e0b # \u516c\u4f17\u53f7\u4fe1\u606f \u8bf7\u6309\u9700\u586b\u5199 -weixin4j.account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\ +weixin4j.account={"id":"wx5017c5f709116d6a","secret":"d4624c36b6795d1d99dcf0547af5443d",\ "components":[{"id":"\u5e94\u7528\u7ec4\u4ef6\u7684id","secret":"\u5e94\u7528\u7ec4\u4ef6\u7684secret"}],\ "mchId":"\u5fae\u4fe1\u5546\u6237\u53f7 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ "certificateKey":"\u52a0\u8f7d\u652f\u4ed8\u8bc1\u4e66\u6587\u4ef6\u7684\u5bc6\u7801 \u5982\u679c\u4e0d\u586b\u5199\u5219\u9ed8\u8ba4\u83b7\u53d6mchId\u4f5c\u4e3a\u5bc6\u7801",\