diff --git a/CHANGE.md b/CHANGE.md index ae874e7d..a487d3bf 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -184,4 +184,15 @@ * 2015-03-17 - + **weixin4j-qy**: 新增企业应用设置接口 \ No newline at end of file + + **weixin4j-qy**: 新增企业应用设置接口 + +* 2015-03-21 + + + 替换

+ + + **weixin-mp**: 新增群发消息给所有人接口 + + + **weixin-mp**: 新增素材管理多个接口 + + + **weixin-mp**: 新增多客服会话管理多个接口 + \ No newline at end of file diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/action/DebugAction.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/action/DebugAction.java index 673debc5..a5d1d06c 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/action/DebugAction.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/action/DebugAction.java @@ -13,7 +13,7 @@ import com.foxinmy.weixin4j.response.ResponseMessage; * @since JDK 1.7 * @see */ -public abstract class DebugAction extends AbstractAction { +public class DebugAction extends AbstractAction { @Override public ResponseMessage execute(M message) { diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/error.xml b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/error.xml index 51b39be7..561239f4 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/error.xml +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/error.xml @@ -579,6 +579,10 @@ Api禁用 + + 61450 + 系统错误(system error) + 61451 参数错误(invalid parameter) @@ -607,6 +611,22 @@ 61457 无效头像文件类型(invalid file type) + + 61458 + 客户正在被其他客服接待(customer accepted by xxx@xxxx) + + + 61459 + 客服不在线(kf offline) + + + 61500 + 日期格式错误 + + + 61501 + 日期范围错误 + 50001 api/redirect_uri unauthorized diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/KfCloseEventMessage.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/KfCloseEventMessage.java new file mode 100644 index 00000000..f1d473f2 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/KfCloseEventMessage.java @@ -0,0 +1,40 @@ +package com.foxinmy.weixin4j.msg.event; + +import com.foxinmy.weixin4j.type.EventType; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + * 客服关闭会话事件 + * + * @className KfCloseEventMessage + * @author jy + * @date 2015年3月22日 + * @since JDK 1.7 + * @see 会话状态通知事件 + */ +public class KfCloseEventMessage extends EventMessage { + + private static final long serialVersionUID = 3644449346935205541L; + + public KfCloseEventMessage() { + super(EventType.kf_close_session); + } + + @XStreamAlias("KfAccount") + private String kfAccount; // 客服账号 + + public String getKfAccount() { + return kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + + @Override + public String toString() { + return "KfCloseEventMessage [kfAccount=" + kfAccount + ", =" + + super.toString() + "]"; + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/KfCreateEventMessage.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/KfCreateEventMessage.java new file mode 100644 index 00000000..4fdabc79 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/KfCreateEventMessage.java @@ -0,0 +1,40 @@ +package com.foxinmy.weixin4j.msg.event; + +import com.foxinmy.weixin4j.type.EventType; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + * 客服接入会话事件 + * + * @className KfCreateEventMessage + * @author jy + * @date 2015年3月22日 + * @since JDK 1.7 + * @see 会话状态通知事件 + */ +public class KfCreateEventMessage extends EventMessage { + + private static final long serialVersionUID = -8968189700999202108L; + + public KfCreateEventMessage() { + super(EventType.kf_create_session); + } + + @XStreamAlias("KfAccount") + private String kfAccount; // 客服账号 + + public String getKfAccount() { + return kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + + @Override + public String toString() { + return "KfCreateEventMessage [kfAccount=" + kfAccount + ", =" + + super.toString() + "]"; + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/KfSwitchEventMessage.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/KfSwitchEventMessage.java new file mode 100644 index 00000000..5099b299 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/KfSwitchEventMessage.java @@ -0,0 +1,51 @@ +package com.foxinmy.weixin4j.msg.event; + +import com.foxinmy.weixin4j.type.EventType; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + * 客服转接会话事件 + * + * @className KfSwitchEventMessage + * @author jy + * @date 2015年3月22日 + * @since JDK 1.7 + * @see 会话状态通知事件 + */ +public class KfSwitchEventMessage extends EventMessage { + + private static final long serialVersionUID = 4319501074109623413L; + + public KfSwitchEventMessage() { + super(EventType.kf_switch_session); + } + + @XStreamAlias("FromKfAccount") + private String fromKfAccount; // 来自的客服账号 + + @XStreamAlias("ToKfAccount") + private String toKfAccount; // 转移给客服账号 + + public String getFromKfAccount() { + return fromKfAccount; + } + + public void setFromKfAccount(String fromKfAccount) { + this.fromKfAccount = fromKfAccount; + } + + public String getToKfAccount() { + return toKfAccount; + } + + public void setToKfAccount(String toKfAccount) { + this.toKfAccount = toKfAccount; + } + + @Override + public String toString() { + return "KfSwitchEventMessage [fromKfAccount=" + fromKfAccount + + ", toKfAccount=" + toKfAccount + "]"; + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/MassEventMessage.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/MassEventMessage.java index 0499e745..c4960dba 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/MassEventMessage.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/MassEventMessage.java @@ -63,9 +63,9 @@ public class MassEventMessage extends EventMessage { } /** - * 发送状态描述
- * err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)
- * err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)
+ * 发送状态描述
+ * err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)
+ * err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)
* err(20013,涉嫌版权) err(22000,涉嫌互推(互相宣传) err(21000,涉嫌其他) * * @param status @@ -76,9 +76,9 @@ public class MassEventMessage extends EventMessage { } /** - * 发送状态描述
- * err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)
- * err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)
+ * 发送状态描述
+ * err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)
+ * err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)
* err(20013,涉嫌版权) err(22000,涉嫌互推(互相宣传) err(21000,涉嫌其他) * * @param status diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/model/Base.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/model/Base.java index 5185504d..3f5c3b1c 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/model/Base.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/model/Base.java @@ -6,6 +6,15 @@ import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.type.MediaType; import com.thoughtworks.xstream.annotations.XStreamOmitField; +/** + * 消息对象基类 + * + * @className Base + * @author jy + * @date 2015年3月21日 + * @since JDK 1.7 + * @see + */ public class Base implements Serializable { private static final long serialVersionUID = 8487251213352068227L; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/EventType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/EventType.java index bb1bb3e8..45499e76 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/EventType.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/EventType.java @@ -2,6 +2,9 @@ package com.foxinmy.weixin4j.type; import com.foxinmy.weixin4j.msg.event.EnterAgentEventMessage; import com.foxinmy.weixin4j.msg.event.EventMessage; +import com.foxinmy.weixin4j.msg.event.KfCloseEventMessage; +import com.foxinmy.weixin4j.msg.event.KfCreateEventMessage; +import com.foxinmy.weixin4j.msg.event.KfSwitchEventMessage; import com.foxinmy.weixin4j.msg.event.LocationEventMessage; import com.foxinmy.weixin4j.msg.event.MassEventMessage; import com.foxinmy.weixin4j.msg.event.ScanEventMessage; @@ -30,9 +33,13 @@ public enum EventType { MenuPhotoEventMessage.class), pic_weixin( MenuPhotoEventMessage.class), location_select( MenuLocationEventMessage.class), click(MenuEventMessage.class), location( - LocationEventMessage.class),masssendjobfinish( + LocationEventMessage.class), masssendjobfinish( MassEventMessage.class), templatesendjobfinish( - TemplatesendjobfinishMessage.class),enter_agent(EnterAgentEventMessage.class); + TemplatesendjobfinishMessage.class), enter_agent( + EnterAgentEventMessage.class), kf_create_session( + KfCreateEventMessage.class), kf_close_session( + KfCloseEventMessage.class), kf_switch_session( + KfSwitchEventMessage.class); private Class eventClass; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/MediaType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/MediaType.java index 0a158da7..36338a1d 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/MediaType.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/MediaType.java @@ -3,13 +3,18 @@ package com.foxinmy.weixin4j.type; /** * 上传的媒体类型
*

- * 公众平台上传限制:
图片(image): 128K,支持JPG格式
- * 语音(voice):256K,播放长度不超过60s,支持AMR\MP3格式
视频(video):1MB,支持MP4格式
+ * 公众平台上传限制:
+ * 图片(image): 128K,支持JPG格式
+ * 语音(voice):256K,播放长度不超过60s,支持AMR\MP3格式
+ * 视频(video):1MB,支持MP4格式
* 缩略图(thumb):64KB,支持JPG格式
*

*

- * 企业号上传限制:
图片(image):1MB,支持JPG格式
语音(voice):2MB,播放长度不超过60s,支持AMR格式
- * 视频(video):10MB,支持MP4格式
普通文件(file):10MB
+ * 企业号上传限制:
+ * 图片(image):1MB,支持JPG格式
+ * 语音(voice):2MB,播放长度不超过60s,支持AMR格式
+ * 视频(video):10MB,支持MP4格式
+ * 普通文件(file):10MB
*

*

* 媒体文件在后台保存时间为3天,即3天后media_id失效 diff --git a/weixin4j-mp/README.md b/weixin4j-mp/README.md index 92944097..6fa033b6 100644 --- a/weixin4j-mp/README.md +++ b/weixin4j-mp/README.md @@ -180,4 +180,12 @@ weixin4j-mp * 2015-03-06 - + **weixin4j-mp-api**: 新增oauth授权接口 \ No newline at end of file + + **weixin4j-mp-api**: 新增oauth授权接口 + +* 2015-03-21 + + + **weixin-mp-api**: 新增群发消息给所有人接口 + + + **weixin-mp-api**: 新增素材管理多个接口 + + + **weixin-mp-api**: 新增多客服会话管理多个接口 \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-api/README.md b/weixin4j-mp/weixin4j-mp-api/README.md index 9263dc9a..2548a858 100644 --- a/weixin4j-mp/weixin4j-mp-api/README.md +++ b/weixin4j-mp/weixin4j-mp-api/README.md @@ -159,4 +159,12 @@ weixin.properties说明 * 2015-03-06 - + 新增oauth授权接口 \ No newline at end of file + + 新增oauth授权接口 + +* 2015-03-21 + + + 新增群发消息给所有人接口 + + + 新增素材管理多个接口 + + + 新增多客服会话管理多个接口 \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java index 0026d4d8..82ca8f2a 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java @@ -25,6 +25,9 @@ import com.foxinmy.weixin4j.mp.model.CustomRecord; import com.foxinmy.weixin4j.mp.model.Following; import com.foxinmy.weixin4j.mp.model.Group; import com.foxinmy.weixin4j.mp.model.KfAccount; +import com.foxinmy.weixin4j.mp.model.KfSession; +import com.foxinmy.weixin4j.mp.model.MediaCounter; +import com.foxinmy.weixin4j.mp.model.MediaRecord; import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.SemQuery; import com.foxinmy.weixin4j.mp.model.SemResult; @@ -105,13 +108,16 @@ public class WeixinProxy { * * @param file * 媒体对象 + * @param isMaterial + * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#uploadMedia(File, MediaType)} * @throws WeixinException * @throws IOException */ - public String uploadMedia(File file) throws WeixinException, IOException { - return mediaApi.uploadMedia(file); + public String uploadMedia(File file, boolean isMaterial) + throws WeixinException, IOException { + return mediaApi.uploadMedia(file, isMaterial); } /** @@ -121,15 +127,17 @@ public class WeixinProxy { * 文件对象 * @param mediaType * 媒体类型 + * @param isMaterial + * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 * @throws WeixinException * @throws IOException * @see com.foxinmy.weixin4j.type.MediaType * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#uploadMedia(String, byte[],String)} */ - public String uploadMedia(File file, MediaType mediaType) + public String uploadMedia(File file, MediaType mediaType, boolean isMaterial) throws WeixinException, IOException { - return mediaApi.uploadMedia(file, mediaType); + return mediaApi.uploadMedia(file, mediaType, isMaterial); } /** @@ -145,15 +153,17 @@ public class WeixinProxy { * 媒体数据包 * @param mediaType * 媒体类型 + * @param isMaterial + * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 * @see 上传下载说明 * @see com.foxinmy.weixin4j.mp.api.MediaApi * @throws WeixinException */ - public String uploadMedia(String fileName, byte[] data, String mediaType) - throws WeixinException { - return mediaApi.uploadMedia(fileName, data, mediaType); + public String uploadMedia(String fileName, byte[] data, String mediaType, + boolean isMaterial) throws WeixinException { + return mediaApi.uploadMedia(fileName, data, mediaType, isMaterial); } /** @@ -166,6 +176,8 @@ public class WeixinProxy { * 存储在微信服务器上的媒体标识 * @param mediaType * 媒体类型 + * @param isMaterial + * 是否永久素材 * @return 写入硬盘后的文件对象 * @throws WeixinException * @see 上传下载说明 */ - public byte[] downloadMedia(String mediaId) throws WeixinException { - return mediaApi.downloadMedia(mediaId); + public byte[] downloadMedia(String mediaId, boolean isMaterial) + throws WeixinException { + return mediaApi.downloadMedia(mediaId, isMaterial); + } + + /** + * 上传永久图文素材 + *

+ * 、新增的永久素材也可以在公众平台官网素材管理模块中看到,永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000, + * 其他类型为1000 + *

+ * + * @param articles + * 图文列表 + * @return 上传到微信服务器返回的媒体标识 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.foxinmy.weixin4j.msg.model.MpArticle + * @see 上传永久媒体素材 + */ + public String uploadMaterialArticle(List articles) + throws WeixinException { + return mediaApi.uploadMaterialArticle(articles); + } + + /** + * 下载永久图文素材 + * + * @param mediaId + * 媒体ID + * @return 图文列表 + * @throws WeixinException + * @see 下载永久媒体素材 + * @see com.foxinmy.weixin4j.msg.model.MpArticle + * @see com.foxinmy.weixin4j.mp.api.MediaApi + */ + public List downloadArticle(String mediaId) + throws WeixinException { + return mediaApi.downloadArticle(mediaId); + } + + /** + * 更新永久图文素材 + * + * @param mediaId + * 要修改的图文消息的id + * @param index + * 要更新的文章在图文消息中的位置(多图文消息时,此字段才有意义),第一篇为0 + * @param articles + * 图文列表 + * @return 处理结果 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.foxinmy.weixin4j.msg.model.MpArticle + * @see 更新永久图文素材 + */ + public JsonResult updateMaterialArticle(String mediaId, int index, + List articles) throws WeixinException { + return mediaApi.updateMaterialArticle(mediaId, index, articles); + } + + /** + * 删除永久媒体素材 + * + * @param mediaId + * 媒体素材的media_id + * @return 处理结果 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see 删除永久媒体素材 + */ + public JsonResult deleteMaterialMedia(String mediaId) + throws WeixinException { + return mediaApi.deleteMaterialMedia(mediaId); + } + + /** + * 上传永久视频素材 + * + * @param file + * 大小不超过1M且格式为MP4的视频文件 + * @param title + * 视频标题 + * @param introduction + * 视频描述 + * @return 上传到微信服务器返回的媒体标识 + * @see 上传永久媒体素材 + * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @throws WeixinException + * @throws IOException + */ + public String uploadMaterialVideo(File file, String title, + String introduction) throws WeixinException, IOException { + return mediaApi.uploadMaterialVideo(file, title, introduction); + } + + /** + * 获取永久媒体素材的总数
.图片和图文消息素材(包括单图文和多图文)的总数上限为5000,其他素材的总数上限为1000 + * + * @return 总数对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.model.MediaCounter + * @see 获取素材总数 + * @see com.foxinmy.weixin4j.mp.api.MediaApi + */ + public MediaCounter countMaterialMedia() throws WeixinException { + return mediaApi.countMaterialMedia(); + } + + /** + * 获取媒体素材记录列表 + * + * @param mediaType + * 素材的类型,图片(image)、视频(video)、语音 (voice)、图文(news) + * @param offset + * 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回 + * @param count + * 返回素材的数量,取值在1到20之间 + * @return 媒体素材的记录对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.foxinmy.weixin4j.mp.model.MediaRecord + * @see com.foxinmy.weixin4j.type.MediaType + * @see com.foxinmy.weixin4j.mp.model.MediaItem + * @see 获取素材列表 + */ + public MediaRecord listMaterialMedia(MediaType mediaType, int offset, + int count) throws WeixinException { + return mediaApi.listMaterialMedia(mediaType, offset, count); } /** @@ -346,6 +494,98 @@ public class WeixinProxy { return customApi.deleteAccount(id); } + /** + * 创建会话 + *

+ * 开发者可以使用本接口,为多客服的客服工号创建会话,将某个客户直接指定给客服工号接待,需要注意此接口不会受客服自动接入数以及自动接入开关限制。 + * 只能为在线的客服(PC客户端在线,或者已绑定多客服助手)创建会话。 + *

+ * + * @param userOpenId + * 用户的userOpenId + * @param kfAccount + * 完整客服账号,格式为:账号前缀@公众号微信号 + * @param text + * 附加信息,文本会展示在客服人员的多客服客户端 + * @return 处理结果 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.CustomApi + * @see 创建会话 + */ + public JsonResult createSession(String userOpenId, String kfAccount, + String text) throws WeixinException { + return customApi.createSession(userOpenId, kfAccount, text); + } + + /** + * 关闭会话 + * + * @param userOpenId + * 用户的userOpenId + * @param kfAccount + * 完整客服账号,格式为:账号前缀@公众号微信号 + * @param text + * 附加信息,文本会展示在客服人员的多客服客户端 + * @return 处理结果 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.CustomApi + * @see 创建会话 + */ + public JsonResult closeSession(String userOpenId, String kfAccount, + String text) throws WeixinException { + return customApi.closeSession(userOpenId, kfAccount, text); + } + + /** + * 获取客户的会话状态:获取客户当前的会话状态。 + * + * @param userOpenId + * 用户的openid + * @return 会话对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.CustomApi + * @see com.foxinmy.weixin4j.mp.model.KfSession + * @see 获取会话状态 + */ + public KfSession getSession(String userOpenId) throws WeixinException { + return customApi.getSession(userOpenId); + } + + /** + * 获取客服的会话列表:获取某个客服正在接待的会话列表。 + * + * @param kfAccount + * 完整客服账号,格式为:账号前缀@公众号微信号,账号前缀最多10个字符,必须是英文或者数字字符。 + * @return 会话列表 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.CustomApi + * @see com.foxinmy.weixin4j.mp.model.KfSession + * @see 获取客服的会话列表 + */ + public List getSessionList(String kfAccount) + throws WeixinException { + return customApi.getSessionList(kfAccount); + } + + /** + * 获取未接入会话列表:获取当前正在等待队列中的会话列表,此接口最多返回最早进入队列的100个未接入会话。
缺陷:没有count字段 + * + * @return 会话列表 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.api.CustomApi + * @see com.foxinmy.weixin4j.mp.model.KfSession + * @see 获取客服的会话列表 + */ + public List getSessionWaitList() throws WeixinException { + return customApi.getSessionWaitList(); + } + /** * 上传图文消息,一个图文消息支持1到10条图文 * @@ -386,26 +626,47 @@ public class WeixinProxy { * 分组群发 * * @param box - * 消息项 + * 消息对象 + * @param groupId + * 分组ID + * @return 群发后的消息ID + * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massMessage(Base,boolean,int)} + * @throws WeixinException + */ + public String massByGroupId(Base box, int groupId) throws WeixinException { + return massApi.massByGroupId(box, groupId); + } + + /** + * 群发消息 + *

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

+ * + * @param box + * 消息对象 + * @param isToAll + * 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户, + * 选择false可根据group_id发送给指定群组的用户 * @param groupId * 分组ID * @return 群发后的消息ID * @throws WeixinException * @see com.foxinmy.weixin4j.mp.model.Group - * @see com.foxinmy.weixin4j.mp.api.MassApi * @see com.foxinmy.weixin4j.msg.model.Text * @see com.foxinmy.weixin4j.msg.model.Image * @see com.foxinmy.weixin4j.msg.model.Voice * @see com.foxinmy.weixin4j.msg.model.MpVideo * @see com.foxinmy.weixin4j.msg.model.MpNews + * @see com.foxinmy.weixin4j.mp.api.MassApi + * @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroups()} * @see 根据分组群发 - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} - * @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroupByOpenId(String)} - * @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroups()} */ - public String massByGroupId(Base box, int groupId) throws WeixinException { - return massApi.massByGroupId(box, groupId); + public String massMessage(Base box, boolean isToAll, int groupId) + throws WeixinException { + return massApi.massMessage(box, isToAll, groupId); } /** @@ -419,6 +680,7 @@ public class WeixinProxy { * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByGroupId(Base,int)} * @see 根据分组群发 + * @see com.foxinmy.weixin4j.msg.model.MpArticle * @throws WeixinException */ public String massArticleByGroupId(List articles, int groupId) @@ -429,19 +691,24 @@ public class WeixinProxy { /** * openId群发 * + *

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

+ * * @param box - * 消息项 + * 消息对象 * @param openIds * openId列表 * @return 群发后的消息ID * @throws WeixinException * @see com.foxinmy.weixin4j.mp.model.User - * @see com.foxinmy.weixin4j.mp.api.MassApi * @see com.foxinmy.weixin4j.msg.model.Text * @see com.foxinmy.weixin4j.msg.model.Image * @see com.foxinmy.weixin4j.msg.model.Voice * @see com.foxinmy.weixin4j.msg.model.MpVideo * @see com.foxinmy.weixin4j.msg.model.MpNews + * @see com.foxinmy.weixin4j.mp.api.MassApi * @see 根据openid群发 * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} @@ -463,6 +730,7 @@ public class WeixinProxy { * @see 根据openid群发 * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByOpenIds(Base,String...)} + * @see com.foxinmy.weixin4j.msg.model.MpArticle * @throws WeixinException */ public String massArticleByOpenIds(List articles, @@ -490,8 +758,7 @@ public class WeixinProxy { } /** - * 预览群发消息
- * 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版 + * 预览群发消息
开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版 * * @param openId * 接收用户的ID diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CustomApi.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CustomApi.java index 55dcb491..64c0e2c5 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CustomApi.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CustomApi.java @@ -11,6 +11,7 @@ import org.apache.http.entity.mime.content.ByteArrayBody; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.PartParameter; @@ -18,6 +19,7 @@ import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.mp.model.CustomRecord; import com.foxinmy.weixin4j.mp.model.KfAccount; +import com.foxinmy.weixin4j.mp.model.KfSession; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.util.IOUtil; @@ -223,4 +225,133 @@ public class CustomApi extends MpApi { return response.getAsJsonResult(); } + + /** + * 创建会话 + *

+ * 开发者可以使用本接口,为多客服的客服工号创建会话,将某个客户直接指定给客服工号接待,需要注意此接口不会受客服自动接入数以及自动接入开关限制。 + * 只能为在线的客服(PC客户端在线,或者已绑定多客服助手)创建会话。 + *

+ * + * @param userOpenId + * 用户的userOpenId + * @param kfAccount + * 完整客服账号,格式为:账号前缀@公众号微信号 + * @param text + * 附加信息,文本会展示在客服人员的多客服客户端 + * @return 处理结果 + * @throws WeixinException + * @see 创建会话 + */ + public JsonResult createSession(String userOpenId, String kfAccount, + String text) throws WeixinException { + Token token = tokenHolder.getToken(); + String kfsession_create_uri = getRequestUri("kfsession_create_uri"); + JSONObject obj = new JSONObject(); + obj.put("openid", userOpenId); + obj.put("kf_account", kfAccount); + obj.put("text", text); + Response response = request.post( + String.format(kfsession_create_uri, token.getAccessToken()), + obj.toJSONString()); + + return response.getAsJsonResult(); + } + + /** + * 关闭会话 + * + * @param userOpenId + * 用户的userOpenId + * @param kfAccount + * 完整客服账号,格式为:账号前缀@公众号微信号 + * @param text + * 附加信息,文本会展示在客服人员的多客服客户端 + * @return 处理结果 + * @throws WeixinException + * @see 创建会话 + */ + public JsonResult closeSession(String userOpenId, String kfAccount, + String text) throws WeixinException { + Token token = tokenHolder.getToken(); + String kfsession_close_uri = getRequestUri("kfsession_close_uri"); + JSONObject obj = new JSONObject(); + obj.put("openid", userOpenId); + obj.put("kf_account", kfAccount); + obj.put("text", text); + Response response = request.post( + String.format(kfsession_close_uri, token.getAccessToken()), + obj.toJSONString()); + + return response.getAsJsonResult(); + } + + /** + * 获取客户的会话状态:获取客户当前的会话状态。 + * + * @param userOpenId + * 用户的openid + * @return 会话对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.model.KfSession + * @see 获取会话状态 + */ + public KfSession getSession(String userOpenId) throws WeixinException { + Token token = tokenHolder.getToken(); + String kfsession_get_uri = getRequestUri("kfsession_get_uri"); + Response response = request.get(String.format(kfsession_get_uri, + token.getAccessToken(), userOpenId)); + + KfSession session = response + .getAsObject(new TypeReference() { + }); + session.setUserOpenId(userOpenId); + return session; + } + + /** + * 获取客服的会话列表:获取某个客服正在接待的会话列表。 + * + * @param kfAccount + * 完整客服账号,格式为:账号前缀@公众号微信号,账号前缀最多10个字符,必须是英文或者数字字符。 + * @return 会话列表 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.model.KfSession + * @see 获取客服的会话列表 + */ + public List getSessionList(String kfAccount) + throws WeixinException { + Token token = tokenHolder.getToken(); + String kfsession_list_uri = getRequestUri("kfsession_list_uri"); + Response response = request.get(String.format(kfsession_list_uri, + token.getAccessToken(), kfAccount)); + + List sessionList = JSON.parseArray(response.getAsJson() + .getString("sessionlist"), KfSession.class); + return sessionList; + } + + /** + * 获取未接入会话列表:获取当前正在等待队列中的会话列表,此接口最多返回最早进入队列的100个未接入会话。
+ * 缺陷:没有count字段 + * @return 会话列表 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.model.KfSession + * @see 获取客服的会话列表 + */ + public List getSessionWaitList() throws WeixinException { + Token token = tokenHolder.getToken(); + String kfsession_wait_uri = getRequestUri("kfsession_wait_uri"); + Response response = request.get(String.format(kfsession_wait_uri, + token.getAccessToken())); + + List sessionList = JSON.parseArray(response.getAsJson() + .getString("waitcaselist"), KfSession.class); + return sessionList; + } } \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/DataApi.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/DataApi.java index a61174d5..de0894b5 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/DataApi.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/DataApi.java @@ -16,8 +16,8 @@ import com.foxinmy.weixin4j.util.DateUtil; /** * 数据分析API *

- * 1、接口侧的公众号数据的数据库中仅存储了2014年12月1日之后的数据,将查询不到在此之前的日期,即使有查到,也是不可信的脏数据;
- * 2、请开发者在调用接口获取数据后,将数据保存在自身数据库中,即加快下次用户的访问速度,也降低了微信侧接口调用的不必要损耗。
+ * 1、接口侧的公众号数据的数据库中仅存储了2014年12月1日之后的数据,将查询不到在此之前的日期,即使有查到,也是不可信的脏数据;
+ * 2、请开发者在调用接口获取数据后,将数据保存在自身数据库中,即加快下次用户的访问速度,也降低了微信侧接口调用的不必要损耗。
*

* * @className DataApi diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java index 287937e1..8c343352 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java @@ -86,13 +86,31 @@ public class MassApi extends MpApi { /** * 分组群发 + * + * @param box + * 消息对象 + * @param groupId + * 分组ID + * @return 群发后的消息ID + * @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massMessage(Base,boolean,int)} + * @throws WeixinException + */ + public String massByGroupId(Base box, int groupId) throws WeixinException { + return massMessage(box, false, groupId); + } + + /** + * 群发消息 *

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

* * @param box - * 消息项 + * 消息对象 + * @param isToAll + * 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户, + * 选择false可根据group_id发送给指定群组的用户 * @param groupId * 分组ID * @return 群发后的消息ID @@ -103,19 +121,21 @@ public class MassApi extends MpApi { * @see com.foxinmy.weixin4j.msg.model.Voice * @see com.foxinmy.weixin4j.msg.model.MpVideo * @see com.foxinmy.weixin4j.msg.model.MpNews + * @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroups()} * @see 根据分组群发 - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} - * @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroups()} */ - public String massByGroupId(Base box, int groupId) throws WeixinException { + public String massMessage(Base box, boolean isToAll, int groupId) + throws WeixinException { if (box instanceof MpNews) { MpNews _news = (MpNews) box; List _articles = _news.getArticles(); - if (StringUtils.isBlank(_news.getMediaId()) && _articles != null - && !_articles.isEmpty()) { - return massArticleByGroupId(_articles, groupId); + if (StringUtils.isBlank(_news.getMediaId()) + && (_articles == null || _articles.isEmpty())) { + throw new WeixinException( + "mass fail:mediaId or articles is required"); } + box = new MpNews(uploadArticle(_articles)); } if (!(box instanceof Massable)) { throw new WeixinException(String.format( @@ -124,7 +144,10 @@ public class MassApi extends MpApi { String msgtype = box.getMediaType().name(); JSONObject obj = new JSONObject(); JSONObject item = new JSONObject(); - item.put("group_id", groupId); + item.put("is_to_all", isToAll); + if (!isToAll) { + item.put("group_id", groupId); + } obj.put("filter", item); obj.put(msgtype, JSON.toJSON(box)); obj.put("msgtype", msgtype); @@ -148,6 +171,7 @@ public class MassApi extends MpApi { * @see 根据分组群发 * @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByGroupId(Base,int)} + * @see com.foxinmy.weixin4j.msg.model.MpArticle * @throws WeixinException */ public String massArticleByGroupId(List articles, int groupId) @@ -160,7 +184,7 @@ public class MassApi extends MpApi { * openId群发 * * @param box - * 消息项 + * 消息对象 * @param openIds * openId列表 * @return 群发后的消息ID @@ -173,7 +197,6 @@ public class MassApi extends MpApi { * @see com.foxinmy.weixin4j.msg.model.MpNews * @see 根据openid群发 - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} * @see {@link com.foxinmy.weixin4j.mp.api.UserApi#getUser(String)} */ public String massByOpenIds(Base box, String... openIds) @@ -181,10 +204,12 @@ public class MassApi extends MpApi { if (box instanceof MpNews) { MpNews _news = (MpNews) box; List _articles = _news.getArticles(); - if (StringUtils.isBlank(_news.getMediaId()) && _articles != null - && !_articles.isEmpty()) { - return massArticleByOpenIds(_articles, openIds); + if (StringUtils.isBlank(_news.getMediaId()) + && (_articles == null || _articles.isEmpty())) { + throw new WeixinException( + "mass fail:mediaId or articles is required"); } + box = new MpNews(uploadArticle(_articles)); } if (!(box instanceof Massable)) { throw new WeixinException(String.format( @@ -215,6 +240,7 @@ public class MassApi extends MpApi { * @see 根据openid群发 * @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByOpenIds(Base,String...)} + * @see com.foxinmy.weixin4j.msg.model.MpArticle * @throws WeixinException */ public String massArticleByOpenIds(List articles, @@ -250,8 +276,7 @@ public class MassApi extends MpApi { } /** - * 预览群发消息
- * 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版 + * 预览群发消息
开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版 * * @param openId * 接收用户的ID diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/MediaApi.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/MediaApi.java index aa71f5fb..9d4d5cb5 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/MediaApi.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/MediaApi.java @@ -5,14 +5,27 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.http.entity.mime.content.ByteArrayBody; +import org.apache.http.entity.mime.content.StringBody; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.alibaba.fastjson.parser.deserializer.ExtraProcessor; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.PartParameter; import com.foxinmy.weixin4j.http.Response; +import com.foxinmy.weixin4j.model.Consts; import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.mp.model.MediaCounter; +import com.foxinmy.weixin4j.mp.model.MediaItem; +import com.foxinmy.weixin4j.mp.model.MediaRecord; +import com.foxinmy.weixin4j.msg.model.MpArticle; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.util.ConfigUtil; @@ -20,14 +33,12 @@ import com.foxinmy.weixin4j.util.FileUtil; import com.foxinmy.weixin4j.util.IOUtil; /** - * 多媒体相关API + * 素材相关API * * @className MediaApi * @author jy.hu * @date 2014年9月25日 * @since JDK 1.7 - * @see 上传多媒体文件 * @see com.foxinmy.weixin4j.type.MediaType */ public class MediaApi extends MpApi { @@ -42,41 +53,46 @@ public class MediaApi extends MpApi { * 上传媒体文件 * * @param file - * 媒体对象 + * 文件对象 + * @param isMaterial + * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)} * @throws WeixinException * @throws IOException */ - public String uploadMedia(File file) throws WeixinException, IOException { + public String uploadMedia(File file, boolean isMaterial) + throws WeixinException, IOException { String mediaTypeKey = IOUtil.getExtension(file.getName()); if (StringUtils.isBlank(mediaTypeKey)) { mediaTypeKey = FileUtil.getFileType(file); } MediaType mediaType = MediaType.getMediaType(mediaTypeKey); - return uploadMedia(file, mediaType); + return uploadMedia(file, mediaType, isMaterial); } /** - * 上传媒体文件 + * 上传媒体文件
此接口只包含图片、语音、缩略图三种媒体类型的上传 * * @param file * 文件对象 * @param mediaType - * 媒体类型 + * 媒体类型 (image)、语音(voice)和缩略图(thumb) + * @param isMaterial + * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 * @throws WeixinException * @see com.foxinmy.weixin4j.type.MediaType - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(String, byte[],String)} + * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(String, byte[],String,boolean)} */ - public String uploadMedia(File file, MediaType mediaType) + public String uploadMedia(File file, MediaType mediaType, boolean isMaterial) throws WeixinException, IOException { byte[] datas = IOUtil.toByteArray(new FileInputStream(file)); - return uploadMedia(file.getName(), datas, mediaType.name()); + return uploadMedia(file.getName(), datas, mediaType.name(), isMaterial); } /** - * 上传媒体文件 + * 上传媒体文件
此接口只包含图片、语音、缩略图、视频(临时)四种媒体类型的上传 *

* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}, * 否则抛出异常. @@ -87,25 +103,51 @@ public class MediaApi extends MpApi { * @param bytes * 媒体数据包 * @param mediaType - * 媒体类型 + * 媒体文件类型:分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb) + * @param isMaterial + * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 * @see 上传下载说明 + * href="http://mp.weixin.qq.com/wiki/5/963fc70b80dc75483a271298a76a8d59.html">上传临时素材 + * @see 上传永久素材 * @throws WeixinException */ - public String uploadMedia(String fileName, byte[] bytes, String mediaType) - throws WeixinException { + public String uploadMedia(String fileName, byte[] bytes, String mediaType, + boolean isMaterial) throws WeixinException { + if (",image,voice,video,thumb,".indexOf(String + .format(",%s,", mediaType)) < 0) { + throw new WeixinException(String.format( + "unsupported media type:%s", mediaType)); + } + if (mediaType.equals(MediaType.video.name()) && isMaterial) { + throw new WeixinException( + "please invoke uploadMaterialVideo method"); + } Token token = tokenHolder.getToken(); - String file_upload_uri = getRequestUri("file_upload_uri"); - Response response = request.post(String.format(file_upload_uri, - token.getAccessToken(), mediaType), new PartParameter("media", - new ByteArrayBody(bytes, fileName))); - + Response response = null; + if (isMaterial) { + String material_media_upload_uri = getRequestUri("material_media_upload_uri"); + try { + response = request.post(String.format( + material_media_upload_uri, token.getAccessToken()), + new PartParameter("media", new ByteArrayBody(bytes, + fileName)), new PartParameter("type", + new StringBody(mediaType, Consts.UTF_8))); + } catch (UnsupportedEncodingException e) { + ; // ignore + } + } else { + String file_upload_uri = getRequestUri("file_upload_uri"); + response = request.post(String.format(file_upload_uri, + token.getAccessToken(), mediaType), new PartParameter( + "media", new ByteArrayBody(bytes, fileName))); + } return response.getAsJson().getString("media_id"); } /** - * 下载媒体文件 + * 下载媒体素材 *

* 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常. *

@@ -113,32 +155,38 @@ public class MediaApi extends MpApi { * @param mediaId * 存储在微信服务器上的媒体标识 * @param mediaType - * 媒体类型 + * 媒体文件类型:分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb) * @return 写入硬盘后的文件对象 * @throws WeixinException * @see 上传下载说明 + * href="http://mp.weixin.qq.com/wiki/11/07b6b76a6b6e8848e855a435d5e34a5f.html">下载临时媒体文件 + * @see 下载永久媒体素材 * @see com.foxinmy.weixin4j.type.MediaType - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#downloadMedia(String)} + * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#downloadMedia(String,boolean)} */ - public File downloadMedia(String mediaId, MediaType mediaType) - throws WeixinException { + public File downloadMedia(String mediaId, MediaType mediaType, + boolean isMaterial) throws WeixinException { + if (",image,voice,video,thumb,".indexOf(String.format(",%s,", + mediaType.name())) < 0) { + throw new WeixinException(String.format( + "unsupported media type:%s", mediaType.name())); + } String media_path = ConfigUtil.getValue("media_path"); File file = new File(media_path + File.separator + mediaId + "." + mediaType.getFormatName()); if (file.exists()) { return file; } - byte[] datas = downloadMedia(mediaId); + byte[] datas = downloadMedia(mediaId, isMaterial); OutputStream os = null; try { - boolean flag = file.createNewFile(); - if (flag) { + if (file.createNewFile()) { os = new FileOutputStream(file); os.write(datas); } else { - throw new WeixinException(String.format( - "create file fail:%s", file.getAbsolutePath())); + throw new WeixinException(String.format("create file fail:%s", + file.getAbsolutePath())); } } catch (IOException e) { throw new WeixinException(e.getMessage()); @@ -155,21 +203,245 @@ public class MediaApi extends MpApi { } /** - * 下载媒体文件 + * 下载媒体素材 * * @param mediaId * 媒体ID + * @param isMaterial + * 是否下载永久素材 * @return 二进制数据包 * @throws WeixinException * @see 上传下载说明 + * href="http://mp.weixin.qq.com/wiki/11/07b6b76a6b6e8848e855a435d5e34a5f.html">下载临时媒体素材 + * @see 下载永久媒体素材 */ - public byte[] downloadMedia(String mediaId) throws WeixinException { + public byte[] downloadMedia(String mediaId, boolean isMaterial) + throws WeixinException { Token token = tokenHolder.getToken(); - String file_download_uri = getRequestUri("file_download_uri"); - Response response = request.get(String.format(file_download_uri, - token.getAccessToken(), mediaId)); - + Response response = null; + if (isMaterial) { + JSONObject media = new JSONObject(); + media.put("media_id", mediaId); + String material_media_download_uri = getRequestUri("material_media_download_uri"); + response = request.post( + String.format(material_media_download_uri, + token.getAccessToken()), media.toJSONString()); + } else { + String file_download_uri = getRequestUri("file_download_uri"); + response = request.get(String.format(file_download_uri, + token.getAccessToken(), mediaId)); + } return response.getBody(); } + + /** + * 上传永久图文素材 + *

+ * 、新增的永久素材也可以在公众平台官网素材管理模块中看到,永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000, + * 其他类型为1000 + *

+ * + * @param articles + * 图文列表 + * @return 上传到微信服务器返回的媒体标识 + * @throws WeixinException + * @see 上传永久媒体素材 + * @see com.foxinmy.weixin4j.msg.model.MpArticle + */ + public String uploadMaterialArticle(List articles) + throws WeixinException { + Token token = tokenHolder.getToken(); + String material_article_upload_uri = getRequestUri("material_article_upload_uri"); + JSONObject obj = new JSONObject(); + obj.put("articles", articles); + Response response = request.post( + String.format(material_article_upload_uri, + token.getAccessToken()), obj.toJSONString()); + + return response.getAsJson().getString("media_id"); + } + + /** + * 下载永久图文素材 + * + * @param mediaId + * 媒体ID + * @return 图文列表 + * @throws WeixinException + * @see 下载永久媒体素材 + * @see com.foxinmy.weixin4j.msg.model.MpArticle + */ + public List downloadArticle(String mediaId) + throws WeixinException { + byte[] bytes = downloadMedia(mediaId, true); + JSONObject obj = JSON.parseObject(bytes, 0, bytes.length, + Consts.UTF_8.newDecoder(), JSONObject.class); + return JSON.parseArray(obj.getString("news_item"), MpArticle.class); + } + + /** + * 更新永久图文素材 + * + * @param mediaId + * 要修改的图文消息的id + * @param index + * 要更新的文章在图文消息中的位置(多图文消息时,此字段才有意义),第一篇为0 + * @param articles + * 图文列表 + * @return 处理结果 + * @throws WeixinException + * @see com.foxinmy.weixin4j.msg.model.MpArticle + * @see 更新永久图文素材 + */ + public JsonResult updateMaterialArticle(String mediaId, int index, + List articles) throws WeixinException { + Token token = tokenHolder.getToken(); + String material_article_update_uri = getRequestUri("material_article_update_uri"); + JSONObject obj = new JSONObject(); + obj.put("articles", articles); + obj.put("media_id", mediaId); + obj.put("index", index); + Response response = request.post( + String.format(material_article_update_uri, + token.getAccessToken()), obj.toJSONString()); + + return response.getAsJsonResult(); + } + + /** + * 删除永久媒体素材 + * + * @param mediaId + * 媒体素材的media_id + * @return 处理结果 + * @throws WeixinException + * @see 删除永久媒体素材 + */ + public JsonResult deleteMaterialMedia(String mediaId) + throws WeixinException { + Token token = tokenHolder.getToken(); + String material_media_del_uri = getRequestUri("material_media_del_uri"); + JSONObject obj = new JSONObject(); + obj.put("media_id", mediaId); + Response response = request.post( + String.format(material_media_del_uri, token.getAccessToken()), + obj.toJSONString()); + + return response.getAsJsonResult(); + } + + /** + * 上传永久视频素材 + * + * @param file + * 大小不超过1M且格式为MP4的视频文件 + * @param title + * 视频标题 + * @param introduction + * 视频描述 + * @return 上传到微信服务器返回的媒体标识 + * @see 上传永久媒体素材 + * @throws WeixinException + * @throws IOException + */ + public String uploadMaterialVideo(File file, String title, + String introduction) throws WeixinException, IOException { + String material_media_upload_uri = getRequestUri("material_media_upload_uri"); + Token token = tokenHolder.getToken(); + try { + JSONObject description = new JSONObject(); + description.put("title", title); + description.put("introduction", introduction); + byte[] bytes = IOUtil.toByteArray(new FileInputStream(file)); + Response response = request.post( + String.format(material_media_upload_uri, + token.getAccessToken()), + new PartParameter("media", new ByteArrayBody(bytes, file + .getName())), + new PartParameter("type", new StringBody(MediaType.video + .name(), Consts.UTF_8)), + new PartParameter("description", new StringBody(description + .toJSONString(), Consts.UTF_8))); + return response.getAsJson().getString("media_id"); + } catch (UnsupportedEncodingException e) { + throw new WeixinException("unsupported encoding"); + } + } + + /** + * 获取永久媒体素材的总数
.图片和图文消息素材(包括单图文和多图文)的总数上限为5000,其他素材的总数上限为1000 + * + * @return 总数对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.model.MediaCounter + * @see 获取素材总数 + */ + public MediaCounter countMaterialMedia() throws WeixinException { + Token token = tokenHolder.getToken(); + String material_media_count_uri = getRequestUri("material_media_count_uri"); + Response response = request.get(String.format(material_media_count_uri, + token.getAccessToken())); + + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 获取媒体素材记录列表 + * + * @param mediaType + * 素材的类型,图片(image)、视频(video)、语音 (voice)、图文(news) + * @param offset + * 从全部素材的该偏移位置开始返回,0表示从第一个素材返回 + * @param count + * 返回素材的数量,取值在1到20之间 + * @return 媒体素材的记录对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.model.MediaRecord + * @see com.foxinmy.weixin4j.type.MediaType + * @see com.foxinmy.weixin4j.mp.model.MediaItem + * @see 获取素材列表 + */ + public MediaRecord listMaterialMedia(MediaType mediaType, int offset, + int count) throws WeixinException { + Token token = tokenHolder.getToken(); + String material_media_list_uri = getRequestUri("material_media_list_uri"); + JSONObject obj = new JSONObject(); + obj.put("type", mediaType.name()); + obj.put("offset", offset); + obj.put("count", count); + Response response = request.post( + String.format(material_media_list_uri, token.getAccessToken()), + obj.toJSONString()); + MediaRecord mediaRecord = null; + if (mediaType == MediaType.news) { + mediaRecord = JSON.parseObject(response.getAsString(), MediaRecord.class, + new ExtraProcessor() { + @Override + public void processExtra(Object object, String key, + Object value) { + if (key.equals("content")) { + ((MediaItem) object).setArticles(JSON + .parseArray(((JSONObject) value) + .getString("news_item"), + MpArticle.class)); + } + } + }); + } else { + mediaRecord = response + .getAsObject(new TypeReference() { + }); + } + mediaRecord.setMediaType(mediaType); + return mediaRecord; + } } diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties index 5ad4b236..046b7191 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties @@ -81,6 +81,16 @@ custom_uploadheadimg_uri={api_base_url}/customservice/kfacount/uploadheadimg?acc custom_delete_uri={api_base_url}/customservice/kfaccount/del?access_token=%s&kf_account=%s # \u5728\u7ebf\u5ba2\u670d\u57fa\u672c\u4fe1\u606f getonlinekflist_uri={api_cgi_url}/customservice/getonlinekflist?access_token=%s +# \u521b\u5efa\u5ba2\u670d\u4f1a\u8bdd +kfsession_create_uri={api_base_url}/customservice/kfsession/create?access_token=%s +# \u5173\u95ed\u5ba2\u670d\u4f1a\u8bdd +kfsession_close_uri={api_base_url}/customservice/kfsession/close?access_token=%s +# \u83b7\u53d6\u5ba2\u670d\u4f1a\u8bdd\u72b6\u6001 +kfsession_get_uri={api_base_url}/customservice/kfsession/getsession?access_token=%s&openid=%s +# \u83b7\u53d6\u5ba2\u670d\u7684\u4f1a\u8bdd\u5217\u8868 +kfsession_list_uri={api_base_url}/customservice/kfsession/getsessionlist?access_token=%s&kf_account=%s +# \u83b7\u53d6\u672a\u63a5\u5165\u4f1a\u8bdd\u5217\u8868 +kfsession_wait_uri={api_base_url}/customservice/kfsession/getwaitcase?access_token=%s # \u957f\u94fe\u63a5\u8f6c\u77ed\u94fe\u63a5 shorturl_uri={api_cgi_url}/shorturl?access_token=%s p_shorturl_uri={mch_base_url}/tools/shorturl @@ -134,4 +144,19 @@ nativepay_v2_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s×tam nativepay_v3_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s # \u6570\u636e\u7edf\u8ba1 -datacube_uri={api_base_url}/datacube/%s?access_token=%s \ No newline at end of file +datacube_uri={api_base_url}/datacube/%s?access_token=%s + +# \u4e0a\u4f20\u6c38\u4e45\u56fe\u6587\u7d20\u6750 +material_article_upload_uri={api_cgi_url}/material/add_news?access_token=%s +# \u4e0a\u4f20\u6c38\u4e45\u5a92\u4f53\u7d20\u6750 +material_media_upload_uri={file_base_url}/material/add_material?access_token=%s +# \u4e0b\u8f7d\u6c38\u4e45\u5a92\u4f53\u7d20\u6750 +material_media_download_uri={api_cgi_url}/material/get_material?access_token=%s +# \u66f4\u65b0\u6c38\u4e45\u56fe\u6587\u7d20\u6750 +material_article_update_uri={api_cgi_url}/material/update_news?access_token=%s +# \u5220\u9664\u6c38\u4e45\u5a92\u4f53\u7d20\u6750 +material_media_del_uri={api_cgi_url}/material/del_material?access_token=%s +# \u83b7\u53d6\u5a92\u4f53\u7d20\u6750\u603b\u6570 +material_media_count_uri={api_cgi_url}/material/get_materialcount?access_token=%s +# \u83b7\u53d6\u5a92\u4f53\u7d20\u6750\u5217\u8868 +material_media_list_uri={api_cgi_url}/material/batchget_material?access_token=%s \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/KfSession.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/KfSession.java new file mode 100644 index 00000000..5b38ef88 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/KfSession.java @@ -0,0 +1,57 @@ +package com.foxinmy.weixin4j.mp.model; + +import java.io.Serializable; +import java.util.Date; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 客服会话信息 + * + * @className KfSession + * @author jy + * @date 2015年3月22日 + * @since JDK 1.7 + * @see + */ +public class KfSession implements Serializable { + + private static final long serialVersionUID = 7236468333492555458L; + + @JSONField(name = "kf_account") + private String kfAccount; // 客服账号 + @JSONField(name = "openid") + private String userOpenId; // 用户ID + @JSONField(name = "createtime") + private Date createTime; // 创建时间 + + public String getKfAccount() { + return kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + + public String getUserOpenId() { + return userOpenId; + } + + public void setUserOpenId(String userOpenId) { + this.userOpenId = userOpenId; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "KfSession [kfAccount=" + kfAccount + ", userOpenId=" + + userOpenId + ", createTime=" + createTime + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/MediaCounter.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/MediaCounter.java new file mode 100644 index 00000000..5f42d96c --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/MediaCounter.java @@ -0,0 +1,67 @@ +package com.foxinmy.weixin4j.mp.model; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 媒体素材总数 + * + * @className MediaCounter + * @author jy + * @date 2015年3月22日 + * @since JDK 1.7 + * @see + */ +public class MediaCounter implements Serializable { + + private static final long serialVersionUID = -1752502821323552783L; + + @JSONField(name = "voice_count") + private long voiceCount;// 语音总数量 + @JSONField(name = "video_count") + private long videoCount;// 视频总数量 + @JSONField(name = "image_count") + private long imageCount; // 图片总数量 + @JSONField(name = "news_count") + private long newsCount; // 图文总数量 + + public long getVoiceCount() { + return voiceCount; + } + + public void setVoiceCount(long voiceCount) { + this.voiceCount = voiceCount; + } + + public long getVideoCount() { + return videoCount; + } + + public void setVideoCount(long videoCount) { + this.videoCount = videoCount; + } + + public long getImageCount() { + return imageCount; + } + + public void setImageCount(long imageCount) { + this.imageCount = imageCount; + } + + public long getNewsCount() { + return newsCount; + } + + public void setNewsCount(long newsCount) { + this.newsCount = newsCount; + } + + @Override + public String toString() { + return "MediaCounter [voiceCount=" + voiceCount + ", videoCount=" + + videoCount + ", imageCount=" + imageCount + ", newsCount=" + + newsCount + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/MediaItem.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/MediaItem.java new file mode 100644 index 00000000..8d977cde --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/MediaItem.java @@ -0,0 +1,68 @@ +package com.foxinmy.weixin4j.mp.model; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.msg.model.MpArticle; + +/** + * 媒体素材信息 + * + * @className MediaItem + * @author jy + * @date 2015年3月22日 + * @since JDK 1.7 + * @see + */ +public class MediaItem implements Serializable { + + private static final long serialVersionUID = -2923028664954250134L; + + @JSONField(name = "media_id") + private String mediaId; // 媒体素材ID + private String name; // 媒体素材名称 + @JSONField(name = "update_time") + private Date updateTime; // 媒体素材最后更新时间 + @JSONField(name = "news_item") + private List articles; // 图文素材列表 + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public List getArticles() { + return articles; + } + + public void setArticles(List articles) { + this.articles = articles; + } + + @Override + public String toString() { + return "MediaItem [mediaId=" + mediaId + ", name=" + name + + ", updateTime=" + updateTime + ", articles=" + articles + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/MediaRecord.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/MediaRecord.java new file mode 100644 index 00000000..fee3c347 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/MediaRecord.java @@ -0,0 +1,69 @@ +package com.foxinmy.weixin4j.mp.model; + +import java.io.Serializable; +import java.util.List; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.MediaType; + +/** + * 媒体素材记录 + * + * @className MediaRecord + * @author jy + * @date 2015年3月22日 + * @since JDK 1.7 + * @see + */ +public class MediaRecord implements Serializable { + + private static final long serialVersionUID = 7017503153256241457L; + + @JSONField(name = "total_count") + private int totalCount;// 该类型的素材的总数 + @JSONField(name = "item_count") + private int itemCount;// 本次调用获取的素材的数量 + @JSONField(serialize = false) + private MediaType mediaType; // 媒体类型 + @JSONField(name = "item") + private List items; // 媒体信息 + + public int getTotalCount() { + return totalCount; + } + + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } + + public int getItemCount() { + return itemCount; + } + + public void setItemCount(int itemCount) { + this.itemCount = itemCount; + } + + public MediaType getMediaType() { + return mediaType; + } + + public void setMediaType(MediaType mediaType) { + this.mediaType = mediaType; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + @Override + public String toString() { + return "MediaRecord [totalCount=" + totalCount + ", itemCount=" + + itemCount + ", mediaType=" + mediaType + ", items=" + items + + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java index 755a5b71..a732e217 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java +++ b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java @@ -2,13 +2,19 @@ package com.foxinmy.weixin4j.mp.test; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.mp.api.MediaApi; +import com.foxinmy.weixin4j.mp.model.MediaCounter; +import com.foxinmy.weixin4j.mp.model.MediaRecord; +import com.foxinmy.weixin4j.msg.model.MpArticle; import com.foxinmy.weixin4j.type.MediaType; /** @@ -30,19 +36,106 @@ public class MediaTest extends TokenTest { } @Test - public void upload() throws IOException, WeixinException { - File file = new File("/tmp/test.jpg"); - String mediaId = mediaApi.uploadMedia(file, MediaType.image); - // vvU_AUtovWyfAxQ8J1DsCoNMtK6U_bUmTpe6lpINUOVRLvt_7rtO4zxzBpPgkmay + public void upload1() throws IOException, WeixinException { + File file = new File("/Users/jy/Downloads/test.jpg"); + String mediaId = mediaApi.uploadMedia(file, MediaType.image, false); + // Sy1KOLsi4ri3kB3TYUuculVelcW2I7W6BrfGwkGvSW8beTCAarxuGQLjuNJChJr8 Assert.assertNotNull(mediaId); + System.err.println(mediaId); } @Test - public void download() throws WeixinException, IOException { + public void download1() throws WeixinException, IOException { File file = mediaApi .downloadMedia( - "vvU_AUtovWyfAxQ8J1DsCoNMtK6U_bUmTpe6lpINUOVRLvt_7rtO4zxzBpPgkmay", - MediaType.image); + "Sy1KOLsi4ri3kB3TYUuculVelcW2I7W6BrfGwkGvSW8beTCAarxuGQLjuNJChJr8", + MediaType.image, false); Assert.assertTrue(file.exists()); } + + @Test + public void upload2() throws IOException, WeixinException { + File file = new File("/Users/jy/Downloads/test.jpg"); + String mediaId = mediaApi.uploadMedia(file, MediaType.image, true); + // 8790403529 + Assert.assertNotNull(mediaId); + System.err.println(mediaId); + } + + @Test + public void uploadMaterialVideo() throws IOException, WeixinException { + File file = new File("/Users/jy/Downloads/test.jpg"); + String mediaId = mediaApi.uploadMaterialVideo(file, "title", + "introduction"); + // Sy1KOLsi4ri3kB3TYUuculVelcW2I7W6BrfGwkGvSW8beTCAarxuGQLjuNJChJr8 + Assert.assertNotNull(mediaId); + System.err.println(mediaId); + } + + @Test + public void uploadMaterialArticle() throws WeixinException { + List articles = new ArrayList(); + articles.add(new MpArticle( + "8790403529", + "title", "content")); + String mediaId = mediaApi.uploadMaterialArticle(articles); + // 17385064953 + Assert.assertNotNull(mediaId); + System.err.println(mediaId); + } + + @Test + public void download2() throws WeixinException, IOException { + File file = mediaApi + .downloadMedia( + "8790403529", + MediaType.image, true); + Assert.assertTrue(file.exists()); + } + + @Test + public void downloadArticle() throws WeixinException { + List articles = mediaApi + .downloadArticle("17385064953"); + Assert.assertTrue(articles != null && !articles.isEmpty()); + System.err.println(articles); + } + + @Test + public void deleteMaterialMedia() throws WeixinException { + JsonResult result = mediaApi + .deleteMaterialMedia("17385064953"); + System.err.println(result); + } + + @Test + public void updateMaterialArticle() throws WeixinException { + MpArticle mpArticle = new MpArticle( + "8790403529", + "title", "content"); + mpArticle.setAuthor("author_update"); + mpArticle.setDigest("digest_update"); + mpArticle.setShowCoverPic(false); + mpArticle.setUrl("http://www.baidu.com"); + List articles = new ArrayList(); + articles.add(mpArticle); + JsonResult result = mediaApi + .updateMaterialArticle( + "17385064953", + 0, articles); + System.err.println(result); + // 17385065153 + } + + @Test + public void countMaterialMedia() throws WeixinException { + MediaCounter counter = mediaApi.countMaterialMedia(); + System.err.println(counter); + } + + @Test + public void listMaterialMedia() throws WeixinException { + MediaRecord mediaRecord = mediaApi.listMaterialMedia(MediaType.news, 0, 20); + System.err.println(mediaRecord); + } } diff --git a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/CustomTest.java b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/CustomTest.java index e79880f6..09c46693 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/CustomTest.java +++ b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/CustomTest.java @@ -15,6 +15,7 @@ import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.mp.api.CustomApi; import com.foxinmy.weixin4j.mp.model.CustomRecord; import com.foxinmy.weixin4j.mp.model.KfAccount; +import com.foxinmy.weixin4j.mp.model.KfSession; import com.foxinmy.weixin4j.mp.test.TokenTest; /** @@ -61,27 +62,60 @@ public class CustomTest extends TokenTest { @Test public void addAccount() throws WeixinException { - JsonResult result = customApi.addAccount("temp1@canyidianzhang", "temp", - "123456"); + JsonResult result = customApi.addAccount("test@test", "test", "123456"); Assert.assertEquals(0, result.getCode()); } - + @Test public void updateAccount() throws WeixinException { - JsonResult result = customApi.updateAccount("temp1@canyidianzhang", "temp", - "123456"); + JsonResult result = customApi.updateAccount("temp1@canyidianzhang", + "temp", "123456"); Assert.assertEquals(0, result.getCode()); } - + @Test public void uploadAccountHeadimg() throws WeixinException, IOException { - JsonResult result = customApi.uploadAccountHeadimg("temp1@canyidianzhang", new File("/Users/jy/Music/简谱/风动草.jpg")); + JsonResult result = customApi.uploadAccountHeadimg( + "temp1@canyidianzhang", new File("/Users/jy/Music/简谱/风动草.jpg")); Assert.assertEquals(0, result.getCode()); } - + @Test public void deleteAccount() throws WeixinException, IOException { JsonResult result = customApi.deleteAccount("temp@canyidianzhang"); Assert.assertEquals(0, result.getCode()); } + + @Test + public void createSession() throws WeixinException { + JsonResult result = customApi.createSession( + "opKwyt6IhrqPmTTZshyqH5W9gIVo", "kfAccount", "text"); + Assert.assertEquals(0, result.getCode()); + } + + @Test + public void closeSession() throws WeixinException { + JsonResult result = customApi.closeSession( + "opKwyt6IhrqPmTTZshyqH5W9gIVo", "kfAccount", "text"); + Assert.assertEquals(0, result.getCode()); + } + + @Test + public void getSession() throws WeixinException { + KfSession session = customApi + .getSession("oz5axuNnJim8yTYs_jzE1bWFj9eA"); + System.err.println(session); + } + + @Test + public void getSessionList() throws WeixinException { + List sessionList = customApi.getSessionList("kfAccount"); + System.err.println(sessionList); + } + + @Test + public void getSessionWaitList() throws WeixinException { + List sessionList = customApi.getSessionWaitList(); + System.err.println(sessionList); + } } diff --git a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/MassMsgTest.java b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/MassMsgTest.java index 8a388e25..0d61b0ab 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/MassMsgTest.java +++ b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/MassMsgTest.java @@ -44,7 +44,7 @@ public class MassMsgTest extends TokenTest { public void uploadArticle() throws IOException, WeixinException { List articles = new ArrayList(); String thumbMediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"), - MediaType.image); + MediaType.image, false); articles.add(new MpArticle(thumbMediaId, "title", "content")); massApi.uploadArticle(articles); } @@ -64,7 +64,8 @@ public class MassMsgTest extends TokenTest { @Test public void massByOpenIds() throws WeixinException { - String msgId = massApi.massByOpenIds(new Text("HI"), "oyFLst1bqtuTcxK-ojF8hOGtLQao"); + String msgId = massApi.massByOpenIds(new Text("HI"), + "oyFLst1bqtuTcxK-ojF8hOGtLQao"); Assert.assertTrue(msgId != null); } @@ -72,7 +73,7 @@ public class MassMsgTest extends TokenTest { public void massArticleByGroup() throws IOException, WeixinException { List articles = new ArrayList(); String thumbMediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"), - MediaType.image); + MediaType.image, false); articles.add(new MpArticle(thumbMediaId, "title", "content")); String massId = massApi.massArticleByGroupId(articles, 0); Assert.assertTrue(massId != null); @@ -82,7 +83,7 @@ public class MassMsgTest extends TokenTest { public void massArticleByOpenIds() throws IOException, WeixinException { List articles = new ArrayList(); String thumbMediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"), - MediaType.image); + MediaType.image, false); articles.add(new MpArticle(thumbMediaId, "title", "content")); String massId = massApi.massArticleByOpenIds(articles, "owGBft_vbBbOaQOmpEUE4xDLeRSU"); @@ -97,10 +98,11 @@ public class MassMsgTest extends TokenTest { @Test public void previewMass() throws WeixinException { - JsonResult result = massApi.previewMassNews("oyFLst1bqtuTcxK-ojF8hOGtLQao", new Text("test")); + JsonResult result = massApi.previewMassNews( + "oyFLst1bqtuTcxK-ojF8hOGtLQao", new Text("test")); Assert.assertEquals("0", result.getCode()); } - + @Test public void getMassNews() throws WeixinException { String status = massApi.getMassNews("82358"); diff --git a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/NotifyMsgTest.java b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/NotifyMsgTest.java index bab2a231..10e83ea8 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/NotifyMsgTest.java +++ b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/msg/NotifyMsgTest.java @@ -92,7 +92,7 @@ public class NotifyMsgTest extends TokenTest { @Test public void send2() throws WeixinException, IOException { String mediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"), - MediaType.image); + MediaType.image, false); NotifyMessage imageNotify = new NotifyMessage( "owGBft_vbBbOaQOmpEUE4xDLeRSU", new Image(mediaId)); JsonResult result = notifyApi.sendNotify(imageNotify); diff --git a/weixin4j-qy/pom.xml b/weixin4j-qy/pom.xml index 4053cae5..e23a899a 100644 --- a/weixin4j-qy/pom.xml +++ b/weixin4j-qy/pom.xml @@ -15,4 +15,4 @@ weixin4j-qy-api weixin4j-qy-server - \ No newline at end of file +