|
@@ -0,0 +1,554 @@
|
|
|
+package com.usoftchina.qywx.sdk.dto;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+
|
|
|
+ * @author yingp
|
|
|
+ */
|
|
|
+public class SendMessageReq {
|
|
|
+
|
|
|
+ private final static int MAX_USER_SIZE = 1000;
|
|
|
+ private final static int MAX_PARTY_SIZE = 100;
|
|
|
+ private final static int MAX_TAG_SIZE = 100;
|
|
|
+
|
|
|
+ private Set<String> userSet;
|
|
|
+ private Set<String> partySet;
|
|
|
+ private Set<String> tagSet;
|
|
|
+
|
|
|
+ * 表示是否是保密消息
|
|
|
+ */
|
|
|
+ private boolean safe;
|
|
|
+
|
|
|
+ * 表示是否开启id转译
|
|
|
+ */
|
|
|
+ private boolean enableIdTrans;
|
|
|
+
|
|
|
+ * 表示是否开启重复消息检查
|
|
|
+ */
|
|
|
+ private boolean enableDuplicateCheck;
|
|
|
+
|
|
|
+ * 表示是否重复消息检查的时间间隔
|
|
|
+ */
|
|
|
+ private Integer duplicateCheckInterval;
|
|
|
+
|
|
|
+ * 消息类型
|
|
|
+ */
|
|
|
+ private String type;
|
|
|
+
|
|
|
+ * 消息内容
|
|
|
+ */
|
|
|
+ private AbstractMessageBody body;
|
|
|
+
|
|
|
+ * 企业应用的id
|
|
|
+ */
|
|
|
+ private Integer agentId;
|
|
|
+
|
|
|
+ public SendMessageReq toUser(String... userIds) {
|
|
|
+ if (null == userSet) {
|
|
|
+ userSet = new HashSet<>(userIds.length);
|
|
|
+ }
|
|
|
+ for (String userId : userIds) {
|
|
|
+ userSet.add(userId);
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SendMessageReq toParty(Integer... partyIds) {
|
|
|
+ if (null == partySet) {
|
|
|
+ partySet = new HashSet<>(partyIds.length);
|
|
|
+ }
|
|
|
+ for (Integer partyId : partyIds) {
|
|
|
+ partySet.add(String.valueOf(partyId));
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SendMessageReq toTag(Integer... tagIds) {
|
|
|
+ if (null == tagSet) {
|
|
|
+ tagSet = new HashSet<>(tagIds.length);
|
|
|
+ }
|
|
|
+ for (Integer tagId : tagIds) {
|
|
|
+ tagSet.add(String.valueOf(tagId));
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SendMessageReq safe(boolean safe) {
|
|
|
+ this.safe = safe;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SendMessageReq enableIdTrans(boolean enableIdTrans) {
|
|
|
+ this.enableIdTrans = enableIdTrans;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SendMessageReq enableDuplicateCheck(boolean enableDuplicateCheck) {
|
|
|
+ this.enableDuplicateCheck = enableDuplicateCheck;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SendMessageReq duplicateCheckInterval(int duplicateCheckInterval) {
|
|
|
+ this.duplicateCheckInterval = duplicateCheckInterval;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SendMessageReq agentId(int agentId) {
|
|
|
+ this.agentId = agentId;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Integer getAgentId() {
|
|
|
+ return agentId;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 文本消息
|
|
|
+ *
|
|
|
+ * @param content
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq text(String content) {
|
|
|
+ this.type = "text";
|
|
|
+ this.body = new Text(content);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 图片消息
|
|
|
+ *
|
|
|
+ * @param mediaId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq image(String mediaId) {
|
|
|
+ this.type = "image";
|
|
|
+ this.body = new Image(mediaId);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 语音消息
|
|
|
+ *
|
|
|
+ * @param mediaId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq voice(String mediaId) {
|
|
|
+ this.type = "voice";
|
|
|
+ this.body = new Voice(mediaId);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 视频消息
|
|
|
+ *
|
|
|
+ * @param mediaId
|
|
|
+ * @param title
|
|
|
+ * @param description
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq video(String mediaId, String title, String description) {
|
|
|
+ this.type = "video";
|
|
|
+ this.body = new Video(mediaId, title, description);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 文件消息
|
|
|
+ *
|
|
|
+ * @param mediaId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq file(String mediaId) {
|
|
|
+ this.type = "file";
|
|
|
+ this.body = new File(mediaId);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 文本卡片消息
|
|
|
+ *
|
|
|
+ * @param title
|
|
|
+ * @param description
|
|
|
+ * @param url
|
|
|
+ * @param btnText
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq textCard(String title, String description, String url, String btnText) {
|
|
|
+ this.type = "textcard";
|
|
|
+ this.body = new TextCard(title, description, url, btnText);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 图文消息
|
|
|
+ *
|
|
|
+ * @param title
|
|
|
+ * @param description
|
|
|
+ * @param url
|
|
|
+ * @param picUrl
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq news(String title, String description, String url, String picUrl) {
|
|
|
+ this.type = "news";
|
|
|
+ this.body = new News(title, description, url, picUrl);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 存储在企业微信的图文消息
|
|
|
+ *
|
|
|
+ * @param title
|
|
|
+ * @param thumbMediaId
|
|
|
+ * @param author
|
|
|
+ * @param contentSourceUrl
|
|
|
+ * @param content
|
|
|
+ * @param digest
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq mpNews(String title, String thumbMediaId, String author, String contentSourceUrl, String content, String digest) {
|
|
|
+ this.type = "mpnews";
|
|
|
+ this.body = new MpNews(title, thumbMediaId, author, contentSourceUrl, content, digest);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * markdown消息
|
|
|
+ *
|
|
|
+ * @param content
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq markdown(String content) {
|
|
|
+ this.type = "markdown";
|
|
|
+ this.body = new Markdown(content);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 任务卡片消息
|
|
|
+ *
|
|
|
+ * @param title
|
|
|
+ * @param description
|
|
|
+ * @param url
|
|
|
+ * @param taskId
|
|
|
+ * @param btns
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public SendMessageReq taskCard(String title, String description, String url, String taskId, List<Btn> btns) {
|
|
|
+ this.type = "taskcard";
|
|
|
+ this.body = new TaskCard(title, description, url, taskId, btns);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> message = new HashMap<>(3);
|
|
|
+ message.put("agentid", agentId);
|
|
|
+ if (null != userSet) {
|
|
|
+ if (userSet.size() > MAX_USER_SIZE) {
|
|
|
+ throw new RuntimeException(String.format("最多支持%s个用户", MAX_USER_SIZE));
|
|
|
+ }
|
|
|
+ message.put("touser", String.join("|", userSet));
|
|
|
+ }
|
|
|
+ if (null != partySet) {
|
|
|
+ if (partySet.size() > MAX_PARTY_SIZE) {
|
|
|
+ throw new RuntimeException(String.format("最多支持%s个部门", MAX_PARTY_SIZE));
|
|
|
+ }
|
|
|
+ message.put("toparty", String.join("|", partySet));
|
|
|
+ }
|
|
|
+ if (null != tagSet) {
|
|
|
+ if (tagSet.size() > MAX_TAG_SIZE) {
|
|
|
+ throw new RuntimeException(String.format("最多支持%s个标签", MAX_TAG_SIZE));
|
|
|
+ }
|
|
|
+ message.put("totag", String.join("|", tagSet));
|
|
|
+ }
|
|
|
+ if (safe) {
|
|
|
+ message.put("safe", 1);
|
|
|
+ }
|
|
|
+ if (enableIdTrans) {
|
|
|
+ message.put("enable_id_trans", 1);
|
|
|
+ }
|
|
|
+ if (enableDuplicateCheck) {
|
|
|
+ message.put("enable_duplicate_check", 1);
|
|
|
+ }
|
|
|
+ if (null != duplicateCheckInterval) {
|
|
|
+ message.put("duplicate_check_interval", duplicateCheckInterval);
|
|
|
+ }
|
|
|
+ if (null != type) {
|
|
|
+ message.put("msgtype", type);
|
|
|
+ message.put(type, body.build());
|
|
|
+ }
|
|
|
+ return message;
|
|
|
+ }
|
|
|
+
|
|
|
+ interface AbstractMessageBody {
|
|
|
+ Map<String, Object> build();
|
|
|
+ }
|
|
|
+
|
|
|
+ class Text implements AbstractMessageBody {
|
|
|
+ private final String content;
|
|
|
+
|
|
|
+ public Text(String content) {
|
|
|
+ this.content = content;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ data.put("content", content);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class Image implements AbstractMessageBody {
|
|
|
+
|
|
|
+ * 图片媒体文件id,可以调用上传临时素材接口获取
|
|
|
+ */
|
|
|
+ private final String mediaId;
|
|
|
+
|
|
|
+ public Image(String mediaId) {
|
|
|
+ this.mediaId = mediaId;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ data.put("media_id", mediaId);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class Voice implements AbstractMessageBody {
|
|
|
+
|
|
|
+ * 语音文件id,可以调用上传临时素材接口获取
|
|
|
+ */
|
|
|
+ private final String mediaId;
|
|
|
+
|
|
|
+ public Voice(String mediaId) {
|
|
|
+ this.mediaId = mediaId;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ data.put("media_id", mediaId);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class Video implements AbstractMessageBody {
|
|
|
+
|
|
|
+ * 视频媒体文件id,可以调用上传临时素材接口获取
|
|
|
+ */
|
|
|
+ private final String mediaId;
|
|
|
+ private final String title;
|
|
|
+ private final String description;
|
|
|
+
|
|
|
+ public Video(String mediaId, String title, String description) {
|
|
|
+ this.mediaId = mediaId;
|
|
|
+ this.title = title;
|
|
|
+ this.description = description;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ data.put("media_id", mediaId);
|
|
|
+ data.put("title", title);
|
|
|
+ data.put("description", description);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class File implements AbstractMessageBody {
|
|
|
+
|
|
|
+ * 文件id,可以调用上传临时素材接口获取
|
|
|
+ */
|
|
|
+ private final String mediaId;
|
|
|
+
|
|
|
+ public File(String mediaId) {
|
|
|
+ this.mediaId = mediaId;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ data.put("media_id", mediaId);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class TextCard implements AbstractMessageBody {
|
|
|
+ private final String title;
|
|
|
+ private final String description;
|
|
|
+ private final String url;
|
|
|
+ private final String btnText;
|
|
|
+
|
|
|
+ public TextCard(String title, String description, String url, String btnText) {
|
|
|
+ this.title = title;
|
|
|
+ this.description = description;
|
|
|
+ this.url = url;
|
|
|
+ this.btnText = btnText;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ data.put("title", title);
|
|
|
+ data.put("description", description);
|
|
|
+ data.put("url", url);
|
|
|
+ data.put("btntxt", btnText);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class News implements AbstractMessageBody {
|
|
|
+ private final String title;
|
|
|
+ private final String description;
|
|
|
+ private final String url;
|
|
|
+ private final String picUrl;
|
|
|
+
|
|
|
+ public News(String title, String description, String url, String picUrl) {
|
|
|
+ this.title = title;
|
|
|
+ this.description = description;
|
|
|
+ this.url = url;
|
|
|
+ this.picUrl = picUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ Map<String, Object> article = new HashMap<>(4);
|
|
|
+ article.put("title", title);
|
|
|
+ article.put("description", description);
|
|
|
+ article.put("url", url);
|
|
|
+ article.put("picurl", picUrl);
|
|
|
+ data.put("articles", Arrays.asList(article));
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class MpNews implements AbstractMessageBody {
|
|
|
+ private final String title;
|
|
|
+ private final String thumbMediaId;
|
|
|
+ private final String author;
|
|
|
+ private final String contentSourceUrl;
|
|
|
+ private final String content;
|
|
|
+ private final String digest;
|
|
|
+
|
|
|
+ public MpNews(String title, String thumbMediaId, String author, String contentSourceUrl, String content, String digest) {
|
|
|
+ this.title = title;
|
|
|
+ this.thumbMediaId = thumbMediaId;
|
|
|
+ this.author = author;
|
|
|
+ this.contentSourceUrl = contentSourceUrl;
|
|
|
+ this.content = content;
|
|
|
+ this.digest = digest;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ Map<String, Object> article = new HashMap<>(4);
|
|
|
+ article.put("title", title);
|
|
|
+ article.put("thumb_media_id", thumbMediaId);
|
|
|
+ article.put("author", author);
|
|
|
+ article.put("content_source_url", contentSourceUrl);
|
|
|
+ article.put("content", content);
|
|
|
+ article.put("digest", digest);
|
|
|
+ data.put("articles", Arrays.asList(article));
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class Markdown implements AbstractMessageBody {
|
|
|
+ private final String content;
|
|
|
+
|
|
|
+ public Markdown(String content) {
|
|
|
+ this.content = content;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ data.put("content", content);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class TaskCard implements AbstractMessageBody {
|
|
|
+ private final String title;
|
|
|
+ private final String description;
|
|
|
+ private final String url;
|
|
|
+ private final String taskId;
|
|
|
+ private final List<Btn> btns;
|
|
|
+
|
|
|
+ public TaskCard(String title, String description, String url, String taskId, List<Btn> btns) {
|
|
|
+ this.title = title;
|
|
|
+ this.description = description;
|
|
|
+ this.url = url;
|
|
|
+ this.taskId = taskId;
|
|
|
+ this.btns = btns;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ data.put("title", title);
|
|
|
+ data.put("description", description);
|
|
|
+ data.put("url", url);
|
|
|
+ data.put("task_id", taskId);
|
|
|
+ data.put("btn", btns.stream().map(Btn::build).collect(Collectors.toList()));
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class Btn {
|
|
|
+
|
|
|
+ * 按钮key值,用户点击后,会产生任务卡片回调事件,回调事件会带上该key值,只能由数字、字母和“_-@.”组成,最长支持128字节
|
|
|
+ */
|
|
|
+ private final String key;
|
|
|
+
|
|
|
+ * 按钮名称
|
|
|
+ */
|
|
|
+ private final String name;
|
|
|
+
|
|
|
+ * 点击按钮后显示的名称,默认为“已处理”
|
|
|
+ */
|
|
|
+ private final String replaceName;
|
|
|
+
|
|
|
+ * 按钮字体颜色,可选“red”或者“blue”,默认为“blue”
|
|
|
+ */
|
|
|
+ private String color;
|
|
|
+
|
|
|
+ * 按钮字体是否加粗,默认false
|
|
|
+ */
|
|
|
+ private boolean bold;
|
|
|
+
|
|
|
+ public Btn(String key, String name, String replaceName) {
|
|
|
+ this.key = key;
|
|
|
+ this.name = name;
|
|
|
+ this.replaceName = replaceName;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Btn(String key, String name, String replaceName, String color, boolean bold) {
|
|
|
+ this.key = key;
|
|
|
+ this.name = name;
|
|
|
+ this.replaceName = replaceName;
|
|
|
+ this.color = color;
|
|
|
+ this.bold = bold;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Map<String, Object> build() {
|
|
|
+ Map<String, Object> data = new HashMap<>(1);
|
|
|
+ data.put("key", key);
|
|
|
+ data.put("name", name);
|
|
|
+ data.put("replaceName", replaceName);
|
|
|
+ if (null != color) {
|
|
|
+ data.put("color", color);
|
|
|
+ }
|
|
|
+ if (bold) {
|
|
|
+ data.put("is_bold", true);
|
|
|
+ }
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|