新增评论管理接口

This commit is contained in:
jinyu 2017-05-19 19:06:26 +08:00
parent 66417fdc8b
commit c53e0718ef
17 changed files with 3720 additions and 3192 deletions

View File

@ -714,72 +714,76 @@
+ 优化PayOldApi
+ weixin4j-mp:新增接口调用次数清零接口
* 2016-06-20
+ version upgrade to 1.7.0
* 2016-07-05
+ weixin4j-mp:初始化开放平台第三方组件TokenCreator
+ weixin4j-mp:新增第三方组件ComponentApi
* 2016-07-06
+ weixin4j-mp:新增第三方组件WeixinComponentProxy
* 2016-07-21
+ weixin4j-base:新增MessageConverter
* 2016-07-22
+ weixin4j-base:主要调整退款相关类与官网一致
+ weixin4j-base:获取cache时加锁处理(via 风车车)
* 2016-08-05
+ weixin4j-base:model包拆分media/paging
+ weixin4j-base:type包拆分card/mch
+ weixin4j-base:新增card卡券相关类
+ weixin4j-mp:新增CardApi:创建卡券接口
* 2016-08-09
+ weixin4j-base:修复媒体消息转换错误bug
+ weixin4j-mp:新增创建卡券二维码接口
+ version upgrade to 1.7.1
+ LOGGER级别优化
* 2016-08-22
+ weixin4j-base:删除`Weixin4jSettings`配置类
* 2016-10-10
+ version upgrade to 1.7.2
* 2016-11-22
+ weixin4j-mp:新增黑名单接口
* 2016-12-13
+ version upgrade to 1.7.3
* 2017-01-09
+ 新增批量发红包接口
+ 新增摇一摇周边接口
+ version upgrade to 1.7.4
+ version upgrade to 1.7.4
* 2017-05-19
+ weixin4j-mp:新增评论管理接口

View File

@ -719,6 +719,18 @@
<code>45059</code>
<text>有粉丝身上的标签数已经超过限制</text>
</error>
<error>
<code>45065</code>
<text>相同 clientmsgid 已存在群发记录,返回数据中带有已存在的群发任务的 msgid</text>
</error>
<error>
<code>45066</code>
<text>相同 clientmsgid 重试速度过快请间隔1分钟重试</text>
</error>
<error>
<code>45067</code>
<text>clientmsgid 长度超过限制</text>
</error>
<error>
<code>45157</code>
<text>标签名非法,请注意不能和其他标签重名</text>
@ -1655,6 +1667,61 @@
<code>86320</code>
<text>不合法的客服类型</text>
</error>
<error>
<code>45009</code>
<msg>reach max api daily quota limit</msg>
<text>没有剩余的调用次数</text>
</error>
<error>
<code>88000</code>
<msg>without comment privilege</msg>
<text>没有留言权限</text>
</error>
<error>
<code>88001</code>
<msg>msg_data is not exists</msg>
<text>该图文不存在</text>
</error>
<error>
<code>88002</code>
<msg>the article is limit for safety</msg>
<text>文章存在敏感信息</text>
</error>
<error>
<code>88003</code>
<msg>elected comment upper limit</msg>
<text>精选评论数已达上限</text>
</error>
<error>
<code>88004</code>
<msg>comment was deleted by user</msg>
<text>已被用户删除,无法精选</text>
</error>
<error>
<code>88005</code>
<msg>already reply</msg>
<text>该评论已回复</text>
</error>
<error>
<code>88007</code>
<msg>reply content beyond max len or content len is zero</msg>
<text>回复超过长度限制或为0</text>
</error>
<error>
<code>88008</code>
<msg>comment is not exists</msg>
<text>该评论不存在</text>
</error>
<error>
<code>88009</code>
<msg>reply is not exists</msg>
<text>该回复不存在</text>
</error>
<error>
<code>88010</code>
<msg>count range error. cout <= 0 or count > 50</msg>
<text>获取评论数目不合法</text>
</error>
<error>
<code>90001</code>
<text>未认证摇一摇周边</text>

View File

