From f30ac6be6c6f11605d5bc2f8fa9b3e850a9a387b Mon Sep 17 00:00:00 2001
From: 0katekate0 <32161300+0katekate0@users.noreply.github.com>
Date: Wed, 6 Jul 2022 23:50:32 +0800
Subject: [PATCH] =?UTF-8?q?:new:=20#2725=E3=80=90=E4=BC=81=E4=B8=9A?=
=?UTF-8?q?=E5=BE=AE=E4=BF=A1=E3=80=91=E5=A2=9E=E5=8A=A0=E5=AE=B6=E6=A0=A1?=
=?UTF-8?q?=E6=B2=9F=E9=80=9A-=E5=8F=91=E9=80=81=E3=80=8C=E5=AD=A6?=
=?UTF-8?q?=E6=A0=A1=E9=80=9A=E7=9F=A5=E3=80=8D=E7=9A=84=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../chanjar/weixin/common/api/WxConsts.java | 50 ++-
.../weixin/cp/api/WxCpMessageService.java | 16 +
.../weixin/cp/api/WxCpSchoolUserService.java | 33 ++
.../cp/api/impl/WxCpMessageServiceImpl.java | 11 +
.../api/impl/WxCpSchoolUserServiceImpl.java | 21 +
.../weixin/cp/bean/article/NewArticle.java | 13 +-
.../bean/message/WxCpLinkedCorpMessage.java | 1 +
.../message/WxCpSchoolContactMessage.java | 311 ++++++++++++++
.../WxCpSchoolContactMessageSendResult.java | 36 ++
.../user/WxCpBatchCreateStudentRequest.java | 59 +++
.../user/WxCpBatchDeleteStudentRequest.java | 36 ++
.../bean/school/user/WxCpBatchResultList.java | 54 +++
.../user/WxCpBatchUpdateStudentRequest.java | 62 +++
.../weixin/cp/constant/WxCpApiPathConsts.java | 13 +
.../weixin/cp/api/WxCpSchoolUserTest.java | 80 ++++
.../api/impl/WxCpMessageServiceImplTest.java | 1 -
.../message/WxCpSchoolContactMessageTest.java | 395 ++++++++++++++++++
17 files changed, 1188 insertions(+), 4 deletions(-)
create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessage.java
create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessageSendResult.java
create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchCreateStudentRequest.java
create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchDeleteStudentRequest.java
create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchResultList.java
create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchUpdateStudentRequest.java
create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessageTest.java
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
index 27b12a925..5bef9f28a 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
@@ -10,7 +10,7 @@ import static me.chanjar.weixin.common.error.WxMpErrorMsgEnum.*;
/**
* 微信开发所使用到的常量类.
*
- * @author Daniel Qian & binarywang
+ * @author Daniel Qian & binarywang & Wang_Wong
*/
public class WxConsts {
/**
@@ -133,6 +133,54 @@ public class WxConsts {
public static final String MP_NEWS_ARTICLE = "mpnewsarticle";
}
+ /**
+ * 发送「学校通知」类型
+ * https://developer.work.weixin.qq.com/document/path/92321
+ */
+ public static class SchoolContactMsgType {
+
+ /**
+ * 文本消息.
+ */
+ public static final String TEXT = "text";
+
+ /**
+ * 图片消息.
+ */
+ public static final String IMAGE = "image";
+
+ /**
+ * 语音消息.
+ */
+ public static final String VOICE = "voice";
+
+ /**
+ * 视频消息.
+ */
+ public static final String VIDEO = "video";
+
+ /**
+ * 文件消息
+ */
+ public static final String FILE = "file";
+
+ /**
+ * 图文消息
+ */
+ public static final String NEWS = "news";
+
+ /**
+ * 图文消息(mpnews)
+ */
+ public static final String MPNEWS = "mpnews";
+
+ /**
+ * 小程序消息
+ */
+ public static final String MINIPROGRAM = "miniprogram";
+
+ }
+
/**
* 企业微信模板卡片消息的卡片类型
*/
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageService.java
index 1b66d00c0..ff71ea0c4 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageService.java
@@ -50,4 +50,20 @@ public interface WxCpMessageService {
* @throws WxErrorException the wx error exception
*/
WxCpLinkedCorpMessageSendResult sendLinkedCorpMessage(WxCpLinkedCorpMessage message) throws WxErrorException;
+
+ /**
+ * 发送「学校通知」
+ * https://developer.work.weixin.qq.com/document/path/92321
+ *
+ * 学校可以通过此接口来给家长发送不同类型的学校通知,来满足多种场景下的学校通知需求。目前支持的消息类型为文本、图片、语音、视频、文件、图文。
+ *
+ * 请求方式:POST(HTTPS)
+ * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/externalcontact/message/send?access_token=ACCESS_TOKEN
+ *
+ * @param message 要发送的消息对象
+ * @return
+ * @throws WxErrorException
+ */
+ WxCpSchoolContactMessageSendResult sendSchoolContactMessage(WxCpSchoolContactMessage message) throws WxErrorException;
+
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpSchoolUserService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpSchoolUserService.java
index 031b17ee7..b12ba0a14 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpSchoolUserService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpSchoolUserService.java
@@ -29,6 +29,39 @@ public interface WxCpSchoolUserService {
*/
WxCpBaseResp createStudent(@NonNull String studentUserId, @NonNull String name, @NonNull List departments) throws WxErrorException;
+ /**
+ * 批量创建学生
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/school/user/batch_create_student?access_token=ACCESS_TOKEN
+ *
+ * @param request
+ * @return
+ * @throws WxErrorException
+ */
+ WxCpBatchResultList batchCreateStudent(@NonNull WxCpBatchCreateStudentRequest request) throws WxErrorException;
+
+ /**
+ * 批量删除学生
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/school/user/batch_delete_student?access_token=ACCESS_TOKEN
+ *
+ * @param request
+ * @return
+ * @throws WxErrorException
+ */
+ WxCpBatchResultList batchDeleteStudent(@NonNull WxCpBatchDeleteStudentRequest request) throws WxErrorException;
+
+ /**
+ * 批量更新学生
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/school/user/batch_update_student?access_token=ACCESS_TOKEN
+ *
+ * @param request
+ * @return
+ * @throws WxErrorException
+ */
+ WxCpBatchResultList batchUpdateStudent(@NonNull WxCpBatchUpdateStudentRequest request) throws WxErrorException;
+
/**
* 删除学生
* 请求方式:GET(HTTPS)
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImpl.java
index 9be2f60df..37b1d1821 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImpl.java
@@ -46,4 +46,15 @@ public class WxCpMessageServiceImpl implements WxCpMessageService {
return WxCpLinkedCorpMessageSendResult.fromJson(this.cpService.post(this.cpService.getWxCpConfigStorage()
.getApiUrl(Message.LINKEDCORP_MESSAGE_SEND), message.toJson()));
}
+
+ @Override
+ public WxCpSchoolContactMessageSendResult sendSchoolContactMessage(WxCpSchoolContactMessage message) throws WxErrorException {
+ if (null == message.getAgentId()) {
+ message.setAgentId(this.cpService.getWxCpConfigStorage().getAgentId());
+ }
+
+ return WxCpSchoolContactMessageSendResult.fromJson(this.cpService.post(this.cpService.getWxCpConfigStorage()
+ .getApiUrl(Message.EXTERNAL_CONTACT_MESSAGE_SEND), message.toJson()));
+ }
+
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java
index 3143e592e..cbf049861 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java
@@ -47,6 +47,27 @@ public class WxCpSchoolUserServiceImpl implements WxCpSchoolUserService {
return WxCpBaseResp.fromJson(responseContent);
}
+ @Override
+ public WxCpBatchResultList batchCreateStudent(@NonNull WxCpBatchCreateStudentRequest request) throws WxErrorException {
+ String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(BATCH_CREATE_STUDENT);
+ String responseContent = this.cpService.post(apiUrl, request.toJson());
+ return WxCpBatchResultList.fromJson(responseContent);
+ }
+
+ @Override
+ public WxCpBatchResultList batchDeleteStudent(@NonNull WxCpBatchDeleteStudentRequest request) throws WxErrorException {
+ String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(BATCH_DELETE_STUDENT);
+ String responseContent = this.cpService.post(apiUrl, request.toJson());
+ return WxCpBatchResultList.fromJson(responseContent);
+ }
+
+ @Override
+ public WxCpBatchResultList batchUpdateStudent(@NonNull WxCpBatchUpdateStudentRequest request) throws WxErrorException {
+ String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(BATCH_UPDATE_STUDENT);
+ String responseContent = this.cpService.post(apiUrl, request.toJson());
+ return WxCpBatchResultList.fromJson(responseContent);
+ }
+
@Override
public WxCpBaseResp deleteStudent(@NonNull String studentUserId) throws WxErrorException {
String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(DELETE_STUDENT) + studentUserId;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java
index 9dd4a4028..f1e199939 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java
@@ -20,18 +20,22 @@ import java.io.Serializable;
@NoArgsConstructor
public class NewArticle implements Serializable {
private static final long serialVersionUID = 4087852055781140659L;
+
/**
* 标题,不超过128个字节,超过会自动截断
*/
private String title;
+
/**
* 描述,不超过512个字节,超过会自动截断
*/
private String description;
+
/**
* 点击后跳转的链接。
*/
private String url;
+
/**
* 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图1068*455,小图150*150。
*/
@@ -42,9 +46,14 @@ public class NewArticle implements Serializable {
*/
private String btnText;
- /**小程序appid,必须是与当前应用关联的小程序,appid和pagepath必须同时填写,填写后会忽略url字段**/
+ /**
+ * 小程序appid,必须是与当前应用关联的小程序,appid和pagepath必须同时填写,填写后会忽略url字段
+ */
private String appid;
- /**点击消息卡片后的小程序页面,仅限本小程序内的页面。appid和pagepath必须同时填写,填写后会忽略url字段**/
+ /**
+ * 点击消息卡片后的小程序页面,仅限本小程序内的页面。appid和pagepath必须同时填写,填写后会忽略url字段
+ */
private String pagepath;
+
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessage.java
index 0e3f67087..042d955bb 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessage.java
@@ -21,6 +21,7 @@ import static me.chanjar.weixin.cp.constant.WxCpConsts.LinkedCorpMsgType.*;
/**
* 互联企业消息.
+ * https://developer.work.weixin.qq.com/document/path/90250
*
* @author Binary Wang
* @date 2020-08-30
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessage.java
new file mode 100644
index 000000000..77ba45de7
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessage.java
@@ -0,0 +1,311 @@
+package me.chanjar.weixin.cp.bean.message;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import me.chanjar.weixin.common.api.WxConsts.SchoolContactMsgType;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
+import me.chanjar.weixin.cp.bean.article.NewArticle;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import static me.chanjar.weixin.common.api.WxConsts.SchoolContactMsgType.*;
+
+/**
+ * 发送「学校通知」
+ * https://developer.work.weixin.qq.com/document/path/92321
+ *
+ * @author Wang_Wong
+ * @date 2022-06-29
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class WxCpSchoolContactMessage implements Serializable {
+ private static final long serialVersionUID = 8833792280163704238L;
+
+ /**
+ * 指定发送对象,0表示发送给家长,1表示发送给学生,2表示发送给家长和学生,默认为0。
+ */
+ @SerializedName("recv_scope")
+ private Integer recvScope = 0;
+
+ /**
+ * 家校通讯录家长列表,recv_scope为0或2表示发送给对应的家长,recv_scope为1忽略,(最多支持1000个)
+ */
+ @SerializedName("to_parent_userid")
+ private String[] toParentUserId;
+
+ /**
+ * 家校通讯录学生列表,recv_scope为0表示发送给学生的所有家长,recv_scope为1表示发送给学生,recv_scope为2表示发送给学生和学生的所有家长(最多支持1000个)
+ */
+ @SerializedName("to_student_userid")
+ private String[] toStudentUserId;
+
+ /**
+ * 家校通讯录部门列表,recv_scope为0表示发送给班级的所有家长,recv_scope为1表示发送给班级的所有学生,recv_scope为2表示发送给班级的所有学生和家长(最多支持100个)
+ */
+ @SerializedName("to_party")
+ private String[] toParty;
+
+ /**
+ * 1表示字段生效,0表示字段无效。recv_scope为0表示发送给学校的所有家长,recv_scope为1表示发送给学校的所有学生,recv_scope为2表示发送给学校的所有学生和家长,默认为0
+ */
+ @SerializedName("toall")
+ private Boolean toAll = false;
+
+ /**
+ * 消息类型
+ */
+ @SerializedName("msgtype")
+ private String msgType;
+
+ /**
+ * 企业应用的id,整型。可在应用的设置页面查看
+ */
+ @SerializedName("agentid")
+ private Integer agentId;
+
+ /**
+ * 消息内容,最长不超过2048个字节(支持id转译)
+ */
+ @SerializedName("content")
+ private String content;
+
+ /**
+ * enable_id_trans
+ * 表示是否开启id转译,0表示否,1表示是,默认0
+ */
+ @SerializedName("enable_id_trans")
+ private Boolean enableIdTrans = false;
+
+ /**
+ * enable_duplicate_check
+ * 表示是否开启重复消息检查,0表示否,1表示是,默认0
+ */
+ @SerializedName("enable_duplicate_check")
+ private Boolean enableDuplicateCheck = false;
+
+ /**
+ * duplicate_check_interval
+ * 表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时
+ */
+ @SerializedName("duplicate_check_interval")
+ private Integer duplicateCheckInterval;
+
+ /**
+ * 图片媒体文件id,可以调用上传临时素材接口获取
+ */
+ @SerializedName("media_id")
+ private String mediaId;
+
+ /**
+ * 视频消息的标题,不超过128个字节,超过会自动截断
+ */
+ @SerializedName("title")
+ private String title;
+
+ /**
+ * 视频消息的描述,不超过512个字节,超过会自动截断
+ */
+ @SerializedName("description")
+ private String description;
+
+ /**
+ * 小程序消息封面的mediaid,封面图建议尺寸为520*416
+ */
+ @SerializedName("thumb_media_id")
+ private String thumbMediaId;
+
+ /**
+ * 小程序appid,必须是关联到企业的小程序应用
+ */
+ @SerializedName("appid")
+ private String appId;
+
+ /**
+ * 点击消息卡片后进入的小程序页面路径
+ */
+ @SerializedName("pagepath")
+ private String pagePath;
+
+ /**
+ * 图文消息
+ * https://developer.work.weixin.qq.com/document/path/92321#%E5%9B%BE%E6%96%87%E6%B6%88%E6%81%AF
+ */
+ private List articles = new ArrayList<>();
+
+ /**
+ * 图文消息(mpnews)
+ * https://developer.work.weixin.qq.com/document/path/92321#%E5%9B%BE%E6%96%87%E6%B6%88%E6%81%AF%EF%BC%88mpnews%EF%BC%89
+ *
+ * mpnews类型的图文消息,跟普通的图文消息一致,唯一的差异是图文内容存储在企业微信。
+ * 多次发送mpnews,会被认为是不同的图文,阅读、点赞的统计会被分开计算。
+ */
+ private List mpNewsArticles = new ArrayList<>();
+
+ /**
+ *
+ * 请使用.
+ * {@link SchoolContactMsgType#TEXT}
+ * {@link SchoolContactMsgType#IMAGE}
+ * {@link SchoolContactMsgType#VOICE}
+ * {@link SchoolContactMsgType#VIDEO}
+ * {@link SchoolContactMsgType#NEWS}
+ * {@link SchoolContactMsgType#MPNEWS}
+ * {@link SchoolContactMsgType#MINIPROGRAM}
+ *
+ *
+ * @param msgType 消息类型
+ */
+ public void setMsgType(String msgType) {
+ this.msgType = msgType;
+ }
+
+ public String toJson() {
+ JsonObject messageJson = new JsonObject();
+
+ if (this.getRecvScope() != null) {
+ messageJson.addProperty("recv_scope", this.getRecvScope());
+ }
+
+ if (ArrayUtils.isNotEmpty(this.getToParentUserId())) {
+ messageJson.add("to_parent_userid", WxGsonBuilder.create().toJsonTree(this.getToParentUserId()));
+ }
+
+ if (ArrayUtils.isNotEmpty(this.getToStudentUserId())) {
+ messageJson.add("to_student_userid", WxGsonBuilder.create().toJsonTree(this.getToStudentUserId()));
+ }
+
+ if (ArrayUtils.isNotEmpty(this.getToParty())) {
+ messageJson.add("to_party", WxGsonBuilder.create().toJsonTree(this.getToParty()));
+ }
+
+ if (this.getToAll() != null) {
+ messageJson.addProperty("toall", this.getToAll() ? 1 : 0);
+ }
+
+ messageJson.addProperty("msgtype", this.getMsgType());
+
+ if (this.getAgentId() != null) {
+ messageJson.addProperty("agentid", this.getAgentId());
+ }
+
+ if (this.getEnableIdTrans() != null && this.getEnableIdTrans()) {
+ messageJson.addProperty("enable_id_trans", 1);
+ }
+
+ if (this.getEnableDuplicateCheck() != null && this.getEnableDuplicateCheck()) {
+ messageJson.addProperty("enable_duplicate_check", 1);
+ }
+
+ if (this.getDuplicateCheckInterval() != null) {
+ messageJson.addProperty("duplicate_check_interval", this.getDuplicateCheckInterval());
+ }
+
+ this.handleMsgType(messageJson);
+
+ return messageJson.toString();
+ }
+
+ /**
+ * 封装消息类型
+ *
+ * @param messageJson
+ */
+ private void handleMsgType(JsonObject messageJson) {
+ switch (this.getMsgType()) {
+ case TEXT: {
+ JsonObject text = new JsonObject();
+ text.addProperty("content", this.getContent());
+ messageJson.add("text", text);
+ break;
+ }
+ case IMAGE: {
+ JsonObject image = new JsonObject();
+ image.addProperty("media_id", this.getMediaId());
+ messageJson.add("image", image);
+ break;
+ }
+ case FILE: {
+ JsonObject image = new JsonObject();
+ image.addProperty("media_id", this.getMediaId());
+ messageJson.add("file", image);
+ break;
+ }
+ case VOICE: {
+ JsonObject voice = new JsonObject();
+ voice.addProperty("media_id", this.getMediaId());
+ messageJson.add("voice", voice);
+ break;
+ }
+ case VIDEO: {
+ JsonObject video = new JsonObject();
+ video.addProperty("media_id", this.getMediaId());
+ video.addProperty("title", this.getTitle());
+ video.addProperty("description", this.getDescription());
+ messageJson.add("video", video);
+ break;
+ }
+ case NEWS: {
+ JsonObject newsJsonObject = new JsonObject();
+ JsonArray articleJsonArray = new JsonArray();
+ for (NewArticle article : this.getArticles()) {
+ JsonObject articleJson = new JsonObject();
+ articleJson.addProperty("title", article.getTitle());
+ articleJson.addProperty("description", article.getDescription());
+ articleJson.addProperty("url", article.getUrl());
+ articleJson.addProperty("picurl", article.getPicUrl());
+ articleJsonArray.add(articleJson);
+ }
+ newsJsonObject.add("articles", articleJsonArray);
+ messageJson.add("news", newsJsonObject);
+ break;
+ }
+ case MPNEWS: {
+ JsonObject newsJsonObject = new JsonObject();
+ JsonArray articleJsonArray = new JsonArray();
+ for (MpnewsArticle article : this.getMpNewsArticles()) {
+ JsonObject articleJson = new JsonObject();
+ articleJson.addProperty("title", article.getTitle());
+ articleJson.addProperty("thumb_media_id", article.getThumbMediaId());
+ articleJson.addProperty("author", article.getAuthor());
+ articleJson.addProperty("content_source_url", article.getContentSourceUrl());
+ articleJson.addProperty("content", article.getContent());
+ articleJson.addProperty("digest", article.getDigest());
+ articleJsonArray.add(articleJson);
+ }
+ newsJsonObject.add("articles", articleJsonArray);
+ messageJson.add("mpnews", newsJsonObject);
+ break;
+ }
+ case MINIPROGRAM: {
+ JsonObject miniprogram = new JsonObject();
+ miniprogram.addProperty("appid", this.getAppId());
+ miniprogram.addProperty("pagepath", this.getPagePath());
+ miniprogram.addProperty("title", this.getTitle());
+ miniprogram.addProperty("thumb_media_id", this.getThumbMediaId());
+
+ messageJson.add("miniprogram", miniprogram);
+ break;
+ }
+ default: {
+ // do nothing
+ }
+
+ }
+
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessageSendResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessageSendResult.java
new file mode 100644
index 000000000..b65e8352d
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessageSendResult.java
@@ -0,0 +1,36 @@
+package me.chanjar.weixin.cp.bean.message;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * 发送「学校通知」返回实体
+ * https://developer.work.weixin.qq.com/document/path/92321
+ *
+ * @author Wang_Wong
+ * @date 2022-06-29
+ */
+@Data
+public class WxCpSchoolContactMessageSendResult extends WxCpBaseResp {
+ private static final long serialVersionUID = 3990693822996824333L;
+
+ @SerializedName("invalid_parent_userid")
+ private String[] invalidParentUserId;
+
+ @SerializedName("invalid_student_userid")
+ private String[] invalidStudentUserId;
+
+ @SerializedName("invalid_party")
+ private String[] invalidParty;
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ public static WxCpSchoolContactMessageSendResult fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpSchoolContactMessageSendResult.class);
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchCreateStudentRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchCreateStudentRequest.java
new file mode 100644
index 000000000..60c208895
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchCreateStudentRequest.java
@@ -0,0 +1,59 @@
+package me.chanjar.weixin.cp.bean.school.user;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.*;
+import lombok.experimental.Accessors;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 批量创建学生请求.
+ *
+ * @author Wang_Wong
+ * @date 2022-07-01
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class WxCpBatchCreateStudentRequest implements Serializable {
+ private static final long serialVersionUID = -4960239393895754138L;
+
+ @SerializedName("students")
+ private List students;
+
+ @Setter
+ @Getter
+ public static class Student implements Serializable {
+
+ @SerializedName("student_userid")
+ private String studentUserId;
+
+ @SerializedName("name")
+ private String name;
+
+ @SerializedName("department")
+ private List department;
+
+ public static Student fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, Student.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ }
+
+ public static WxCpBatchCreateStudentRequest fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpBatchCreateStudentRequest.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchDeleteStudentRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchDeleteStudentRequest.java
new file mode 100644
index 000000000..801832cb1
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchDeleteStudentRequest.java
@@ -0,0 +1,36 @@
+package me.chanjar.weixin.cp.bean.school.user;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.*;
+import lombok.experimental.Accessors;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 批量删除学生请求.
+ *
+ * @author Wang_Wong
+ * @date 2022-07-01
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class WxCpBatchDeleteStudentRequest implements Serializable {
+ private static final long serialVersionUID = -4960239393895754138L;
+
+ @SerializedName("useridlist")
+ private List userIdList;
+
+ public static WxCpBatchDeleteStudentRequest fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpBatchDeleteStudentRequest.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchResultList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchResultList.java
new file mode 100644
index 000000000..a3cf805db
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchResultList.java
@@ -0,0 +1,54 @@
+package me.chanjar.weixin.cp.bean.school.user;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 批量返回结果.
+ *
+ * @author Wang_Wong
+ * @date 2022-07-01
+ */
+@Data
+public class WxCpBatchResultList extends WxCpBaseResp implements Serializable {
+ private static final long serialVersionUID = -5028321625140879571L;
+
+ @SerializedName("result_list")
+ private List resultList;
+
+ @Setter
+ @Getter
+ public static class ResultList extends WxCpBaseResp{
+
+ @SerializedName("parent_userid")
+ private String parentUserId;
+
+ @SerializedName("student_userid")
+ private String studentUserId;
+
+ public static ResultList fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, ResultList.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ }
+
+ public static WxCpBatchResultList fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpBatchResultList.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchUpdateStudentRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchUpdateStudentRequest.java
new file mode 100644
index 000000000..106450672
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/school/user/WxCpBatchUpdateStudentRequest.java
@@ -0,0 +1,62 @@
+package me.chanjar.weixin.cp.bean.school.user;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.*;
+import lombok.experimental.Accessors;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 批量更新学生请求.
+ *
+ * @author Wang_Wong
+ * @date 2022-07-01
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class WxCpBatchUpdateStudentRequest implements Serializable {
+ private static final long serialVersionUID = -4960239393895754138L;
+
+ @SerializedName("students")
+ private List students;
+
+ @Setter
+ @Getter
+ public static class Student implements Serializable {
+
+ @SerializedName("student_userid")
+ private String studentUserId;
+
+ @SerializedName("new_student_userid")
+ private String newStudentUserId;
+
+ @SerializedName("name")
+ private String name;
+
+ @SerializedName("department")
+ private List department;
+
+ public static Student fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, Student.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ }
+
+ public static WxCpBatchUpdateStudentRequest fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpBatchUpdateStudentRequest.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
index 04f67f2c6..042d13485 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
@@ -28,6 +28,7 @@ public interface WxCpApiPathConsts {
* https://work.weixin.qq.com/api/doc/90000/90135/90235
*/
interface Message {
+
/**
* 发送应用消息
*/
@@ -40,8 +41,16 @@ public interface WxCpApiPathConsts {
/**
* 互联企业发送应用消息
+ * https://developer.work.weixin.qq.com/document/path/90250
*/
String LINKEDCORP_MESSAGE_SEND = "/cgi-bin/linkedcorp/message/send";
+
+ /**
+ * 发送「学校通知」
+ * https://developer.work.weixin.qq.com/document/path/92321
+ */
+ String EXTERNAL_CONTACT_MESSAGE_SEND = "/cgi-bin/externalcontact/message/send";
+
}
interface Agent {
@@ -183,6 +192,10 @@ public interface WxCpApiPathConsts {
String GET_STUDENT_CUSTOMIZE_HEALTH_INFO = "/cgi-bin/school/user/get_student_customize_health_info";
String GET_HEALTH_QRCODE = "/cgi-bin/school/user/get_health_qrcode";
+ String BATCH_CREATE_STUDENT = "/cgi-bin/school/user/batch_create_student";
+ String BATCH_DELETE_STUDENT = "/cgi-bin/school/user/batch_delete_student";
+ String BATCH_UPDATE_STUDENT = "/cgi-bin/school/user/batch_update_student";
+
String CREATE_STUDENT = "/cgi-bin/school/user/create_student";
String DELETE_STUDENT = "/cgi-bin/school/user/delete_student?userid=";
String UPDATE_STUDENT = "/cgi-bin/school/user/update_student";
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpSchoolUserTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpSchoolUserTest.java
index d77d24cba..dca1c04c4 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpSchoolUserTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpSchoolUserTest.java
@@ -52,6 +52,86 @@ public class WxCpSchoolUserTest {
final String exUserId = "wmOQpTDwAAJFHrryZ8I8ALLEZuLHIUKA";
+ // 返回值
+ String batchResult = "{\n" +
+ "\t\"errcode\": 1,\n" +
+ "\t\"errmsg\": \"invalid student_userid: zhangsan\",\n" +
+ "\t\"result_list\": [\n" +
+ "\t\t{\n" +
+ "\t\t\t\"student_userid\": \"zhangsan\",\n" +
+ "\t\t\t\"errcode\": 1,\n" +
+ "\t\t\t\"errmsg\": \"invalid student_userid: zhangsan\"\n" +
+ "\t\t}\n" +
+ "\t]\n" +
+ "}";
+
+ WxCpBatchResultList batchResultList = WxCpBatchResultList.fromJson(batchResult);
+ log.info("batchResultList: {}", batchResultList.toJson());
+
+
+ /**
+ * 批量更新学生
+ * https://developer.work.weixin.qq.com/document/path/92330
+ *
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/school/user/batch_update_student?access_token=ACCESS_TOKEN
+ */
+ String batchUpdateStudent = "{\n" +
+ "\t\"students\":[\n" +
+ " {\n" +
+ "\t\t\t\"student_userid\": \"zhangsan\",\n" +
+ "\t\t\t\"new_student_userid\":\"zhangsan_new\",\n" +
+ "\t\t\t\"name\": \"张三\",\n" +
+ "\t\t\t\"department\": [1, 2]\n" +
+ "\t\t},\n" +
+ " {\n" +
+ "\t\t\t\"student_userid\": \"lisi\",\n" +
+ "\t\t\t\"name\": \"李四\",\n" +
+ "\t\t\t\"department\": [3, 4]\n" +
+ "\t\t}\n" +
+ " ]\n" +
+ "}";
+ WxCpBatchUpdateStudentRequest batchUpdateStudentRequest = WxCpBatchUpdateStudentRequest.fromJson(batchUpdateStudent);
+ WxCpBatchResultList list3 = cpService.getSchoolUserService().batchUpdateStudent(batchUpdateStudentRequest);
+ log.info("list3: {}", list3.toJson());
+
+ /**
+ * 批量删除学生
+ * https://developer.work.weixin.qq.com/document/path/92329
+ *
+ * 请求方式:POST(HTTPS)
+ * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/school/user/batch_delete_student?access_token=ACCESS_TOKEN
+ */
+ String batchDeleteStudent = "{\n" +
+ "\t\"useridlist\": [\"zhangsan\", \"lisi\"]\n" +
+ "}\n";
+ WxCpBatchDeleteStudentRequest batchDeleteStudentRequest = WxCpBatchDeleteStudentRequest.fromJson(batchDeleteStudent);
+ WxCpBatchResultList list2 = cpService.getSchoolUserService().batchDeleteStudent(batchDeleteStudentRequest);
+ log.info("list2: {}", list2.toJson());
+
+ /**
+ * 批量创建学生
+ * https://developer.work.weixin.qq.com/document/path/92328
+ */
+ String batchCreateStudent = "{\n" +
+ "\t\"students\":[\n" +
+ " {\n" +
+ "\t\t\t\"student_userid\": \"zhangsan\",\n" +
+ "\t\t\t\"name\": \"张三\",\n" +
+ "\t\t\t\"department\": [1, 2]\n" +
+ "\t\t},\n" +
+ " {\n" +
+ "\t\t\t\"student_userid\": \"lisi\",\n" +
+ "\t\t\t\"name\": \"李四\",\n" +
+ "\t\t\t\"department\": [3, 4]\n" +
+ "\t\t}\n" +
+ " ]\n" +
+ "}";
+ WxCpBatchCreateStudentRequest batchCreateStudentRequest = WxCpBatchCreateStudentRequest.fromJson(batchCreateStudent);
+ WxCpBatchResultList list1 = cpService.getSchoolUserService().batchCreateStudent(batchCreateStudentRequest);
+ log.info("list1: {}", list1.toJson());
+
+
// String changeContact = WxCpConsts.EventType.CHANGE_CONTACT;
/**
* 增加变更事件类型:
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java
index 3a1e5460f..d8ba80d99 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java
@@ -7,7 +7,6 @@ import com.google.inject.Inject;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.ApiTestModule;
-import me.chanjar.weixin.cp.api.ApiTestModuleWithMockServer;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpLinkedCorpMessage;
import me.chanjar.weixin.cp.bean.message.WxCpMessage;
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessageTest.java
new file mode 100644
index 000000000..aa1236c58
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpSchoolContactMessageTest.java
@@ -0,0 +1,395 @@
+package me.chanjar.weixin.cp.bean.message;
+
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.api.WxConsts;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.json.GsonParser;
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
+import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
+import me.chanjar.weixin.cp.bean.article.NewArticle;
+import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.demo.WxCpDemoInMemoryConfigStorage;
+import org.testng.annotations.Test;
+
+import java.io.InputStream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * 发送「学校通知」消息测试类
+ * https://developer.work.weixin.qq.com/document/path/92321
+ *
+ * @author Wang_Wong
+ * @date 2022-06-29
+ */
+@Slf4j
+public class WxCpSchoolContactMessageTest {
+
+ private static WxCpConfigStorage wxCpConfigStorage;
+ private static WxCpService cpService;
+
+
+ /**
+ * 发送「学校通知」
+ * 学校可以通过此接口来给家长发送不同类型的学校通知,来满足多种场景下的学校通知需求。目前支持的消息类型为文本、图片、语音、视频、文件、图文。
+ *
+ * https://developer.work.weixin.qq.com/document/path/92321
+ *
+ * 消息体类型请参考测试类
+ * WxCpSchoolContactMessageTest
+ * {@link WxCpSchoolContactMessageTest}
+ * @throws WxErrorException
+ */
+ @Test
+ public void testSendSchoolContactMessage() throws WxErrorException {
+
+ InputStream inputStream = ClassLoader.getSystemResourceAsStream("test-config.xml");
+ WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage.fromXml(inputStream);
+
+ wxCpConfigStorage = config;
+ cpService = new WxCpServiceImpl();
+ cpService.setWxCpConfigStorage(config);
+
+ WxCpSchoolContactMessageSendResult sendResult = this.cpService.getMessageService().sendSchoolContactMessage(
+
+ WxCpSchoolContactMessage.builder()
+ .recvScope(0)
+ .msgType(WxConsts.SchoolContactMsgType.TEXT)
+ .toParentUserId(new String[]{"parent_userid1", "parent_userid2"})
+ .toStudentUserId(new String[]{"student_userid1", "student_userid2"})
+ .toParty(new String[]{"partyid1", "partyid2"})
+ .toAll(false)
+ .agentId(1)
+ .content("你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看邮件中心视频实况,聪明避开排队。")
+ .enableIdTrans(false)
+ .enableDuplicateCheck(false)
+ .duplicateCheckInterval(1800)
+ .build()
+
+ );
+
+ log.info("sendResult: {}", sendResult.toJson());
+
+ }
+
+ // WxCpConsts.SchoolContactChangeType
+ @Test
+ public void testToJson_text() {
+
+ WxCpSchoolContactMessage message = WxCpSchoolContactMessage.builder()
+ .recvScope(0)
+ .msgType(WxConsts.SchoolContactMsgType.TEXT)
+ .toParentUserId(new String[]{"parent_userid1", "parent_userid2"})
+ .toStudentUserId(new String[]{"student_userid1", "student_userid2"})
+ .toParty(new String[]{"partyid1", "partyid2"})
+ .toAll(false)
+ .agentId(1)
+ .content("你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看邮件中心视频实况,聪明避开排队。")
+ .enableIdTrans(false)
+ .enableDuplicateCheck(false)
+ .duplicateCheckInterval(1800)
+ .build();
+
+ WxCpSchoolContactMessage schoolContactMessage1 = new WxCpSchoolContactMessage();
+ schoolContactMessage1.setMsgType(WxConsts.SchoolContactMsgType.TEXT);
+ schoolContactMessage1.setRecvScope(0);
+ schoolContactMessage1.setToParentUserId(new String[]{"parent_userid1", "parent_userid2"});
+ schoolContactMessage1.setToStudentUserId(new String[]{"student_userid1", "student_userid2"});
+ schoolContactMessage1.setToParty(new String[]{"partyid1", "partyid2"});
+ schoolContactMessage1.setToAll(false);
+ schoolContactMessage1.setAgentId(1);
+ schoolContactMessage1.setContent("你的快递已到,请携带工卡前往邮件中心领取");
+ schoolContactMessage1.setEnableIdTrans(false);
+ schoolContactMessage1.setEnableDuplicateCheck(false);
+ schoolContactMessage1.setDuplicateCheckInterval(1800);
+ final String jsonMsg = schoolContactMessage1.toJson();
+
+ final String json = message.toJson();
+ String expectedJson = "{\n" +
+ "\t\"recv_scope\" : 0,\n" +
+ "\t\"to_parent_userid\": [\"parent_userid1\", \"parent_userid2\"],\n" +
+ "\t\"to_student_userid\": [\"student_userid1\", \"student_userid2\"],\n" +
+ "\t\"to_party\": [\"partyid1\", \"partyid2\"],\n" +
+ "\t\"toall\" : 0,\n" +
+ "\t\"msgtype\" : \"text\",\n" +
+ "\t\"agentid\" : 1,\n" +
+ "\t\"text\" : {\n" +
+ "\t\t\"content\" : \"你的快递已到,请携带工卡前往邮件中心领取。\\n出发前可查看邮件中心视频实况,聪明避开排队。\"\n" +
+ "\t},\n" +
+ "\t\"enable_id_trans\": 0,\n" +
+ "\t\"enable_duplicate_check\": 0,\n" +
+ "\t\"duplicate_check_interval\": 1800\n" +
+ "}";
+
+ assertThat(json).isEqualTo(GsonParser.parse(expectedJson).toString());
+ }
+
+ @Test
+ public void testToJson_image() {
+ WxCpSchoolContactMessage message = WxCpSchoolContactMessage.builder()
+ .recvScope(0)
+ .msgType(WxConsts.SchoolContactMsgType.IMAGE)
+ .toParentUserId(new String[]{"parent_userid1", "parent_userid2"})
+ .toStudentUserId(new String[]{"student_userid1", "student_userid2"})
+ .toParty(new String[]{"partyid1", "partyid2"})
+ .toAll(false)
+ .agentId(1)
+ .mediaId("MEDIA_ID")
+ .build();
+
+ final String json = message.toJson();
+ String expectedJson = "{\n" +
+ "\t\"recv_scope\" : 0,\n" +
+ "\t\"to_parent_userid\": [\"parent_userid1\", \"parent_userid2\"],\n" +
+ "\t\"to_student_userid\": [\"student_userid1\", \"student_userid2\"],\n" +
+ "\t\"to_party\": [\"partyid1\", \"partyid2\"],\n" +
+ "\t\"toall\" : 0,\n" +
+ "\t\"msgtype\" : \"image\",\n" +
+ "\t\"agentid\" : 1,\n" +
+ "\t\"image\" : {\n" +
+ "\t\t\"media_id\" : \"MEDIA_ID\"\n" +
+ "\t},\n" +
+ "\t\"enable_duplicate_check\": 0,\n" +
+ "\t\"duplicate_check_interval\": 1800\n" +
+ "}";
+
+ assertThat(json).isEqualTo(GsonParser.parse(expectedJson).toString());
+ }
+
+ @Test
+ public void testToJson_voice() {
+ WxCpSchoolContactMessage message = WxCpSchoolContactMessage.builder()
+ .recvScope(0)
+ .msgType(WxConsts.SchoolContactMsgType.VOICE)
+ .toParentUserId(new String[]{"parent_userid1", "parent_userid2"})
+ .toStudentUserId(new String[]{"student_userid1", "student_userid2"})
+ .toParty(new String[]{"partyid1", "partyid2"})
+ .toAll(false)
+ .agentId(1)
+ .mediaId("MEDIA_ID")
+ .build();
+
+ final String json = message.toJson();
+ String expectedJson = "{\n" +
+ "\t\"recv_scope\" : 0,\n" +
+ "\t\"to_parent_userid\": [\"parent_userid1\", \"parent_userid2\"],\n" +
+ "\t\"to_student_userid\": [\"student_userid1\", \"student_userid2\"],\n" +
+ "\t\"to_party\": [\"partyid1\", \"partyid2\"],\n" +
+ "\t\"toall\" : 0,\n" +
+ "\t\"msgtype\" : \"voice\",\n" +
+ "\t\"agentid\" : 1,\n" +
+ "\t\"voice\" : {\n" +
+ "\t\t\"media_id\" : \"MEDIA_ID\"\n" +
+ "\t},\n" +
+ "\t\"enable_duplicate_check\": 0,\n" +
+ "\t\"duplicate_check_interval\": 1800\n" +
+ "}";
+
+ assertThat(json).isEqualTo(GsonParser.parse(expectedJson).toString());
+ }
+
+ @Test
+ public void testToJson_video() {
+ WxCpSchoolContactMessage message = WxCpSchoolContactMessage.builder()
+ .recvScope(0)
+ .msgType(WxConsts.SchoolContactMsgType.VIDEO)
+ .toParentUserId(new String[]{"parent_userid1", "parent_userid2"})
+ .toStudentUserId(new String[]{"student_userid1", "student_userid2"})
+ .toParty(new String[]{"partyid1", "partyid2"})
+ .toAll(false)
+ .agentId(1)
+ .mediaId("MEDIA_ID")
+ .title("Title")
+ .description("Description")
+ .build();
+
+ final String json = message.toJson();
+ String expectedJson = "{\n" +
+ "\t\"recv_scope\" : 0,\n" +
+ "\t\"to_parent_userid\": [\"parent_userid1\", \"parent_userid2\"],\n" +
+ "\t\"to_student_userid\": [\"student_userid1\", \"student_userid2\"],\n" +
+ "\t\"to_party\": [\"partyid1\", \"partyid2\"],\n" +
+ "\t\"toall\" : 0,\n" +
+ "\t\"msgtype\" : \"video\",\n" +
+ "\t\"agentid\" : 1,\n" +
+ "\t\"video\" : {\n" +
+ " \"media_id\" : \"MEDIA_ID\",\n" +
+ " \"title\" : \"Title\",\n" +
+ " \"description\" : \"Description\"\n" +
+ "\t},\n" +
+ "\t\"enable_duplicate_check\": 0,\n" +
+ "\t\"duplicate_check_interval\": 1800\n" +
+ "}";
+
+ assertThat(json).isEqualTo(GsonParser.parse(expectedJson).toString());
+ }
+
+ @Test
+ public void testToJson_file() {
+ WxCpSchoolContactMessage message = WxCpSchoolContactMessage.builder()
+ .recvScope(0)
+ .msgType(WxConsts.SchoolContactMsgType.FILE)
+ .toParentUserId(new String[]{"parent_userid1", "parent_userid2"})
+ .toStudentUserId(new String[]{"student_userid1", "student_userid2"})
+ .toParty(new String[]{"partyid1", "partyid2"})
+ .toAll(false)
+ .agentId(1)
+ .mediaId("1Yv-zXfHjSjU-7LH-GwtYqDGS-zz6w22KmWAT5COgP7o")
+ .build();
+
+ final String json = message.toJson();
+ String expectedJson = "{\n" +
+ "\t\"recv_scope\" : 0,\n" +
+ "\t\"to_parent_userid\": [\"parent_userid1\", \"parent_userid2\"],\n" +
+ "\t\"to_student_userid\": [\"student_userid1\", \"student_userid2\"],\n" +
+ "\t\"to_party\": [\"partyid1\", \"partyid2\"],\n" +
+ "\t\"toall\" : 0,\n" +
+ "\t\"msgtype\" : \"file\",\n" +
+ "\t\"agentid\" : 1,\n" +
+ "\t\"file\" : {\n" +
+ " \"media_id\" : \"1Yv-zXfHjSjU-7LH-GwtYqDGS-zz6w22KmWAT5COgP7o\"\n" +
+ "\t},\n" +
+ "\t\"enable_duplicate_check\": 0,\n" +
+ "\t\"duplicate_check_interval\": 1800\n" +
+ "}";
+
+ assertThat(json).isEqualTo(GsonParser.parse(expectedJson).toString());
+ }
+
+ @Test
+ public void testToJson_news() {
+ WxCpSchoolContactMessage message = WxCpSchoolContactMessage.builder()
+ .recvScope(0)
+ .msgType(WxConsts.SchoolContactMsgType.NEWS)
+ .toParentUserId(new String[]{"parent_userid1", "parent_userid2"})
+ .toStudentUserId(new String[]{"student_userid1", "student_userid2"})
+ .toParty(new String[]{"partyid1", "partyid2"})
+ .toAll(false)
+ .agentId(1)
+ .articles(Lists.newArrayList(NewArticle.builder()
+ .title("中秋节礼品领取")
+ .description("今年中秋节公司有豪礼相送")
+ .url("URL")
+ .picUrl("http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png")
+ .build()))
+ .build();
+
+ final String json = message.toJson();
+ String expectedJson = "{\n" +
+ " \"recv_scope\" : 0,\n" +
+ " \"to_parent_userid\": [\"parent_userid1\", \"parent_userid2\"],\n" +
+ " \"to_student_userid\": [\"student_userid1\", \"student_userid2\"],\n" +
+ " \"to_party\": [\"partyid1\", \"partyid2\"],\n" +
+ " \"toall\" : 0,\n" +
+ " \"msgtype\" : \"news\",\n" +
+ " \"agentid\" : 1,\n" +
+ " \"news\" : {\n" +
+ " \"articles\" : [\n" +
+ " {\n" +
+ " \"title\" : \"中秋节礼品领取\",\n" +
+ " \"description\" : \"今年中秋节公司有豪礼相送\",\n" +
+ " \"url\" : \"URL\",\n" +
+ " \"picurl\" : \"http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png\"\n" +
+ " }\n" +
+ "\t\t]\n" +
+ " },\n" +
+ " \"enable_id_trans\": 0,\n" +
+ " \"enable_duplicate_check\": 0,\n" +
+ " \"duplicate_check_interval\": 1800\n" +
+ "}";
+
+ assertThat(json).isEqualTo(GsonParser.parse(expectedJson).toString());
+ }
+
+
+ @Test
+ public void testToJson_mpnews() {
+ WxCpSchoolContactMessage message = WxCpSchoolContactMessage.builder()
+ .recvScope(0)
+ .msgType(WxConsts.SchoolContactMsgType.MPNEWS)
+ .toParentUserId(new String[]{"parent_userid1", "parent_userid2"})
+ .toStudentUserId(new String[]{"student_userid1", "student_userid2"})
+ .toParty(new String[]{"partyid1", "partyid2"})
+ .toAll(false)
+ .agentId(1)
+ .mpNewsArticles(Lists.newArrayList(MpnewsArticle.newBuilder()
+ .title("Title")
+ .thumbMediaId("MEDIA_ID")
+ .author("Author")
+ .contentSourceUrl("URL")
+ .content("Content")
+ .digest("Digest description")
+ .build()))
+ .build();
+
+ final String json = message.toJson();
+ String expectedJson = "{\n" +
+ " \"recv_scope\" : 0,\n" +
+ " \"to_parent_userid\": [\"parent_userid1\", \"parent_userid2\"],\n" +
+ " \"to_student_userid\": [\"student_userid1\", \"student_userid2\"],\n" +
+ " \"to_party\": [\"partyid1\", \"partyid2\"],\n" +
+ " \"toall\" : 0,\n" +
+ " \"msgtype\" : \"mpnews\",\n" +
+ " \"agentid\" : 1,\n" +
+ " \"mpnews\" : {\n" +
+ " \"articles\":[\n" +
+ " {\n" +
+ " \"title\": \"Title\", \n" +
+ " \"thumb_media_id\": \"MEDIA_ID\",\n" +
+ " \"author\": \"Author\",\n" +
+ " \"content_source_url\": \"URL\",\n" +
+ " \"content\": \"Content\",\n" +
+ " \"digest\": \"Digest description\"\n" +
+ " }\n" +
+ " ]\n" +
+ " },\n" +
+ " \"enable_id_trans\": 0,\n" +
+ " \"enable_duplicate_check\": 0,\n" +
+ " \"duplicate_check_interval\": 1800\n" +
+ "}\n";
+
+ assertThat(json).isEqualTo(GsonParser.parse(expectedJson).toString());
+ }
+
+ @Test
+ public void testToJson_miniProgram() {
+ WxCpSchoolContactMessage message = WxCpSchoolContactMessage.builder()
+ .recvScope(0)
+ .msgType(WxConsts.SchoolContactMsgType.MINIPROGRAM)
+ .toParentUserId(new String[]{"parent_userid1", "parent_userid2"})
+ .toStudentUserId(new String[]{"student_userid1", "student_userid2"})
+ .toParty(new String[]{"partyid1", "partyid2"})
+ .toAll(false)
+ .agentId(1)
+ .appId("APPID")
+ .title("欢迎报名夏令营")
+ .thumbMediaId("MEDIA_ID")
+ .pagePath("PAGE_PATH")
+ .build();
+
+ final String json = message.toJson();
+ String expectedJson = "{\n" +
+ " \"recv_scope\" : 0,\n" +
+ " \"to_parent_userid\": [\"parent_userid1\", \"parent_userid2\"],\n" +
+ " \"to_student_userid\": [\"student_userid1\", \"student_userid2\"],\n" +
+ " \"to_party\": [\"partyid1\", \"partyid2\"],\n" +
+ " \"toall\" : 0,\n" +
+ " \"agentid\" : 1,\n" +
+ " \"msgtype\" : \"miniprogram\",\n" +
+ " \"miniprogram\" : {\n" +
+ " \"appid\": \"APPID\",\n" +
+ " \"title\": \"欢迎报名夏令营\",\n" +
+ " \"thumb_media_id\": \"MEDIA_ID\",\n" +
+ " \"pagepath\": \"PAGE_PATH\"\n" +
+ " },\n" +
+ " \"enable_id_trans\": 0,\n" +
+ " \"enable_duplicate_check\": 0,\n" +
+ " \"duplicate_check_interval\": 1800\n" +
+ "}\n";
+
+ assertThat(json).isEqualTo(GsonParser.parse(expectedJson).toString());
+ }
+
+}