send(@RequestBody @Valid MessageSendV2Req req);
+
+}
\ No newline at end of file
diff --git a/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/req/MessageSendV2Req.java b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/req/MessageSendV2Req.java
new file mode 100644
index 00000000..672ac2e3
--- /dev/null
+++ b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/req/MessageSendV2Req.java
@@ -0,0 +1,167 @@
+package cn.axzo.msg.center.api.v2.message.req;
+
+import cn.axzo.basics.common.util.AssertUtil;
+import com.alibaba.fastjson.JSONObject;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author yanglin
+ */
+@Setter
+@Getter
+@Slf4j
+public class MessageSendV2Req implements Serializable {
+
+ /**
+ * 发送待办时, channelParams 的 key, 传值 {@link PendingSendInfo}
+ */
+ public static final String CHANNEL_PENDING = "channel_pending";
+
+ /**
+ * 发起者
+ * 如果是平台,则发起人为空
+ */
+ private PersonV2DTO sender;
+
+ /**
+ * 接收者列表
+ */
+ @NotNull(message = "接收者列表不能为空")
+ private List receivers;
+
+ /**
+ * 业务事件code
+ * oms->消息模板 配置
+ */
+ @NotBlank(message = "业务事件code不能为空")
+ private String bizEventMappingCode;
+
+ /**
+ * 关联业务唯一标识
+ * 例如: 请假申请的编号
+ */
+ private String bizCode;
+
+ /**
+ * 业务扩展参数-JSON字符串格式
+ */
+ private JSONObject bizExtParams;
+
+ /**
+ * 路由参数-JSON字符串格式
+ */
+ private JSONObject routerParams;
+
+ /**
+ * 发送者项目部ID
+ */
+ private Long senderWorkspaceId;
+
+ /**
+ * 发送者企业ID
+ */
+ private Long senderOuId;
+
+ /**
+ * 接收者项目部ID
+ */
+ private Long receiversWorkspaceId;
+
+ /**
+ * 接收者企业ID
+ * 如果是工人,则所在企业可以为空;其它均必传
+ */
+ private Long receiversOuId;
+
+ /**
+ * 接收者(消息)所属组织类型
+ */
+ private Integer receiversOrgType;
+
+ /**
+ * 副标题
+ */
+ private String subtitle;
+
+ /**
+ * 渠道参数
+ */
+ private JSONObject channelParams;
+
+ public void addChannelParam(String key, Object object) {
+ if (channelParams == null) {
+ channelParams = new JSONObject();
+ }
+ channelParams.put(key, object);
+ }
+
+ public T getChannelParam(String key, Class asType) {
+ if (channelParams == null) {
+ return null;
+ }
+ if (!channelParams.containsKey(key)) {
+ return null;
+ }
+ return channelParams.getObject(key, asType);
+ }
+
+ public Collection distinctReceivers() {
+ if (receivers == null) {
+ return Collections.emptySet();
+ }
+ HashMap personId2Person = new HashMap<>();
+ for (PersonV2DTO receiver : receivers) {
+ if (!personId2Person.containsKey(receiver.getId())) {
+ personId2Person.put(receiver.getId(), receiver);
+ }
+ }
+ return personId2Person.values();
+ }
+
+ public List receivers() {
+ if (receivers == null) {
+ return Collections.emptyList();
+ }
+ return receivers;
+ }
+
+ public Long determineReceiversOuId() {
+ return receiversOuId == null ? 0L : receiversOuId;
+ }
+
+ public Long determineReceiversWorkspaceId() {
+ return receiversWorkspaceId == null ? 0L : receiversWorkspaceId;
+ }
+
+ public String determineBizCode() {
+ return bizCode == null ? "" : bizCode;
+ }
+
+ public void validate() {
+ AssertUtil.notNull(bizEventMappingCode, "bizEventCode不能为空");
+ AssertUtil.notEmpty(receivers, "receivers不能为空");
+
+ for (PersonV2DTO receiver : receivers) {
+ AssertUtil.notNull(receiver.getId(), "接收者ID不能为空");
+ if (receiver.getId() <= 0)
+ log.warn("接收者ID <= 0, request={}", this);
+ // 去掉这个校验
+ //AssertUtil.isFalse(receiver.getId() <= 0, "接收者ID必须>=0");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return JSONObject.toJSONString(this);
+ }
+}
\ No newline at end of file
diff --git a/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/req/PersonV2DTO.java b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/req/PersonV2DTO.java
new file mode 100644
index 00000000..7c1c9571
--- /dev/null
+++ b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/req/PersonV2DTO.java
@@ -0,0 +1,59 @@
+package cn.axzo.msg.center.api.v2.message.req;
+
+import lombok.*;
+
+import java.io.Serializable;
+
+/**
+ * @author yanglin
+ */
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PersonV2DTO implements Serializable {
+
+ private static final long serialVersionUID = 1231840051925115741L;
+
+ public PersonV2DTO(Long id) {
+ this.id = id;
+ }
+
+ public PersonV2DTO(Long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ /**
+ * 自然人id
+ */
+ private Long id;
+ /**
+ * 姓名
+ */
+ private String name;
+
+ /**
+ * IM消息接收模型, 可以为空
+ * 优先使用这里的ouId, 如果这里没有传, 就使用 {@link cn.axzo.msg.center.api.request.v3.MessageSendReqV3} 中的相应的信息
+ */
+ private ReceiveModel imReceiveModel;
+
+ @Data
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class ReceiveModel {
+
+ /**
+ * 接收者单位id
+ */
+ private Long ouId;
+
+ /**
+ * 接收者项目部id
+ */
+ private Long workspaceId;
+ }
+
+}
\ No newline at end of file
diff --git a/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/resp/MessageSendResultV2.java b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/resp/MessageSendResultV2.java
new file mode 100644
index 00000000..9cb266f2
--- /dev/null
+++ b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/resp/MessageSendResultV2.java
@@ -0,0 +1,33 @@
+package cn.axzo.msg.center.api.v2.message.resp;
+
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * @author yanglin
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class MessageSendResultV2 implements Serializable {
+ /**
+ * 接收者id
+ */
+ private Long receiverPersonId;
+
+ /**
+ * 渠道结果id
+ */
+ private Long resultId;
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
\ No newline at end of file
diff --git a/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/resp/MessageSendV2Resp.java b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/resp/MessageSendV2Resp.java
new file mode 100644
index 00000000..7f3cfd80
--- /dev/null
+++ b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/resp/MessageSendV2Resp.java
@@ -0,0 +1,48 @@
+package cn.axzo.msg.center.api.v2.message.resp;
+
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * @author yanglin
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class MessageSendV2Resp implements Serializable {
+ /**
+ * 这次批量发送的批次号, 如果配置了多个模版,多个渠道, 可以用批次号串联起来
+ */
+ private String batchNo;
+
+ /**
+ * 模版code -> 模版发送结果
+ */
+ private Map templateCode2SendResult;
+
+ public void addResult(TemplateSendV2Result result) {
+ templateCode2SendResult.put(result.getTemplateCode(), result);
+ }
+
+ public Optional findTemplateSendResult(String templateCode) {
+ return Optional.ofNullable(templateCode2SendResult.get(templateCode));
+ }
+
+ public Set templateCodes() {
+ return new HashSet<>(templateCode2SendResult.keySet());
+ }
+
+ public Map templateSendResults() {
+ return Collections.unmodifiableMap(templateCode2SendResult);
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
\ No newline at end of file
diff --git a/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/resp/TemplateSendV2Result.java b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/resp/TemplateSendV2Result.java
new file mode 100644
index 00000000..b2327c26
--- /dev/null
+++ b/msg-center-api-v2/src/main/java/cn/axzo/msg/center/api/v2/message/resp/TemplateSendV2Result.java
@@ -0,0 +1,74 @@
+package cn.axzo.msg.center.api.v2.message.resp;
+
+import com.alibaba.fastjson.JSON;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * @author yanglin
+ */
+@Data
+public class TemplateSendV2Result implements Serializable {
+ /**
+ * 模版编码
+ */
+ private String templateCode;
+
+ /**
+ * 渠道
+ * NOTIFICATION: 通知, PENDING: 待办
+ */
+ private String channel;
+
+ /**
+ * 接收者personId -> 接收人发送结果
+ * key: string, 兼容json的key必须为string类型
+ */
+ private Map receiverPersonId2SendResult;
+
+ @SuppressWarnings("unused")
+ public TemplateSendV2Result() {
+ }
+
+ public TemplateSendV2Result(String templateCode, String channel) {
+ this.templateCode = templateCode;
+ this.channel = channel;
+ this.receiverPersonId2SendResult = new HashMap<>();
+ }
+
+ public void addResult(MessageSendResultV2 result) {
+ if (receiverPersonId2SendResult == null)
+ // 序列化问题
+ throw new RuntimeException("需要通过构造函数初始化receiverPersonId2SendResult");
+ String receiverPersonId = String.valueOf(result.getReceiverPersonId());
+ receiverPersonId2SendResult.put(receiverPersonId, result);
+ }
+
+ public Optional findResultByReceiver(Long receiverPersonId) {
+ if (receiverPersonId2SendResult == null)
+ return Optional.empty();
+ if (receiverPersonId == null)
+ return Optional.empty();
+ String strReceiverPersonId = String.valueOf(receiverPersonId);
+ return Optional.ofNullable(receiverPersonId2SendResult.get(strReceiverPersonId));
+ }
+
+ /**
+ * 返回的数量不一定和发送请求中的receivers数量一致, 发送的时候根据receiver的personId去了重
+ * 推荐使用 {@link #findResultByReceiver}, 根据接收者获取发送结果
+ *
+ * @return 所有的发送结果
+ */
+ public Collection messageSendResults() {
+ if (receiverPersonId2SendResult == null)
+ return Collections.emptyList();
+ return new ArrayList<>(receiverPersonId2SendResult.values());
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(receiverPersonId2SendResult);
+ }
+}
\ No newline at end of file
diff --git a/msg-center-api-v2/src/main/resources/META-INF/spring.factories b/msg-center-api-v2/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000..b238b5c7
--- /dev/null
+++ b/msg-center-api-v2/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+cn.axzo.msg.center.api.v2.config.MsgCenterApiV2Config
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index fab19410..9a308783 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,6 +24,7 @@
start
msg-center-dal
msg-center-domain
+ msg-center-api-v2
@@ -32,6 +33,7 @@
UTF-8
1.0.0-SNAPSHOT
1.0.1-SNAPSHOT
+ 1.0.1-SNAPSHOT
2.0.0-SNAPSHOT
2.0.0-SNAPSHOT
1.18.22
@@ -99,6 +101,11 @@
annotations
${jetbrains.version}
+
+ cn.axzo.msgcenter
+ msg-center-api-v2
+ ${msg-center-api-v2-version}
+