@ -22,129 +22,186 @@ import com.foxinmy.weixin4j.type.ButtonType;
*/
public class Button implements Serializable {
private static final long serialVersionUID = -6422234732203854866L;
private static final long serialVersionUID = -6422234732203854866L;
/**
* 菜单标题不超过16个字节子菜单不超过40个字节
*/
private String name;
/**
* 菜单类型 </br> <font color="red">
* 公众平台官网上能够设置的菜单类型有viewtextimgphotovideovoice </font>
*
* @see com.foxinmy.weixin4j.type.ButtonType
*/
private ButtonType type;
/**
* 菜单KEY值,根据type的类型而定</p> 通过公众平台设置的自定义菜单</br> <li>text:保存文字 <li>
* imgvoice保存媒体ID <li>video保存视频URL <li>
* news保存图文消息媒体ID <li>view保存链接URL
* <p>
* 使用API设置的自定义菜单
* </p> <li>
* clickscancode_pushscancode_waitmsgpic_sysphotopic_photo_or_album
* pic_weixinlocation_select保存key <li>view保存链接URL; <li>
* media_idview_limited保存媒体ID
*/
private String content;
/**
* 扩展属性比如在公众平台设置菜单时的图文列表
*/
@JSONField(serialize = false, deserialize = false)
private Object extra;
/**
* 二级菜单数组个数应为1~5个
*/
@JSONField(name = "sub_button")
private List<Button> subs;
/**
* 菜单标题不超过16个字节子菜单不超过40个字节
*/
private String name;
/**
* 菜单类型 </br>
* <font color="red"> 公众平台官网上能够设置的菜单类型有viewtextimgphotovideovoice
* </font>
*
* @see com.foxinmy.weixin4j.type.ButtonType
*/
private String type;
/**
* 菜单KEY值,根据type的类型而定
* </p>
* 通过公众平台设置的自定义菜单</br>
* <li>text:保存文字
* <li>imgvoice保存媒体ID
* <li>video保存视频URL
* <li>news保存图文消息媒体ID
* <li>view保存链接URL
* <p>
* 使用API设置的自定义菜单
* </p>
* <li>clickscancode_pushscancode_waitmsgpic_sysphotopic_photo_or_album
* pic_weixinlocation_select保存key
* <li>view保存链接URL;
* <li>media_idview_limited保存媒体ID
*/
private String content;
/**
* 扩展属性比如在公众平台设置菜单时的图文列表
*/
@JSONField(serialize = false, deserialize = false)
private Object extra;
/**
* miniprogram类型必须 小程序的appid仅认证公众号可配置
*/
private String appid;
/**
* miniprogram类型必须 小程序的页面路径
*/
private String pagepath;
protected Button() {
this.subs = new ArrayList<Button>();
}
/**
* 二级菜单数组个数应为1~5个
*/
@JSONField(name = "sub_button")
private List<Button> subs;
/**
* 创建一个具有子菜单的菜单
*
* @param name
* 菜单名
* @param subButtons
* 二级菜单列表
*/
public Button(String name, Button... subButtons) {
this.name = name;
this.subs = new ArrayList<Button>(Arrays.asList(subButtons));
}
protected Button() {
this.subs = new ArrayList<Button>();
}
/**
* 创建一个普通菜单
*
* @param name
* 菜单名
* @param content
* 菜单内容
* @param type
* 菜单类型
*/
public Button(String name, String content, ButtonType type) {
this.name = name;
this.content = content;
this.type = type;
this.subs = new ArrayList<Button>();
}
/**
* 创建一个具有子菜单的菜单
*
* @param name
* 菜单名
* @param subButtons
* 二级菜单列表
*/
public Button(String name, Button... subButtons) {
this.name = name;
this.subs = new ArrayList<Button>(Arrays.asList(subButtons));
}
public String getName() {
return name;
}
/**
* 创建一个普通菜单
*
* @param name
* 菜单名
* @param content
* 菜单内容
* @param type
* 菜单类型
*/
public Button(String name, String content, ButtonType type) {
this.name = name;
this.content = content;
this.type = type.name();
this.subs = new ArrayList<Button>();
}
public void setName(String name) {
this.name = name;
}
/**
* 小程序菜单
*
* @param name
* 菜单名
* @param url
* 小程序的url页面
* @param appid
* 小程序的appid
* @param pagepath
* 小程序员的页面路径
*/
public Button(String name, String url, String appid, String pagepath) {
this.name = name;
this.content = url;
this.appid = appid;
this.pagepath = pagepath;
this.type = ButtonType.miniprogram.name();
this.subs = new ArrayList<Button>();
}
public ButtonType getType() {
return type;
}
public String getName() {
return name;
}
public void setType(ButtonType type) {
this.type = type;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public String getType() {
return type;
}
public void setContent(String content) {
this.content = content;
}
public void setType(String type) {
this.type = type;
}
public Object getExtra() {
return extra;
}
public void setType(ButtonType type) {
this.type = type.name();
}
/**
* 扩展只读属性设置无效
*
* @param extra
*/
public void setExtra(Object extra) {
this.extra = extra;
}
public String getContent() {
return content;
}
public List<Button> getSubs() {
return subs;
}
public void setContent(String content) {
this.content = content;
}
public void setSubs(List<Button> subs) {
this.subs = subs;
}
public Object getExtra() {
return extra;
}
public Button pushSub(Button btn) {
this.subs.add(btn);
return this;
}
/**
* 扩展只读属性设置无效
*
* @param extra
*/
public void setExtra(Object extra) {
this.extra = extra;
}
@Override
public String toString() {
return "Button [name=" + name + ", type=" + type + ", content="
+ content + ", extra=" + extra + ", subs=" + subs + "]";
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getPagepath() {
return pagepath;
}
public void setPagepath(String pagepath) {
this.pagepath = pagepath;
}
public List<Button> getSubs() {
return subs;
}
public void setSubs(List<Button> subs) {
this.subs = subs;
}
public Button pushSub(Button btn) {
this.subs.add(btn);
return this;
}
@Override
public String toString() {
return "Button [name=" + name + ", type=" + type + ", content=" + content + ", extra=" + extra + ", appid="
+ appid + ", pagepath=" + pagepath + ", subs=" + subs + "]";
}
}

View File

@ -8,42 +8,42 @@ import com.alibaba.fastjson.annotation.JSONField;
/**
* 卡券对象
* <p>
* <font color="red">可用于群发消息</font>
* <font color="red">可用于群发消息客服消息</font>
* </p>
*
*
* @className Card
* @author jinyu(foxinmy@gmail.com)
* @date 2015年6月8日
* @since JDK 1.6
* @see
*/
public class Card implements MassTuple {
public class Card implements MassTuple, NotifyTuple {
private static final long serialVersionUID = 6119453633595102147L;
private static final long serialVersionUID = 6119453633595102147L;
@Override
public String getMessageType() {
return "wxcard";
}
@Override
public String getMessageType() {
return "wxcard";
}
/**
* 上传后的微信返回的媒体ID
*/
@JSONField(name = "card_id")
@XmlElement(name = "CardId")
private String cardId;
/**
* 上传后的微信返回的媒体ID
*/
@JSONField(name = "card_id")
@XmlElement(name = "CardId")
private String cardId;
@JSONCreator
public Card(@JSONField(name = "cardId") String cardId) {
this.cardId = cardId;
}
@JSONCreator
public Card(@JSONField(name = "cardId") String cardId) {
this.cardId = cardId;
}
public String getCardId() {
return cardId;
}
public String getCardId() {
return cardId;
}
@Override
public String toString() {
return "Card [cardId=" + cardId + "]";
}
@Override
public String toString() {
return "Card [cardId=" + cardId + "]";
}
}

View File

@ -14,153 +14,196 @@ import com.alibaba.fastjson.annotation.JSONField;
*/
public class MpArticle implements Serializable {
private static final long serialVersionUID = 5583479943661639234L;
private static final long serialVersionUID = 5583479943661639234L;
/**
* 图文消息缩略图的media_id可以在基础支持-上传多媒体文件接口中获得 非空
*/
@JSONField(name = "thumb_media_id")
private String thumbMediaId;
/**
* 图文消息的封面图片的地址(不一定有请关注thumbMediaId)
*/
@JSONField(name = "thumb_url")
private String thumbUrl;
/**
* 图文消息的作者 可为空
*/
private String author;
/**
* 图文消息的标题 非空
*/
private String title;
/**
* 图文页的URL 获取图文消息时群发消息时填写无效
*/
private String url;
/**
* 在图文消息页面点击阅读原文后的页面 可为空
*/
@JSONField(name = "content_source_url")
private String sourceUrl;
/**
* 图文消息页面的内容支持HTML标签 非空
*/
private String content;
/**
* 图文消息的描述 可为空
*/
private String digest;
/**
* 是否显示封面1为显示0为不显示 可为空
*/
@JSONField(name = "show_cover_pic")
private String showCoverPic;
/**
* 图文消息缩略图的media_id可以在基础支持-上传多媒体文件接口中获得 非空
*/
@JSONField(name = "thumb_media_id")
private String thumbMediaId;
/**
* 图文消息的封面图片的地址(不一定有请关注thumbMediaId)
*/
@JSONField(name = "thumb_url")
private String thumbUrl;
/**
* 图文消息的作者 可为空
*/
private String author;
/**
* 图文消息的标题 非空
*/
private String title;
/**
* 图文页的URL 获取图文消息时群发消息时填写无效
*/
private String url;
/**
* 在图文消息页面点击阅读原文后的页面 可为空
*/
@JSONField(name = "content_source_url")
private String sourceUrl;
/**
* 图文消息页面的内容支持HTML标签 非空
*/
private String content;
/**
* 图文消息的描述 可为空
*/
private String digest;
/**
* 是否显示封面1为显示0为不显示 可为空
*/
@JSONField(name = "show_cover_pic")
private String showCoverPic;
/**
* 是否打开评论0不打开1打开
*/
@JSONField(name = "need_open_comment")
private String openComment;
/**
* 是否粉丝才可评论0所有人可评论1粉丝才可评论
*/
@JSONField(name = "only_fans_can_comment")
private String onlyFansCanComment;
protected MpArticle() {
}
protected MpArticle() {
}
/**
* @param thumbMediaId
* 缩略图
* @param title
* 标题
* @param content
* 内容
*/
public MpArticle(String thumbMediaId, String title, String content) {
this.thumbMediaId = thumbMediaId;
this.title = title;
this.content = content;
}
/**
* @param thumbMediaId
* 缩略图
* @param title
* 标题
* @param content
* 内容
*/
public MpArticle(String thumbMediaId, String title, String content) {
this.thumbMediaId = thumbMediaId;
this.title = title;
this.content = content;
}
public String getThumbMediaId() {
return thumbMediaId;
}
public String getThumbMediaId() {
return thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
public String getThumbUrl() {
return thumbUrl;
}
public String getThumbUrl() {
return thumbUrl;
}
public void setThumbUrl(String thumbUrl) {
this.thumbUrl = thumbUrl;
}
public void setThumbUrl(String thumbUrl) {
this.thumbUrl = thumbUrl;
}
public String getAuthor() {
return author;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public void setUrl(String url) {
this.url = url;
}
public String getSourceUrl() {
return sourceUrl;
}
public String getSourceUrl() {
return sourceUrl;
}
public void setSourceUrl(String sourceUrl) {
this.sourceUrl = sourceUrl;
}
public void setSourceUrl(String sourceUrl) {
this.sourceUrl = sourceUrl;
}
public String getContent() {
return content;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public void setContent(String content) {
this.content = content;
}
public String getDigest() {
return digest;
}
public String getDigest() {
return digest;
}
public void setDigest(String digest) {
this.digest = digest;
}
public void setDigest(String digest) {
this.digest = digest;
}
public String getShowCoverPic() {
return showCoverPic;
}
public String getShowCoverPic() {
return showCoverPic;
}
public void setShowCoverPic(String showCoverPic) {
this.showCoverPic = showCoverPic;
}
public void setShowCoverPic(String showCoverPic) {
this.showCoverPic = showCoverPic;
}
public void setShowCoverPic(boolean showCoverPic) {
this.showCoverPic = showCoverPic ? "1" : "0";
}
public void setShowCoverPic(boolean showCoverPic) {
this.showCoverPic = showCoverPic ? "1" : "0";
}
@JSONField(serialize = false)
public boolean getFormatShowCoverPic() {
return this.showCoverPic != null && this.showCoverPic.equals("1");
}
@JSONField(serialize = false)
public boolean getFormatShowCoverPic() {
return this.showCoverPic != null && this.showCoverPic.equals("1");
}
@Override
public String toString() {
return "MpArticle [thumbMediaId=" + thumbMediaId + ", thumbUrl="
+ thumbUrl + ", author=" + author + ", title=" + title
+ ", sourceUrl=" + sourceUrl + ", content=" + content
+ ", url=" + url + ", digest=" + digest + ", showCoverPic="
+ showCoverPic + "]";
}
public void setOpenComment(boolean openComment) {
this.openComment = openComment ? "1" : "0";
}
public String getOpenComment() {
return openComment;
}
public void setOpenComment(String openComment) {
this.openComment = openComment;
}
public String getOnlyFansCanComment() {
return onlyFansCanComment;
}
public void setOnlyFansCanComment(String onlyFansCanComment) {
this.onlyFansCanComment = onlyFansCanComment;
}
@JSONField(serialize = false)
public boolean getFormatOpenComment() {
return this.openComment != null && this.openComment.equals("1");
}
public void setOnlyFansCanComment(boolean onlyFansCanComment) {
this.onlyFansCanComment = onlyFansCanComment ? "1" : "0";
}
@JSONField(serialize = false)
public boolean getFormatOnlyFansCanComment() {
return this.onlyFansCanComment != null && this.onlyFansCanComment.equals("1");
}
@Override
public String toString() {
return "MpArticle [thumbMediaId=" + thumbMediaId + ", thumbUrl=" + thumbUrl + ", author=" + author + ", title="
+ title + ", url=" + url + ", sourceUrl=" + sourceUrl + ", content=" + content + ", digest=" + digest
+ ", showCoverPic=" + showCoverPic + ", openComment=" + openComment + ", onlyFansCanComment="
+ onlyFansCanComment + "]";
}
}

View File

@ -66,9 +66,5 @@ public enum ButtonType {
/**
* 小程序
*/
miniprogram,
/**
* 以下类型请勿使用,在公众平台设置的按钮类型,如果尝试使用API方式创建菜单则会出错
*/
popups,text,img,voice,video,news;
miniprogram;
}

View File

@ -3,129 +3,129 @@
+ 用netty构建http服务器&消息分发
* 2014-10-28
+ 调整`ActionMapping`抽象化
* 2014-10-31
+ `weixin.properties`切分为API调用地址和公众号appid等信息两部分
* 2014-11-03
+ 分离为`weixin-mp-api``weixin-mp-server`两个工程
+ 新增`支付模块`
* 2014-11-06
+ 新增V3版本`退款申请`接口
* 2014-11-08
+ 新增V2版本`退款申请``退款查询``对账单下载`三个接口
+ 新增一个简单的`语义理解`接口
* 2014-11-11
+ 自定义`assembly``weixin4j-base`工程也一起打包(`weixin4j-mp-api-full.jar`)
* 2014-11-15
+ 新增获取`微信服务器IP地址接口`
* 2014-11-16
+ 新增`多客服`接口
* 2014-11-17
+ 新增`冲正``被扫支付`接口
* 2014-12-12
+ 新增设置`模板消息所处行业``获取模板消息ID`接口
* 2014-12-16
+ 调整方法上@see注解的文档说明接口url
+ 新增群发消息预览、状态查询接口
+ 新增多客服添加账号、更新账号、上传头像、删除账号接口
* 2015-01-04
+ 支付模块拆分为V2跟V3,新增WeixinPayProxy类
+ 退款相关类拆分为V2跟V3
+ 新增接口上报接口
* 2015-01-31
+ 新增数据分析接口
* 2015-03-06
+ 新增oauth授权接口
* 2015-03-21
+ 新增群发消息给所有人接口
+ 新增素材管理多个接口
+ 新增多客服会话管理多个接口
* 2015-03-25
+ 根据《微信商户平台文档》修缮[Pay3Api](./src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java)类
* 2015-03-29
+ 单行注释调整为多行文档注释
+ 新增[CouponApi](./src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java)代金券接口
* 2015-04-01
+ 新增[CashApi](./src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java)发红包、企业付款接口
* 2015-04-13
+ 新增WeixinTokenCreator与WeixinJSTicketCreator类
+ 新增用户分组批量移动、删除组别接口
* 2015-04-16
+ **weixin4j-mp-api**: <font color="red">调整[二维码参数](./src/main/java/com/foxinmy/weixin4j/mp/model/QRParameter.java)类</font>
+ **weixin4j-mp-api**: 新增获取[自定义菜单配置、自动回复配置](./src/main/java/com/foxinmy/weixin4j/mp/api/HelperApi.java)接口
* 2015-04-18
+ <font color="red">调整[客服接口](./src/main/java/com/foxinmy/weixin4j/mp/api/CustomApi.java)类的方法名</font>
+ <font color="red">在[二维码接口](./src/main/java/com/foxinmy/weixin4j/mp/api/QRApi.java)类新增获取二维码url方法</font>
* 2015-06-04
+ 新增查询红包接口
* 2015-06-23
+ 新增企业付款查询接口
* 2015-07-04
+ released 1.5.1
* 2015-07-29
+ 新增二维码结果类[QRResult.java](./src/main/java/com/foxinmy/weixin4j/mp/model/QRResult.java)并将二维码接口[QRApi.java](./weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java)名称变更为createQR和createQRFile
+ [Oauth授权](./src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java)跳转的uri在配置文件的属性名改为`oauth_redirect_uri`
* 2015-07-31
@ -135,25 +135,25 @@
* 2015-08-01
+ 新增了群发消息中的上传视频接口
+ 调整群发消息接口返回类型为字符串数组[{msg_id,msg_data_id}]
* 2015-08-09
+ version upgrade to 1.5.2
+ oauth_redirect_uri配置属性名更改为user_oauth_redirect_uri
* 2015-08-13
+ version upgrade to 1.5.3
+ 媒体接口类(MediaApi)查询素材接口调整:去掉offset,count替换为Pageable类
* 2015-09-08
+ 新增批量获取用户信息接口
* 2015-09-11
+ version upgrade to 1.6.0
@ -165,105 +165,109 @@
* 2015-09-21
+ version upgrade to 1.6.2
* 2015-11-09
+ version upgrade to 1.6.3
* 2015-12-10
+ version upgrade to 1.6.4
+ 【特大注意】weixin4j.properties全部的属性名添加`weixin4j`前缀,并用`.`代替原来的`_`
* 2015-12-15
+ version upgrade to 1.6.5
* 2015-12-18
+ 新增个性化菜单接口
+ WeixinProxy.getCustomRecord 参数变更为 Date startTime, Date endTime, Pageable pageable
* 2015-12-25
+ WeixinProxy新增获取appid(getAppId)方法
+ WeixinProxy新增获取jsticket(getJSTicketHolder)方法
+ 私有化WeixinProxy(TokenHolder)构造器
+ 调整WeixinTicketCreator类
* 2015-12-31
+ version upgrade to 1.6.6
* 2016-01-20
+ 新增获取模板和删除模板接口
+ 新增自定义个性化菜单语言信息匹配项
* 2015-02-04
+ version upgrade to 1.6.7
* 2016-04-02
+ version upgrade to 1.6.8
* 2016-04-29
+ weixin4j-mp:新增标签管理API
* 2016-05-07
+ version upgrade to 1.6.9
* 2016-05-30
+ 新增接口调用次数清零接口
* 2016-06-20
+ version upgrade to 1.7.0
* 2016-07-05
+ 初始化开放平台第三方组件TokenCreator
+ 新增第三方组件ComponentApi
* 2016-07-06
+ 新增第三方组件WeixinComponentProxy
* 2016-08-05
+ 新增CardApi:创建卡券接口
* 2016-08-09
+ 新增创建卡券二维码接口
+ version upgrade to 1.7.1
* 2016-10-10
+ version upgrade to 1.7.2
* 2016-11-22
+ 新增黑名单接口
* 2016-12-13
+ version upgrade to 1.7.3
* 2017-01-09
+ 新增批量发红包接口
+ version upgrade to 1.7.4
+ version upgrade to 1.7.4
* 2017-05-19
+ 新增评论管理接口

View File

@ -32,13 +32,15 @@ weixin4j-mp
* TmplApi `模板消息API`
* UserApi `用户管理API`
* TagApi `用户标签管理API`
* ComponentApi `第三方组件API`
* CardApi `卡券API`
* CommentApi `评论API`
[如何使用](https://github.com/foxinmy/weixin4j/wiki)
---------

View File

@ -0,0 +1,240 @@
package com.foxinmy.weixin4j.mp.api;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSON;
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.model.paging.Pageable;
import com.foxinmy.weixin4j.model.paging.Pagedata;
import com.foxinmy.weixin4j.mp.model.ArticleComment;
import com.foxinmy.weixin4j.mp.model.ArticleComment.ArticleCommentType;
import com.foxinmy.weixin4j.token.TokenManager;
/**
* 文章评论API
*
* @className CommentApi
* @author jinyu
* @date May 19, 2017
* @since JDK 1.6
* @see <a href=
* "https://mp.weixin.qq.com/wiki?action=doc&id=mp1494572718_WzHIY&t=0.6758084213658122">图文消息留言管理接口</a>
*/
public class CommentApi extends MpApi {
private final TokenManager tokenManager;
public CommentApi(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
/**
* 打开/关闭已群发文章评论
*
* @param open
* true为打开false为关闭
* @param msgid
* 群发返回的msg_data_id
* @param index
* 多图文时用来指定第几篇图文从0开始不带默认操作该msg_data_id的第一篇图文
* @return 操作结果
* @see {@link MassApi#massByTagId(com.foxinmy.weixin4j.tuple.MassTuple, int)}
* @see {@link MassApi#massByOpenIds(com.foxinmy.weixin4j.tuple.MassTuple, String...)}
* @throws WeixinException
*/
public ApiResult openComment(boolean open, String msgid, int index) throws WeixinException {
String news_comment = open ? getRequestUri("news_comment_open") : getRequestUri("news_comment_close");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("msg_data_id", msgid);
obj.put("index", index);
WeixinResponse response = weixinExecutor.post(String.format(news_comment, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
/**
* 获取评论列表
*
* @param page
* 分页信息
* @param commentType
* 评论类型 为空获取全部类型
* @param msgid
* 群发返回的msg_data_id
* @param index
* 多图文时用来指定第几篇图文从0开始不带默认操作该msg_data_id的第一篇图文
* @return 分页数据
* @see ArticleComment
* @see ArticleCommentType
* @see {@link MassApi#massByTagId(com.foxinmy.weixin4j.tuple.MassTuple, int)}
* @see {@link MassApi#massByOpenIds(com.foxinmy.weixin4j.tuple.MassTuple, String...)}
* @throws WeixinException
*/
public Pagedata<ArticleComment> listArticleComments(Pageable page, ArticleCommentType commentType, String msgid,
int index) throws WeixinException {
String news_comment_list = getRequestUri("news_comment_list");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("msg_data_id", "msgid");
obj.put("index", index);
obj.put("begin", page.getOffset());
obj.put("count", Math.max(50, page.getPageSize())); // 获取数目>=50会被拒绝
if (commentType != null) {
obj.put("type", commentType.ordinal() + 1);
} else {
obj.put("type", 0);
}
WeixinResponse response = weixinExecutor.post(String.format(news_comment_list, token.getAccessToken()),
obj.toJSONString());
JSONObject result = response.getAsJson();
int total = result.getIntValue("total");
List<ArticleComment> content = JSON.parseArray(result.getString("comment"), ArticleComment.class);
return new Pagedata<ArticleComment>(page, total, content);
}
/**
* 获取评论列表
*
* @param commentType
* 评论类型 为空获取全部类型
* @param msgid
* 群发返回的msg_data_id
* @param index
* 多图文时用来指定第几篇图文从0开始不带默认操作该msg_data_id的第一篇图文
* @return 分页数据
* @see #listArticleComments(Pageable, ArticleCommentType, String, int)
* @throws WeixinException
*/
public List<ArticleComment> listAllArticleComments(ArticleCommentType commentType, String msgid, int index)
throws WeixinException {
List<ArticleComment> comments = new ArrayList<ArticleComment>();
Pagedata<ArticleComment> page = null;
Pageable pageable = null;
for (pageable = new Pageable(1, 50);; pageable = pageable.next()) {
page = listArticleComments(pageable, commentType, msgid, index);
if (!page.hasContent()) {
break;
}
comments.addAll(page.getContent());
}
return comments;
}
/**
* 评论标记/取消精选
*
* @param markelect
* true为标记false为取消
* @param msgid
* 群发返回的msg_data_id
* @param index
* 多图文时用来指定第几篇图文从0开始不带默认操作该msg_data_id的第一篇图文
* @param commentId
* 用户评论ID
* @return 操作结果
* @see #listArticleComments(Pageable, ArticleCommentType, String, int)
* @throws WeixinException
*/
public ApiResult markelectComment(boolean markelect, String msgid, int index, String commentId)
throws WeixinException {
String news_comment = markelect ? getRequestUri("news_comment_markelect")
: getRequestUri("news_comment_unmarkelect");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("msg_data_id", "msgid");
obj.put("index", index);
obj.put("user_comment_id", commentId);
WeixinResponse response = weixinExecutor.post(String.format(news_comment, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
/**
* 删除评论
*
* @param msgid
* 群发返回的msg_data_id
* @param index
* 多图文时用来指定第几篇图文从0开始不带默认操作该msg_data_id的第一篇图文
* @param commentId
* 用户评论ID
* @return 操作结果
* @see #listArticleComments(Pageable, ArticleCommentType, String, int)
* @throws WeixinException
*/
public ApiResult deleteComment(String msgid, int index, String commentId) throws WeixinException {
String news_comment_delete = getRequestUri("news_comment_delete");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("msg_data_id", "msgid");
obj.put("index", index);
obj.put("user_comment_id", commentId);
WeixinResponse response = weixinExecutor.post(String.format(news_comment_delete, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
/**
* 回复评论
*
* @param msgid
* 群发返回的msg_data_id
* @param index
* 多图文时用来指定第几篇图文从0开始不带默认操作该msg_data_id的第一篇图文
* @param commentId
* 用户评论ID
* @param content
* 回复内容
* @return 操作结果
* @see #listArticleComments(Pageable, ArticleCommentType, String, int)
* @throws WeixinException
*/
public ApiResult replyComment(String msgid, int index, String commentId, String content) throws WeixinException {
String news_comment_reply = getRequestUri("news_comment_reply_add");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("msg_data_id", "msgid");
obj.put("index", index);
obj.put("user_comment_id", commentId);
obj.put("content", content);
WeixinResponse response = weixinExecutor.post(String.format(news_comment_reply, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
/**
* 删除回复
*
* @param msgid
* 群发返回的msg_data_id
* @param index
* 多图文时用来指定第几篇图文从0开始不带默认操作该msg_data_id的第一篇图文
* @param commentId
* 用户评论ID
* @return 操作结果
* @see #listArticleComments(Pageable, ArticleCommentType, String, int)
* @throws WeixinException
*/
public ApiResult deleteCommentReply(String msgid, int index, String commentId) throws WeixinException {
String news_comment_reply = getRequestUri("news_comment_reply_delete");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("msg_data_id", "msgid");
obj.put("index", index);
obj.put("user_comment_id", commentId);
WeixinResponse response = weixinExecutor.post(String.format(news_comment_reply, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
}

View File

@ -19,7 +19,6 @@ import com.foxinmy.weixin4j.mp.model.SemQuery;
import com.foxinmy.weixin4j.mp.model.SemResult;
import com.foxinmy.weixin4j.token.TokenManager;
import com.foxinmy.weixin4j.tuple.MpArticle;
import com.foxinmy.weixin4j.type.ButtonType;
/**
* 辅助相关API
@ -32,214 +31,193 @@ import com.foxinmy.weixin4j.type.ButtonType;
*/
public class HelperApi extends MpApi {
private final TokenManager tokenManager;
private final TokenManager tokenManager;
public HelperApi(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
public HelperApi(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
/**
* 长链接转短链接
*
* @param url
* 待转换的链接
* @return 短链接
* @throws WeixinException
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433600&token=&lang=zh_CN">长链接转短链接</a>
*/
public String getShorturl(String url) throws WeixinException {
String shorturl_uri = getRequestUri("shorturl_uri");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("action", "long2short");
obj.put("long_url", url);
WeixinResponse response = weixinExecutor.post(
String.format(shorturl_uri, token.getAccessToken()),
obj.toJSONString());
/**
* 长链接转短链接
*
* @param url
* 待转换的链接
* @return 短链接
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433600&token=&lang=zh_CN">长链接转短链接</a>
*/
public String getShorturl(String url) throws WeixinException {
String shorturl_uri = getRequestUri("shorturl_uri");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("action", "long2short");
obj.put("long_url", url);
WeixinResponse response = weixinExecutor.post(String.format(shorturl_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsJson().getString("short_url");
}
return response.getAsJson().getString("short_url");
}
/**
* 语义理解
*
* @param semQuery
* 语义理解协议
* @return 语义理解结果
* @see com.foxinmy.weixin4j.mp.model.SemQuery
* @see com.foxinmy.weixin4j.mp.model.SemResult
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141241&token=&lang=zh_CN">语义理解</a>
* @throws WeixinException
*/
public SemResult semantic(SemQuery semQuery) throws WeixinException {
String semantic_uri = getRequestUri("semantic_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.post(
String.format(semantic_uri, token.getAccessToken()),
semQuery.toJson());
return response.getAsObject(new TypeReference<SemResult>() {
});
}
/**
* 语义理解
*
* @param semQuery
* 语义理解协议
* @return 语义理解结果
* @see com.foxinmy.weixin4j.mp.model.SemQuery
* @see com.foxinmy.weixin4j.mp.model.SemResult
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141241&token=&lang=zh_CN">语义理解</a>
* @throws WeixinException
*/
public SemResult semantic(SemQuery semQuery) throws WeixinException {
String semantic_uri = getRequestUri("semantic_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.post(String.format(semantic_uri, token.getAccessToken()),
semQuery.toJson());
return response.getAsObject(new TypeReference<SemResult>() {
});
}
/**
* 获取微信服务器IP地址
*
* @return IP地址
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140187&token=&lang=zh_CN">获取IP地址</a>
* @throws WeixinException
*/
public List<String> getWechatServerIp() throws WeixinException {
String getcallbackip_uri = getRequestUri("getcallbackip_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(
getcallbackip_uri, token.getAccessToken()));
return JSON.parseArray(response.getAsJson().getString("ip_list"),
String.class);
}
/**
* 获取微信服务器IP地址
*
* @return IP地址
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140187&token=&lang=zh_CN">获取IP地址</a>
* @throws WeixinException
*/
public List<String> getWechatServerIp() throws WeixinException {
String getcallbackip_uri = getRequestUri("getcallbackip_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(getcallbackip_uri, token.getAccessToken()));
return JSON.parseArray(response.getAsJson().getString("ip_list"), String.class);
}
/**
* 获取公众号当前使用的自定义菜单的配置如果公众号是通过API调用设置的菜单则返回菜单的开发配置
* 而如果公众号是在公众平台官网通过网站功能发布菜单则本接口返回运营者设置的菜单配置
*
* @return 菜单配置信息
* @see {@link MenuApi#getMenu()}
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1434698695&token=&lang=zh_CN">获取自定义菜单配置</a>
* @see com.foxinmy.weixin4j.model.Button
* @see com.foxinmy.weixin4j.mp.model.MenuSetting
* @see com.foxinmy.weixin4j.tuple.MpArticle
* @throws WeixinException
*/
public MenuSetting getMenuSetting() throws WeixinException {
String menu_get_selfmenu_uri = getRequestUri("menu_get_selfmenu_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(
menu_get_selfmenu_uri, token.getAccessToken()));
JSONObject result = response.getAsJson();
JSONArray buttons = result.getJSONObject("selfmenu_info").getJSONArray(
"button");
List<Button> buttonList = new ArrayList<Button>(buttons.size());
JSONObject buttonObj = null;
for (int i = 0; i < buttons.size(); i++) {
buttonObj = buttons.getJSONObject(i);
if (buttonObj.containsKey("sub_button")) {
buttonObj.put(
"sub_button",
buttonObj.getJSONObject("sub_button").getJSONArray(
"list"));
buttonObj.put("type", ButtonType.popups);
}
buttonList.add(JSON.parseObject(buttonObj.toJSONString(),
Button.class, ButtonExtraProcessor.global));
}
return new MenuSetting(result.getBooleanValue("is_menu_open"),
buttonList);
}
/**
* 获取公众号当前使用的自定义菜单的配置如果公众号是通过API调用设置的菜单则返回菜单的开发配置
* 而如果公众号是在公众平台官网通过网站功能发布菜单则本接口返回运营者设置的菜单配置
*
* @return 菜单配置信息
* @see {@link MenuApi#getMenu()}
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1434698695&token=&lang=zh_CN">获取自定义菜单配置</a>
* @see com.foxinmy.weixin4j.model.Button
* @see com.foxinmy.weixin4j.mp.model.MenuSetting
* @see com.foxinmy.weixin4j.tuple.MpArticle
* @throws WeixinException
*/
public MenuSetting getMenuSetting() throws WeixinException {
String menu_get_selfmenu_uri = getRequestUri("menu_get_selfmenu_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(menu_get_selfmenu_uri, token.getAccessToken()));
JSONObject result = response.getAsJson();
JSONArray buttons = result.getJSONObject("selfmenu_info").getJSONArray("button");
List<Button> buttonList = new ArrayList<Button>(buttons.size());
JSONObject buttonObj = null;
for (int i = 0; i < buttons.size(); i++) {
buttonObj = buttons.getJSONObject(i);
if (buttonObj.containsKey("sub_button")) {
buttonObj.put("sub_button", buttonObj.getJSONObject("sub_button").getJSONArray("list"));
buttonObj.put("type", "popups");
}
buttonList.add(JSON.parseObject(buttonObj.toJSONString(), Button.class, ButtonExtraProcessor.global));
}
return new MenuSetting(result.getBooleanValue("is_menu_open"), buttonList);
}
private static final class ButtonExtraProcessor implements ExtraProcessor {
private static ButtonExtraProcessor global = new ButtonExtraProcessor();
private static final String KEY = "news_info";
private static final class ButtonExtraProcessor implements ExtraProcessor {
private static ButtonExtraProcessor global = new ButtonExtraProcessor();
private static final String KEY = "news_info";
private ButtonExtraProcessor() {
}
private ButtonExtraProcessor() {
}
@Override
public void processExtra(Object object, String key, Object value) {
if (KEY.equalsIgnoreCase(key)) {
JSONArray news = ((JSONObject) value).getJSONArray("list");
List<MpArticle> newsList = new ArrayList<MpArticle>(news.size());
JSONObject article = null;
for (int i = 0; i < news.size(); i++) {
article = news.getJSONObject(i);
article.put("show_cover_pic", article.remove("show_cover"));
article.put("thumb_url", article.remove("cover_url"));
article.put("url", article.remove("content_url"));
article.put("content_source_url",
article.remove("source_url"));
newsList.add(JSON.toJavaObject(article, MpArticle.class));
}
((Button) object).setExtra(newsList);
} else {
((Button) object).setContent(String.valueOf(value));
}
}
};
@Override
public void processExtra(Object object, String key, Object value) {
if (KEY.equalsIgnoreCase(key)) {
JSONArray news = ((JSONObject) value).getJSONArray("list");
List<MpArticle> newsList = new ArrayList<MpArticle>(news.size());
JSONObject article = null;
for (int i = 0; i < news.size(); i++) {
article = news.getJSONObject(i);
article.put("show_cover_pic", article.remove("show_cover"));
article.put("thumb_url", article.remove("cover_url"));
article.put("url", article.remove("content_url"));
article.put("content_source_url", article.remove("source_url"));
newsList.add(JSON.toJavaObject(article, MpArticle.class));
}
((Button) object).setExtra(newsList);
} else {
((Button) object).setContent(String.valueOf(value));
}
}
};
/**
* 获取公众号当前使用的自动回复规则包括关注后自动回复消息自动回复60分钟内触发一次关键词自动回复
*
* @see com.foxinmy.weixin4j.mp.model.AutoReplySetting
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751299&token=&lang=zh_CN">获取自动回复规则</a>
* @return 自定义回复配置信息
* @throws WeixinException
*/
public AutoReplySetting getAutoReplySetting() throws WeixinException {
String autoreply_setting_get_uri = getRequestUri("autoreply_setting_get_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(
autoreply_setting_get_uri, token.getAccessToken()));
/**
* 获取公众号当前使用的自动回复规则包括关注后自动回复消息自动回复60分钟内触发一次关键词自动回复
*
* @see com.foxinmy.weixin4j.mp.model.AutoReplySetting
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751299&token=&lang=zh_CN">获取自动回复规则</a>
* @return 自定义回复配置信息
* @throws WeixinException
*/
public AutoReplySetting getAutoReplySetting() throws WeixinException {
String autoreply_setting_get_uri = getRequestUri("autoreply_setting_get_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(autoreply_setting_get_uri, token.getAccessToken()));
JSONObject result = response.getAsJson();
JSONObject result = response.getAsJson();
AutoReplySetting replySetting = JSON.toJavaObject(result,
AutoReplySetting.class);
List<AutoReplySetting.Rule> ruleList = null;
if (result.containsKey("keyword_autoreply_info")) {
JSONArray keywordList = result.getJSONObject(
"keyword_autoreply_info").getJSONArray("list");
ruleList = new ArrayList<AutoReplySetting.Rule>(keywordList.size());
JSONObject keywordObj = null;
JSONArray replyList = null;
JSONObject replyObj = null;
for (int i = 0; i < keywordList.size(); i++) {
keywordObj = keywordList.getJSONObject(i);
AutoReplySetting.Rule rule = JSON.toJavaObject(keywordObj,
AutoReplySetting.Rule.class);
replyList = keywordObj.getJSONArray("reply_list_info");
List<AutoReplySetting.Entry> entryList = new ArrayList<AutoReplySetting.Entry>(
replyList.size());
for (int j = 0; j < replyList.size(); j++) {
replyObj = replyList.getJSONObject(j);
if (replyObj.getString("type").equals("news")) {
entryList.add(JSON.parseObject(replyObj.toJSONString(),
AutoReplySetting.Entry.class,
ButtonExtraProcessor.global));
} else {
entryList.add(JSON.toJavaObject(replyObj,
AutoReplySetting.Entry.class));
}
}
rule.setReplyList(entryList);
ruleList.add(rule);
}
}
replySetting.setKeywordReplyList(ruleList);
return replySetting;
}
AutoReplySetting replySetting = JSON.toJavaObject(result, AutoReplySetting.class);
List<AutoReplySetting.Rule> ruleList = null;
if (result.containsKey("keyword_autoreply_info")) {
JSONArray keywordList = result.getJSONObject("keyword_autoreply_info").getJSONArray("list");
ruleList = new ArrayList<AutoReplySetting.Rule>(keywordList.size());
JSONObject keywordObj = null;
JSONArray replyList = null;
JSONObject replyObj = null;
for (int i = 0; i < keywordList.size(); i++) {
keywordObj = keywordList.getJSONObject(i);
AutoReplySetting.Rule rule = JSON.toJavaObject(keywordObj, AutoReplySetting.Rule.class);
replyList = keywordObj.getJSONArray("reply_list_info");
List<AutoReplySetting.Entry> entryList = new ArrayList<AutoReplySetting.Entry>(replyList.size());
for (int j = 0; j < replyList.size(); j++) {
replyObj = replyList.getJSONObject(j);
if (replyObj.getString("type").equals("news")) {
entryList.add(JSON.parseObject(replyObj.toJSONString(), AutoReplySetting.Entry.class,
ButtonExtraProcessor.global));
} else {
entryList.add(JSON.toJavaObject(replyObj, AutoReplySetting.Entry.class));
}
}
rule.setReplyList(entryList);
ruleList.add(rule);
}
}
replySetting.setKeywordReplyList(ruleList);
return replySetting;
}
/**
* 接口调用次数调用清零公众号调用接口并不是无限制的为了防止公众号的程序错误而引发微信服务器负载异常默认情况下
* 每个公众号调用接口都不能超过一定限制
* 当超过一定限制时调用对应接口会收到{"errcode":45009,"errmsg":"api freq out of limit"
* }错误返回码
*
* @param appId
* 公众号ID
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433744592&token=&lang=zh_CN">接口清零</a>
* @return 操作结果
* @throws WeixinException
*/
public ApiResult clearQuota(String appId) throws WeixinException {
String clearquota_uri = getRequestUri("clearquota_uri");
String body = String.format("{\"appid\":\"%s\"}", appId);
WeixinResponse response = weixinExecutor.post(
String.format(clearquota_uri, tokenManager.getAccessToken()),
body);
return response.getAsResult();
}
/**
* 接口调用次数调用清零公众号调用接口并不是无限制的为了防止公众号的程序错误而引发微信服务器负载异常默认情况下
* 每个公众号调用接口都不能超过一定限制 当超过一定限制时调用对应接口会收到{"errcode":45009,"errmsg":"api freq
* out of limit" }错误返回码。
*
* @param appId
* 公众号ID
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433744592&token=&lang=zh_CN">接口清零</a>
* @return 操作结果
* @throws WeixinException
*/
public ApiResult clearQuota(String appId) throws WeixinException {
String clearquota_uri = getRequestUri("clearquota_uri");
String body = String.format("{\"appid\":\"%s\"}", appId);
WeixinResponse response = weixinExecutor.post(String.format(clearquota_uri, tokenManager.getAccessToken()),
body);
return response.getAsResult();
}
}

View File

@ -19,7 +19,7 @@ import com.foxinmy.weixin4j.util.StringUtil;
/**
* 群发相关API
*
*
* @className MassApi
* @author jinyu(foxinmy@gmail.com)
* @date 2014年9月25日
@ -27,374 +27,386 @@ import com.foxinmy.weixin4j.util.StringUtil;
*/
public class MassApi extends MpApi {
private final TokenManager tokenManager;
private final TokenManager tokenManager;
public MassApi(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
public MassApi(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
/**
* 上传图文消息,一个图文消息支持1到10条图文</br> <font
* color="red">具备微信支付权限的公众号在使用高级群发接口上传群发图文消息类型时可使用&lta&gt标签加入外链</font>
*
* @param articles
* 图片消息
* @return 媒体ID
* @throws WeixinException
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">上传图文素材</a>
* @see com.foxinmy.weixin4j.tuple.MpArticle
*/
public String uploadArticle(List<MpArticle> articles)
throws WeixinException {
String article_upload_uri = getRequestUri("article_upload_uri");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("articles", articles);
WeixinResponse response = weixinExecutor.post(
String.format(article_upload_uri, token.getAccessToken()),
obj.toJSONString());
/**
* 上传图文消息,一个图文消息支持1到10条图文</br>
* <font color=
* "red">具备微信支付权限的公众号在使用高级群发接口上传群发图文消息类型时可使用&lta&gt标签加入外链</font>
*
* @param articles
* 图片消息
* @return 媒体ID
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">上传图文素材</a>
* @see com.foxinmy.weixin4j.tuple.MpArticle
*/
public String uploadArticle(List<MpArticle> articles) throws WeixinException {
String article_upload_uri = getRequestUri("article_upload_uri");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("articles", articles);
WeixinResponse response = weixinExecutor.post(String.format(article_upload_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsJson().getString("media_id");
}
return response.getAsJson().getString("media_id");
}
/**
* 分组群发
* <p>
* 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息,
* 如消息有时会进行审核服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕
* </p>
*
* @param tuple
* 消息元件
* @param isToAll
* 用于设定是否向全部用户发送值为true或false选择true该消息群发给所有用户
* 选择false可根据group_id发送给指定群组的用户
* @param groupId
* 分组ID
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现,可以用于在图文分析数据接口中
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.Group
* @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 GroupApi#getGroups()}
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据分组群发</a>
*/
@Deprecated
public String[] massByGroupId(MassTuple tuple, boolean isToAll, int groupId)
throws WeixinException {
if (tuple instanceof MpNews) {
MpNews _news = (MpNews) tuple;
List<MpArticle> _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("group_id", groupId);
}
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());
/**
* 分组群发
* <p>
* 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息,
* 如消息有时会进行审核服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕
* </p>
*
* @param tuple
* 消息元件
* @param isToAll
* 用于设定是否向全部用户发送值为true或false选择true该消息群发给所有用户
* 选择false可根据group_id发送给指定群组的用户
* @param groupId
* 分组ID
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现,可以用于在图文分析数据接口中
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.Group
* @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 GroupApi#getGroups()}
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据分组群发</a>
*/
@Deprecated
public String[] massByGroupId(MassTuple tuple, boolean isToAll, int groupId) throws WeixinException {
if (tuple instanceof MpNews) {
MpNews _news = (MpNews) tuple;
List<MpArticle> _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("group_id", groupId);
}
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") };
}
obj = response.getAsJson();
return new String[] { obj.getString("msg_id"), obj.getString("msg_data_id") };
}
/**
* 分组ID群发图文消息
*
* @param articles
* 图文列表
* @param groupId
* 分组ID
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据分组群发</a>
* @see {@link #massByGroupId(Tuple,int)}
* @see com.foxinmy.weixin4j.tuple.MpArticle
* @throws WeixinException
*/
@Deprecated
public String[] massArticleByGroupId(List<MpArticle> articles, int groupId)
throws WeixinException {
String mediaId = uploadArticle(articles);
return massByGroupId(new MpNews(mediaId), false, groupId);
}
/**
* 分组ID群发图文消息
*
* @param articles
* 图文列表
* @param groupId
* 分组ID
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据分组群发</a>
* @see {@link #massByGroupId(Tuple,int)}
* @see com.foxinmy.weixin4j.tuple.MpArticle
* @throws WeixinException
*/
@Deprecated
public String[] massArticleByGroupId(List<MpArticle> articles, int groupId) throws WeixinException {
String mediaId = uploadArticle(articles);
return massByGroupId(new MpNews(mediaId), false, groupId);
}
/**
* 标签群发
* <p>
* 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息,
* 如消息有时会进行审核服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕
* </p>
*
* @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 <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据标签群发</a>
*/
public String[] massByTagId(MassTuple tuple, boolean isToAll, int tagId)
throws WeixinException {
if (tuple instanceof MpNews) {
MpNews _news = (MpNews) tuple;
List<MpArticle> _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());
/**
* 群发消息
* <p>
* 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息,
* 如消息有时会进行审核服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕
* </p>
*
* @param tuple
* 消息元件
* @param filter
* 过滤条件
* @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
*/
private String[] mass(MassTuple tuple, JSONObject filter) throws WeixinException {
if (tuple instanceof MpNews) {
MpNews _news = (MpNews) tuple;
List<MpArticle> _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));
}
if (!filter.containsKey("send_ignore_reprint")) {
filter.put("send_ignore_reprint", 0);
}
}
String msgtype = tuple.getMessageType();
JSONObject obj = new JSONObject();
obj.putAll(filter);
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") };
}
obj = response.getAsJson();
return new String[] { obj.getString("msg_id"), obj.getString("msg_data_id") };
}
/**
* 标签群发图文消息
*
* @param articles
* 图文列表
* @param tagId
* 标签ID
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据标签群发</a>
* @see {@link #massByTagId(Tuple,int)}
* @see com.foxinmy.weixin4j.tuple.MpArticle
* @throws WeixinException
*/
public String[] massArticleByTagId(List<MpArticle> articles, int tagId)
throws WeixinException {
String mediaId = uploadArticle(articles);
return massByTagId(new MpNews(mediaId), false, tagId);
}
/**
* 群发消息给所有粉丝
*
* @param tuple
* 消息元件
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现,可以用于在图文分析数据接口中
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据标签群发</a>
*/
public String[] massToAll(MassTuple tuple) throws WeixinException {
String filter = String.format("{\"filter\":{\"is_to_all\":true}}");
return mass(tuple, JSON.parseObject(filter));
}
/**
* openId群发
*
* @param tuple
* 消息元件
* @param openIds
* openId列表
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现,可以用于在图文分析数据接口中
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.User
* @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 <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据openid群发</a>
* @see {@link UserApi#getUser(String)}
*/
public String[] massByOpenIds(MassTuple tuple, String... openIds)
throws WeixinException {
if (tuple instanceof MpNews) {
MpNews _news = (MpNews) tuple;
List<MpArticle> _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();
obj.put("touser", openIds);
obj.put(msgtype, JSON.toJSON(tuple));
obj.put("msgtype", msgtype);
String mass_openid_uri = getRequestUri("mass_openid_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.post(
String.format(mass_openid_uri, token.getAccessToken()),
obj.toJSONString());
/**
* 标签群发消息
*
* @param tuple
* 消息元件
* @param tagId
* 标签ID
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现,可以用于在图文分析数据接口中
* @throws WeixinException
* @see Tag
* @see {@link TagApi#listTags()}
* @see #mass(MassTuple, JSONObject, boolean)
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据标签群发</a>
*/
public String[] massByTagId(MassTuple tuple, int tagId) throws WeixinException {
String filter = String.format("{\"filter\":{\"is_to_all\":false,\"tag_id\":%d}}", tagId);
return mass(tuple, JSON.parseObject(filter));
}
obj = response.getAsJson();
return new String[] { obj.getString("msg_id"),
obj.getString("msg_data_id") };
}
/**
* 标签群发图文消息
*
* @param articles
* 图文列表
* @param tagId
* 标签ID
* @param ignoreReprint
* 图文消息被判定为转载时是否继续群发
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据标签群发</a>
* @see {@link #massByTagId(Tuple,int)}
* @see com.foxinmy.weixin4j.tuple.MpArticle
* @throws WeixinException
*/
public String[] massArticleByTagId(List<MpArticle> articles, int tagId, boolean ignoreReprint)
throws WeixinException {
String mediaId = uploadArticle(articles);
String text = String.format("{\"filter\":{\"is_to_all\":false,\"tag_id\":%d}}", tagId);
JSONObject filter = JSON.parseObject(text);
filter.put("send_ignore_reprint", ignoreReprint ? 1 : 0);
return mass(new MpNews(mediaId), filter);
}
/**
* 根据openid群发图文消息
*
* @param articles
* 图文列表
* @param openIds
* openId列表
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现,可以用于在图文分析数据接口中.
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据openid群发</a>
* @see {@link #massByOpenIds(Tuple,String...)}
* @see com.foxinmy.weixin4j.tuple.MpArticle
* @throws WeixinException
*/
public String[] massArticleByOpenIds(List<MpArticle> articles,
String... openIds) throws WeixinException {
String mediaId = uploadArticle(articles);
return massByOpenIds(new MpNews(mediaId), openIds);
}
/**
* openId群发消息
*
* @param tuple
* 消息元件
* @param openIds
* openId列表
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现,可以用于在图文分析数据接口中
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据openid群发</a>
* @see {@link UserApi#getUser(String)}
* @see #mass(MassTuple, JSONObject, boolean)
*/
public String[] massByOpenIds(MassTuple tuple, String... openIds) throws WeixinException {
JSONObject filter = new JSONObject();
filter.put("touser", openIds);
return mass(tuple, filter);
}
/**
* 删除群发消息
* <p>
* 请注意,只有已经发送成功的消息才能删除删除消息只是将消息的图文详情页失效,已经收到的用户,还是能在其本地看到消息卡片
* </p>
*
* @param msgid
* 发送出去的消息ID
* @throws WeixinException
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">删除群发</a>
* @see {@link #massByTagId(Tuple, int)}
* @see {@link #massByOpenIds(Tuple, String...)
/**
* openid群发图文消息
*
* @param articles
* 图文列表
* @param ignoreReprint
* 图文消息被判定为转载时是否继续群发
* @param openIds
* openId列表
* @return 第一个元素为消息发送任务的ID,第二个元素为消息的数据ID该字段只有在群发图文消息时才会出现,可以用于在图文分析数据接口中.
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">根据openid群发</a>
* @see {@link #massByOpenIds(Tuple,String...)}
* @see com.foxinmy.weixin4j.tuple.MpArticle
* @throws WeixinException
*/
public String[] massArticleByOpenIds(List<MpArticle> articles, boolean ignoreReprint, String... openIds)
throws WeixinException {
String mediaId = uploadArticle(articles);
JSONObject filter = new JSONObject();
filter.put("touser", openIds);
filter.put("send_ignore_reprint", ignoreReprint ? 1 : 0);
return mass(new MpNews(mediaId), filter);
}
*/
public ApiResult deleteMassNews(String msgid) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("msgid", msgid);
String mass_delete_uri = getRequestUri("mass_delete_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.post(
String.format(mass_delete_uri, token.getAccessToken()),
obj.toJSONString());
/**
* 删除群发消息
*
* @param msgid
* 发送出去的消息ID
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">删除群发</a>
* @see #deleteMassNews(String, int)
*/
public ApiResult deleteMassNews(String msgid) throws WeixinException {
return deleteMassNews(msgid, 0);
}
return response.getAsResult();
}
/**
* 删除群发消息
* <p>
* 请注意,只有已经发送成功的消息才能删除删除消息只是将消息的图文详情页失效,已经收到的用户,还是能在其本地看到消息卡片
* </p>
*
* @param msgid
* 发送出去的消息ID
* @param articleIndex
* 要删除的文章在图文消息中的位置第一篇编号为1该字段不填或填0会删除全部文章
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">删除群发</a>
* @see {@link #massByTagId(Tuple, int)}
* @see {@link #massByOpenIds(Tuple, String...)
*
*/
public ApiResult deleteMassNews(String msgid, int articleIndex) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("msgid", msgid);
if (articleIndex > 0)
obj.put("article_idx", articleIndex);
String mass_delete_uri = getRequestUri("mass_delete_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.post(String.format(mass_delete_uri, token.getAccessToken()),
obj.toJSONString());
/**
* 预览群发消息</br> 开发者可通过该接口发送消息给指定用户在手机端查看消息的样式和排版
*
* @param toUser
* 接收用户的openID
* @param toWxName
* 接收用户的微信号 towxname和touser同时赋值时以towxname优先
* @param tuple
* 消息元件
* @return 处理结果
* @throws WeixinException
* @see com.foxinmy.weixin4j.tuple.MassTuple
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">预览群发消息</a>
*/
public ApiResult previewMassNews(String toUser, String toWxName,
MassTuple tuple) throws WeixinException {
String msgtype = tuple.getMessageType();
JSONObject obj = new JSONObject();
obj.put("touser", toUser);
obj.put("towxname", toWxName);
obj.put(msgtype, JSON.toJSON(tuple));
obj.put("msgtype", msgtype);
String mass_preview_uri = getRequestUri("mass_preview_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.post(
String.format(mass_preview_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
return response.getAsResult();
}
/**
* 预览群发消息</br>
* 开发者可通过该接口发送消息给指定用户在手机端查看消息的样式和排版
*
* @param toUser
* 接收用户的openID
* @param toWxName
* 接收用户的微信号 towxname和touser同时赋值时以towxname优先
* @param tuple
* 消息元件
* @return 处理结果
* @throws WeixinException
* @see com.foxinmy.weixin4j.tuple.MassTuple
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">预览群发消息</a>
*/
public ApiResult previewMassNews(String toUser, String toWxName, MassTuple tuple) throws WeixinException {
String msgtype = tuple.getMessageType();
JSONObject obj = new JSONObject();
obj.put("touser", toUser);
obj.put("towxname", toWxName);
obj.put(msgtype, JSON.toJSON(tuple));
obj.put("msgtype", msgtype);
String mass_preview_uri = getRequestUri("mass_preview_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.post(String.format(mass_preview_uri, token.getAccessToken()),
obj.toJSONString());
/**
* 查询群发发送状态
*
* @param msgId
* 消息ID
* @return 消息发送状态,如sendsuccess:发送成功sendfail:发送失败
* @throws WeixinException
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">查询群发状态</a>
*/
public String getMassNewStatus(String msgId) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("msg_id", msgId);
String mass_get_uri = getRequestUri("mass_get_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.post(
String.format(mass_get_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
String status = response.getAsJson().getString("msg_status");
String desc = massStatusMap.get(status);
return String.format("%s:%s", status, desc);
}
/**
* 查询群发发送状态
*
* @param msgId
* 消息ID
* @return 消息发送状态,如sendsuccess:发送成功sendfail:发送失败
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN">查询群发状态</a>
*/
public String getMassNewStatus(String msgId) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("msg_id", msgId);
String mass_get_uri = getRequestUri("mass_get_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.post(String.format(mass_get_uri, token.getAccessToken()),
obj.toJSONString());
private final static Map<String, String> massStatusMap;
static {
massStatusMap = new HashMap<String, String>();
massStatusMap.put("sendsuccess", "发送成功");
massStatusMap.put("send_success", "发送成功");
massStatusMap.put("success", "发送成功");
massStatusMap.put("send success", "发送成功");
massStatusMap.put("sendfail", "发送失败");
massStatusMap.put("send_fail", "发送失败");
massStatusMap.put("fail", "发送失败");
massStatusMap.put("send fail", "发送失败");
massStatusMap.put("err(10001)", "涉嫌广告");
massStatusMap.put("err(20001)", "涉嫌政治");
massStatusMap.put("err(20004)", "涉嫌社会");
massStatusMap.put("err(20006)", "涉嫌违法犯罪");
massStatusMap.put("err(20008)", "涉嫌欺诈");
massStatusMap.put("err(20013)", "涉嫌版权");
massStatusMap.put("err(22000)", "涉嫌互推(互相宣传)");
massStatusMap.put("err(21000)", "涉嫌其他");
}
String status = response.getAsJson().getString("msg_status");
String desc = massStatusMap.get(status);
return String.format("%s:%s", status, desc);
}
private final static Map<String, String> massStatusMap;
static {
massStatusMap = new HashMap<String, String>();
massStatusMap.put("sendsuccess", "发送成功");
massStatusMap.put("send_success", "发送成功");
massStatusMap.put("success", "发送成功");
massStatusMap.put("send success", "发送成功");
massStatusMap.put("sendfail", "发送失败");
massStatusMap.put("send_fail", "发送失败");
massStatusMap.put("fail", "发送失败");
massStatusMap.put("send fail", "发送失败");
massStatusMap.put("err(10001)", "涉嫌广告");
massStatusMap.put("err(20001)", "涉嫌政治");
massStatusMap.put("err(20004)", "涉嫌社会");
massStatusMap.put("err(20006)", "涉嫌违法犯罪");
massStatusMap.put("err(20008)", "涉嫌欺诈");
massStatusMap.put("err(20013)", "涉嫌版权");
massStatusMap.put("err(22000)", "涉嫌互推(互相宣传)");
massStatusMap.put("err(21000)", "涉嫌其他");
}
}

View File

@ -21,7 +21,7 @@ import com.foxinmy.weixin4j.type.ButtonType;
/**
* 菜单相关API
*
*
* @className MenuApi
* @author jinyu(foxinmy@gmail.com)
* @date 2014年9月25日
@ -29,216 +29,203 @@ import com.foxinmy.weixin4j.type.ButtonType;
*/
public class MenuApi extends MpApi {
private final TokenManager tokenManager;
private final TokenManager tokenManager;
public MenuApi(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
public MenuApi(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
/**
* 自定义菜单
*
* @param buttons
* 菜单列表
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN">
* 创建自定义菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @return 处理结果
*/
public ApiResult createMenu(List<Button> buttons) throws WeixinException {
String menu_create_uri = getRequestUri("menu_create_uri");
JSONObject obj = new JSONObject();
obj.put("button", buttons);
return createMenu0(menu_create_uri, obj).getAsResult();
}
/**
* 自定义菜单
*
* @param buttons
* 菜单列表
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN">
* 创建自定义菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @return 处理结果
*/
public ApiResult createMenu(List<Button> buttons) throws WeixinException {
String menu_create_uri = getRequestUri("menu_create_uri");
JSONObject obj = new JSONObject();
obj.put("button", buttons);
return createMenu0(menu_create_uri, obj).getAsResult();
}
private WeixinResponse createMenu0(String url, JSONObject data)
throws WeixinException {
return weixinExecutor.post(
String.format(url, tokenManager.getAccessToken()),
JSON.toJSONString(data, new NameFilter() {
@Override
public String process(Object object, String name,
Object value) {
if (object instanceof Button && name.equals("content")) {
ButtonType buttonType = ((Button) object).getType();
if (buttonType != null) {
if (ButtonType.view == buttonType) {
return "url";
} else if (ButtonType.media_id == buttonType
|| ButtonType.view_limited == buttonType) {
return "media_id";
} else {
return "key";
}
}
}
return name;
}
}));
private WeixinResponse createMenu0(String url, JSONObject data) throws WeixinException {
return weixinExecutor.post(String.format(url, tokenManager.getAccessToken()),
JSON.toJSONString(data, new NameFilter() {
@Override
public String process(Object object, String name, Object value) {
if (object instanceof Button && name.equals("content")) {
ButtonType buttonType = ButtonType.valueOf(((Button) object).getType());
if (buttonType != null) {
if (ButtonType.view == buttonType || ButtonType.miniprogram == buttonType) {
return "url";
} else if (ButtonType.media_id == buttonType || ButtonType.view_limited == buttonType) {
return "media_id";
} else {
return "key";
}
}
}
return name;
}
}));
}
}
/**
* 查询菜单
*
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN">
* 查询菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @return 菜单集合
*/
public List<Button> getMenu() throws WeixinException {
return buttonsConvertor(getMenu0().getJSONObject("menu"));
}
/**
* 查询菜单
*
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN">
* 查询菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @return 菜单集合
*/
public List<Button> getMenu() throws WeixinException {
return buttonsConvertor(getMenu0().getJSONObject("menu"));
}
private JSONObject getMenu0() throws WeixinException {
String menu_get_uri = getRequestUri("menu_get_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(
menu_get_uri, token.getAccessToken()));
return response.getAsJson();
}
private JSONObject getMenu0() throws WeixinException {
String menu_get_uri = getRequestUri("menu_get_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(menu_get_uri, token.getAccessToken()));
return response.getAsJson();
}
/**
* 查询全部菜单(包含个性化菜单)
*
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN">
* 普通菜单</a>
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN">
* 个性化菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @see com.foxinmy.weixin4j.mp.model.Menu
* @return 菜单集合
*/
public List<Menu> getAllMenu() throws WeixinException {
JSONObject response = getMenu0();
List<Menu> menus = new ArrayList<Menu>();
// 普通菜单
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)));
}
}
return menus;
}
/**
* 查询全部菜单(包含个性化菜单)
*
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN">
* 普通菜单</a>
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN">
* 个性化菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @see com.foxinmy.weixin4j.mp.model.Menu
* @return 菜单集合
*/
public List<Menu> getAllMenu() throws WeixinException {
JSONObject response = getMenu0();
List<Menu> menus = new ArrayList<Menu>();
// 普通菜单
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)));
}
}
return menus;
}
/**
* 删除菜单
*
* @return 处理结果
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN">
* 删除菜单</a>
* @return 处理结果
*/
public ApiResult deleteMenu() throws WeixinException {
String menu_delete_uri = getRequestUri("menu_delete_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(
menu_delete_uri, token.getAccessToken()));
/**
* 删除菜单
*
* @return 处理结果
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN">
* 删除菜单</a>
* @return 处理结果
*/
public ApiResult deleteMenu() throws WeixinException {
String menu_delete_uri = getRequestUri("menu_delete_uri");
Token token = tokenManager.getCache();
WeixinResponse response = weixinExecutor.get(String.format(menu_delete_uri, token.getAccessToken()));
return response.getAsResult();
}
return response.getAsResult();
}
/**
* 创建个性化菜单
*
* @param buttons
* 菜单列表
* @param matchRule
* 匹配规则 至少要有一个匹配信息是不为空
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN">
* 创建个性化菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @return 菜单ID
*/
public String createCustomMenu(List<Button> 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).getAsJson()
.getString("menuid");
}
/**
* 创建个性化菜单
*
* @param buttons
* 菜单列表
* @param matchRule
* 匹配规则 至少要有一个匹配信息是不为空
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN">
* 创建个性化菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @return 菜单ID
*/
public String createCustomMenu(List<Button> 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).getAsJson().getString("menuid");
}
/**
* 删除个性化菜单
*
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN">
* 删除个性化菜单</a>
* @return 处理结果
*/
public ApiResult deleteCustomMenu(String menuId) throws WeixinException {
String menu_delete_uri = getRequestUri("menu_delete_custom_uri");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("menuid", menuId);
WeixinResponse response = weixinExecutor.post(
String.format(menu_delete_uri, token.getAccessToken()),
obj.toJSONString());
/**
* 删除个性化菜单
*
* @throws WeixinException
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN">
* 删除个性化菜单</a>
* @return 处理结果
*/
public ApiResult deleteCustomMenu(String menuId) throws WeixinException {
String menu_delete_uri = getRequestUri("menu_delete_custom_uri");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("menuid", menuId);
WeixinResponse response = weixinExecutor.post(String.format(menu_delete_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
return response.getAsResult();
}
/**
* 测试个性化菜单匹配结果
*
* @param userId
* 可以是粉丝的OpenID也可以是粉丝的微信号
* @return 匹配到的菜单配置
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN">
* 测试个性化菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @throws WeixinException
*/
public List<Button> matchCustomMenu(String userId) throws WeixinException {
String menu_trymatch_uri = getRequestUri("menu_trymatch_uri");
Token token = tokenManager.getCache();
JSONObject obj = new JSONObject();
obj.put("user_id", userId);
WeixinResponse response = weixinExecutor.post(
String.format(menu_trymatch_uri, token.getAccessToken()),
obj.toJSONString());
/**
* 测试个性化菜单匹配结果
*
* @param userId
* 可以是粉丝的OpenID也可以是粉丝的微信号
* @return 匹配到的菜单配置
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN">
* 测试个性化菜单</a>
* @see com.foxinmy.weixin4j.model.Button
* @throws WeixinException
*/
public List<Button> matchCustomMenu(String userId) throws WeixinException {
String menu_trymatch_uri = getRequestUri("menu_trymatch_uri");
Token token = tokenManager.getCache();
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"));
}
return buttonsConvertor(response.getAsJson().getJSONObject("menu"));
}
private final ParseProcess buttonProcess = new ExtraProcessor() {
@Override
public void processExtra(Object object, String key, Object value) {
((Button) object).setContent(String.valueOf(value));
}
};
private final ParseProcess buttonProcess = new ExtraProcessor() {
@Override
public void processExtra(Object object, String key, Object value) {
((Button) object).setContent(String.valueOf(value));
}
};
private List<Button> buttonsConvertor(JSONObject menu) {
JSONArray buttons = menu.getJSONArray("button");
List<Button> buttonList = new ArrayList<Button>(buttons.size());
for (int i = 0; i < buttons.size(); i++) {
buttonList.add(JSON.parseObject(buttons.getString(i), Button.class,
buttonProcess));
}
return buttonList;
}
private List<Button> buttonsConvertor(JSONObject menu) {
JSONArray buttons = menu.getJSONArray("button");
List<Button> buttonList = new ArrayList<Button>(buttons.size());
for (int i = 0; i < buttons.size(); i++) {
buttonList.add(JSON.parseObject(buttons.getString(i), Button.class, buttonProcess));
}
return buttonList;
}
}

View File

@ -238,4 +238,23 @@ shake_around_device_update_uri={api_base_url}/shakearound/device/update?access_t
#\u6447\u4e00\u6447\u5468\u8fb9-\u67e5\u8be2\u8bbe\u5907\u5217\u8868
shake_around_device_search_uri={api_base_url}/shakearound/device/search?access_token=%s
#\u6447\u4e00\u6447\u5468\u8fb9-\u83b7\u53d6\u8bbe\u5907\u548c\u7528\u6237\u4fe1\u606f
shake_around_user_get_shake_info={api_base_url}/shakearound/user/getshakeinfo?access_token=%s
shake_around_user_get_shake_info={api_base_url}/shakearound/user/getshakeinfo?access_token=%s
# \u6253\u5f00\u5df2\u7fa4\u53d1\u6587\u7ae0\u8bc4\u8bba
news_comment_open={api_cgi_url}/comment/open?access_token=%s
# \u5173\u95ed\u5df2\u7fa4\u53d1\u6587\u7ae0\u8bc4\u8bba
news_comment_open={api_cgi_url}/comment/close?access_token=%s
# \u5c06\u8bc4\u8bba\u6807\u8bb0\u7cbe\u9009
news_comment_markelect={api_cgi_url}/comment/markelect?access_token=%s
# \u5c06\u8bc4\u8bba\u53d6\u6d88\u7cbe\u9009
news_comment_unmarkelect={api_cgi_url}/comment/unmarkelect?access_token=%s
# \u5220\u9664\u8bc4\u8bba
news_comment_delete={api_cgi_url}/comment/delete?access_token=%s
# \u56de\u590d\u8bc4\u8bba
news_comment_reply_add={api_cgi_url}/comment/reply/add?access_token=%s
# \u5220\u9664\u56de\u590d
news_comment_reply_delete={api_cgi_url}/comment/reply/delete?access_token=%s
# \u83b7\u53d6\u8bc4\u8bba
news_comment_list={api_cgi_url}/comment/list?access_token=%s

View File

@ -0,0 +1,22 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
/**
* 文章评论
*
* @className ArticleComment
* @author jinyu
* @date May 19, 2017
* @since JDK 1.6
* @see
*/
public class ArticleComment implements Serializable {
private static final long serialVersionUID = -8506024679132313314L;
public enum ArticleCommentType {
GENERAL, // 普通评论
MARKELECT // 精选评论
}
}

View File

@ -21,7 +21,7 @@ import com.foxinmy.weixin4j.tuple.Text;
/**
* 群发消息
*
*
* @className MpNewsTest
* @author jinyu(foxinmy@gmail.com)
* @date 2014年4月27日
@ -29,78 +29,72 @@ import com.foxinmy.weixin4j.tuple.Text;
* @see
*/
public class MassTest extends TokenTest {
private MassApi massApi;
private MediaApi mediaApi;
private MassApi massApi;
private MediaApi mediaApi;
@Before
public void init() {
this.massApi = new MassApi(tokenManager);
this.mediaApi = new MediaApi(tokenManager);
}
@Before
public void init() {
this.massApi = new MassApi(tokenManager);
this.mediaApi = new MediaApi(tokenManager);
}
@Test
public void uploadArticle() throws IOException, WeixinException {
List<MpArticle> articles = new ArrayList<MpArticle>();
File file = new File("/tmp/test.jpg");
MediaUploadResult mediaResult = mediaApi.uploadMedia(false,
new FileInputStream(file), file.getName());
articles.add(new MpArticle(mediaResult.getMediaId(), "title", "content"));
massApi.uploadArticle(articles);
}
@Test
public void uploadArticle() throws IOException, WeixinException {
List<MpArticle> articles = new ArrayList<MpArticle>();
File file = new File("/tmp/test.jpg");
MediaUploadResult mediaResult = mediaApi.uploadMedia(false, new FileInputStream(file), file.getName());
articles.add(new MpArticle(mediaResult.getMediaId(), "title", "content"));
massApi.uploadArticle(articles);
}
@Test
public void massByGroupId() throws WeixinException {
String[] msgId = massApi.massByGroupId(new Image("mediaId"), true, 0);
Assert.assertTrue(msgId[0] != null);
}
@Test
public void massByGroupId() throws WeixinException {
String[] msgId = massApi.massByGroupId(new Image("mediaId"), true, 0);
Assert.assertTrue(msgId[0] != null);
}
@Test
public void massByOpenIds() throws WeixinException {
String[] msgId = massApi.massByOpenIds(new Text("HI"),
"oyFLst1bqtuTcxK-ojF8hOGtLQao");
Assert.assertTrue(msgId[0] != null);
}
@Test
public void massByOpenIds() throws WeixinException {
String[] msgId = massApi.massByOpenIds(new Text("HI"), "oyFLst1bqtuTcxK-ojF8hOGtLQao");
Assert.assertTrue(msgId[0] != null);
}
@Test
public void massArticleByGroup() throws IOException, WeixinException {
List<MpArticle> articles = new ArrayList<MpArticle>();
File file = new File("/tmp/test.jpg");
MediaUploadResult mediaResult = mediaApi.uploadMedia(false,
new FileInputStream(file), file.getName());
articles.add(new MpArticle(mediaResult.getMediaId(), "title", "content"));
String[] massId = massApi.massArticleByGroupId(articles, 0);
Assert.assertTrue(massId[0] != null);
}
@Test
public void massArticleByGroup() throws IOException, WeixinException {
List<MpArticle> articles = new ArrayList<MpArticle>();
File file = new File("/tmp/test.jpg");
MediaUploadResult mediaResult = mediaApi.uploadMedia(false, new FileInputStream(file), file.getName());
articles.add(new MpArticle(mediaResult.getMediaId(), "title", "content"));
String[] massId = massApi.massArticleByGroupId(articles, 0);
Assert.assertTrue(massId[0] != null);
}
@Test
public void massArticleByOpenIds() throws IOException, WeixinException {
List<MpArticle> articles = new ArrayList<MpArticle>();
File file = new File("/tmp/test.jpg");
MediaUploadResult mediaResult = mediaApi.uploadMedia(false,
new FileInputStream(file), file.getName());
articles.add(new MpArticle(mediaResult.getMediaId(), "title", "content"));
String[] massId = massApi.massArticleByOpenIds(articles,
"owGBft_vbBbOaQOmpEUE4xDLeRSU");
Assert.assertTrue(massId[0] != null);
}
@Test
public void massArticleByOpenIds() throws IOException, WeixinException {
List<MpArticle> articles = new ArrayList<MpArticle>();
File file = new File("/tmp/test.jpg");
MediaUploadResult mediaResult = mediaApi.uploadMedia(false, new FileInputStream(file), file.getName());
articles.add(new MpArticle(mediaResult.getMediaId(), "title", "content"));
String[] massId = massApi.massArticleByOpenIds(articles, false, "owGBft_vbBbOaQOmpEUE4xDLeRSU");
Assert.assertTrue(massId[0] != null);
}
@Test
public void deleteMass() throws WeixinException {
ApiResult result = massApi.deleteMassNews("34182");
Assert.assertEquals("0", result.getReturnCode());
}
@Test
public void deleteMass() throws WeixinException {
ApiResult result = massApi.deleteMassNews("34182");
Assert.assertEquals("0", result.getReturnCode());
}
@Test
public void previewMass() throws WeixinException {
ApiResult result = massApi.previewMassNews(
"oyFLst1bqtuTcxK-ojF8hOGtLQao", null, new Text("test"));
Assert.assertEquals("0", result.getReturnCode());
}
@Test
public void previewMass() throws WeixinException {
ApiResult result = massApi.previewMassNews("oyFLst1bqtuTcxK-ojF8hOGtLQao", null, new Text("test"));
Assert.assertEquals("0", result.getReturnCode());
}
@Test
public void getMassNews() throws WeixinException {
String status = massApi.getMassNewStatus("82358");
System.out.println(status);
Assert.assertNotNull(status);
}
@Test
public void getMassNews() throws WeixinException {
String status = massApi.getMassNewStatus("82358");
System.out.println(status);
Assert.assertNotNull(status);
}
}

View File

@ -19,7 +19,7 @@ import com.foxinmy.weixin4j.type.ButtonType;
/**
* 菜单相关API
*
*
* @className MenuApi
* @author jinyu(foxinmy@gmail.com)
* @date 2014年9月25日
@ -36,10 +36,10 @@ public class MenuApi extends QyApi {
/**
* 自定义菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式)
*
*
* @param agentid
* 应用ID
*
*
* @param buttons
* 菜单列表
* @throws WeixinException
@ -58,7 +58,7 @@ public class MenuApi extends QyApi {
@Override
public String process(Object object, String name, Object value) {
if (object instanceof Button && name.equals("content")) {
ButtonType buttonType = ((Button) object).getType();
ButtonType buttonType = ButtonType.valueOf(((Button) object).getType());
if (buttonType != null) {
if (ButtonType.view == buttonType) {
return "url";
@ -78,7 +78,7 @@ public class MenuApi extends QyApi {
/**
* 查询菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式)
*
*
* @param agentid
* 应用ID
* @return 菜单集合
@ -108,7 +108,7 @@ public class MenuApi extends QyApi {
/**
* 删除菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式)
*
*
* @param agentid
* 应用ID
* @throws WeixinException