{
+
+ private static final long serialVersionUID=1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 渠道模板号
+ */
+ @TableField("template_no")
+ private String templateNo;
+
+ /**
+ * 变量名称
+ */
+ @TableField("param_name")
+ private String paramName;
+
+ /**
+ * 变量描述
+ */
+ @TableField("param_desc")
+ private String paramDesc;
+
+ /**
+ * 变量排序(升序:数字越小,排在越前)
+ */
+ @TableField("param_order")
+ private Integer paramOrder;
+
+ /**
+ * 备注
+ */
+ @TableField("remark")
+ private String remark;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_at")
+ private Date createAt;
+
+ /**
+ * 修改时间
+ */
+ @TableField("update_at")
+ private Date updateAt;
+
+ /**
+ * 创建人
+ */
+ @TableField("create_by")
+ private String createBy;
+
+ /**
+ * 修改人
+ */
+ @TableField("update_by")
+ private String updateBy;
+
+ /**
+ * 是否删除(0:未删除;1:已删除)
+ */
+ @TableField("is_delete")
+ private Integer isDelete;
+
+
+ @Override
+ protected Serializable pkVal() {
+ return this.id;
+ }
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/BatchMessageMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/BatchMessageMapper.java
new file mode 100644
index 00000000..9664abca
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/BatchMessageMapper.java
@@ -0,0 +1,22 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.domain.BatchMessageStatisticsResponseDto;
+import cn.axzo.msg.notices.dao.entity.BatchMessage;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ *
+ * 渠道模板变量序列表 Mapper 接口
+ *
+ *
+ * @author szg
+ * @since 2021-08-09
+ */
+public interface BatchMessageMapper extends BaseMapper {
+
+ BatchMessageStatisticsResponseDto getStatisticsMessageInfo(@Param("appNo") String appNo,
+ @Param("requestNo") String requestNo);
+
+ BatchMessage getByChannelMsgIdAndLock(@Param("msgId") String msgId);
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/BatchMessageRequestMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/BatchMessageRequestMapper.java
new file mode 100644
index 00000000..8d364878
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/BatchMessageRequestMapper.java
@@ -0,0 +1,16 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.BatchMessageRequest;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 渠道模板变量序列表 Mapper 接口
+ *
+ *
+ * @author szg
+ * @since 2021-08-09
+ */
+public interface BatchMessageRequestMapper extends BaseMapper {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/ChannelMessageTemplateMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/ChannelMessageTemplateMapper.java
new file mode 100644
index 00000000..b3798963
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/ChannelMessageTemplateMapper.java
@@ -0,0 +1,21 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.ChannelMessageTemplate;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ *
+ * 渠道消息模板表 Mapper 接口
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface ChannelMessageTemplateMapper extends BaseMapper {
+
+ /**
+ * 按照短信编码删除
+ */
+ Integer deleteByTemplateNo(@Param("templateNo") String templateNo);
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageAppMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageAppMapper.java
new file mode 100644
index 00000000..986f4fd4
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageAppMapper.java
@@ -0,0 +1,16 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.MessageApp;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 消息应用表 Mapper 接口
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageAppMapper extends BaseMapper {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageChannelLogMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageChannelLogMapper.java
new file mode 100644
index 00000000..ca830233
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageChannelLogMapper.java
@@ -0,0 +1,16 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.MessageChannelLog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 请求消息渠道日志表 Mapper 接口
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageChannelLogMapper extends BaseMapper {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageChannelMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageChannelMapper.java
new file mode 100644
index 00000000..4eb2ddb6
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageChannelMapper.java
@@ -0,0 +1,16 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.MessageChannel;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 消息渠道表 Mapper 接口
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageChannelMapper extends BaseMapper {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageMapper.java
new file mode 100644
index 00000000..dbf24540
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageMapper.java
@@ -0,0 +1,16 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.Message;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 消息记录表 Mapper 接口
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageMapper extends BaseMapper {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageRedoMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageRedoMapper.java
new file mode 100644
index 00000000..6e780ec4
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageRedoMapper.java
@@ -0,0 +1,8 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.MessageRedo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface MessageRedoMapper extends BaseMapper {
+
+}
\ No newline at end of file
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageRequestLogMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageRequestLogMapper.java
new file mode 100644
index 00000000..f02f209e
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageRequestLogMapper.java
@@ -0,0 +1,16 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.MessageRequestLog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 外部系统请求表 Mapper 接口
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageRequestLogMapper extends BaseMapper {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageTemplateMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageTemplateMapper.java
new file mode 100644
index 00000000..7d374741
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageTemplateMapper.java
@@ -0,0 +1,20 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.MessageTemplate;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ *
+ * 内部消息模板表 Mapper 接口
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageTemplateMapper extends BaseMapper {
+ /**
+ * 按照短信编码删除
+ */
+ Integer deleteByTemplateNo(@Param("templateNo") String templateNo);
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageTemplateParamMapper.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageTemplateParamMapper.java
new file mode 100644
index 00000000..f06bb9e0
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/mapper/MessageTemplateParamMapper.java
@@ -0,0 +1,16 @@
+package cn.axzo.msg.notices.dao.mapper;
+
+import cn.axzo.msg.notices.dao.entity.MessageTemplateParam;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 渠道模板变量序列表 Mapper 接口
+ *
+ *
+ * @author szg
+ * @since 2021-08-07
+ */
+public interface MessageTemplateParamMapper extends BaseMapper {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/persistence/BaseDataEntity.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/persistence/BaseDataEntity.java
new file mode 100644
index 00000000..f4935cad
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/persistence/BaseDataEntity.java
@@ -0,0 +1,13 @@
+package cn.axzo.msg.notices.dao.persistence;
+
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+
+/**
+ * Entity 支持类
+ *
+ * @author Smile
+ * @date 2019/3/26 17:33
+ */
+public abstract class BaseDataEntity> extends BaseEntity {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/persistence/BaseEntity.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/persistence/BaseEntity.java
new file mode 100644
index 00000000..f03f5ce5
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/persistence/BaseEntity.java
@@ -0,0 +1,45 @@
+package cn.axzo.msg.notices.dao.persistence;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 实体的基类
+ *
+ * @author Smile
+ */
+@Data
+public abstract class BaseEntity> extends Model {
+
+ /**
+ * id
+ */
+ @TableId(type = IdType.AUTO)
+ protected Long id;
+
+ /**
+ * 创建时间
+ */
+ @TableField(fill = FieldFill.INSERT)
+ protected Date createAt;
+
+ /**
+ * 修改时间
+ */
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ protected Date updateAt;
+
+ /**
+ * 是否删除
+ */
+ @TableLogic
+ @TableField("is_delete")
+ protected Integer isDelete;
+
+ {
+ isDelete = 0;
+ }
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/persistence/BaseOwnEntity.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/persistence/BaseOwnEntity.java
new file mode 100644
index 00000000..044c7d67
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/persistence/BaseOwnEntity.java
@@ -0,0 +1,28 @@
+package cn.axzo.msg.notices.dao.persistence;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * Entity 支持类
+ *
+ * @author Smile
+ * @date 2019/3/26 17:33
+ */
+@Data
+public abstract class BaseOwnEntity> extends BaseDataEntity {
+
+ /**
+ * 创建人
+ */
+ @TableField(fill = FieldFill.INSERT)
+ protected String createBy;
+
+ /**
+ * 修改人
+ */
+ @TableField(fill = FieldFill.UPDATE)
+ protected String updateBy;
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/BatchMessageDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/BatchMessageDao.java
new file mode 100644
index 00000000..579de115
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/BatchMessageDao.java
@@ -0,0 +1,35 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.domain.BatchMessageQuery;
+import cn.axzo.msg.notices.dao.domain.BatchMessageStatisticsResponseDto;
+import cn.axzo.msg.notices.dao.entity.BatchMessage;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 渠道模板变量序列表 服务类
+ *
+ *
+ * @author szg
+ * @since 2021-08-09
+ */
+public interface BatchMessageDao extends IService {
+
+ IPage queryByPage(BatchMessageQuery query);
+
+ BatchMessage queryBatchMessage(String batchNo);
+
+ boolean updateBatchMessage(BatchMessage batchMessage, String batchNo);
+
+ BatchMessage getByChannelMsgIdAndLock(String msgId);
+
+ boolean updateChannelInfo(String channelCode, String templateNo, String batchNo);
+
+ BatchMessageStatisticsResponseDto getStatisticsMessageInfo(String appNo, String requestNo);
+
+ Boolean updateStatusById(Long id, Integer status);
+
+ Boolean updateBachMessageInfoById(Long id, Integer status, Integer successCount,
+ Integer failCount);
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/BatchMessageRequestDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/BatchMessageRequestDao.java
new file mode 100644
index 00000000..88652bfe
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/BatchMessageRequestDao.java
@@ -0,0 +1,29 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.domain.BatchMessageRequestQuery;
+import cn.axzo.msg.notices.dao.entity.BatchMessageRequest;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 渠道模板变量序列表 服务类
+ *
+ *
+ * @author szg
+ * @since 2021-08-09
+ */
+public interface BatchMessageRequestDao extends IService {
+
+ IPage queryByPage(BatchMessageRequestQuery query);
+
+ BatchMessageRequest queryBatchMessage(String appCode, String requestNo);
+
+ boolean updateStatusById(Long id, Integer status);
+
+ boolean updateBatchMessageRequestInfoById(Long id, Integer status, Integer successCount,
+ Integer failCount);
+
+ boolean updateRequestSuccess(String remark, Long id);
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/ChannelMessageTemplateDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/ChannelMessageTemplateDao.java
new file mode 100644
index 00000000..001c0e3a
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/ChannelMessageTemplateDao.java
@@ -0,0 +1,20 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.entity.ChannelMessageTemplate;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 渠道消息模板表 服务类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface ChannelMessageTemplateDao extends IService {
+
+ ChannelMessageTemplate queryByTemplateNo(String innerTemplateNo, String channelCode);
+
+ ChannelMessageTemplate queryByChannelTemplateNo(String channelTemplateNo);
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageAppDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageAppDao.java
new file mode 100644
index 00000000..7d2091f2
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageAppDao.java
@@ -0,0 +1,22 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.entity.MessageApp;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 消息应用表 服务类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageAppDao extends IService {
+
+ /**
+ * 通过appCode获取
+ * @param appCode
+ * @return
+ */
+ MessageApp queryByAppCode(String appCode);
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageChannelDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageChannelDao.java
new file mode 100644
index 00000000..5a374a34
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageChannelDao.java
@@ -0,0 +1,23 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.entity.MessageChannel;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ *
+ * 消息渠道表 服务类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageChannelDao extends IService {
+
+ /**
+ * 获取可用的渠道
+ * @return
+ */
+ List queryAvailable();
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageChannelLogDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageChannelLogDao.java
new file mode 100644
index 00000000..e0aa4cce
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageChannelLogDao.java
@@ -0,0 +1,18 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.entity.MessageChannelLog;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 请求消息渠道日志表 服务类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageChannelLogDao extends IService {
+
+ boolean updateCallbackDate(String toJSONString, String messageOrderNo);
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageDao.java
new file mode 100644
index 00000000..00009d43
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageDao.java
@@ -0,0 +1,75 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.domain.MessageQuery;
+import cn.axzo.msg.notices.dao.entity.Message;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 消息记录表 服务类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageDao extends IService {
+
+ /**
+ * 分页查询消息
+ * @param query
+ * @return
+ */
+ IPage queryByPage(MessageQuery query);
+
+ /**
+ * 渠道网络异常
+ * @param id
+ * @return
+ */
+ boolean channelException(Long id);
+
+ Boolean updateExceptionToFail(String messageOrderNo);
+
+ /**
+ * 通过批次号和手机号查询message
+ * @param batchNo
+ * @param mobile
+ * @return
+ */
+ Message getByBatchNoAndPhone(String batchNo, String mobile);
+
+ /**
+ * 根据渠道响应查询
+ * @param channelMsgId
+ * @param mobile
+ * @return
+ */
+ Message getByChannelMsgId(String channelMsgId, String mobile);
+
+ /**
+ * 更新批量消息渠道消息
+ * @param channelCode
+ * @param channelName
+ * @param batchNo
+ * @return
+ */
+ boolean updateBatchMessageChannelInfo(String channelCode, String channelName, String batchNo);
+
+ /**
+ * 更新所有批量消息失败
+ * @param errorMsg
+ * @param batchNo
+ * @return
+ */
+ boolean updateAllBatchMessageFail(String errorMsg, String batchNo);
+
+ /**
+ * 更新消息状态和备注
+ * @param id
+ * @param status
+ * @param remark
+ * @return
+ */
+ boolean updateStatusAndRemarkById(Long id, String status, String remark);
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageRedoDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageRedoDao.java
new file mode 100644
index 00000000..0e52ad75
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageRedoDao.java
@@ -0,0 +1,15 @@
+package cn.axzo.msg.notices.dao.repository;
+
+
+import cn.axzo.msg.notices.dao.domain.MessageRedoQuery;
+import cn.axzo.msg.notices.dao.entity.MessageRedo;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+public interface MessageRedoDao extends IService {
+
+ IPage queryByPage(MessageRedoQuery query);
+
+ boolean updateExceptionToFail(Long id);
+
+}
\ No newline at end of file
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageRequestLogDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageRequestLogDao.java
new file mode 100644
index 00000000..7687236e
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageRequestLogDao.java
@@ -0,0 +1,16 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.entity.MessageRequestLog;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 外部系统请求表 服务类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageRequestLogDao extends IService {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageTemplateDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageTemplateDao.java
new file mode 100644
index 00000000..adda4c07
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageTemplateDao.java
@@ -0,0 +1,22 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.entity.MessageTemplate;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 内部消息模板表 服务类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+public interface MessageTemplateDao extends IService {
+
+ /**
+ * 通过模板号查询
+ * @param templateNo
+ * @return
+ */
+ MessageTemplate queryByTemplateNo(String templateNo);
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageTemplateParamDao.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageTemplateParamDao.java
new file mode 100644
index 00000000..f6f556d4
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/MessageTemplateParamDao.java
@@ -0,0 +1,22 @@
+package cn.axzo.msg.notices.dao.repository;
+
+import cn.axzo.msg.notices.dao.entity.MessageTemplateParam;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ *
+ * 渠道模板变量序列表 服务类
+ *
+ *
+ * @author szg
+ * @since 2021-08-07
+ */
+public interface MessageTemplateParamDao extends IService {
+
+ List getByTemplateNo(String templateNo);
+
+ List getAllMessageTemplateParams();
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/BatchMessageDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/BatchMessageDaoImpl.java
new file mode 100644
index 00000000..dfb441ac
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/BatchMessageDaoImpl.java
@@ -0,0 +1,106 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.common.enums.IsDeletedEnum;
+import cn.axzo.msg.notices.dao.domain.BatchMessageQuery;
+import cn.axzo.msg.notices.dao.domain.BatchMessageStatisticsResponseDto;
+import cn.axzo.msg.notices.dao.entity.BatchMessage;
+import cn.axzo.msg.notices.dao.mapper.BatchMessageMapper;
+import cn.axzo.msg.notices.dao.repository.BatchMessageDao;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Repository;
+
+import javax.annotation.Resource;
+import java.util.Objects;
+
+/**
+ *
+ * 渠道模板变量序列表 Dao实现类
+ *
+ *
+ * @author szg
+ * @since 2021-08-09
+ */
+@Repository("batchMessageDao")
+public class BatchMessageDaoImpl extends ServiceImpl implements BatchMessageDao {
+
+ @Resource
+ private BatchMessageMapper batchMessageMapper;
+
+ @Override
+ public IPage queryByPage(BatchMessageQuery query) {
+
+ return this.page(query.toPage(), new LambdaQueryWrapper()
+ .eq(query.getId() != null, BatchMessage::getId, query.getId())
+ .ge(query.getStartCreateTime() != null, BatchMessage::getCreateAt, query.getStartCreateTime())
+ .le(query.getEndCreateTime() != null, BatchMessage::getCreateAt, query.getEndCreateTime())
+ .in(CollectionUtils.isNotEmpty(query.getStatuses()), BatchMessage::getStatus, query.getStatuses())
+ .eq(Objects.nonNull(query.getSendType()),BatchMessage::getSendType,query.getSendType())
+ .eq(BatchMessage::getIsDelete, 0)
+ .orderByDesc(BatchMessage::getCreateAt)
+ );
+ }
+
+ @Override
+ public BatchMessage queryBatchMessage(String batchNo) {
+ return this.lambdaQuery()
+ .eq(BatchMessage::getBatchNo, batchNo)
+ .eq(BatchMessage::getIsDelete, IsDeletedEnum.NO.getCode())
+ .one();
+ }
+
+ @Override
+ public boolean updateBatchMessage(BatchMessage batchMessage, String batchNo) {
+ return this.update(batchMessage, new UpdateWrapper()
+ .eq("batch_no", batchNo)
+ .eq("is_delete", IsDeletedEnum.NO.getCode()));
+ }
+
+ @Override
+ public boolean updateChannelInfo(String channelCode, String channelTemplateNo, String batchNo) {
+ return this.lambdaUpdate()
+ .set(BatchMessage::getChannelCode, channelCode)
+ .set(BatchMessage::getChannelTemplateNo, channelTemplateNo)
+ .eq(BatchMessage::getBatchNo, batchNo)
+ .eq(BatchMessage::getIsDelete, IsDeletedEnum.NO.getCode())
+ .update();
+ }
+
+ @Override
+ public BatchMessageStatisticsResponseDto getStatisticsMessageInfo(String appNo,
+ String requestNo) {
+
+ return batchMessageMapper.getStatisticsMessageInfo(appNo,requestNo);
+ }
+
+ @Override
+ public Boolean updateStatusById(Long id, Integer status) {
+ return lambdaUpdate()
+ .set(BatchMessage::getStatus,status)
+ .eq(BatchMessage::getId,id)
+ .eq(BatchMessage::getIsDelete, IsDeletedEnum.NO.getCode())
+ .update();
+ }
+
+ @Override
+ public Boolean updateBachMessageInfoById(Long id, Integer status,
+ Integer successCount, Integer failCount) {
+ return lambdaUpdate()
+ .set(BatchMessage::getStatus, status)
+ .set(BatchMessage::getSuccessCount,successCount)
+ .set(BatchMessage::getFailCount,failCount)
+ .eq(BatchMessage::getId, id)
+ .eq(BatchMessage::getIsDelete, IsDeletedEnum.NO.getCode())
+ .update();
+ }
+
+ @Override
+ public BatchMessage getByChannelMsgIdAndLock(String msgId) {
+ return batchMessageMapper.getByChannelMsgIdAndLock(msgId);
+
+ }
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/BatchMessageRequestDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/BatchMessageRequestDaoImpl.java
new file mode 100644
index 00000000..d461a6ef
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/BatchMessageRequestDaoImpl.java
@@ -0,0 +1,81 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.common.enums.BatchMessageStatusEnum;
+import cn.axzo.msg.notices.dao.domain.BatchMessageRequestQuery;
+import cn.axzo.msg.notices.dao.entity.BatchMessageRequest;
+import cn.axzo.msg.notices.dao.mapper.BatchMessageRequestMapper;
+import cn.axzo.msg.notices.dao.repository.BatchMessageRequestDao;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Repository;
+
+import java.util.Objects;
+
+/**
+ *
+ * 渠道模板变量序列表 Dao实现类
+ *
+ *
+ * @author szg
+ * @since 2021-08-09
+ */
+@Repository("batchMessageRequestDao")
+public class BatchMessageRequestDaoImpl extends
+ ServiceImpl implements BatchMessageRequestDao {
+
+ @Override
+ public IPage queryByPage(BatchMessageRequestQuery query) {
+
+ return this.page(query.toPage(), new LambdaQueryWrapper()
+ .eq(query.getId() != null, BatchMessageRequest::getId, query.getId())
+ .ge(query.getStartCreateTime() != null, BatchMessageRequest::getCreateAt, query.getStartCreateTime())
+ .le(query.getEndCreateTime() != null, BatchMessageRequest::getCreateAt, query.getEndCreateTime())
+ .in(CollectionUtils.isNotEmpty(query.getStatuses()), BatchMessageRequest::getStatus, query.getStatuses())
+ .eq(Objects.nonNull(query.getSendType()),BatchMessageRequest::getSendType,query.getSendType())
+ .eq(BatchMessageRequest::getIsDelete, 0)
+ .orderByDesc(BatchMessageRequest::getCreateAt)
+ );
+
+ }
+
+ @Override
+ public BatchMessageRequest queryBatchMessage(String appCode, String requestNo) {
+ return this.lambdaQuery()
+ .eq(BatchMessageRequest::getAppNo, appCode)
+ .eq(BatchMessageRequest::getRequestNo, requestNo)
+ .one();
+ }
+
+ @Override
+ public boolean updateStatusById(Long id, Integer status) {
+ return lambdaUpdate()
+ .set(BatchMessageRequest::getStatus,status)
+ .eq(BatchMessageRequest::getId,id)
+ .eq(BatchMessageRequest::getIsDelete, 0)
+ .update();
+ }
+
+ @Override
+ public boolean updateBatchMessageRequestInfoById(Long id, Integer status,
+ Integer successCount, Integer failCount) {
+ return lambdaUpdate()
+ .set(BatchMessageRequest::getStatus,status)
+ .set(BatchMessageRequest::getSuccessCount,successCount)
+ .set(BatchMessageRequest::getFailCount,failCount)
+ .eq(BatchMessageRequest::getId,id)
+ .eq(BatchMessageRequest::getIsDelete, 0)
+ .update();
+ }
+
+ @Override
+ public boolean updateRequestSuccess(String remark, Long id) {
+ return lambdaUpdate()
+ .set(BatchMessageRequest::getRemark, remark)
+ .set(BatchMessageRequest::getStatus, BatchMessageStatusEnum.SEND_SUCCESS.getCode())
+ .eq(BatchMessageRequest::getId, id)
+ .update();
+ }
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/ChannelMessageTemplateDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/ChannelMessageTemplateDaoImpl.java
new file mode 100644
index 00000000..8fb3daa2
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/ChannelMessageTemplateDaoImpl.java
@@ -0,0 +1,34 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.dao.entity.ChannelMessageTemplate;
+import cn.axzo.msg.notices.dao.mapper.ChannelMessageTemplateMapper;
+import cn.axzo.msg.notices.dao.repository.ChannelMessageTemplateDao;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Repository;
+
+/**
+ *
+ * 渠道消息模板表 Dao实现类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+@Repository("channelMessageTemplateDao")
+public class ChannelMessageTemplateDaoImpl extends ServiceImpl implements ChannelMessageTemplateDao {
+
+ @Override
+ public ChannelMessageTemplate queryByTemplateNo(String innerTemplateNo, String channelCode) {
+ return this.lambdaQuery()
+ .eq(ChannelMessageTemplate::getInnerTemplateNo, innerTemplateNo)
+ .eq(ChannelMessageTemplate::getChannelCode, channelCode)
+ .one();
+ }
+
+ @Override
+ public ChannelMessageTemplate queryByChannelTemplateNo(String channelTemplateNo) {
+ return this.lambdaQuery().eq(ChannelMessageTemplate::getTemplateNo, channelTemplateNo)
+ .eq(ChannelMessageTemplate::getIsDelete, 0)
+ .one();
+ }
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageAppDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageAppDaoImpl.java
new file mode 100644
index 00000000..19de8222
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageAppDaoImpl.java
@@ -0,0 +1,27 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.dao.entity.MessageApp;
+import cn.axzo.msg.notices.dao.mapper.MessageAppMapper;
+import cn.axzo.msg.notices.dao.repository.MessageAppDao;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Repository;
+
+/**
+ *
+ * 消息应用表 Dao实现类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+@Repository("messageAppDao")
+public class MessageAppDaoImpl extends ServiceImpl implements MessageAppDao {
+
+ @Override
+ public MessageApp queryByAppCode(String appCode) {
+ return this.lambdaQuery()
+ .eq(MessageApp::getAppCode, appCode)
+ .one();
+ }
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageChannelDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageChannelDaoImpl.java
new file mode 100644
index 00000000..127cd4e8
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageChannelDaoImpl.java
@@ -0,0 +1,29 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.common.enums.AvailableStatusEnum;
+import cn.axzo.msg.notices.dao.entity.MessageChannel;
+import cn.axzo.msg.notices.dao.mapper.MessageChannelMapper;
+import cn.axzo.msg.notices.dao.repository.MessageChannelDao;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ *
+ * 消息渠道表 Dao实现类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+@Repository("messageChannelDao")
+public class MessageChannelDaoImpl extends ServiceImpl implements MessageChannelDao {
+
+ @Override
+ public List queryAvailable() {
+ return this.lambdaQuery()
+ .eq(MessageChannel::getStatus, AvailableStatusEnum.AVAILABLE.getStatus())
+ .list();
+ }
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageChannelLogDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageChannelLogDaoImpl.java
new file mode 100644
index 00000000..2e34b1a0
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageChannelLogDaoImpl.java
@@ -0,0 +1,30 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.common.enums.IsDeletedEnum;
+import cn.axzo.msg.notices.dao.entity.MessageChannelLog;
+import cn.axzo.msg.notices.dao.mapper.MessageChannelLogMapper;
+import cn.axzo.msg.notices.dao.repository.MessageChannelLogDao;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Repository;
+
+/**
+ *
+ * 请求消息渠道日志表 Dao实现类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+@Repository("messageChannelLogDao")
+public class MessageChannelLogDaoImpl extends ServiceImpl implements MessageChannelLogDao {
+
+ @Override
+ public boolean updateCallbackDate(String callbackDate, String messageOrderNo) {
+ return this.lambdaUpdate()
+ .set(MessageChannelLog::getCallbackData, callbackDate)
+ .eq(MessageChannelLog::getMessageOrderNo, messageOrderNo)
+ .eq(MessageChannelLog::getIsDelete, IsDeletedEnum.NO.getCode())
+ .update();
+ }
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageDaoImpl.java
new file mode 100644
index 00000000..a84dcb74
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageDaoImpl.java
@@ -0,0 +1,110 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.common.enums.IsDeletedEnum;
+import cn.axzo.msg.notices.common.enums.MessageStatusEnum;
+import cn.axzo.msg.notices.dao.domain.MessageQuery;
+import cn.axzo.msg.notices.dao.entity.Message;
+import cn.axzo.msg.notices.dao.mapper.MessageMapper;
+import cn.axzo.msg.notices.dao.repository.MessageDao;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+
+/**
+ *
+ * 消息记录表 Dao实现类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+@Repository("messageDao")
+public class MessageDaoImpl extends ServiceImpl implements MessageDao {
+
+ @Override
+ public IPage queryByPage(MessageQuery query) {
+ return this.page(query.toPage(), new LambdaQueryWrapper()
+ .eq(query.getId() != null, Message::getId, query.getId())
+ .ge(query.getStartCreateTime() != null, Message::getCreateAt, query.getStartCreateTime())
+ .le(query.getEndCreateTime() != null, Message::getCreateAt, query.getEndCreateTime())
+ .in(CollectionUtils.isNotEmpty(query.getStatuses()), Message::getStatus, query.getStatuses())
+ .eq(StringUtils.isNoneBlank(query.getChannelCode()), Message::getChannelCode, query.getChannelCode())
+ .eq(Message::getIsDelete, IsDeletedEnum.NO.getCode())
+ .orderByDesc(Message::getCreateAt));
+ }
+
+ @Override
+ public boolean channelException(Long id) {
+ return this.lambdaUpdate()
+ .set(Message::getStatus, MessageStatusEnum.EXCEPTION.getCode())
+ .set(Message::getUpdateAt, new Date())
+ .eq(Message::getId, id)
+ .eq(Message::getStatus, MessageStatusEnum.INIT.getCode())
+ .update();
+ }
+
+ @Override
+ public Boolean updateExceptionToFail(String messageOrderNo) {
+ return lambdaUpdate()
+ .set(Message::getStatus, MessageStatusEnum.FAIL.getCode())
+ .eq(Message::getMessageOrderNo, messageOrderNo)
+ .eq(Message::getStatus, MessageStatusEnum.EXCEPTION.getCode())
+ .update();
+ }
+
+ @Override
+ public Message getByBatchNoAndPhone(String batchNo, String mobile) {
+ return lambdaQuery()
+ .eq(Message::getBatchNo,batchNo)
+ .eq(Message::getTargetAddress,mobile)
+ .eq(Message::getStatus,MessageStatusEnum.INIT.getCode())
+ .eq(Message::getIsDelete,0)
+ .one();
+ }
+
+ @Override
+ public Message getByChannelMsgId(String channelMsgId, String mobile) {
+ return lambdaQuery()
+ .eq(Message::getTargetAddress,mobile)
+ .eq(Message::getChannelRequestId, channelMsgId)
+ .eq(Message::getIsDelete,0)
+ .one();
+ }
+
+ @Override
+ public boolean updateBatchMessageChannelInfo(String channelCode, String channelName, String batchNo) {
+ return lambdaUpdate()
+ .set(Message::getChannelCode, channelCode)
+ .set(Message::getChannelName, channelName)
+ .eq(Message::getBatchNo, batchNo)
+ .eq(Message::getIsDelete, IsDeletedEnum.NO.getCode())
+ .update();
+ }
+
+ @Override
+ public boolean updateAllBatchMessageFail(String errorMsg, String batchNo) {
+ return lambdaUpdate()
+ .set(Message::getRemark, errorMsg)
+ .set(Message::getStatus, MessageStatusEnum.FAIL.getCode())
+ .eq(Message::getBatchNo, batchNo)
+ .eq(Message::getIsDelete, IsDeletedEnum.NO.getCode())
+ .update();
+ }
+
+ @Override
+ public boolean updateStatusAndRemarkById(Long id, String status, String remark) {
+
+ return lambdaUpdate()
+ .eq(Message::getId,id)
+ .set(Message::getStatus,status)
+ .set(Message::getUpdateAt, new Date())
+ .set(!StringUtils.isEmpty(remark),Message::getRemark,remark)
+ .update();
+ }
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageRedoDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageRedoDaoImpl.java
new file mode 100644
index 00000000..fa3f9968
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageRedoDaoImpl.java
@@ -0,0 +1,41 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.common.enums.IsDeletedEnum;
+import cn.axzo.msg.notices.common.enums.MessageStatusEnum;
+import cn.axzo.msg.notices.common.enums.RetryingFlagEnum;
+import cn.axzo.msg.notices.dao.domain.MessageRedoQuery;
+import cn.axzo.msg.notices.dao.entity.MessageRedo;
+import cn.axzo.msg.notices.dao.mapper.MessageRedoMapper;
+import cn.axzo.msg.notices.dao.repository.MessageRedoDao;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Repository;
+
+@Repository("messageRedoDao")
+public class MessageRedoDaoImpl extends ServiceImpl implements MessageRedoDao {
+
+ @Override
+ public IPage queryByPage(MessageRedoQuery query) {
+ return this.page(query.toPage(), new LambdaQueryWrapper()
+ .eq(query.getId() != null, MessageRedo::getId, query.getId())
+ .ge(query.getStartCreateTime() != null, MessageRedo::getCreateAt, query.getStartCreateTime())
+ .le(query.getEndCreateTime() != null, MessageRedo::getCreateAt, query.getEndCreateTime())
+ .in(CollectionUtils.isNotEmpty(query.getStatuses()), MessageRedo::getStatus, query.getStatuses())
+ .eq(StringUtils.isNoneBlank(query.getChannelCode()), MessageRedo::getChannelCode, query.getChannelCode())
+ .eq(MessageRedo::getRetryingFlag, RetryingFlagEnum.Y.name())
+ .eq(MessageRedo::getIsDelete, IsDeletedEnum.NO.getCode())
+ .orderByDesc(MessageRedo::getCreateAt));
+ }
+
+ @Override
+ public boolean updateExceptionToFail(Long id) {
+ return lambdaUpdate()
+ .set(MessageRedo::getStatus, MessageStatusEnum.FAIL.getCode())
+ .eq(MessageRedo::getId, id)
+ .eq(MessageRedo::getStatus, MessageStatusEnum.EXCEPTION.getCode())
+ .update();
+ }
+}
\ No newline at end of file
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageRequestLogDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageRequestLogDaoImpl.java
new file mode 100644
index 00000000..6cb66ffe
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageRequestLogDaoImpl.java
@@ -0,0 +1,20 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.dao.entity.MessageRequestLog;
+import cn.axzo.msg.notices.dao.mapper.MessageRequestLogMapper;
+import cn.axzo.msg.notices.dao.repository.MessageRequestLogDao;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Repository;
+
+/**
+ *
+ * 外部系统请求表 Dao实现类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+@Repository("messageRequestLogDao")
+public class MessageRequestLogDaoImpl extends ServiceImpl implements MessageRequestLogDao {
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageTemplateDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageTemplateDaoImpl.java
new file mode 100644
index 00000000..c7ea71a3
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageTemplateDaoImpl.java
@@ -0,0 +1,27 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.dao.entity.MessageTemplate;
+import cn.axzo.msg.notices.dao.mapper.MessageTemplateMapper;
+import cn.axzo.msg.notices.dao.repository.MessageTemplateDao;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Repository;
+
+/**
+ *
+ * 内部消息模板表 Dao实现类
+ *
+ *
+ * @author zhaoyong
+ * @since 2021-05-19
+ */
+@Repository("messageTemplateDao")
+public class MessageTemplateDaoImpl extends ServiceImpl implements MessageTemplateDao {
+
+
+ @Override
+ public MessageTemplate queryByTemplateNo(String templateNo) {
+ return this.lambdaQuery()
+ .eq(MessageTemplate::getTemplateNo, templateNo)
+ .one();
+ }
+}
diff --git a/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageTemplateParamDaoImpl.java b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageTemplateParamDaoImpl.java
new file mode 100644
index 00000000..34343147
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/java/cn/axzo/msg/notices/dao/repository/impl/MessageTemplateParamDaoImpl.java
@@ -0,0 +1,39 @@
+package cn.axzo.msg.notices.dao.repository.impl;
+
+import cn.axzo.msg.notices.common.enums.IsDeletedEnum;
+import cn.axzo.msg.notices.dao.entity.MessageTemplateParam;
+import cn.axzo.msg.notices.dao.mapper.MessageTemplateParamMapper;
+import cn.axzo.msg.notices.dao.repository.MessageTemplateParamDao;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ *
+ * 渠道模板变量序列表 Dao实现类
+ *
+ *
+ * @author szg
+ * @since 2021-08-07
+ */
+@Repository("messageTemplateParamDao")
+public class MessageTemplateParamDaoImpl extends ServiceImpl implements
+ MessageTemplateParamDao {
+
+ @Override
+ public List getByTemplateNo(String templateNo) {
+ return this.lambdaQuery().eq(MessageTemplateParam::getTemplateNo, templateNo)
+ .eq(MessageTemplateParam::getIsDelete, IsDeletedEnum.NO.getCode())
+ .orderByAsc(MessageTemplateParam::getParamOrder)
+ .list();
+ }
+
+ @Override
+ public List getAllMessageTemplateParams() {
+ return this.lambdaQuery()
+ .eq(MessageTemplateParam::getIsDelete, IsDeletedEnum.NO.getCode())
+ .list();
+ }
+
+}
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/BatchMessageMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/BatchMessageMapper.xml
new file mode 100644
index 00000000..d24364ff
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/BatchMessageMapper.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, request_no, batch_no, app_no, template_no, channel_template_no, message_order_no, sms_content, batch_size, success_count, fail_count, send_type, status, submit_success_num, submit_fail_num, channel_msg_id, channel_code, channel_return_code, channel_error_msg, create_at, update_at, is_delete
+
+
+
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/BatchMessageRequestMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/BatchMessageRequestMapper.xml
new file mode 100644
index 00000000..e98da982
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/BatchMessageRequestMapper.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_no, request_no, template_no, sms_content, total_size, success_count, fail_count, repeat_count, send_type, status, remark, create_at, update_at, is_delete
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/ChannelMessageTemplateMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/ChannelMessageTemplateMapper.xml
new file mode 100644
index 00000000..ec4375d3
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/ChannelMessageTemplateMapper.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, inner_template_no, template_no, channel_code, channel_name, title, template_content, type, status, has_param, remark, reason, create_at, update_at, create_by, update_by, is_delete
+
+
+ delete from channel_message_template where inner_template_no = #{templateNo}
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageAppMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageAppMapper.xml
new file mode 100644
index 00000000..95f71c03
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageAppMapper.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_code, app_name, status, remark, extension, create_at, update_at, create_by, update_by, is_delete
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageChannelLogMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageChannelLogMapper.xml
new file mode 100644
index 00000000..6de71096
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageChannelLogMapper.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_no, app_request_no, message_order_no, target_address, response_data, callback_data, task_data, create_at, update_at, create_by, update_by, is_delete
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageChannelMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageChannelMapper.xml
new file mode 100644
index 00000000..4874b523
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageChannelMapper.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, channel_code, channel_name, status, priority, config_json, create_at, update_at, create_by, update_by, is_delete
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageMapper.xml
new file mode 100644
index 00000000..dc8ee9aa
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageMapper.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_no, request_no, message_order_no, message_type, notify_type, status, channel_code, channel_name, template_no, subject, target_address, channel_biz_id, channel_request_id, notify_rule, remark, create_at, update_at, create_by, update_by, is_delete
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageRedoMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageRedoMapper.xml
new file mode 100644
index 00000000..0093470f
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageRedoMapper.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_no, request_no, message_order_no, redo_order_no,channel_biz_id, message_type, notify_type,
+ `status`, channel_code, channel_name, template_no, subject, target_address, retrying_flag,
+ retry_count, notify_rule, retry_at, create_at, update_at, create_by, update_by, is_delete
+
+
\ No newline at end of file
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageRequestLogMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageRequestLogMapper.xml
new file mode 100644
index 00000000..0e158209
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageRequestLogMapper.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_no, request_no, method_name, request_body, response_body, create_at, update_at, create_by, update_by, is_delete
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageTemplateMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageTemplateMapper.xml
new file mode 100644
index 00000000..2fcd5ce9
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageTemplateMapper.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, template_no, title, template_content, type, status, reason, remark, create_at, update_at, create_by, update_by, is_delete
+
+
+ delete from message_template where template_no = #{templateNo}
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageTemplateParamMapper.xml b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageTemplateParamMapper.xml
new file mode 100644
index 00000000..bb498934
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/mapper/MessageTemplateParamMapper.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, template_no, param_name, param_desc, param_order, remark, create_at, update_at, create_by, update_by, is_delete
+
+
+
diff --git a/msg-notices/msg-notices-dao/src/main/resources/templates/serviceimpl.java.vm b/msg-notices/msg-notices-dao/src/main/resources/templates/serviceimpl.java.vm
new file mode 100644
index 00000000..ec6a4c0a
--- /dev/null
+++ b/msg-notices/msg-notices-dao/src/main/resources/templates/serviceimpl.java.vm
@@ -0,0 +1,26 @@
+package ${package.ServiceImpl};
+
+import ${package.Entity}.${entity};
+import ${package.Mapper}.${table.mapperName};
+import ${package.Service}.${table.serviceName};
+import ${superServiceImplClassPackage};
+import org.springframework.stereotype.Repository;
+
+/**
+ *
+ * $!{table.comment} Dao实现类
+ *
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+@Repository("${table.serviceName.substring(0,1).toLowerCase().concat(${table.serviceName.substring(1)})}")
+#if(${kotlin})
+open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
+
+ }
+#else
+public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
+
+}
+#end
diff --git a/msg-notices/msg-notices-http-api/pom.xml b/msg-notices/msg-notices-http-api/pom.xml
new file mode 100644
index 00000000..0409d9d2
--- /dev/null
+++ b/msg-notices/msg-notices-http-api/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+ msg-notices
+ cn.axzo.msgcenter
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ cn.axzo.msg.notices.http.api
+ msg-notices-http-api
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ cn.axzo.framework
+ axzo-common
+
+
+ javax.validation
+ validation-api
+
+
+ org.hibernate.validator
+ hibernate-validator
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+
\ No newline at end of file
diff --git a/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/api/MessageNotifyApi.java b/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/api/MessageNotifyApi.java
new file mode 100644
index 00000000..904078cd
--- /dev/null
+++ b/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/api/MessageNotifyApi.java
@@ -0,0 +1,40 @@
+package cn.axzo.msg.notices.http.api.api;
+
+
+import cn.axzo.msg.notices.http.api.request.SendBatchMessageRequest;
+import cn.axzo.msg.notices.http.api.request.SendMobileMessageRequest;
+import cn.azxo.framework.common.model.CommonResponse;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+/**
+ * 短信通知接口
+ *
+ * @author zhaoyong_sh
+ * @see MessageNotifyApi
+ * @since 2021-05-20 11:27
+ */
+@FeignClient(
+ name = "mns",
+ url = "http://mns:8989"
+)
+public interface MessageNotifyApi {
+
+ /**
+ * 发送手机短信
+ * @param request
+ * @return
+ */
+ @RequestMapping(value = "/api/v1/message/send", method = RequestMethod.POST)
+ CommonResponse sendMobileMessage(SendMobileMessageRequest request);
+
+ /**
+ * 批量发送短信
+ * @param request
+ * @return
+ */
+ @RequestMapping(value = "/api/v1/message/batch", method = RequestMethod.POST)
+ CommonResponse sendBatchMessage(SendBatchMessageRequest request);
+
+}
diff --git a/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/request/SendBatchMessageRequest.java b/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/request/SendBatchMessageRequest.java
new file mode 100644
index 00000000..2b845533
--- /dev/null
+++ b/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/request/SendBatchMessageRequest.java
@@ -0,0 +1,56 @@
+package cn.axzo.msg.notices.http.api.request;
+
+import cn.azxo.framework.common.annotation.ValidNumberValue;
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 批量发送短信请求
+ *
+ * @author zhaoyong
+ * @see SendBatchMessageRequest
+ * @since 2021-08-05 12:50
+ */
+@Data
+public class SendBatchMessageRequest {
+
+ /**
+ * 请求号
+ */
+ @NotBlank(message = "request no must not be null")
+ private String requestNo;
+
+ /**
+ * 应用接入码
+ */
+ @NotBlank(message = "app code must not be null")
+ private String appCode;
+
+ /**
+ * 消息模板号
+ */
+ @NotBlank(message = "templateNo must not be null")
+ private String templateNo;
+
+ /**
+ * 发送类型
+ *
+ * 1:实时;2:非实时
+ *
+ */
+ @NotNull(message = "sendType must not be null")
+ @ValidNumberValue(value = {1, 2}, message = "sendType must be in {value}")
+ private Integer sendType;
+
+ /**
+ * 消息内容
+ */
+ @Valid
+ @NotNull(message = "smsContents must not be null")
+ private List smsContents;
+
+}
diff --git a/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/request/SendMobileMessageRequest.java b/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/request/SendMobileMessageRequest.java
new file mode 100644
index 00000000..176e65d8
--- /dev/null
+++ b/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/request/SendMobileMessageRequest.java
@@ -0,0 +1,42 @@
+package cn.axzo.msg.notices.http.api.request;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 发送手机信息请求类
+ *
+ * @author zhaoyong_sh
+ * @see SendMobileMessageRequest
+ * @since 2021-05-20 11:28
+ */
+@Data
+public class SendMobileMessageRequest {
+
+ /** 请求号 */
+ @NotBlank(message = "request no must not be null")
+ private String requestNo;
+
+ /** 应用接入码 */
+ @NotBlank(message = "app code must not be null")
+ private String appCode;
+
+ /** 短信模板号 */
+ @NotBlank(message = "template no must not be null")
+ private String templateNo;
+
+ /** 电话号码 */
+ @NotBlank(message = "phone no must not be null")
+ private String phoneNo;
+
+ /** 短信模板变更 */
+ @NotNull(message = "params must not be null")
+ private Map params = new HashMap<>();
+ /** 扩展参数 */
+ private String expansion;
+
+}
diff --git a/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/request/SmsContent.java b/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/request/SmsContent.java
new file mode 100644
index 00000000..4f275441
--- /dev/null
+++ b/msg-notices/msg-notices-http-api/src/main/java/cn/axzo/msg/notices/http/api/request/SmsContent.java
@@ -0,0 +1,29 @@
+package cn.axzo.msg.notices.http.api.request;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 短信上下文
+ *
+ * @author zhaoyong
+ * @see SmsContent
+ * @since 2021-08-05 15:05
+ */
+@Data
+public class SmsContent {
+
+ /**
+ * 手机号
+ */
+ @NotBlank(message = "phoneNo must not be null")
+ private String phoneNo;
+
+ /**
+ * 模板参数
+ * 使用无变量模板时,可不带templateParams参数
+ */
+ private String templateParams;
+
+}
diff --git a/msg-notices/msg-notices-integration/pom.xml b/msg-notices/msg-notices-integration/pom.xml
new file mode 100644
index 00000000..717cb45e
--- /dev/null
+++ b/msg-notices/msg-notices-integration/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+ msg-notices
+ cn.axzo.msgcenter
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ cn.axzo.msg.notices.integration
+ msg-notices-integration
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ cn.axzo.msg.notices.common
+ msg-notices-common
+ ${revision}
+
+
+ com.aliyun
+ dysmsapi20170525
+ 2.0.4
+
+
+ org.springframework
+ spring-web
+
+
+
+
\ No newline at end of file
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/AliYunSmsClient.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/AliYunSmsClient.java
new file mode 100644
index 00000000..d4c3d4a1
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/AliYunSmsClient.java
@@ -0,0 +1,42 @@
+package cn.axzo.msg.notices.integration.client;
+
+import cn.axzo.msg.notices.common.enums.SendDetailsStatusEnum;
+import cn.axzo.msg.notices.integration.dto.request.SendSmsCommonRequest;
+import cn.axzo.msg.notices.integration.dto.response.SendSmsCommonResponse;
+
+/**
+ * 短信服务
+ *
+ * @author zhaoyong_sh
+ * @see AliYunSmsClient
+ * @since 2021-05-19 12:38
+ */
+public interface AliYunSmsClient {
+
+ /**
+ * 查询异常短信发送详情
+ * @param cellphone
+ * @param sendDate
+ * @param outId
+ * @return
+ */
+ SendDetailsStatusEnum queryExceptionSendDetails(String cellphone, String sendDate, String outId);
+
+ /**
+ * 查询处理中短信发送详情
+ * @param cellphone
+ * @param sendDate
+ * @param bizId
+ * @return
+ */
+ SendDetailsStatusEnum queryProcessingSendDetail(String cellphone, String sendDate, String bizId);
+
+
+ /**
+ * 通过
+ * @param request
+ * @return
+ */
+ SendSmsCommonResponse sendSms(SendSmsCommonRequest request) throws Exception;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/AliyunSmsClientFactory.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/AliyunSmsClientFactory.java
new file mode 100644
index 00000000..fd769cac
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/AliyunSmsClientFactory.java
@@ -0,0 +1,31 @@
+package cn.axzo.msg.notices.integration.client;
+
+import com.aliyun.dysmsapi20170525.Client;
+import com.aliyun.teaopenapi.models.Config;
+import lombok.SneakyThrows;
+import org.springframework.stereotype.Component;
+
+/**
+ * 阿里云 SMS 客户端工厂
+ *
+ * @author zhaoyong_sh
+ * @see AliyunSmsClientFactory
+ * @since 2021-05-19 14:02
+ */
+@Component("aliyunSmsClientFactory")
+public class AliyunSmsClientFactory {
+
+ @SneakyThrows
+ public Client getClient(String accessKeyId, String accessKeySecret) {
+ Config config = new Config()
+ // 您的AccessKey ID
+ .setAccessKeyId(accessKeyId)
+ // 您的AccessKey Secret
+ .setAccessKeySecret(accessKeySecret)
+ // Endpoint
+ .setEndpoint("dysmsapi.aliyuncs.com");
+ Client client = new Client(config);
+ return client;
+ }
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/ChuangLanSmsClient.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/ChuangLanSmsClient.java
new file mode 100644
index 00000000..6c7a67f9
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/ChuangLanSmsClient.java
@@ -0,0 +1,17 @@
+package cn.axzo.msg.notices.integration.client;
+
+import cn.axzo.msg.notices.integration.dto.request.MessageRequest;
+import cn.axzo.msg.notices.integration.dto.response.ChuangLanSmsResponse;
+
+/**
+ * 创蓝短信客户端
+ *
+ * @author zhaoyong
+ * @see ChuangLanSmsClient
+ * @since 2021-08-07 16:57
+ */
+public interface ChuangLanSmsClient {
+
+ ChuangLanSmsResponse sendMessage(MessageRequest request);
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/DingDingClient.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/DingDingClient.java
new file mode 100644
index 00000000..7ccec8e1
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/DingDingClient.java
@@ -0,0 +1,50 @@
+package cn.axzo.msg.notices.integration.client;
+
+/**
+ * 钉钉客户端
+ *
+ * @author zhaoyong
+ * @see DingDingClient
+ * @since 2021-07-12 11:59
+ */
+public interface DingDingClient {
+
+ /**
+ * 钉钉群通知验证码
+ * @param mobile
+ * @param title
+ * @param param
+ */
+ void notifyMockMessage(String mobile, String title, String param);
+
+ /**
+ * 单条短信发送失败
+ * @param templateNo
+ * @param requestNo
+ * @param errorMsg
+ */
+ void notifySingleMessage(String templateNo, String requestNo, String errorMsg);
+
+ /**
+ * 批量短信发送失败
+ * @param templateNo
+ * @param batchNo
+ * @param errorMsg
+ */
+ void notifyBatchMessage(String templateNo, String batchNo, String errorMsg);
+
+ /**
+ * 渠道回调异常
+ * @param channelName
+ * @param callbackData
+ * @param errorMsg
+ */
+ void notifyChannelCallback(String channelName, String callbackData, String errorMsg);
+
+ /**
+ * RocketMQ 不可用
+ * @param errorMsg
+ */
+ void notifyRocketMqError(String errorMsg);
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/impl/AliYunSmsClientImpl.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/impl/AliYunSmsClientImpl.java
new file mode 100644
index 00000000..0cc567fb
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/impl/AliYunSmsClientImpl.java
@@ -0,0 +1,217 @@
+package cn.axzo.msg.notices.integration.client.impl;
+
+import cn.axzo.msg.notices.common.constans.AliyunConstants;
+import cn.axzo.msg.notices.common.domain.ServiceContextHolder;
+import cn.axzo.msg.notices.common.enums.ReturnCodeEnum;
+import cn.axzo.msg.notices.common.enums.SendDetailsStatusEnum;
+import cn.axzo.msg.notices.common.exception.BizException;
+import cn.axzo.msg.notices.integration.client.AliYunSmsClient;
+import cn.axzo.msg.notices.integration.client.AliyunSmsClientFactory;
+import cn.axzo.msg.notices.integration.dto.request.SendSmsCommonRequest;
+import cn.axzo.msg.notices.integration.dto.response.SendSmsCommonResponse;
+import cn.azxo.framework.common.utils.LogUtil;
+import com.alibaba.fastjson.JSON;
+import com.aliyun.dysmsapi20170525.Client;
+import com.aliyun.dysmsapi20170525.models.*;
+import com.aliyun.dysmsapi20170525.models.QuerySendDetailsResponseBody.QuerySendDetailsResponseBodySmsSendDetailDTOs;
+import com.aliyun.dysmsapi20170525.models.QuerySendDetailsResponseBody.QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO;
+import com.aliyun.teautil.models.RuntimeOptions;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 阿里云短信服务
+ *
+ * @author zhaoyong_sh
+ * @see AliYunSmsClientImpl
+ * @since 2021-05-19 12:39
+ */
+@Slf4j
+@Service("aliYunSmsClient")
+public class AliYunSmsClientImpl implements AliYunSmsClient {
+
+ @Resource(name = "aliyunSmsClientFactory")
+ private AliyunSmsClientFactory aliyunSmsClientFactory;
+
+ @Value("${sms.aliyun.accessKeyId}")
+ private String accessKeyId;
+
+ @Value("${sms.aliyun.accessSecret}")
+ private String accessSecret;
+
+ @Value("${sms.aliyun.signName}")
+ private String signName;
+
+ @Override
+ public SendDetailsStatusEnum queryExceptionSendDetails(String cellphone, String sendDate,
+ String outId) {
+ RuntimeOptions runtime = new RuntimeOptions();
+ QuerySendDetailsRequest request = new QuerySendDetailsRequest();
+ request.setCurrentPage(1L);
+ request.setPageSize(50L);
+ request.setPhoneNumber(cellphone);
+ request.setSendDate(sendDate);
+ QuerySendDetailsResponse response;
+ try {
+ log.info("AliyunSmsService#queryExceptionSendDetails request param is {}", cellphone);
+ response = getClient().querySendDetailsWithOptions(request, runtime);
+ log.info("AliyunSmsService#queryExceptionSendDetails response is {}",
+ JSON.toJSONString(response));
+ } catch (Exception e) {
+ LogUtil.error("AliyunSmsService#queryExceptionSendDetails is error", e);
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "query send details fail");
+ }
+ List sendDetailDTOS = checkResponse(
+ response);
+ if (CollectionUtils.isEmpty(sendDetailDTOS)) {
+ return null;
+ }
+ Optional matchOutIdOptional =
+ sendDetailDTOS.stream().filter(v -> outId.equals(v.getOutId())).findFirst();
+ if (!matchOutIdOptional.isPresent()) {
+ return null;
+ }
+ QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO dto = matchOutIdOptional.get();
+ SendDetailsStatusEnum sendStatusEnum = SendDetailsStatusEnum.getByCode(dto.getSendStatus());
+ BizException.error(sendStatusEnum != null, ReturnCodeEnum.SYSTEM_ERROR,
+ "非法的响应值:" + dto.getSendStatus());
+ return sendStatusEnum;
+ }
+
+ @Override
+ public SendDetailsStatusEnum queryProcessingSendDetail(String cellphone, String sendDate,
+ String bizId) {
+ RuntimeOptions runtime = new RuntimeOptions();
+ QuerySendDetailsRequest request = new QuerySendDetailsRequest();
+ request.setCurrentPage(1L);
+ request.setPageSize(50L);
+ request.setPhoneNumber(cellphone);
+ request.setSendDate(sendDate);
+ request.setBizId(bizId);
+ QuerySendDetailsResponse response;
+ try {
+ log.info("AliyunSmsService#queryExceptionSendDetails request param is {}", cellphone);
+ response = getClient().querySendDetailsWithOptions(request, runtime);
+ log.info("AliyunSmsService#queryExceptionSendDetails response is {}",
+ JSON.toJSONString(response));
+ } catch (Exception e) {
+ LogUtil.error("AliyunSmsService#queryExceptionSendDetails is error", e);
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "query send details fail");
+ }
+ List sendDetailDTOS = checkResponse(
+ response);
+ if (CollectionUtils.isEmpty(sendDetailDTOS)) {
+ return null;
+ }
+ QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO dto = sendDetailDTOS.get(0);
+ SendDetailsStatusEnum sendStatusEnum = SendDetailsStatusEnum.getByCode(dto.getSendStatus());
+ BizException.error(sendStatusEnum != null, ReturnCodeEnum.SYSTEM_ERROR,
+ "非法的响应值:" + dto.getSendStatus());
+ return sendStatusEnum;
+ }
+
+ @Override
+ public SendSmsCommonResponse sendSms(SendSmsCommonRequest request) {
+ log.info("[发送sms方法调用] -> {}", JSON.toJSONString(request));
+ Client client = getClient();
+ SendSmsRequest aliyunRequest = new SendSmsRequest();
+ aliyunRequest.setPhoneNumbers(request.getPhoneNo());
+ aliyunRequest.setOutId(request.getRequestChannelNo());
+ aliyunRequest.setSignName(signName);
+ aliyunRequest.setTemplateCode(request.getTemplateCode());
+ aliyunRequest.setTemplateParam(JSON.toJSONString(request.getTemplateMap()));
+ log.info("[mns <- aliyun]AliyunSmsService.sendSms response is {}", JSON.toJSONString(aliyunRequest));
+ SendSmsResponse response;
+ try {
+ response = client.sendSms(aliyunRequest);
+ log.info("[mns <- aliyun]AliyunSmsService.sendSms response is {}", JSON.toJSONString(response));
+ } catch (Exception e) {
+ LogUtil.error("[mns <- aliyun]AliyunSmsService.sendSms is fail", e);
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "invoke aliyun fail");
+ }
+
+ // 添加响应到上下文
+ ServiceContextHolder.get().setChannelResponse(response);
+
+ // 检查响应
+ SendSmsResponseBody responseBody = checkSendResponse(response);
+
+ // 响应转换
+ SendSmsCommonResponse smsResponse = new SendSmsCommonResponse();
+ smsResponse.setRequestId(responseBody.getRequestId());
+ smsResponse.setMessage(responseBody.getMessage());
+ smsResponse.setBizId(responseBody.getBizId());
+ smsResponse.setCode(responseBody.getCode());
+ return smsResponse;
+ }
+
+ /**
+ * 获取客户端
+ *
+ * @return
+ */
+ private Client getClient() {
+ return aliyunSmsClientFactory.getClient(accessKeyId, accessSecret);
+ }
+
+ /**
+ * 检查发送短信结果
+ * @param response
+ * @return
+ */
+ private SendSmsResponseBody checkSendResponse(SendSmsResponse response) {
+ if (response == null) {
+ log.info("AliyunSmsService#checkSendResponse response is null");
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "aliyun response is null");
+ }
+ SendSmsResponseBody responseBody = response.getBody();
+ if (responseBody == null) {
+ log.info("AliyunSmsService#checkSendResponse response body is null");
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "aliyun response body is null");
+ }
+ if (!AliyunConstants.SUCCESS_CODE.equals(responseBody.getCode())) {
+ String message = responseBody.getMessage();
+ log.info("AliyunSmsService#checkResponse is fail, error message : {}", message);
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, message);
+ }
+ return responseBody;
+ }
+
+ /**
+ * 检查查询短信发送详情响应
+ *
+ * @param response
+ * @return
+ */
+ private List checkResponse(
+ QuerySendDetailsResponse response) {
+ if (response == null) {
+ log.info("AliyunSmsService#checkResponse response is null");
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "aliyun response is null");
+ }
+ QuerySendDetailsResponseBody responseBody = response.getBody();
+ if (responseBody == null) {
+ log.info("AliyunSmsService#checkResponse response body is null");
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "aliyun response body is null");
+ }
+ if (!AliyunConstants.SUCCESS_CODE.equals(responseBody.getCode())) {
+ String message = responseBody.getMessage();
+ log.info("AliyunSmsService#checkResponse is fail, error message : {}", message);
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, message);
+ }
+ QuerySendDetailsResponseBodySmsSendDetailDTOs smsSendDetailDTOs = responseBody
+ .getSmsSendDetailDTOs();
+ if (smsSendDetailDTOs == null) {
+ log.info("AliyunSmsService#checkResponse sms send details is null");
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "sms send details is null");
+ }
+ return smsSendDetailDTOs.getSmsSendDetailDTO();
+ }
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/impl/ChuangLanSmsClientImpl.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/impl/ChuangLanSmsClientImpl.java
new file mode 100644
index 00000000..66ad0f60
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/impl/ChuangLanSmsClientImpl.java
@@ -0,0 +1,85 @@
+package cn.axzo.msg.notices.integration.client.impl;
+
+import cn.axzo.msg.notices.common.constans.ChuangLanConstants;
+import cn.axzo.msg.notices.common.domain.ServiceContextHolder;
+import cn.axzo.msg.notices.common.enums.ReturnCodeEnum;
+import cn.axzo.msg.notices.common.exception.BizException;
+import cn.axzo.msg.notices.integration.client.ChuangLanSmsClient;
+import cn.axzo.msg.notices.integration.dto.request.BaseSmsRequest;
+import cn.axzo.msg.notices.integration.dto.request.MessageRequest;
+import cn.axzo.msg.notices.integration.dto.response.ChuangLanSmsResponse;
+import cn.axzo.msg.notices.integration.support.ChuangLanMessageRequestResolver;
+import cn.axzo.msg.notices.integration.support.ChuangLanMessageRequestResolverFactory;
+import cn.azxo.framework.common.utils.LogUtil;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import javax.annotation.Resource;
+
+/**
+ * 创蓝短信客户端实现类
+ *
+ * @author zhaoyong
+ * @see ChuangLanSmsClientImpl
+ * @since 2021-08-07 17:02
+ */
+@Slf4j
+@Component("chuangLanSmsClient")
+public class ChuangLanSmsClientImpl implements ChuangLanSmsClient {
+
+ @Resource(name = "chuangLanMessageRequestResolverFactory")
+ private ChuangLanMessageRequestResolverFactory factory;
+
+ @Resource(name = "restTemplate")
+ private RestTemplate restTemplate;
+
+ @Override
+ public ChuangLanSmsResponse sendMessage(MessageRequest request) {
+ log.info("[manager -> client]ChuangLanSmsClientImpl.sendBatchMessage request param is {}", JSON.toJSONString(request));
+
+ // 获取请求参数解析器
+ ChuangLanMessageRequestResolver requestResolver = factory.getService(request.getMessageTemplateType());
+ BizException.error(requestResolver != null,
+ ReturnCodeEnum.INVALID_PARAMETER, "不支持的模板类型 : " + request.getMessageTemplateType());
+
+ // 获取发送创蓝短信请求类
+ BaseSmsRequest smsRequest = requestResolver.resolve(request);
+ log.info("[mns -> chuanglan]ChuangLanSmsClientImpl.sendBatchMessage request param is {}", JSON.toJSONString(smsRequest));
+
+ // 发送短信
+ ChuangLanSmsResponse response;
+ try {
+ response = restTemplate.postForObject(request.getRequestUrl(),
+ smsRequest, ChuangLanSmsResponse.class);
+ } catch (Exception e) {
+ LogUtil.error("[mns -> chuanglan]ChuangLanSmsClientImpl.sendBatchMessage is fail.", e);
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "invoke chuanglang fail");
+ }
+
+ // 添加响应对象
+ ServiceContextHolder.get().setChannelResponse(response);
+
+ // 检查响应对象
+ checkResponse(response);
+
+ log.info("[mns <- chuanglan]ChuangLanSmsClientImpl.sendBatchMessage response is {}", JSON.toJSONString(response));
+
+ // 返回响应
+ return response;
+ }
+
+ /**
+ * 检查响应信息
+ * @param response
+ */
+ private void checkResponse(ChuangLanSmsResponse response) {
+ if(response == null) {
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "response is null");
+ }
+ if(!ChuangLanConstants.SUCCESS_CODE.equals(response.getCode())) {
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR.getCode(), response.getErrorMsg(), response);
+ }
+ }
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/impl/DingDingClientImpl.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/impl/DingDingClientImpl.java
new file mode 100644
index 00000000..93846804
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/client/impl/DingDingClientImpl.java
@@ -0,0 +1,178 @@
+package cn.axzo.msg.notices.integration.client.impl;
+
+import cn.axzo.msg.notices.common.constans.CommonConstants;
+import cn.axzo.msg.notices.integration.client.DingDingClient;
+import cn.axzo.msg.notices.integration.dto.request.At;
+import cn.axzo.msg.notices.integration.dto.request.DingMessageRequest;
+import cn.axzo.msg.notices.integration.dto.request.MessageText;
+import cn.axzo.msg.notices.integration.dto.response.DingMessageResponse;
+import cn.azxo.framework.common.utils.LogUtil;
+import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import javax.annotation.Resource;
+
+/**
+ * 钉钉客户端实现类
+ *
+ * @author zhaoyong
+ * @see DingDingClientImpl
+ * @since 2021-07-12 12:00
+ */
+@Slf4j
+@Service("dingDingClient")
+@RefreshScope
+public class DingDingClientImpl implements DingDingClient, EnvironmentAware {
+
+ public static final String NOTIFY_VERIFICATION_CODE = "https://oapi.dingtalk.com/robot/send?access_token=ac574ebc7f9f5c197f6a58e122332689a5b5b75a3b7e4413e67b33bba4e95af6";
+
+ public static final String NOTIFY_BATCH_MESSAGE = "https://oapi.dingtalk.com/robot/send?access_token=65845830bc350344abdcb2c196a0dafe100053a812ff47d65ce1f395f12ec484";
+
+ public static final String NOTIFY_SINGLE_MESSAGE = "https://oapi.dingtalk.com/robot/send?access_token=9fb3a8a8f1c827ddb07e2e138b21351845e9381b62aa206e0c06333b0e4c95f7";
+
+ public static final String NOTIFY_MQ_MESSAGE = "https://oapi.dingtalk.com/robot/send?access_token=bff5747081dccd33d57276ffc67a4b2d7caca550081b0d1c8e5f7af9cf473221";
+
+ public static final String NOTIFY_CHANNEL_CALLBACK = "https://oapi.dingtalk.com/robot/send?access_token=cf51872a50040a2a7ac88397de2c8c9fad6e37059d2525ced3084d2d6781af05";
+
+ @Resource(name = "restTemplate")
+ private RestTemplate restTemplate;
+
+ private final static String NOTIFY_MESSAGE_FORMAT = "主题:短信 Mock\n环境: %s \n手机号: %s \n模板名称: %s \n短信内容: %s";
+
+ private final static String BATCH_MESSAGE_FORMAT = "主题:批量短信发送失败\n环境: %s \n消息模板号: %s \n批次号: %s \n错误信息: %s";
+
+ private final static String SINGLE_MESSAGE_FORMAT = "主题:单条短信发送失败\n环境: %s \n消息模板号: %s \n请求号: %s \n错误信息: %s";
+
+ private final static String MQ_MESSAGE_FORMAT = "主题:RocketMQ异常\n环境: %s \n错误信息: %s";
+
+ private final static String CHANNEL_CALLBACK_FORMAT = "主题:渠道回调异常\n环境: %s \n渠道名称: %s \n回调信息: %s \n错误信息: %s";
+
+ private Environment environment;
+
+ @Value("${dingDing.at:false}")
+ private boolean dingDingAt;
+
+ @Override
+ public void notifyMockMessage(String mobile, String title, String param) {
+ try {
+ DingMessageRequest request = new DingMessageRequest();
+ request.setMsgtype(CommonConstants.DING_TEXT_MESSAGE_TYPE);
+ MessageText text = new MessageText();
+ String content = String.format(NOTIFY_MESSAGE_FORMAT, getProfile(), mobile, title, param);
+ text.setContent(content);
+ request.setText(text);
+ if(dingDingAt){
+ At at = new At();
+ at.setAtMobiles(Lists.newArrayList(mobile));
+ request.setAt(at);
+ }
+ log.info("[mns -> ding] DingDingClientImpl.notify request param is {}", JSON.toJSONString(request));
+ DingMessageResponse response = restTemplate.postForObject(NOTIFY_VERIFICATION_CODE, request, DingMessageResponse.class);
+ log.info("[mns <- ding] DingDingClientImpl.notify response is {}", JSON.toJSONString(response));
+ } catch (Exception e) {
+ LogUtil.error("[mns <- ding] DingDingClientImpl.notify response is error", e);
+ }
+ }
+
+ @Override
+ public void notifySingleMessage(String templateNo, String requestNo, String errorMsg) {
+ try {
+ DingMessageRequest request = new DingMessageRequest();
+ request.setMsgtype(CommonConstants.DING_TEXT_MESSAGE_TYPE);
+ MessageText text = new MessageText();
+ String content = String.format(SINGLE_MESSAGE_FORMAT, getProfile(), templateNo, requestNo, errorMsg);
+ text.setContent(content);
+ request.setText(text);
+ At at = new At();
+ at.setAtMobiles(Lists.newArrayList("13585844124", "15928328930", "17605414211"));
+ request.setAt(at);
+ log.info("[mns -> ding] DingDingClientImpl.notifySingleMessage request param is {}", JSON.toJSONString(request));
+ DingMessageResponse response = restTemplate.postForObject(NOTIFY_SINGLE_MESSAGE, request, DingMessageResponse.class);
+ log.info("[mns <- ding] DingDingClientImpl.notifySingleMessage response is {}", JSON.toJSONString(response));
+ } catch (Exception e) {
+ LogUtil.error("[mns <- ding] DingDingClientImpl.notifySingleMessage response is error", e);
+ }
+ }
+
+ @Override
+ public void notifyBatchMessage(String templateNo, String batchNo, String errorMsg) {
+ try {
+ DingMessageRequest request = new DingMessageRequest();
+ request.setMsgtype(CommonConstants.DING_TEXT_MESSAGE_TYPE);
+ MessageText text = new MessageText();
+ String content = String.format(BATCH_MESSAGE_FORMAT, getProfile(), templateNo, batchNo, errorMsg);
+ text.setContent(content);
+ request.setText(text);
+ At at = new At();
+ at.setAtMobiles(Lists.newArrayList("13585844124", "15928328930", "17605414211"));
+ request.setAt(at);
+ log.info("[mns -> ding] DingDingClientImpl.notifyBatchMessage request param is {}", JSON.toJSONString(request));
+ DingMessageResponse response = restTemplate.postForObject(NOTIFY_BATCH_MESSAGE, request, DingMessageResponse.class);
+ log.info("[mns <- ding] DingDingClientImpl.notifyBatchMessage response is {}", JSON.toJSONString(response));
+ } catch (Exception e) {
+ LogUtil.error("[mns <- ding] DingDingClientImpl.notifyBatchMessage response is error", e);
+ }
+ }
+
+ @Override
+ public void notifyChannelCallback(String channelName, String callbackData, String errorMsg) {
+ try {
+ DingMessageRequest request = new DingMessageRequest();
+ request.setMsgtype(CommonConstants.DING_TEXT_MESSAGE_TYPE);
+ MessageText text = new MessageText();
+ String content = String.format(CHANNEL_CALLBACK_FORMAT, getProfile(), channelName, callbackData, errorMsg);
+ text.setContent(content);
+ request.setText(text);
+ At at = new At();
+ at.setAtMobiles(Lists.newArrayList("13585844124", "15928328930", "17605414211"));
+ request.setAt(at);
+ log.info("[mns -> ding] DingDingClientImpl.notifyChannelCallback request param is {}", JSON.toJSONString(request));
+ DingMessageResponse response = restTemplate.postForObject(NOTIFY_CHANNEL_CALLBACK, request, DingMessageResponse.class);
+ log.info("[mns <- ding] DingDingClientImpl.notifyChannelCallback response is {}", JSON.toJSONString(response));
+ } catch (Exception e) {
+ LogUtil.error("[mns <- ding] DingDingClientImpl.notifyChannelCallback response is error", e);
+ }
+ }
+
+ @Override
+ public void notifyRocketMqError(String errorMsg) {
+ try {
+ DingMessageRequest request = new DingMessageRequest();
+ request.setMsgtype(CommonConstants.DING_TEXT_MESSAGE_TYPE);
+ MessageText text = new MessageText();
+ String content = String.format(MQ_MESSAGE_FORMAT, getProfile(), errorMsg);
+ text.setContent(content);
+ request.setText(text);
+ At at = new At();
+ at.setAtMobiles(Lists.newArrayList("13585844124", "15928328930", "17605414211"));
+ request.setAt(at);
+ log.info("[mns -> ding] DingDingClientImpl.notifyRocketMqError request param is {}", JSON.toJSONString(request));
+ DingMessageResponse response = restTemplate.postForObject(NOTIFY_MQ_MESSAGE, request, DingMessageResponse.class);
+ log.info("[mns <- ding] DingDingClientImpl.notifyRocketMqError response is {}", JSON.toJSONString(response));
+ } catch (Exception e) {
+ LogUtil.error("[mns <- ding] DingDingClientImpl.notifyRocketMqError response is error", e);
+ }
+ }
+
+ @Override
+ public void setEnvironment(Environment environment) {
+ this.environment = environment;
+ }
+
+ private String getProfile() {
+ String[] activeProfiles = environment.getActiveProfiles();
+ if(ArrayUtils.isEmpty(activeProfiles)) {
+ return CommonConstants.DEFAULT_ENV;
+ }
+ return activeProfiles[0];
+ }
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/At.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/At.java
new file mode 100644
index 00000000..ad600393
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/At.java
@@ -0,0 +1,21 @@
+package cn.axzo.msg.notices.integration.dto.request;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 钉钉群 @ 通知人
+ *
+ * @author zhaoyong
+ * @see At
+ * @since 2021-07-12 11:31
+ */
+@Data
+public class At {
+
+ private List atMobiles;
+
+ private boolean isAtAll;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/BaseSmsRequest.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/BaseSmsRequest.java
new file mode 100644
index 00000000..10f77a8b
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/BaseSmsRequest.java
@@ -0,0 +1,58 @@
+package cn.axzo.msg.notices.integration.dto.request;
+
+import lombok.Data;
+
+/**
+ * 创蓝短信基础请求类
+ *
+ * @author zhaoyong
+ * @see BaseSmsRequest
+ * @since 2021-08-07 17:16
+ */
+@Data
+public class BaseSmsRequest {
+
+ /**
+ * 必传
+ *
+ * API账号,管理后台获取
+ */
+ private String account;
+ /**
+ * 必传
+ *
+ * API密码,管理后台获取(8-16位)
+ */
+ private String password;
+ /**
+ * 必传
+ *
+ * 审核通过的签名以及模板,长度不超过536个字符
+ */
+ private String msg;
+ /**
+ * 非必传
+ *
+ * 定时发送短信时间,格式为yyyyMMddHHmm,值小于或等于当前时间则立即发送,默认立即发送;且定时时间在7天以内
+ */
+ private String sendtime;
+ /**
+ * 非必传
+ *
+ * 是否需要状态报告,默认false;如需状态报告则传”true”
+ */
+ private String report;
+ /**
+ * 非必传
+ *
+ * 下发短信号码扩展码,纯数字,需保证手机端口号加自定义扩展码总位数不超过20位,建议1-3位,如需上行短信推送或拉取则必填
+ */
+ private String extend;
+ /**
+ * 非必传
+ *
+ * 该条短信在您业务系统内的ID,一般可以设置订单号或者短信发送记录流水号,用于区分短信业务,总位数不超过40位
+ */
+ private String uid;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/DingMessageRequest.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/DingMessageRequest.java
new file mode 100644
index 00000000..361f399a
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/DingMessageRequest.java
@@ -0,0 +1,21 @@
+package cn.axzo.msg.notices.integration.dto.request;
+
+import lombok.Data;
+
+/**
+ * 钉钉消息请求类
+ *
+ * @author zhaoyong
+ * @see DingMessageRequest
+ * @since 2021-07-12 13:16
+ */
+@Data
+public class DingMessageRequest {
+
+ private String msgtype;
+
+ private MessageText text;
+
+ private At at;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/MessageRequest.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/MessageRequest.java
new file mode 100644
index 00000000..6c973fa4
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/MessageRequest.java
@@ -0,0 +1,48 @@
+package cn.axzo.msg.notices.integration.dto.request;
+
+import cn.axzo.msg.notices.common.enums.MessageTemplateTypeEnum;
+import lombok.Data;
+
+/**
+ * 批量消息请求类
+ *
+ * @author zhaoyong
+ * @see MessageRequest
+ * @since 2021-08-07 17:28
+ */
+@Data
+public class MessageRequest {
+
+ /**
+ * 模板消息类型
+ */
+ private MessageTemplateTypeEnum messageTemplateType;
+
+ /**
+ * 渠道请求号
+ */
+ private String requestChannelNo;
+
+ /**
+ * 短信请求地址
+ */
+ private String requestUrl;
+
+ /**
+ * 模板内容
+ */
+ private String templateContent;
+
+ /**
+ * 模板内容是否有参数
+ */
+ private boolean hasParam;
+
+ /**
+ * 消息内容
+ */
+ private String smsContent;
+
+
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/MessageText.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/MessageText.java
new file mode 100644
index 00000000..3df9530c
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/MessageText.java
@@ -0,0 +1,10 @@
+package cn.axzo.msg.notices.integration.dto.request;
+
+import lombok.Data;
+
+@Data
+public class MessageText {
+
+ private String content;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/SendSmsCommonRequest.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/SendSmsCommonRequest.java
new file mode 100644
index 00000000..cafebe14
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/SendSmsCommonRequest.java
@@ -0,0 +1,34 @@
+package cn.axzo.msg.notices.integration.dto.request;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+
+/**
+ * @Author: LiuYang
+ * @Date: 2021/5/21 11:38
+ */
+@NoArgsConstructor
+@Data
+public class SendSmsCommonRequest {
+
+ /**
+ * 发送的手机号集合
+ */
+ private String phoneNo;
+
+ /**
+ * 模板编号
+ */
+ private String templateCode;
+
+ /**
+ * 模板参数
+ */
+ private Map templateMap;
+
+ /** 渠道请求号 */
+ private String requestChannelNo;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/SmsCommonRequest.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/SmsCommonRequest.java
new file mode 100644
index 00000000..fb272db7
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/SmsCommonRequest.java
@@ -0,0 +1,22 @@
+package cn.axzo.msg.notices.integration.dto.request;
+
+import lombok.Data;
+
+/**
+ * 相同内容群发接口请求类
+ *
+ * @author zhaoyong
+ * @see SmsCommonRequest
+ * @since 2021-08-03 18:54
+ */
+@Data
+public class SmsCommonRequest extends BaseSmsRequest {
+
+ /**
+ * 必传
+ *
+ * 接收的手机号,多个手机号使用英文逗号间隔,一次不要超过1000个;
+ */
+ private String phone;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/SmsVariableRequest.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/SmsVariableRequest.java
new file mode 100644
index 00000000..c3e749dd
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/request/SmsVariableRequest.java
@@ -0,0 +1,22 @@
+package cn.axzo.msg.notices.integration.dto.request;
+
+import lombok.Data;
+
+/**
+ * 相同内容变量接口请求类
+ *
+ * @author zhaoyong
+ * @see SmsVariableRequest
+ * @since 2021-08-03 18:54
+ */
+@Data
+public class SmsVariableRequest extends BaseSmsRequest {
+
+ /**
+ * 必传
+ *
+ * 手机号码和变量参数,多组参数使用英文分号区分;此字段上限支持 1000个参数组。格式不符的参数,系统自动会过滤掉
+ */
+ private String params;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/response/ChuangLanSmsResponse.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/response/ChuangLanSmsResponse.java
new file mode 100644
index 00000000..5c5572f0
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/response/ChuangLanSmsResponse.java
@@ -0,0 +1,40 @@
+package cn.axzo.msg.notices.integration.dto.response;
+
+import lombok.Data;
+
+/**
+ * 创蓝短信响应
+ *
+ * @author zhaoyong
+ * @see ChuangLanSmsResponse
+ * @since 2021-08-07 18:26
+ */
+@Data
+public class ChuangLanSmsResponse {
+
+ /**
+ * 提交响应状态码,返回“0”表示提交成功(详细参考提交响应状态码)
+ */
+ private String code;
+ /**
+ * 状态码说明(提交成功返回空)
+ */
+ private String errorMsg;
+ /**
+ * 消息id
+ */
+ private String msgId;
+ /**
+ * 响应时间
+ */
+ private String time;
+ /**
+ * 失败条数
+ */
+ private int successNum;
+ /**
+ * 成功条数
+ */
+ private int failNum;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/response/DingMessageResponse.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/response/DingMessageResponse.java
new file mode 100644
index 00000000..0045e6bd
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/response/DingMessageResponse.java
@@ -0,0 +1,18 @@
+package cn.axzo.msg.notices.integration.dto.response;
+
+import lombok.Data;
+
+/**
+ * 钉钉请求响应类
+ *
+ * @author zhaoyong
+ * @see DingMessageResponse
+ * @since 2021-07-12 11:02
+ */
+@Data
+public class DingMessageResponse {
+
+ private int errcode;
+ private String errmsg;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/response/SendSmsCommonResponse.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/response/SendSmsCommonResponse.java
new file mode 100644
index 00000000..3d873103
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/dto/response/SendSmsCommonResponse.java
@@ -0,0 +1,34 @@
+package cn.axzo.msg.notices.integration.dto.response;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @Author: LiuYang
+ * @Date: 2021/5/21 11:38
+ */
+@NoArgsConstructor
+@Data
+public class SendSmsCommonResponse {
+
+ /**
+ * 请求ID
+ */
+ private String requestId;
+
+ /**
+ * 响应消息
+ */
+ private String message;
+
+ /**
+ * 回执ID
+ */
+ private String bizId;
+
+ /**
+ * 响应码
+ */
+ private String code;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/AbstractChuangLanMessageRequestResolver.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/AbstractChuangLanMessageRequestResolver.java
new file mode 100644
index 00000000..45cb3950
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/AbstractChuangLanMessageRequestResolver.java
@@ -0,0 +1,31 @@
+package cn.axzo.msg.notices.integration.support;
+
+import cn.axzo.msg.notices.integration.dto.request.BaseSmsRequest;
+import cn.axzo.msg.notices.integration.dto.request.MessageRequest;
+import cn.axzo.msg.notices.integration.dto.request.SmsCommonRequest;
+import cn.axzo.msg.notices.integration.dto.request.SmsVariableRequest;
+
+/**
+ * 创蓝短信请求解析抽象类
+ *
+ * @author zhaoyong
+ * @see AbstractChuangLanMessageRequestResolver
+ * @since 2021-08-07 18:07
+ */
+public abstract class AbstractChuangLanMessageRequestResolver implements ChuangLanMessageRequestResolver {
+
+ public BaseSmsRequest getBaseSmsRequest(MessageRequest request){
+ if(request.isHasParam()) {
+ SmsVariableRequest result = new SmsVariableRequest();
+ result.setUid(request.getRequestChannelNo());
+ result.setParams(request.getSmsContent());
+ return result;
+ } else {
+ SmsCommonRequest result = new SmsCommonRequest();
+ result.setUid(request.getRequestChannelNo());
+ result.setPhone(request.getSmsContent());
+ return result;
+ }
+ }
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/ChuangLanAccountProperties.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/ChuangLanAccountProperties.java
new file mode 100644
index 00000000..b7b5d67c
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/ChuangLanAccountProperties.java
@@ -0,0 +1,38 @@
+package cn.axzo.msg.notices.integration.support;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 创蓝不同账户信息配置类
+ *
+ * @author zhaoyong
+ * @see ChuangLanAccountProperties
+ * @since 2021-08-26 11:24
+ */
+@Data
+@Configuration
+@RefreshScope
+public class ChuangLanAccountProperties {
+
+ @Value("${chuanlan.member.account}")
+ private String memberAccount;
+
+ @Value("${chuanlan.member.password}")
+ private String memberPassword;
+
+ @Value("${chuanlan.notice.account}")
+ private String noticeAccount;
+
+ @Value("${chuanlan.notice.password}")
+ private String noticePassword;
+
+ @Value("${chuanlan.verification.account}")
+ private String verificationAccount;
+
+ @Value("${chuanlan.verification.password}")
+ private String verificationPassword;
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/ChuangLanMessageRequestResolver.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/ChuangLanMessageRequestResolver.java
new file mode 100644
index 00000000..d6688f85
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/ChuangLanMessageRequestResolver.java
@@ -0,0 +1,24 @@
+package cn.axzo.msg.notices.integration.support;
+
+import cn.axzo.msg.notices.common.enums.MessageTemplateTypeEnum;
+import cn.axzo.msg.notices.integration.dto.request.BaseSmsRequest;
+import cn.axzo.msg.notices.integration.dto.request.MessageRequest;
+import cn.azxo.framework.common.spring.SimpleRegisterableService;
+
+/**
+ * 创蓝消息请求解析器
+ *
+ * @author zhaoyong
+ * @see ChuangLanMessageRequestResolver
+ * @since 2021-08-07 17:26
+ */
+public interface ChuangLanMessageRequestResolver extends SimpleRegisterableService {
+
+ /**
+ * 发送消息请求解析器
+ * @param request
+ * @return
+ */
+ BaseSmsRequest resolve(MessageRequest request);
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/ChuangLanMessageRequestResolverFactory.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/ChuangLanMessageRequestResolverFactory.java
new file mode 100644
index 00000000..08daa2cd
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/ChuangLanMessageRequestResolverFactory.java
@@ -0,0 +1,28 @@
+package cn.axzo.msg.notices.integration.support;
+
+import cn.axzo.msg.notices.common.enums.MessageTemplateTypeEnum;
+import cn.azxo.framework.common.spring.AbstractSimpleRegisterableServiceFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * 创蓝消息请求解析器工厂类
+ *
+ * @author zhaoyong
+ * @see ChuangLanMessageRequestResolverFactory
+ * @since 2021-08-07 18:17
+ */
+@Component("chuangLanMessageRequestResolverFactory")
+public class ChuangLanMessageRequestResolverFactory extends
+ AbstractSimpleRegisterableServiceFactory {
+
+ @Override
+ protected String getFactoryName() {
+ return "创蓝消息请求解析器工厂类";
+ }
+
+ @Override
+ protected Class getServiceClazz() {
+ return ChuangLanMessageRequestResolver.class;
+ }
+
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/impl/ChuangLanMemberMessageRequestResolver.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/impl/ChuangLanMemberMessageRequestResolver.java
new file mode 100644
index 00000000..c2406744
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/impl/ChuangLanMemberMessageRequestResolver.java
@@ -0,0 +1,39 @@
+package cn.axzo.msg.notices.integration.support.impl;
+
+import cn.axzo.msg.notices.common.enums.MessageTemplateTypeEnum;
+import cn.axzo.msg.notices.integration.dto.request.BaseSmsRequest;
+import cn.axzo.msg.notices.integration.dto.request.MessageRequest;
+import cn.axzo.msg.notices.integration.support.AbstractChuangLanMessageRequestResolver;
+import cn.axzo.msg.notices.integration.support.ChuangLanAccountProperties;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 创蓝会员营销短信请求类
+ *
+ * @author zhaoyong
+ * @see ChuangLanMemberMessageRequestResolver
+ * @since 2021-08-07 17:53
+ */
+@Component
+public class ChuangLanMemberMessageRequestResolver extends AbstractChuangLanMessageRequestResolver {
+
+ @Resource(name = "chuangLanAccountProperties")
+ private ChuangLanAccountProperties chuangLanAccountProperties;
+
+ @Override
+ public BaseSmsRequest resolve(MessageRequest request) {
+ BaseSmsRequest result = getBaseSmsRequest(request);
+ result.setAccount(chuangLanAccountProperties.getMemberAccount());
+ result.setPassword(chuangLanAccountProperties.getMemberPassword());
+ result.setReport("true");
+ result.setMsg(request.getTemplateContent());
+ return result;
+ }
+
+ @Override
+ public MessageTemplateTypeEnum getRouteKey() {
+ return MessageTemplateTypeEnum.PROMOTIONAL;
+ }
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/impl/ChuangLanNoticeMessageRequestResolver.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/impl/ChuangLanNoticeMessageRequestResolver.java
new file mode 100644
index 00000000..48fb855d
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/impl/ChuangLanNoticeMessageRequestResolver.java
@@ -0,0 +1,39 @@
+package cn.axzo.msg.notices.integration.support.impl;
+
+import cn.axzo.msg.notices.common.enums.MessageTemplateTypeEnum;
+import cn.axzo.msg.notices.integration.dto.request.BaseSmsRequest;
+import cn.axzo.msg.notices.integration.dto.request.MessageRequest;
+import cn.axzo.msg.notices.integration.support.AbstractChuangLanMessageRequestResolver;
+import cn.axzo.msg.notices.integration.support.ChuangLanAccountProperties;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 创蓝通知短信请求类
+ *
+ * @author zhaoyong
+ * @see ChuangLanNoticeMessageRequestResolver
+ * @since 2021-08-07 17:53
+ */
+@Component
+public class ChuangLanNoticeMessageRequestResolver extends AbstractChuangLanMessageRequestResolver {
+
+ @Resource(name = "chuangLanAccountProperties")
+ private ChuangLanAccountProperties chuangLanAccountProperties;
+
+ @Override
+ public BaseSmsRequest resolve(MessageRequest request) {
+ BaseSmsRequest result = getBaseSmsRequest(request);
+ result.setAccount(chuangLanAccountProperties.getNoticeAccount());
+ result.setPassword(chuangLanAccountProperties.getNoticePassword());
+ result.setReport("true");
+ result.setMsg(request.getTemplateContent());
+ return result;
+ }
+
+ @Override
+ public MessageTemplateTypeEnum getRouteKey() {
+ return MessageTemplateTypeEnum.SHORT_NOTE;
+ }
+}
diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/impl/ChuangLanVerificationCodeMessageRequestResolver.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/impl/ChuangLanVerificationCodeMessageRequestResolver.java
new file mode 100644
index 00000000..8d413e01
--- /dev/null
+++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/notices/integration/support/impl/ChuangLanVerificationCodeMessageRequestResolver.java
@@ -0,0 +1,39 @@
+package cn.axzo.msg.notices.integration.support.impl;
+
+import cn.axzo.msg.notices.common.enums.MessageTemplateTypeEnum;
+import cn.axzo.msg.notices.integration.dto.request.BaseSmsRequest;
+import cn.axzo.msg.notices.integration.dto.request.MessageRequest;
+import cn.axzo.msg.notices.integration.support.AbstractChuangLanMessageRequestResolver;
+import cn.axzo.msg.notices.integration.support.ChuangLanAccountProperties;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 创蓝验证码短信请求类
+ *
+ * @author zhaoyong
+ * @see ChuangLanVerificationCodeMessageRequestResolver
+ * @since 2021-08-07 17:53
+ */
+@Component
+public class ChuangLanVerificationCodeMessageRequestResolver extends AbstractChuangLanMessageRequestResolver {
+
+ @Resource(name = "chuangLanAccountProperties")
+ private ChuangLanAccountProperties chuangLanAccountProperties;
+
+ @Override
+ public BaseSmsRequest resolve(MessageRequest request) {
+ BaseSmsRequest result = getBaseSmsRequest(request);
+ result.setAccount(chuangLanAccountProperties.getVerificationAccount());
+ result.setPassword(chuangLanAccountProperties.getVerificationPassword());
+ result.setReport("true");
+ result.setMsg(request.getTemplateContent());
+ return result;
+ }
+
+ @Override
+ public MessageTemplateTypeEnum getRouteKey() {
+ return MessageTemplateTypeEnum.VERIFICATION_CODE;
+ }
+}
diff --git a/msg-notices/msg-notices-manager-api/pom.xml b/msg-notices/msg-notices-manager-api/pom.xml
new file mode 100644
index 00000000..987d77e2
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/pom.xml
@@ -0,0 +1,44 @@
+
+
+
+ msg-notices
+ cn.axzo.msgcenter
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ cn.axzo.msg.notices.manager.api
+ msg-notices-manager-api
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ cn.axzo.msg.notices.common
+ msg-notices-common
+
+
+ cn.axzo.msg.notices.dao
+ msg-notices-dao
+
+
+ cn.axzo.msg.notices.dao
+ msg-notices-dao
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.common
+ msg-notices-common
+ 1.0.0-SNAPSHOT
+ compile
+
+
+
\ No newline at end of file
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/BatchMessageManger.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/BatchMessageManger.java
new file mode 100644
index 00000000..4d5c1168
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/BatchMessageManger.java
@@ -0,0 +1,39 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.common.lang.Page;
+import cn.axzo.msg.notices.dao.entity.BatchMessage;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageRequestDto;
+
+/**
+ * @Auther: szg
+ * @Date: 2021/8/9 17:16
+ * @Description:
+ */
+public interface BatchMessageManger {
+
+ /**
+ * 根据条件分页查询发送批次
+ * @param dto
+ * @return
+ */
+ Page queryByPage(BatchMessageRequestDto dto);
+
+ /**
+ * 查询批量消息
+ * @param batchNo
+ * @return
+ */
+ BatchMessage queryBatchMessage(String batchNo);
+
+ /**
+ * 发送批次拆分消息
+ * @param batchMessage
+ */
+ boolean batchMessageSplitToMessage(BatchMessage batchMessage);
+
+ /**
+ * 按照批次发送消息、更新状态和回执单号
+ * @param batchMessage
+ */
+ void sendBatchMessageAndHandleReceipt(BatchMessage batchMessage);
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/BatchMessageRequestManger.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/BatchMessageRequestManger.java
new file mode 100644
index 00000000..b10d31bd
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/BatchMessageRequestManger.java
@@ -0,0 +1,59 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.common.lang.Page;
+import cn.axzo.msg.notices.dao.entity.BatchMessageRequest;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageRequestDto;
+
+import java.util.List;
+
+/**
+ * @Auther: szg
+ * @Date: 2021/8/9 14:07
+ * @Description:
+ */
+public interface BatchMessageRequestManger {
+
+ /**
+ * 保存批量请求对象
+ * @param batchMessageRequest
+ * @return
+ */
+ boolean saveBatchMessageRequest(BatchMessageRequest batchMessageRequest);
+
+ /**
+ * 分页查询
+ * @param dto
+ * @return
+ */
+ Page queryPageByBatchMessageQueryRequestDto(BatchMessageRequestDto dto);
+
+ /**
+ * 批量短信拆分批次和生成批次
+ * @param requestDto
+ */
+ List batchMessageRequestSplitAndSave(BatchMessageRequest requestDto);
+
+ /**
+ * 查询批量短信请求
+ * @param appCode
+ * @param requestNo
+ * @return
+ */
+ BatchMessageRequest queryBatchMessage(String appCode, String requestNo);
+
+ /**
+ * 修改统计信息
+ * @param batchMessageRequest
+ */
+ void handleBatchMessageRequestStatistics(BatchMessageRequest batchMessageRequest);
+
+ /**
+ * 修改短信批量请求为成功
+ *
+ * @param remark
+ * @param id
+ * @return
+ */
+ boolean updateRequestSuccess(String remark, Long id);
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageChannelRouter.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageChannelRouter.java
new file mode 100644
index 00000000..cef9067a
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageChannelRouter.java
@@ -0,0 +1,21 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.dao.entity.MessageChannel;
+
+/**
+ * 消息渠道路由
+ *
+ * @author zhaoyong_sh
+ * @see MessageChannelRouter
+ * @since 2021-05-27 15:03
+ */
+public interface MessageChannelRouter {
+
+ /**
+ * 消息渠道路由
+ * @param condition
+ * @return
+ */
+ MessageChannel route(String condition);
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageManager.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageManager.java
new file mode 100644
index 00000000..48571589
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageManager.java
@@ -0,0 +1,113 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.common.lang.Page;
+import cn.axzo.msg.notices.dao.entity.Message;
+import cn.axzo.msg.notices.dao.entity.MessageRedo;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageQueryRequestDto;
+
+/**
+ * 消息记录管理类
+ *
+ * @author zhaoyong_sh
+ * @see MessageManager
+ * @since 2021-05-19 15:54
+ */
+public interface MessageManager {
+
+ /**
+ * 分页查询消息记录
+ *
+ * @param requestDto
+ * @return
+ */
+ Page queryPageByMessageQueryRequestDto(MessageQueryRequestDto requestDto);
+
+ /**
+ * 保存消息
+ *
+ * @param message
+ * @return
+ */
+ boolean saveMessage(Message message);
+
+ /**
+ * 保存重试消息
+ *
+ * @param messageRedo
+ * @return
+ */
+ boolean saveMessageRedo(MessageRedo messageRedo);
+
+ /**
+ * 更新为处理中
+ *
+ * @param bizId
+ * @param requestId
+ * @param id
+ * @return
+ */
+ boolean updateToProcessing(String bizId, String requestId, Long id);
+
+ /**
+ * 渠道业务异常
+ *
+ * @param id
+ * @return
+ */
+ boolean updateToFail(Long id);
+
+ /**
+ * 网络异常
+ *
+ * @param id
+ * @param messageRedo
+ * @return
+ */
+ boolean updateToException(MessageRedo messageRedo, Long id);
+
+ /**
+ * 修改定时任务异常到查询状态
+ *
+ * @param targetStatus
+ * @param id
+ * @return
+ */
+ boolean updateExceptionToQueryStatus(String targetStatus, Long id);
+
+ /**
+ * 根据messageOrderNo和phoneNumber查询message
+ *
+ * @param messageOrderNo
+ * @param phoneNumber
+ * @return
+ */
+ Message queryMessageByMessageOrderNoAndPhoneNumber(String messageOrderNo,String channelBizId, String phoneNumber);
+
+ /**
+ * 根据id更新状态
+ *
+ * @param id
+ * @param status
+ * @return
+ */
+ boolean updateProcessingMessageStatusById(Long id, String status);
+
+ /**
+ * 根据messageOrderNo更新状态
+ *
+ * @param messageOrderNo
+ * @param status
+ * @return
+ */
+ boolean updateMessageStatusByMessageOrderNo(String messageOrderNo, String status);
+
+ /**
+ * 更新为成功
+ * @param bizId
+ * @param requestId
+ * @param id
+ * @return
+ */
+ boolean updateToSuccess(String bizId, String requestId, Long id);
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageRedoManger.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageRedoManger.java
new file mode 100644
index 00000000..0558bc23
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageRedoManger.java
@@ -0,0 +1,59 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.common.domain.MessageContext;
+import cn.axzo.msg.notices.common.lang.Page;
+import cn.axzo.msg.notices.dao.entity.Message;
+import cn.axzo.msg.notices.dao.entity.MessageRedo;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageRedoQueryRequestDto;
+
+import java.util.Date;
+
+/**
+ * 消息重试
+ */
+public interface MessageRedoManger {
+
+ /**
+ * 查询重试消息
+ * @param requestDto
+ * @return
+ */
+ Page queryPageByMessageRedoQueryRequestDto(MessageRedoQueryRequestDto requestDto);
+
+ /**
+ * 根据重试单号和手机号查询重试消息信息
+ * @param redoOrderNo
+ * @param phoneNumber
+ * @return
+ */
+ MessageRedo queryMessageRedoByRedoOrderNoAndPhoneNumber(String redoOrderNo, String bizId, String phoneNumber);
+
+ /**
+ * 根据id更新重试状态
+ * @param id
+ * @param oldStatus
+ * @param newStatus
+ * @return
+ */
+ boolean updateMessageRedoStatusById(Long id, String oldStatus, String newStatus);
+
+ /**
+ * 通过message来新增
+ * @param message
+ */
+ void saveByMessage(Message message);
+
+ boolean lockMessage(MessageContext context, Long id);
+
+ boolean updateRetry(Date retryAt, Long id);
+
+ boolean updateExceptionToFail(Long id, String messageOrderNo);
+
+ /**
+ * 更新重试渠道回执id
+ * @param id
+ * @param bizId
+ * @return
+ */
+ boolean updateMessageRedoChannelById(Long id, String bizId,String redoMessageNo);
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageRequestLogManager.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageRequestLogManager.java
new file mode 100644
index 00000000..a2a5c1bc
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageRequestLogManager.java
@@ -0,0 +1,29 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.dao.entity.MessageRequestLog;
+
+/**
+ * 请求日志处理类
+ *
+ * @author zhaoyong_sh
+ * @see MessageRequestLogManager
+ * @since 2021-05-28 10:50
+ */
+public interface MessageRequestLogManager {
+
+ /**
+ * 保存请求日志
+ * @param requestLog
+ * @return
+ */
+ Long saveRequestLog(MessageRequestLog requestLog);
+
+ /**
+ * 修改请求日志
+ * @param responseBody
+ * @param id
+ * @return
+ */
+ boolean updateRequestLog(String responseBody, Long id);
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageTemplateManager.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageTemplateManager.java
new file mode 100644
index 00000000..c120b794
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageTemplateManager.java
@@ -0,0 +1,40 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.dao.entity.ChannelMessageTemplate;
+import cn.axzo.msg.notices.dao.entity.MessageTemplate;
+import cn.axzo.msg.notices.manager.api.dto.response.TemplateParamDto;
+
+import java.util.List;
+
+/**
+ * 消息模板处理类
+ *
+ * @author zhaoyong_sh
+ * @see MessageTemplateManager
+ * @since 2021-05-27 20:23
+ */
+public interface MessageTemplateManager {
+
+ /**
+ * 验证内部模板
+ * @param innerTemplateNo
+ * @return
+ */
+ MessageTemplate queryAndCheckInnerTemplate(String innerTemplateNo);
+
+ /**
+ * 获取渠道模板
+ * @param innerTemplateNo
+ * @param channelCode
+ * @return
+ */
+ ChannelMessageTemplate queryChannelTemplate(String innerTemplateNo, String channelCode);
+
+ /**
+ * 查询模板变量
+ * @param innerTemplateNo
+ * @return
+ */
+ List queryTemplateParam(String innerTemplateNo);
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageTemplateParamManager.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageTemplateParamManager.java
new file mode 100644
index 00000000..fc5eec88
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/MessageTemplateParamManager.java
@@ -0,0 +1,23 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.manager.api.dto.response.TemplateParamDto;
+
+import java.util.List;
+
+/**
+ * 消息模板参数
+ *
+ * @author zhaoyong
+ * @see MessageTemplateParamManager
+ * @since 2021-08-20 21:34
+ */
+public interface MessageTemplateParamManager {
+
+ /**
+ * 根据模板号查询
+ * @param templateCode
+ * @return
+ */
+ List getByCode(String templateCode);
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/RetryStrategy.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/RetryStrategy.java
new file mode 100644
index 00000000..2dba2ee5
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/RetryStrategy.java
@@ -0,0 +1,29 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.common.domain.MessageContext;
+
+import java.util.List;
+
+/**
+ * 重试策略
+ *
+ * @author zhaoyong_sh
+ * @see RetryStrategy
+ * @since 2021-05-19 10:39
+ */
+public interface RetryStrategy {
+
+ /**
+ * 获取通知时间列表
+ * @return
+ */
+ List getRetryStrategy();
+
+ /**
+ * 获取下一次通知秒数
+ * @param context
+ * @return
+ */
+ Integer getNextNotifySecond(MessageContext context);
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/SmsSendManager.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/SmsSendManager.java
new file mode 100644
index 00000000..09098d14
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/SmsSendManager.java
@@ -0,0 +1,33 @@
+package cn.axzo.msg.notices.manager.api;
+
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.response.BatchMessageSendResponseDto;
+import cn.axzo.msg.notices.manager.api.dto.response.SendSmsCommonResponseDto;
+
+/**
+ * sms 管理者
+ * @Author: LiuYang
+ * @Date: 2021/5/21 15:39
+ */
+public interface SmsSendManager {
+
+ /**
+ * 发送短信
+ *
+ * @param requestDto
+ * @return
+ * @throws Exception
+ */
+ SendSmsCommonResponseDto sendMessage(MessageSendRequestDto requestDto);
+
+ /**
+ * 发送批量短信
+ *
+ * TODO 多个渠道请求对象响应对象需求统一
+ * @param requestDto
+ * @return
+ */
+ BatchMessageSendResponseDto sendBatchMessage(BatchMessageSendRequestDto requestDto);
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/AliMessageCallbackRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/AliMessageCallbackRequestDto.java
new file mode 100644
index 00000000..74c99c94
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/AliMessageCallbackRequestDto.java
@@ -0,0 +1,36 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 阿里云短信回调对象
+ */
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AliMessageCallbackRequestDto {
+
+ private String phone_number;
+
+ private String send_time;
+
+ private String report_time;
+
+ private Boolean success;
+
+ private String err_code;
+
+ private String err_msg;
+
+ private String sms_size;
+
+ private String biz_id;
+
+ private String out_id;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/BaseRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/BaseRequestDto.java
new file mode 100644
index 00000000..88458e49
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/BaseRequestDto.java
@@ -0,0 +1,19 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import lombok.Data;
+
+/**
+ * 基础请求对象
+ *
+ * @author zhaoyong_sh
+ * @see BaseRequestDto
+ * @since 2021-05-28 11:01
+ */
+@Data
+public class BaseRequestDto {
+
+ private String appCode;
+
+ private String requestNo;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/BatchMessageRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/BatchMessageRequestDto.java
new file mode 100644
index 00000000..751e728f
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/BatchMessageRequestDto.java
@@ -0,0 +1,41 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import cn.axzo.msg.notices.common.lang.PageRequest;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 消息查询请求
+ *
+ * @author zhaoyong_sh
+ * @see BatchMessageRequestDto
+ * @since 2021-05-19 18:02
+ */
+@Data
+public class BatchMessageRequestDto extends PageRequest {
+
+ private Long id;
+
+ /**
+ * 状态
+ */
+ private List statuses;
+
+ /**
+ * 创建开始时间
+ */
+ private Date startCreateTime;
+
+ /**
+ * 创建结束时间
+ */
+ private Date endCreateTime;
+
+ /**
+ * 发送类型
+ */
+ private Integer sendType;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/BatchMessageSendRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/BatchMessageSendRequestDto.java
new file mode 100644
index 00000000..135113e4
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/BatchMessageSendRequestDto.java
@@ -0,0 +1,47 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import cn.axzo.msg.notices.common.utils.KeyUtils;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 批量短信请求
+ *
+ * @author zhaoyong
+ * @see BatchMessageSendRequestDto
+ * @since 2021-08-07 18:56
+ */
+@Data
+public class BatchMessageSendRequestDto {
+
+ /**
+ * 应用码
+ */
+ private String appCode;
+ /**
+ * 应用请求号
+ */
+ private String appRequestNo;
+ /**
+ * 批次号
+ */
+ private String batchNo;
+ /**
+ * 渠道请求号
+ */
+ private String requestChannelNo;
+ /**
+ * 内部模板号
+ */
+ private String innerTemplateNo;
+ /**
+ * 消息内容
+ */
+ private List smsContentDtos;
+
+ public String getMessageKey(){
+ return KeyUtils.getKey(appCode, appRequestNo);
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/ChuangLanSmsReportRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/ChuangLanSmsReportRequestDto.java
new file mode 100644
index 00000000..4ef7e52c
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/ChuangLanSmsReportRequestDto.java
@@ -0,0 +1,46 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import lombok.Data;
+
+/**
+ *
+ * @author szg
+ * @Description:状态报告响应实体类
+ */
+@Data
+public class ChuangLanSmsReportRequestDto {
+
+ /**
+ * 消息ID
+ */
+ private String msgid;
+ /**
+ * 状态更新时间
+ */
+ private String reportTime;
+ /**
+ * 接收短信的手机号码
+ */
+ private String mobile;
+ /**
+ * 状态(详细参考状态报告状态码)
+ */
+ private String status;
+ /**
+ * 253平台收到运营商回复状态报告的时间,格式yyMMddHHmmss
+ */
+ private String notifyTime;
+ /**
+ * 状态说明
+ */
+ private String statusDesc;
+ /**
+ * 该条短信在您业务系统内的ID,如订单号或者短信发送记录流水号
+ */
+ private String uid;
+ /**
+ * 下发短信计费条数
+ */
+ private String length;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/MessageQueryRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/MessageQueryRequestDto.java
new file mode 100644
index 00000000..e7e065ef
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/MessageQueryRequestDto.java
@@ -0,0 +1,44 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import cn.axzo.msg.notices.common.lang.PageRequest;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 消息查询请求
+ *
+ * @author zhaoyong_sh
+ * @see MessageQueryRequestDto
+ * @since 2021-05-19 18:02
+ */
+@Data
+public class MessageQueryRequestDto extends PageRequest {
+
+ /**
+ * 主键
+ */
+ private Long id;
+
+ /**
+ * 渠道码
+ */
+ private String channelCode;
+
+ /**
+ * 状态
+ */
+ private List statuses;
+
+ /**
+ * 创建开始时间
+ */
+ private Date startCreateTime;
+
+ /**
+ * 创建结束时间
+ */
+ private Date endCreateTime;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/MessageRedoQueryRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/MessageRedoQueryRequestDto.java
new file mode 100644
index 00000000..d9d7585a
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/MessageRedoQueryRequestDto.java
@@ -0,0 +1,38 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import cn.axzo.msg.notices.common.lang.PageRequest;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 消息查询请求
+ *
+ * @author zhaoyong_sh
+ * @see MessageRedoQueryRequestDto
+ * @since 2021-05-19 18:02
+ */
+@Data
+public class MessageRedoQueryRequestDto extends PageRequest {
+
+ private Long id;
+
+ private String channelCode;
+
+ /**
+ * 状态
+ */
+ private List statuses;
+
+ /**
+ * 创建开始时间
+ */
+ private Date startCreateTime;
+
+ /**
+ * 创建结束时间
+ */
+ private Date endCreateTime;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/MessageSendRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/MessageSendRequestDto.java
new file mode 100644
index 00000000..95e353f3
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/MessageSendRequestDto.java
@@ -0,0 +1,50 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import lombok.Data;
+
+import java.util.Map;
+
+/**
+ * 发送短信请求类
+ *
+ * @author zhaoyong_sh
+ * @see MessageSendRequestDto
+ * @since 2021-05-27 17:30
+ */
+@Data
+public class MessageSendRequestDto {
+
+ /**
+ * app_code
+ */
+ private String appCode;
+ /**
+ * 渠道码
+ */
+ private String channelCode;
+ /**
+ * 手机号
+ */
+ private String phoneNo;
+ /**
+ * 内部模板号
+ */
+ private String innerTemplateNo;
+ /**
+ * 渠道模板号
+ */
+ private String templateNo;
+ /**
+ * 模板变量内容
+ */
+ private Map templateMap;
+ /**
+ * app请求号
+ */
+ private String appRequestNo;
+ /**
+ * 渠道请求编号
+ */
+ private String requestChannelNo;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/SendBatchMessageRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/SendBatchMessageRequestDto.java
new file mode 100644
index 00000000..4b742007
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/SendBatchMessageRequestDto.java
@@ -0,0 +1,49 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * 发送消息请求
+ * @Author: LiuYang
+ * @Date: 2021/5/20 18:12
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Data
+public class SendBatchMessageRequestDto {
+
+ /**
+ * 请求号
+ */
+ private String requestNo;
+
+ /**
+ * 应用接入码
+ */
+ private String appCode;
+
+ /**
+ * 消息模板号
+ */
+ private String templateNo;
+
+ /**
+ * 发送类型
+ *
+ * 1:实时;2:非实时
+ *
+ */
+ private Integer sendType;
+
+ /**
+ * 消息内容
+ */
+ private List smsContentDtos;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/SendMessageRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/SendMessageRequestDto.java
new file mode 100644
index 00000000..6478c5d7
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/SendMessageRequestDto.java
@@ -0,0 +1,51 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+
+/**
+ * 发送消息请求
+ * @Author: LiuYang
+ * @Date: 2021/5/20 18:12
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Data
+public class SendMessageRequestDto {
+
+ /**
+ * 请求号
+ */
+ private String requestNo;
+
+ /**
+ * 接入码
+ */
+ private String appCode;
+
+ /**
+ * 短信模板号
+ */
+ private String templateNo;
+
+ /**
+ * 电话号码
+ */
+ private String phoneNo;
+
+ /**
+ * 参数
+ */
+ private Map params;
+
+ /**
+ * 扩展参数
+ */
+ private String expansion;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/SmsContentDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/SmsContentDto.java
new file mode 100644
index 00000000..4f264bc2
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/SmsContentDto.java
@@ -0,0 +1,26 @@
+package cn.axzo.msg.notices.manager.api.dto.request;
+
+import lombok.Data;
+
+/**
+ * 消息内容
+ *
+ * @author zhaoyong
+ * @see SmsContentDto
+ * @since 2021-08-07 16:34
+ */
+@Data
+public class SmsContentDto {
+
+ /**
+ * 手机号
+ */
+ private String phoneNo;
+
+ /**
+ * 模板参数
+ * 使用无变量模板时,可不带templateParams参数
+ */
+ private String templateParams;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/plat/CreateTemplateRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/plat/CreateTemplateRequestDto.java
new file mode 100644
index 00000000..4cef618f
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/plat/CreateTemplateRequestDto.java
@@ -0,0 +1,45 @@
+package cn.axzo.msg.notices.manager.api.dto.request.plat;
+
+import lombok.Data;
+
+/**
+ * 创建模板参数
+ */
+@Data
+public class CreateTemplateRequestDto {
+
+ /**
+ * 服务名称
+ */
+ private String serviceName;
+
+ /**
+ * 模板类型(1:验证码;2:短信通知;3:推广短信;4:群发助手)
+ */
+ private Integer messageTemplateType;
+
+ /**
+ * 短信模板编码
+ */
+ private String templateNo;
+
+ /**
+ * 阿里短信模板编码
+ */
+ private String templateAliNo;
+
+ /**
+ * 标题
+ */
+ private String title;
+
+ /**
+ * 模板内容
+ */
+ private String templateContent;
+
+ /**
+ * 模板原因
+ */
+ private String remark;
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/plat/QueryTemplateRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/plat/QueryTemplateRequestDto.java
new file mode 100644
index 00000000..f516cc90
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/request/plat/QueryTemplateRequestDto.java
@@ -0,0 +1,33 @@
+package cn.axzo.msg.notices.manager.api.dto.request.plat;
+
+import cn.axzo.msg.notices.dao.domain.PageQuery;
+import lombok.Data;
+
+/**
+ * 查询模板参数
+ */
+@Data
+public class QueryTemplateRequestDto extends PageQuery {
+
+ /**
+ * 模版类型
+ */
+ private Integer messageTemplateType;
+ /**
+ * 服务名
+ */
+ private String serviceName;
+ /**
+ * ali模版编码
+ */
+ private String templateAliNo;
+ /**
+ * axzo模版编码
+ */
+ private String templateNo;
+ /**
+ * 标题
+ */
+ private String title;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/AliCallbackResponseDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/AliCallbackResponseDto.java
new file mode 100644
index 00000000..ebbbedd1
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/AliCallbackResponseDto.java
@@ -0,0 +1,22 @@
+package cn.axzo.msg.notices.manager.api.dto.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AliCallbackResponseDto {
+
+ private Integer code;
+
+ private String msg;
+
+ public static AliCallbackResponseDto success(){
+ return new AliCallbackResponseDto(0, "success");
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/BatchMessageSendResponseDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/BatchMessageSendResponseDto.java
new file mode 100644
index 00000000..0f1eee49
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/BatchMessageSendResponseDto.java
@@ -0,0 +1,40 @@
+package cn.axzo.msg.notices.manager.api.dto.response;
+
+import lombok.Data;
+
+/**
+ * 批量发送短信响应类
+ *
+ * @author zhaoyong
+ * @see BatchMessageSendResponseDto
+ * @since 2021-08-07 18:57
+ */
+@Data
+public class BatchMessageSendResponseDto {
+
+ /**
+ * 提交响应状态码,返回“0”表示提交成功(详细参考提交响应状态码)
+ */
+ private String code;
+ /**
+ * 状态码说明(提交成功返回空)
+ */
+ private String errorMsg;
+ /**
+ * 消息id
+ */
+ private String msgId;
+ /**
+ * 响应时间
+ */
+ private String time;
+ /**
+ * 失败条数
+ */
+ private int successNum;
+ /**
+ * 成功条数
+ */
+ private int failNum;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/ChuangLanCallbackResponseDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/ChuangLanCallbackResponseDto.java
new file mode 100644
index 00000000..a6682434
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/ChuangLanCallbackResponseDto.java
@@ -0,0 +1,25 @@
+package cn.axzo.msg.notices.manager.api.dto.response;
+
+import cn.axzo.msg.notices.common.enums.ChuangLanStatusEnum;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ChuangLanCallbackResponseDto {
+
+ private String clcode;
+
+ public static ChuangLanCallbackResponseDto success(){
+ return new ChuangLanCallbackResponseDto(ChuangLanStatusEnum.SUCCESS.getCode());
+ }
+
+ public static ChuangLanCallbackResponseDto fail(){
+ return new ChuangLanCallbackResponseDto(ChuangLanStatusEnum.FAIL.getCode());
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/SendMessageResponseDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/SendMessageResponseDto.java
new file mode 100644
index 00000000..a1810ef5
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/SendMessageResponseDto.java
@@ -0,0 +1,10 @@
+package cn.axzo.msg.notices.manager.api.dto.response;
+
+/**
+ * 发送消息响应
+ * @Author: LiuYang
+ * @Date: 2021/5/20 18:13
+ */
+public class SendMessageResponseDto {
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/SendSmsCommonResponseDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/SendSmsCommonResponseDto.java
new file mode 100644
index 00000000..e82f6f41
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/SendSmsCommonResponseDto.java
@@ -0,0 +1,35 @@
+package cn.axzo.msg.notices.manager.api.dto.response;
+
+import cn.axzo.msg.notices.common.enums.MessageCommonStatusEnum;
+import lombok.Data;
+
+/**
+ * 消息发送通用结果
+ * @Author: LiuYang
+ * @Date: 2021/5/25 15:59
+ */
+@Data
+public class SendSmsCommonResponseDto {
+
+ /**
+ * 响应码
+ */
+ private MessageCommonStatusEnum status;
+
+ /**
+ * 响应消息
+ */
+ private String message;
+
+ /**
+ * 回执ID
+ */
+ private String bizId;
+
+ /**
+ * 请求ID
+ */
+ private String requestId;
+
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/TemplateParamDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/TemplateParamDto.java
new file mode 100644
index 00000000..38aeca44
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/TemplateParamDto.java
@@ -0,0 +1,36 @@
+package cn.axzo.msg.notices.manager.api.dto.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 模板参数
+ *
+ * @author zhaoyong
+ * @see TemplateParamDto
+ * @since 2021-08-20 21:41
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class TemplateParamDto {
+
+ /**
+ * 模板编号
+ */
+ private String templateNo;
+
+ /**
+ * 参数名称
+ */
+ private String paramName;
+
+ /**
+ * 参数顺序
+ */
+ private Integer paramOrder;
+
+}
diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/plat/QueryTemplateResponseDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/plat/QueryTemplateResponseDto.java
new file mode 100644
index 00000000..2a78e52f
--- /dev/null
+++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/notices/manager/api/dto/response/plat/QueryTemplateResponseDto.java
@@ -0,0 +1,50 @@
+package cn.axzo.msg.notices.manager.api.dto.response.plat;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class QueryTemplateResponseDto {
+
+ /**
+ * 主键id
+ */
+ private Long id;
+ /**
+ * 模版状态
+ */
+ private Integer messageTemplateStatus;
+ /**
+ * 模版类型
+ */
+ private Integer messageTemplateType;
+ /**
+ * 原因
+ */
+ private String reason;
+ /**
+ * 备注
+ */
+ private String remark;
+ /**
+ * 服务名
+ */
+ private String serviceName;
+ /**
+ * 阿里短信模版编码
+ */
+ private String templateAliNo;
+ /**
+ * 模版内容
+ */
+ private String templateContent;
+ /**
+ * 模版编码
+ */
+ private String templateNo;
+ /**
+ * 标题
+ */
+ private String title;
+}
diff --git a/msg-notices/msg-notices-manager/pom.xml b/msg-notices/msg-notices-manager/pom.xml
new file mode 100644
index 00000000..c4aaedfb
--- /dev/null
+++ b/msg-notices/msg-notices-manager/pom.xml
@@ -0,0 +1,55 @@
+
+
+
+ msg-notices
+ cn.axzo.msgcenter
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ cn.axzo.msg.notices.manager
+ msg-notices-manager
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+ cn.axzo.platform
+ axzo-log-api
+
+
+ org.apache.tomcat.embed
+ tomcat-embed-core
+
+
+ cn.axzo.msg.notices.manager.api
+ msg-notices-manager-api
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.dao
+ msg-notices-dao
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.integration
+ msg-notices-integration
+ 1.0.0-SNAPSHOT
+ compile
+
+
+
+
\ No newline at end of file
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/AliyunSmsSendManagerImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/AliyunSmsSendManagerImpl.java
new file mode 100644
index 00000000..b29eaa91
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/AliyunSmsSendManagerImpl.java
@@ -0,0 +1,56 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.integration.client.impl.AliYunSmsClientImpl;
+import cn.axzo.msg.notices.integration.dto.request.SendSmsCommonRequest;
+import cn.axzo.msg.notices.integration.dto.response.SendSmsCommonResponse;
+import cn.axzo.msg.notices.manager.api.SmsSendManager;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.response.BatchMessageSendResponseDto;
+import cn.axzo.msg.notices.manager.api.dto.response.SendSmsCommonResponseDto;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * sms服务
+ *
+ * @Author: LiuYang
+ * @Date: 2021/5/25 16:04
+ */
+@Slf4j
+@Service("aliyunSmsSendManager")
+public class AliyunSmsSendManagerImpl implements SmsSendManager {
+
+ @Resource
+ private AliYunSmsClientImpl aliyunSmsService;
+
+ @Override
+ public SendSmsCommonResponseDto sendMessage(MessageSendRequestDto requestDto) {
+ log.info("[AliyunSmsSendManagerImpl#sendMessage] -> aliyun - 发送sms {}", JSON.toJSONString(requestDto));
+ // 请求转换
+ SendSmsCommonRequest request = new SendSmsCommonRequest();
+ request.setPhoneNo(requestDto.getPhoneNo());
+ request.setTemplateCode(requestDto.getTemplateNo());
+ request.setTemplateMap(requestDto.getTemplateMap());
+ request.setRequestChannelNo(requestDto.getRequestChannelNo());
+
+ // 发送短信
+ SendSmsCommonResponse response = aliyunSmsService.sendSms(request);
+
+ // 响应请求
+ SendSmsCommonResponseDto result = new SendSmsCommonResponseDto();
+ result.setBizId(response.getBizId());
+ result.setRequestId(response.getRequestId());
+ result.setMessage(result.getMessage());
+ return result;
+ }
+
+ @Override
+ public BatchMessageSendResponseDto sendBatchMessage(BatchMessageSendRequestDto requestDto) {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/BatchMessageMangerImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/BatchMessageMangerImpl.java
new file mode 100644
index 00000000..0677f44a
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/BatchMessageMangerImpl.java
@@ -0,0 +1,164 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.enums.BatchMessageStatusEnum;
+import cn.axzo.msg.notices.common.enums.MessageStatusEnum;
+import cn.axzo.msg.notices.common.enums.MessageTypeEnum;
+import cn.axzo.msg.notices.common.enums.NotifyTypeEnum;
+import cn.axzo.msg.notices.common.lang.Page;
+import cn.axzo.msg.notices.dao.domain.BatchMessageQuery;
+import cn.axzo.msg.notices.dao.entity.BatchMessage;
+import cn.axzo.msg.notices.dao.entity.Message;
+import cn.axzo.msg.notices.dao.repository.BatchMessageDao;
+import cn.axzo.msg.notices.dao.repository.MessageDao;
+import cn.axzo.msg.notices.manager.api.BatchMessageManger;
+import cn.axzo.msg.notices.manager.api.SmsSendManager;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.SmsContentDto;
+import cn.azxo.framework.common.utils.LogUtil;
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.core.convert.support.GenericConversionService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @Classname BatchMessageMangerImpl
+ * @Author: szg
+ * @Date: 2021年08月09日 17:17
+ * @Description:
+ */
+@Service("batchMessageManger")
+@Slf4j
+public class BatchMessageMangerImpl implements BatchMessageManger {
+
+ @Resource(name = "messageDao")
+ private MessageDao messageDao;
+
+ @Resource(name = "batchMessageDao")
+ private BatchMessageDao batchMessageDao;
+
+ @Resource(name = "transactionTemplate")
+ private TransactionTemplate transactionTemplate;
+
+ @Resource(name = "smsSendManagerComposite")
+ private SmsSendManager smsSendManagerComposite;
+
+ @Resource(name = "genericConversionService")
+ private GenericConversionService genericConversionService;
+
+ @Override
+ public Page queryByPage(BatchMessageRequestDto requestDto) {
+ BatchMessageQuery query = new BatchMessageQuery();
+ BeanUtils.copyProperties(requestDto, query);
+ IPage messagePage = batchMessageDao.queryByPage(query);
+ if (messagePage == null) {
+ log.info("BatchMessageMangerImpl.queryByPage result is null");
+ return null;
+ }
+ Page result = new Page<>();
+ result.setPageNum(messagePage.getCurrent());
+ result.setPageSize(messagePage.getSize());
+ result.setTotalElements(messagePage.getTotal());
+ result.setList(messagePage.getRecords());
+ return result;
+ }
+
+ @Override
+ public BatchMessage queryBatchMessage(String batchNo) {
+ return batchMessageDao.queryBatchMessage(batchNo);
+ }
+
+ @Override
+ public boolean batchMessageSplitToMessage(BatchMessage batchMessage) {
+ List messages = initMessageList(batchMessage);
+ if (CollectionUtils.isEmpty(messages)) {
+ log.info("BatchMessageMangerImpl.batchMessageSplitToMessage initMessageList result is null ");
+ return false;
+ }
+ return transactionTemplate.execute(status -> {
+ Boolean updateRes = batchMessageDao
+ .updateStatusById(batchMessage.getId(), BatchMessageStatusEnum.SPLIT_COMPLETED.getCode());
+ if (updateRes) {
+ return messageDao.saveBatch(messages);
+ }
+ return false;
+ });
+ }
+
+ @Override
+ public void sendBatchMessageAndHandleReceipt(BatchMessage batchMessage) {
+ if (Objects.isNull(batchMessage)) {
+ log.info("BatchMessageMangerImpl.sendBatchMessageAndHandleReceipt batchMessage is null");
+ return;
+ }
+ BatchMessageSendRequestDto requestDto = genericConversionService
+ .convert(batchMessage, BatchMessageSendRequestDto.class);
+ //1.变更状态
+ batchMessageDao.updateStatusById(batchMessage.getId(),BatchMessageStatusEnum.PROCESSING.getCode());
+ //2.发送消息
+ try {
+ log.info("开始发送短信批次->BatchMessageMangerImpl.sendBatchMessageAndHandleReceipt BatchMessage = {}",
+ JSON.toJSONString(requestDto));
+ smsSendManagerComposite.sendBatchMessage(requestDto);
+ }catch (Exception e){
+ LogUtil.error(
+ "发送短信批次失败->BatchMessageMangerImpl.sendBatchMessageAndHandleReceipt BatchMessage = {} ",
+ JSON.toJSONString(requestDto));
+ }
+ }
+
+ /**
+ * 初始化短信模板
+ *
+ * @param request
+ * @return
+ */
+ private List initMessageList(BatchMessage request) {
+
+ String smsContent = request.getSmsContent();
+ if (StringUtils.isEmpty(smsContent)) {
+ return null;
+ }
+ List totalList = JSON.parseArray(smsContent, SmsContentDto.class);
+ if (CollectionUtils.isEmpty(totalList)) {
+ return null;
+ }
+ List messageList = new ArrayList<>();
+ for (SmsContentDto smsContentDto : totalList) {
+ if (Objects.isNull(smsContentDto)) {
+ continue;
+ }
+
+ Message message = new Message();
+ message.setAppNo(request.getAppNo());
+ message.setRequestNo(request.getRequestNo());
+ message.setBatchNo(request.getRequestNo());
+ message.setMessageOrderNo(IdUtil.simpleUUID());
+ message.setMessageType(MessageTypeEnum.S.name());
+ message.setNotifyType(NotifyTypeEnum.BATCH.name());
+ message.setStatus(MessageStatusEnum.INIT.getCode());
+ message.setChannelCode("batch");
+ message.setChannelName("batch");
+ message.setTemplateNo(request.getTemplateNo());
+ message.setSubject(JSON.toJSONString(smsContentDto.getTemplateParams()));
+ message.setTargetAddress(smsContentDto.getPhoneNo());
+ message.setBatchNo(request.getBatchNo());
+ message.setNotifyRule("");
+ message.setRemark("");
+ messageList.add(message);
+ }
+
+ return messageList;
+ }
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/BatchMessageRequestMangerImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/BatchMessageRequestMangerImpl.java
new file mode 100644
index 00000000..508b89a8
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/BatchMessageRequestMangerImpl.java
@@ -0,0 +1,199 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.enums.BatchMessageRequestStatusEnum;
+import cn.axzo.msg.notices.common.enums.BatchMessageStatusEnum;
+import cn.axzo.msg.notices.common.lang.Page;
+import cn.axzo.msg.notices.dao.domain.BatchMessageRequestQuery;
+import cn.axzo.msg.notices.dao.domain.BatchMessageStatisticsResponseDto;
+import cn.axzo.msg.notices.dao.entity.BatchMessage;
+import cn.axzo.msg.notices.dao.entity.BatchMessageRequest;
+import cn.axzo.msg.notices.dao.repository.BatchMessageDao;
+import cn.axzo.msg.notices.dao.repository.BatchMessageRequestDao;
+import cn.axzo.msg.notices.manager.api.BatchMessageRequestManger;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.SmsContentDto;
+import cn.azxo.framework.common.utils.LogUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @Classname BatchMessageRequestMangerImpl
+ * @Author: szg
+ * @Date: 2021年08月09日 14:10
+ * @Description:
+ */
+@RefreshScope
+@Service("batchMessageRequestManger")
+@Slf4j
+public class BatchMessageRequestMangerImpl implements BatchMessageRequestManger {
+
+ @Resource
+ private BatchMessageRequestDao batchMessageRequestDao;
+
+ @Resource
+ private BatchMessageDao batchMessageDao;
+
+ @Resource(name = "transactionTemplate")
+ private TransactionTemplate transactionTemplate;
+
+ @Value("${batch.request.splitSize:100}")
+ private Integer splitSize;
+
+ @Override
+ public boolean saveBatchMessageRequest(BatchMessageRequest batchMessageRequest) {
+ return batchMessageRequestDao.save(batchMessageRequest);
+ }
+
+ @Override
+ public Page queryPageByBatchMessageQueryRequestDto(
+ BatchMessageRequestDto requestDto) {
+ BatchMessageRequestQuery query = new BatchMessageRequestQuery();
+ BeanUtils.copyProperties(requestDto, query);
+ IPage messagePage = batchMessageRequestDao.queryByPage(query);
+ if (messagePage == null) {
+ return null;
+ }
+ Page result = new Page<>();
+ result.setPageNum(messagePage.getCurrent());
+ result.setPageSize(messagePage.getSize());
+ result.setTotalElements(messagePage.getTotal());
+ result.setList(messagePage.getRecords());
+ return result;
+ }
+
+ @Override
+ public List batchMessageRequestSplitAndSave(BatchMessageRequest batchMessageRequest) {
+
+ String smsContent = batchMessageRequest.getSmsContent();
+ if (StringUtils.isEmpty(smsContent)) {
+ log.info("BatchMessageRequestMangerImpl.batchMessageRequestSplitAndSave smsContent is null");
+ return Lists.newArrayList();
+ }
+ List totalList = JSON.parseArray(smsContent, SmsContentDto.class);
+ if (CollectionUtils.isEmpty(totalList)) {
+ log.info("BatchMessageRequestMangerImpl.batchMessageRequestSplitAndSave totalList is null");
+ return Lists.newArrayList();
+ }
+ List> split = ListUtil.split(totalList, splitSize);
+ //保存batch_message
+ List batchMessageList = new ArrayList<>();
+ for (List dtoList : split) {
+ if (CollectionUtils.isEmpty(dtoList)) {
+ log.info("BatchMessageRequestMangerImpl.batchMessageRequestSplitAndSave split is null");
+ continue;
+ }
+ BatchMessage batchMessage = buildBatchMessage(batchMessageRequest, dtoList);
+ batchMessageList.add(batchMessage);
+ }
+
+ boolean result = transactionTemplate.execute(status ->{
+ boolean updateRes = batchMessageRequestDao.updateStatusById(batchMessageRequest.getId(),
+ BatchMessageRequestStatusEnum.SPLIT_COMPLETED.getCode());
+ if (updateRes){
+ return batchMessageDao.saveBatch(batchMessageList);
+ }
+ return false;
+ });
+
+ if(result) {
+ return batchMessageList.stream().map(v -> v.getBatchNo()).collect(Collectors.toList());
+ }
+
+ return Lists.newArrayList();
+ }
+
+ @Override
+ public BatchMessageRequest queryBatchMessage(String appCode, String requestNo) {
+ return batchMessageRequestDao.queryBatchMessage(appCode, requestNo);
+ }
+
+ @Override
+ public boolean updateRequestSuccess(String remark, Long id) {
+ return batchMessageRequestDao.updateRequestSuccess(remark, id);
+ }
+
+ @Override
+ public void handleBatchMessageRequestStatistics(BatchMessageRequest request) {
+ if (Objects.isNull(request)) {
+ LogUtil.error("批次处理完成消息 handleBatchMessageRequestInfoUpdate batchMessageRequest is null");
+ return;
+ }
+ // 统计 batch_message
+ BatchMessageStatisticsResponseDto responseDto = batchMessageDao
+ .getStatisticsMessageInfo(request.getAppNo(), request.getRequestNo());
+
+ if (Objects.isNull(responseDto)) {
+ LogUtil.error(
+ "批次处理完成消息 handleBatchMessageRequestInfoUpdate 统计 BatchMessageStatisticsResponseDto is null");
+ return;
+ }
+
+ //batchMessageRequest状态处理
+ Integer batchMessageRequestStatus = getBatchMessageRequestStatus(request,
+ responseDto);
+ //更新此次统计
+ batchMessageRequestDao
+ .updateBatchMessageRequestInfoById(request.getId(), batchMessageRequestStatus,
+ responseDto.getSuccessCount(), responseDto.getFailCount());
+ }
+
+ /**
+ * 构建批量消息
+ * @param batchMessageRequest
+ * @param dtoList
+ * @return
+ */
+ private BatchMessage buildBatchMessage(BatchMessageRequest batchMessageRequest,
+ List dtoList) {
+ BatchMessage batchMessage = new BatchMessage();
+ batchMessage.setAppNo(batchMessageRequest.getAppNo());
+ batchMessage.setRequestNo(batchMessageRequest.getRequestNo());
+ batchMessage.setBatchNo(IdUtil.simpleUUID());
+ batchMessage.setTemplateNo(batchMessageRequest.getTemplateNo());
+ batchMessage.setMessageOrderNo(IdUtil.simpleUUID());
+ batchMessage.setSmsContent(JSON.toJSONString(dtoList));
+ batchMessage.setBatchSize(dtoList.size());
+ batchMessage.setSendType(batchMessageRequest.getSendType());
+ batchMessage.setStatus(BatchMessageStatusEnum.INITIALIZE.getCode());
+ batchMessage.setChannelMsgId("");
+ batchMessage.setChannelCode("");
+ batchMessage.setChannelErrorMsg("");
+ return batchMessage;
+ }
+
+ /**
+ * 获取状态
+ * @param batchMessageRequest
+ * @param responseDto
+ * @return
+ */
+ private Integer getBatchMessageRequestStatus(BatchMessageRequest batchMessageRequest,
+ BatchMessageStatisticsResponseDto responseDto) {
+ Integer batchMessageRequestStatus = BatchMessageRequestStatusEnum.PARTIAL_SUCCESS.getCode();
+ //处理状态
+ if (Objects.equals(batchMessageRequest.getTotalSize(), responseDto.getSuccessCount())) {
+ batchMessageRequestStatus = BatchMessageRequestStatusEnum.SEND_SUCCESS.getCode();
+ } else if (Objects.equals(batchMessageRequest.getTotalSize(), responseDto.getFailCount())) {
+ batchMessageRequestStatus = BatchMessageRequestStatusEnum.ALL_FAILED.getCode();
+ }
+ return batchMessageRequestStatus;
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/ChuangLanSmsSendManagerImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/ChuangLanSmsSendManagerImpl.java
new file mode 100644
index 00000000..9b60fbbb
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/ChuangLanSmsSendManagerImpl.java
@@ -0,0 +1,279 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.domain.BatchMessageCountContext;
+import cn.axzo.msg.notices.common.enums.*;
+import cn.axzo.msg.notices.common.exception.BizException;
+import cn.axzo.msg.notices.dao.entity.BatchMessage;
+import cn.axzo.msg.notices.dao.entity.ChannelMessageTemplate;
+import cn.axzo.msg.notices.dao.repository.BatchMessageDao;
+import cn.axzo.msg.notices.dao.repository.ChannelMessageTemplateDao;
+import cn.axzo.msg.notices.dao.repository.MessageDao;
+import cn.axzo.msg.notices.integration.client.ChuangLanSmsClient;
+import cn.axzo.msg.notices.integration.client.DingDingClient;
+import cn.axzo.msg.notices.integration.dto.request.MessageRequest;
+import cn.axzo.msg.notices.integration.dto.response.ChuangLanSmsResponse;
+import cn.axzo.msg.notices.manager.api.SmsSendManager;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.response.BatchMessageSendResponseDto;
+import cn.axzo.msg.notices.manager.api.dto.response.SendSmsCommonResponseDto;
+import cn.axzo.msg.notices.manager.support.ChuangLanMessageContentSupport;
+import cn.azxo.framework.common.utils.LogUtil;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.convert.support.GenericConversionService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionSynchronizationAdapter;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.Resource;
+
+/**
+ * 创蓝短信发送 Manager
+ *
+ * @author zhaoyong
+ * @see ChuangLanSmsSendManagerImpl
+ * @since 2021-08-07 19:06
+ */
+@Slf4j
+@Service("chuangLanSmsSendManager")
+public class ChuangLanSmsSendManagerImpl implements SmsSendManager {
+
+ @Resource(name = "chuangLanSmsClient")
+ private ChuangLanSmsClient chuangLanSmsClient;
+
+ @Resource(name = "channelMessageTemplateDao")
+ private ChannelMessageTemplateDao templateDao;
+
+ @Resource(name = "messageDao")
+ private MessageDao messageDao;
+
+ @Resource(name = "batchMessageDao")
+ private BatchMessageDao batchMessageDao;
+
+ @Resource(name = "dingDingClient")
+ private DingDingClient dingDingClient;
+
+ @Resource(name = "chuangLanMessageContentSupport")
+ private ChuangLanMessageContentSupport chuangLanMessageContentSupport;
+
+ @Resource(name = "transactionTemplate")
+ private TransactionTemplate transactionTemplate;
+
+ @Resource(name = "genericConversionService")
+ private GenericConversionService genericConversionService;
+
+ /** 相同内容群发接口 URL */
+ private final static String COMMON_URL = "http://smssh1.253.com/msg/v1/send/json";
+
+ /** 相同内容变量接口 URL */
+ private final static String VARIABLE_URL = "http://smssh1.253.com/msg/variable/json";
+
+ @Override
+ public SendSmsCommonResponseDto sendMessage(MessageSendRequestDto requestDto) {
+ String channelCode = MessageChannelEnum.CHUANG_LAN.getCode();
+ // 获取渠道模板
+ ChannelMessageTemplate template =
+ templateDao.queryByTemplateNo(requestDto.getInnerTemplateNo(), channelCode);
+ BizException.error(template != null, ReturnCodeEnum.SYSTEM_ERROR, "渠道模板不能为空");
+
+ MessageRequest request = new MessageRequest();
+ boolean hasParam = template.hasParam();
+ request.setHasParam(hasParam);
+ if(hasParam) {
+ request.setRequestUrl(VARIABLE_URL);
+ } else {
+ request.setRequestUrl(COMMON_URL);
+ }
+ String smsContent = chuangLanMessageContentSupport.getSingleSmsContent(requestDto, template, hasParam);
+ request.setSmsContent(smsContent);
+ MessageTemplateTypeEnum typeEnum = MessageTemplateTypeEnum.getByCode(template.getType());
+ request.setMessageTemplateType(typeEnum);
+ request.setTemplateContent(template.getTemplateContent());
+ request.setRequestChannelNo(MessageSendTypeEnum.SINGLE.getCode());
+
+ // 发送单条短信
+ ChuangLanSmsResponse response = chuangLanSmsClient.sendMessage(request);
+ SendSmsCommonResponseDto result = new SendSmsCommonResponseDto();
+ result.setRequestId(response.getMsgId());
+ result.setMessage(result.getMessage());
+ return result;
+ }
+
+ @Override
+ public BatchMessageSendResponseDto sendBatchMessage(BatchMessageSendRequestDto requestDto) {
+ log.info("ChuangLanSmsManagerImpl.sendBatchMessage request param is {}", JSON.toJSONString(requestDto));
+ String channelCode = MessageChannelEnum.CHUANG_LAN.getCode();
+ String channelName = MessageChannelEnum.CHUANG_LAN.getMessage();
+
+ // 获取渠道模板
+ ChannelMessageTemplate template =
+ templateDao.queryByTemplateNo(requestDto.getInnerTemplateNo(), channelCode);
+ BizException.error(template != null, ReturnCodeEnum.SYSTEM_ERROR, "渠道模板不能为空");
+
+ // 修改批量短信渠道和渠道模板
+ transactionTemplate.executeWithoutResult(status -> {
+ batchMessageDao.updateChannelInfo(channelCode, template.getTemplateNo(), requestDto.getBatchNo());
+ messageDao.updateBatchMessageChannelInfo(channelCode, channelName, requestDto.getBatchNo());
+ });
+
+ MessageRequest request = new MessageRequest();
+ boolean hasParam = template.hasParam();
+ request.setHasParam(hasParam);
+ if(hasParam) {
+ request.setRequestUrl(VARIABLE_URL);
+ } else {
+ request.setRequestUrl(COMMON_URL);
+ }
+ String smsContent = chuangLanMessageContentSupport.getBatchSmsContent(requestDto, template, hasParam);
+ request.setSmsContent(smsContent);
+ MessageTemplateTypeEnum typeEnum = MessageTemplateTypeEnum.getByCode(template.getType());
+ request.setMessageTemplateType(typeEnum);
+ request.setTemplateContent(template.getTemplateContent());
+ request.setRequestChannelNo(MessageSendTypeEnum.BATCH.getCode());
+ try {
+ // 发送批量短信
+ ChuangLanSmsResponse response = chuangLanSmsClient.sendMessage(request);
+
+ transactionTemplate.executeWithoutResult(status -> {
+ if(response.getFailNum() == requestDto.getSmsContentDtos().size()) {
+ // 失败提交数为总条数
+ updateBatchMessageToFail(requestDto, response);
+ } else {
+ // 失败提交数小于总条数
+ updateAfterChannelResponse(requestDto, response);
+ }
+ });
+
+ return genericConversionService.convert(response, BatchMessageSendResponseDto.class);
+ } catch (BizException e) {
+ LogUtil.error("ChuangLanSmsManagerImpl.sendBatchMessage is BizException.", e);
+
+ transactionTemplate.executeWithoutResult(status -> {
+ updateBatchMessageToFail(requestDto, e);
+ });
+ throw e;
+ }
+ }
+
+ /**
+ * 提交渠道成功
+ * @param requestDto
+ * @param response
+ */
+ private void updateAfterChannelResponse(BatchMessageSendRequestDto requestDto, ChuangLanSmsResponse response) {
+ BatchMessage batchMessage = new BatchMessage();
+ batchMessage.setChannelReturnCode(response.getCode());
+ batchMessage.setChannelErrorMsg(response.getErrorMsg());
+ batchMessage.setChannelMsgId(response.getMsgId());
+ batchMessage.setFailCount(response.getFailNum());
+ batchMessage.setSubmitFailNum(response.getFailNum());
+ batchMessage.setSubmitSuccessNum(response.getSuccessNum());
+ batchMessageDao.updateBatchMessage(batchMessage, requestDto.getBatchNo());
+ }
+
+ /**
+ * 提交渠道全部失败
+ * @param requestDto
+ * @param response
+ */
+ private void updateBatchMessageToFail(BatchMessageSendRequestDto requestDto, ChuangLanSmsResponse response){
+ // 更新 batch_message 表
+ BatchMessage batchMessage = new BatchMessage();
+ batchMessage.setStatus(BatchMessageStatusEnum.ALL_FAILED.getCode());
+ batchMessage.setSubmitFailNum(response.getFailNum());
+ batchMessage.setSubmitSuccessNum(response.getSuccessNum());
+ batchMessage.setChannelReturnCode(response.getCode());
+ batchMessage.setChannelErrorMsg(response.getErrorMsg());
+ batchMessage.setChannelMsgId(response.getMsgId());
+ batchMessageDao.updateBatchMessage(batchMessage, requestDto.getBatchNo());
+
+ // 更新 message 表
+ messageDao.updateAllBatchMessageFail(response.getErrorMsg(), requestDto.getBatchNo());
+
+ // 事务提交后操作
+ doAfterCommit(requestDto, response, null);
+ }
+
+ /**
+ * 提交渠道异常
+ * @param requestDto
+ * @param e
+ */
+ private void updateBatchMessageToFail(BatchMessageSendRequestDto requestDto, BizException e) {
+ BatchMessage batchMessage = new BatchMessage();
+ batchMessage.setChannelReturnCode(e.getBizCode() + "");
+ batchMessage.setChannelErrorMsg(e.getMessage());
+ batchMessage.setStatus(BatchMessageStatusEnum.ALL_FAILED.getCode());
+ int batchSize = requestDto.getSmsContentDtos().size();
+ batchMessage.setFailCount(batchSize);
+ batchMessage.setSubmitFailNum(batchSize);
+ batchMessage.setChannelErrorMsg(e.getMessage());
+ batchMessageDao.updateBatchMessage(batchMessage, requestDto.getBatchNo());
+
+ // 更新 message 表
+ messageDao.updateAllBatchMessageFail(e.getMessage(), requestDto.getBatchNo());
+
+ // 事务提交后操作
+ doAfterCommit(requestDto, null, e);
+ }
+
+ /**
+ * 事务提交后操作(必须依赖事务)
+ * @param request
+ */
+ private void doAfterCommit(BatchMessageSendRequestDto request
+ , ChuangLanSmsResponse response, BizException e) {
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){
+ @Override
+ public void afterCommit() {
+ // 获取消息内容
+ BatchMessageCountContext context = getMessageContext(request, response, e);
+
+ // remove rocketmq
+
+ // 发送钉钉消息
+ dingDingClient.notifyBatchMessage(request.getInnerTemplateNo(), request.getBatchNo(), getErrorMsg(response, e));
+ }
+ });
+ }
+
+ /**
+ * 获取消息上下文
+ * @param request
+ * @param response
+ * @param e
+ * @return
+ */
+ private BatchMessageCountContext getMessageContext(BatchMessageSendRequestDto request
+ , ChuangLanSmsResponse response, BizException e){
+ boolean hasException = false;
+ if(e != null) {
+ hasException = true;
+ }
+ BatchMessageCountContext context = new BatchMessageCountContext();
+ context.setAppCode(request.getAppCode());
+ context.setAppRequestNo(request.getAppRequestNo());
+ context.setBatchNo(request.getBatchNo());
+ if(hasException) {
+ context.setFailNum(request.getSmsContentDtos().size());
+ } else {
+ context.setFailNum(response.getFailNum());
+ }
+ return context;
+ }
+
+ /**
+ * 获取错误信息
+ * @return
+ */
+ private String getErrorMsg(ChuangLanSmsResponse response, BizException e) {
+ if(e != null) {
+ return e.getMessage();
+ } else {
+ return response.getErrorMsg();
+ }
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageChannelRouteImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageChannelRouteImpl.java
new file mode 100644
index 00000000..620dbdb4
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageChannelRouteImpl.java
@@ -0,0 +1,84 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.constans.CommonConstants;
+import cn.axzo.msg.notices.common.enums.AvailableStatusEnum;
+import cn.axzo.msg.notices.common.enums.MessageChannelEnum;
+import cn.axzo.msg.notices.common.enums.ReturnCodeEnum;
+import cn.axzo.msg.notices.common.exception.BizException;
+import cn.axzo.msg.notices.dao.entity.MessageChannel;
+import cn.axzo.msg.notices.dao.repository.MessageChannelDao;
+import cn.axzo.msg.notices.manager.api.MessageChannelRouter;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 消息渠道路由实现类
+ *
+ * @author zhaoyong_sh
+ * @see MessageChannelRouteImpl
+ * @since 2021-05-27 15:04
+ */
+@Service("messageChannelRoute")
+public class MessageChannelRouteImpl implements MessageChannelRouter {
+
+ @Resource(name = "messageChannelDao")
+ private MessageChannelDao messageChannelDao;
+
+ @Override
+ public MessageChannel route(String condition) {
+ List messageChannels = messageChannelDao.queryAvailable();
+
+ BizException.error(CollectionUtils.isNotEmpty(messageChannels), ReturnCodeEnum.MESSAGE_CHANNEL_NOT_VALID);
+ Optional messageChannelOptional = messageChannels.stream()
+ // 有效渠道
+ .filter(this::isValid)
+ // 条件过滤
+ .filter(messageChannel -> conditionFilter(condition, messageChannel))
+ // 优先级越小,排在越前
+ .sorted(Comparator.comparing(MessageChannel::getPriority))
+ // 查询优先级最高的一个
+ .findFirst();
+ return messageChannelOptional.orElse(null);
+ }
+
+ /**
+ * 渠道是否有效
+ * @param messageChannel
+ * @return
+ */
+ private boolean isValid(MessageChannel messageChannel){
+ return AvailableStatusEnum.AVAILABLE.getStatus().equals(messageChannel.getStatus());
+ }
+
+ /**
+ * 条件路由
+ * @param condition
+ * @param messageChannel
+ * @return
+ */
+ private boolean conditionFilter(String condition, MessageChannel messageChannel){
+ try {
+ JSONObject conditionJO = JSON.parseObject(condition);
+ // 指定路由渠道
+ String channelCode = conditionJO.getString(CommonConstants.ASSIGN_CHANNEL);
+ if(StringUtils.isNoneBlank(channelCode)) {
+ MessageChannelEnum channelEnum = MessageChannelEnum.getByCode(channelCode);
+ if(channelEnum != null) {
+ return channelCode.equals(messageChannel.getChannelCode());
+ }
+ }
+ return true;
+ } catch (Exception e) {
+ return true;
+ }
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageManagerImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageManagerImpl.java
new file mode 100644
index 00000000..cd319657
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageManagerImpl.java
@@ -0,0 +1,151 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.enums.MessageStatusEnum;
+import cn.axzo.msg.notices.common.lang.Page;
+import cn.axzo.msg.notices.dao.domain.MessageQuery;
+import cn.axzo.msg.notices.dao.entity.Message;
+import cn.axzo.msg.notices.dao.entity.MessageRedo;
+import cn.axzo.msg.notices.dao.persistence.BaseEntity;
+import cn.axzo.msg.notices.dao.repository.MessageDao;
+import cn.axzo.msg.notices.dao.repository.MessageRedoDao;
+import cn.axzo.msg.notices.manager.api.MessageManager;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageQueryRequestDto;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * 消息记录管理实现类
+ *
+ * @author zhaoyong_sh
+ * @see MessageManagerImpl
+ * @since 2021-05-19 18:04
+ */
+@Service("messageManager")
+public class MessageManagerImpl implements MessageManager {
+
+ @Resource(name = "messageDao")
+ private MessageDao messageDao;
+
+ @Resource(name = "messageRedoDao")
+ private MessageRedoDao messageRedoDao;
+
+ @Resource(name = "transactionTemplate")
+ private TransactionTemplate transactionTemplate;
+
+ @Override
+ public Page queryPageByMessageQueryRequestDto(MessageQueryRequestDto requestDto) {
+ MessageQuery query = new MessageQuery();
+ BeanUtils.copyProperties(requestDto, query);
+ IPage messagePage = messageDao.queryByPage(query);
+ if (messagePage == null) {
+ return null;
+ }
+ Page result = new Page<>();
+ result.setPageNum(messagePage.getCurrent());
+ result.setPageSize(messagePage.getSize());
+ result.setTotalElements(messagePage.getTotal());
+ result.setList(messagePage.getRecords());
+ return result;
+ }
+
+ @Override
+ public boolean saveMessage(Message message) {
+ return messageDao.save(message);
+ }
+
+ @Override
+ public boolean saveMessageRedo(MessageRedo messageRedo) {
+ return messageRedoDao.save(messageRedo);
+ }
+
+ @Override
+ public boolean updateToProcessing(String bizId, String requestId, Long id) {
+ return messageDao.lambdaUpdate()
+ .set(StringUtils.isNoneBlank(bizId), Message::getChannelBizId, bizId)
+ .set(StringUtils.isNoneBlank(requestId), Message::getChannelRequestId, requestId)
+ .set(Message::getStatus, MessageStatusEnum.PROCESSING.getCode())
+ .set(Message::getUpdateAt, new Date())
+ .eq(Message::getId, id)
+ .eq(Message::getStatus, MessageStatusEnum.INIT.getCode())
+ .update();
+ }
+
+ @Override
+ public boolean updateToFail(Long id) {
+ return messageDao.lambdaUpdate()
+ .set(Message::getStatus, MessageStatusEnum.FAIL.getCode())
+ .set(Message::getUpdateAt, new Date())
+ .eq(Message::getId, id)
+ .eq(Message::getStatus, MessageStatusEnum.INIT.getCode())
+ .update();
+ }
+
+ @Override
+ public boolean updateToException(MessageRedo messageRedo, Long id) {
+ return transactionTemplate.execute(status -> {
+ messageDao.channelException(id);
+ return messageRedoDao.save(messageRedo);
+ });
+ }
+
+ @Override
+ public boolean updateExceptionToQueryStatus(String targetStatus, Long id) {
+ return messageDao.lambdaUpdate().eq(Message::getId, id)
+ .eq(Message::getStatus, MessageStatusEnum.EXCEPTION.getCode())
+ .set(Message::getStatus, targetStatus)
+ .update();
+ }
+
+
+ @Override
+ public Message queryMessageByMessageOrderNoAndPhoneNumber(String messageOrderNo,String channelBizId,
+ String phoneNumber) {
+ return messageDao.lambdaQuery()
+ .eq(Objects.nonNull(messageOrderNo),Message::getMessageOrderNo, messageOrderNo)
+ .eq(Objects.nonNull(channelBizId),Message::getChannelBizId, channelBizId)
+ .eq(Message::getTargetAddress, phoneNumber)
+ .eq(Message::getIsDelete, 0)
+ .one();
+ }
+
+ @Override
+ public boolean updateProcessingMessageStatusById(Long id, String status) {
+ return messageDao
+ .lambdaUpdate()
+ .eq(Message::getId, id)
+ .eq(Message::getIsDelete, 0)
+ .eq(Message::getStatus,MessageStatusEnum.PROCESSING.getCode())
+ .set(Message::getStatus, status)
+ .update();
+ }
+
+ @Override
+ public boolean updateMessageStatusByMessageOrderNo(String messageOrderNo, String status) {
+ return messageDao
+ .lambdaUpdate()
+ .eq(Message::getMessageOrderNo, messageOrderNo)
+ .eq(Message::getIsDelete, 0)
+ .set(Message::getStatus, status)
+ .update();
+ }
+
+ @Override
+ public boolean updateToSuccess(String bizId, String requestId, Long id) {
+ return messageDao.lambdaUpdate()
+ .set(StringUtils.isNoneBlank(bizId), Message::getChannelBizId, bizId)
+ .set(StringUtils.isNoneBlank(requestId), Message::getChannelRequestId, requestId)
+ .set(Message::getStatus, MessageStatusEnum.SUCCESS.getCode())
+ .set(BaseEntity::getUpdateAt, new Date())
+ .eq(BaseEntity::getId, id)
+ .eq(Message::getStatus, MessageStatusEnum.INIT.getCode())
+ .update();
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageRedoMangerImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageRedoMangerImpl.java
new file mode 100644
index 00000000..4149bfd7
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageRedoMangerImpl.java
@@ -0,0 +1,133 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.domain.MessageContext;
+import cn.axzo.msg.notices.common.enums.MessageStatusEnum;
+import cn.axzo.msg.notices.common.enums.RetryingFlagEnum;
+import cn.axzo.msg.notices.common.lang.Page;
+import cn.axzo.msg.notices.dao.domain.MessageRedoQuery;
+import cn.axzo.msg.notices.dao.entity.Message;
+import cn.axzo.msg.notices.dao.entity.MessageRedo;
+import cn.axzo.msg.notices.dao.repository.MessageDao;
+import cn.axzo.msg.notices.dao.repository.MessageRedoDao;
+import cn.axzo.msg.notices.manager.api.MessageRedoManger;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageRedoQueryRequestDto;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+/**
+ * 消息重试
+ * @author szg
+ */
+@Service("messageRedoManger")
+public class MessageRedoMangerImpl implements MessageRedoManger {
+
+ @Resource(name = "messageDao")
+ private MessageDao messageDao;
+
+ @Resource
+ private MessageRedoDao messageRedoDao;
+
+ @Resource(name = "transactionTemplate")
+ private TransactionTemplate transactionTemplate;
+
+ @Override
+ public Page queryPageByMessageRedoQueryRequestDto(MessageRedoQueryRequestDto requestDto) {
+ MessageRedoQuery query = new MessageRedoQuery();
+ BeanUtils.copyProperties(requestDto, query);
+ IPage messagePage = messageRedoDao.queryByPage(query);
+ if (messagePage == null) {
+ return null;
+ }
+ Page result = new Page<>();
+ result.setPageNum(messagePage.getCurrent());
+ result.setPageSize(messagePage.getSize());
+ result.setTotalElements(messagePage.getTotal());
+ result.setList(messagePage.getRecords());
+ return result;
+ }
+
+ @Override
+ public MessageRedo queryMessageRedoByRedoOrderNoAndPhoneNumber(String redoOrderNo, String bizId, String phoneNumber) {
+ return messageRedoDao.lambdaQuery()
+ .eq(!StringUtils.isEmpty(redoOrderNo),MessageRedo::getRedoOrderNo,redoOrderNo)
+ .eq(!StringUtils.isEmpty(bizId),MessageRedo::getChannelBizId,bizId)
+ .eq(MessageRedo::getTargetAddress,phoneNumber)
+ .eq(MessageRedo::getIsDelete,0)
+ .one();
+ }
+
+ @Override
+ public boolean updateMessageRedoStatusById(Long id, String oldStatus, String newStatus) {
+ messageRedoDao.lambdaUpdate()
+ .set(MessageRedo::getStatus,newStatus)
+ .eq(MessageRedo::getStatus,oldStatus)
+ .eq(MessageRedo::getId,id)
+ .eq(MessageRedo::getIsDelete,0)
+ .update();
+ return false;
+ }
+
+ @Override
+ public void saveByMessage(Message message) {
+ MessageRedo messageRedo = new MessageRedo();
+ messageRedo.setAppNo(message.getAppNo());
+ messageRedo.setRequestNo(message.getRequestNo());
+ messageRedo.setMessageOrderNo(message.getMessageOrderNo());
+ messageRedo.setRedoOrderNo(message.getChannelCode());
+ messageRedo.setMessageType(message.getMessageType());
+ messageRedo.setNotifyType(message.getNotifyType());
+ messageRedo.setStatus(MessageStatusEnum.INIT.getCode());
+ messageRedo.setChannelCode(message.getChannelCode());
+ messageRedo.setChannelName(message.getChannelName());
+ messageRedo.setTemplateNo(message.getTemplateNo());
+ messageRedo.setSubject(message.getSubject());
+ messageRedo.setTargetAddress(message.getTargetAddress());
+ messageRedo.setRetryingFlag(RetryingFlagEnum.N.name());
+ messageRedo.setRetryCount(0);
+ messageRedo.insert();
+ }
+
+ @Override
+ public boolean lockMessage(MessageContext context, Long id) {
+ Integer retryCount = context.getRetryCount() + 1;
+ context.setRetryCount(retryCount);
+ return messageRedoDao.lambdaUpdate()
+ .set(MessageRedo::getRetryCount, retryCount)
+ .set(MessageRedo::getRetryingFlag, RetryingFlagEnum.N.name())
+ .eq(MessageRedo::getId, id).update();
+ }
+
+ @Override
+ public boolean updateRetry(Date retryAt, Long id) {
+ return messageRedoDao.lambdaUpdate()
+ .set(MessageRedo::getRetryAt, retryAt)
+ .set(MessageRedo::getRetryingFlag, RetryingFlagEnum.Y.name())
+ .eq(MessageRedo::getId, id)
+ .update();
+ }
+
+ @Override
+ public boolean updateExceptionToFail(Long id, String messageOrderNo) {
+ return transactionTemplate.execute(status -> {
+ messageRedoDao.updateExceptionToFail(id);
+ return messageDao.updateExceptionToFail(messageOrderNo);
+ });
+ }
+
+ @Override
+ public boolean updateMessageRedoChannelById(Long id, String bizId,String redoMessageNo) {
+ return messageRedoDao.lambdaUpdate()
+ .set(MessageRedo::getChannelBizId, bizId)
+ .set(MessageRedo::getRedoOrderNo,redoMessageNo)
+ .eq(MessageRedo::getId, id)
+ .eq(MessageRedo::getIsDelete,0)
+ .update();
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageRequestLogManagerImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageRequestLogManagerImpl.java
new file mode 100644
index 00000000..7bd3fc51
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageRequestLogManagerImpl.java
@@ -0,0 +1,36 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.dao.entity.MessageRequestLog;
+import cn.axzo.msg.notices.dao.repository.MessageRequestLogDao;
+import cn.axzo.msg.notices.manager.api.MessageRequestLogManager;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * 请求日志处理实现类
+ *
+ * @author zhaoyong_sh
+ * @see MessageRequestLogManagerImpl
+ * @since 2021-05-28 10:51
+ */
+@Service("messageRequestLogManager")
+public class MessageRequestLogManagerImpl implements MessageRequestLogManager {
+
+ @Resource(name = "messageRequestLogDao")
+ private MessageRequestLogDao messageRequestLogDao;
+
+ @Override
+ public Long saveRequestLog(MessageRequestLog requestLog) {
+ messageRequestLogDao.save(requestLog);
+ return requestLog.getId();
+ }
+
+ @Override
+ public boolean updateRequestLog(String responseBody, Long id) {
+ return messageRequestLogDao.lambdaUpdate()
+ .set(MessageRequestLog::getResponseBody, responseBody)
+ .eq(MessageRequestLog::getId, id)
+ .update();
+ }
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageTemplateManagerImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageTemplateManagerImpl.java
new file mode 100644
index 00000000..4e4be921
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageTemplateManagerImpl.java
@@ -0,0 +1,62 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.enums.AvailableStatusEnum;
+import cn.axzo.msg.notices.common.enums.ReturnCodeEnum;
+import cn.axzo.msg.notices.common.exception.BizException;
+import cn.axzo.msg.notices.dao.entity.ChannelMessageTemplate;
+import cn.axzo.msg.notices.dao.entity.MessageTemplate;
+import cn.axzo.msg.notices.dao.repository.ChannelMessageTemplateDao;
+import cn.axzo.msg.notices.dao.repository.MessageTemplateDao;
+import cn.axzo.msg.notices.manager.api.MessageTemplateManager;
+import cn.axzo.msg.notices.manager.api.MessageTemplateParamManager;
+import cn.axzo.msg.notices.manager.api.dto.response.TemplateParamDto;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 消息模板处理实现类
+ *
+ * @author zhaoyong_sh
+ * @see MessageTemplateManagerImpl
+ * @since 2021-05-27 20:26
+ */
+@Service("messageTemplateManager")
+public class MessageTemplateManagerImpl implements MessageTemplateManager {
+
+ @Resource(name = "messageTemplateDao")
+ private MessageTemplateDao messageTemplateDao;
+
+ @Resource(name = "channelMessageTemplateDao")
+ private ChannelMessageTemplateDao channelMessageTemplateDao;
+
+ @Resource(name = "messageTemplateParamManager")
+ private MessageTemplateParamManager messageTemplateParamManager;
+
+ @Override
+ public MessageTemplate queryAndCheckInnerTemplate(String innerTemplateNo) {
+ MessageTemplate messageTemplate = messageTemplateDao.queryByTemplateNo(innerTemplateNo);
+ BizException.error(messageTemplate != null, ReturnCodeEnum.MESSAGE_TEMPLATE_NOT_EXIST);
+ BizException
+ .error(AvailableStatusEnum.AVAILABLE.getStatus().equals(messageTemplate.getStatus()),
+ ReturnCodeEnum.MESSAGE_TEMPLATE_NOT_VALID);
+ return messageTemplate;
+ }
+
+ @Override
+ public ChannelMessageTemplate queryChannelTemplate(String innerTemplateNo, String channelCode) {
+ ChannelMessageTemplate channelMessageTemplate = channelMessageTemplateDao
+ .queryByTemplateNo(innerTemplateNo, channelCode);
+ BizException.error(channelMessageTemplate != null, ReturnCodeEnum.MESSAGE_TEMPLATE_NOT_EXIST);
+ BizException
+ .error(AvailableStatusEnum.AVAILABLE.getStatus().equals(channelMessageTemplate.getStatus()),
+ ReturnCodeEnum.MESSAGE_TEMPLATE_NOT_VALID);
+ return channelMessageTemplate;
+ }
+
+ @Override
+ public List queryTemplateParam(String innerTemplateNo) {
+ return messageTemplateParamManager.getByCode(innerTemplateNo);
+ }
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageTemplateParamManagerImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageTemplateParamManagerImpl.java
new file mode 100644
index 00000000..b7d19b3d
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/MessageTemplateParamManagerImpl.java
@@ -0,0 +1,133 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.utils.KeyUtils;
+import cn.axzo.msg.notices.dao.entity.MessageTemplateParam;
+import cn.axzo.msg.notices.dao.repository.MessageTemplateParamDao;
+import cn.axzo.msg.notices.manager.api.MessageTemplateParamManager;
+import cn.axzo.msg.notices.manager.api.dto.response.TemplateParamDto;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static cn.axzo.msg.notices.common.constans.CacheConstants.*;
+
+/**
+ * 消息模板参数 Manager
+ *
+ * @author zhaoyong
+ * @see MessageTemplateParamManagerImpl
+ * @since 2021-08-20 22:44
+ */
+@Slf4j
+@Service("messageTemplateParamManager")
+public class MessageTemplateParamManagerImpl implements MessageTemplateParamManager {
+
+ @Resource(name = "messageTemplateParamDao")
+ private MessageTemplateParamDao messageTemplateParamDao;
+
+ @Resource(name = "stringRedisTemplate")
+ private StringRedisTemplate stringRedisTemplate;
+
+ @PostConstruct
+ public void init() {
+ List templateParams = messageTemplateParamDao.getAllMessageTemplateParams();
+
+ if(CollectionUtils.isEmpty(templateParams)) {
+ log.info("MessageTemplateParamManager.init message template params size is zero");
+ return;
+ }
+
+ Map> templateParamIndex = templateParams.stream()
+ .map(v -> build(v))
+ .collect(Collectors.groupingBy(v -> getCacheKey(v.getTemplateNo())));
+
+ templateParamIndex.forEach((k, v) -> {
+ // 参数排序
+ List sortedValue = v.stream().sorted(Comparator.comparing(o -> o.getParamOrder(),
+ Comparator.comparingInt(o -> o))).collect(Collectors.toList());
+
+ // 构建缓存
+ buildCache(k, sortedValue);
+ });
+
+ }
+
+ @Override
+ public List getByCode(String templateCode) {
+ // 获取缓存 key
+ String cacheKey = getCacheKey(templateCode);
+
+ // 从缓存中获取对象
+ String value = stringRedisTemplate.opsForValue().get(cacheKey);
+
+ // 不存在对象
+ if(REDIS_NULL_VALUE.equals(value)){
+ return null;
+ }
+
+ // 对象不为空
+ List templateParamInCache = JSON.parseArray(value, TemplateParamDto.class);
+ if(CollectionUtils.isNotEmpty(templateParamInCache)) {
+ return templateParamInCache;
+ }
+
+ // 查询数据库信息
+ List result = messageTemplateParamDao.getByTemplateNo(templateCode);
+ if(result == null) {
+ // 防止缓存恶意穿透
+ stringRedisTemplate.opsForValue().set(cacheKey, REDIS_NULL_VALUE, NULL_VALUE_CACHE_SECONDS, TimeUnit.SECONDS);
+ return null;
+ }
+
+ // 对象转换
+ List paramDtos = result.stream().map(v -> build(v))
+ .collect(Collectors.toList());
+
+ // 构建缓存
+ buildCache(cacheKey, paramDtos);
+
+ return paramDtos;
+ }
+
+ /**
+ * 获取分组 KEY
+ * @param templateNo
+ * @return
+ */
+ private String getCacheKey(String templateNo) {
+ return KeyUtils.getKey(MNS, MESSAGE_TEMPLATE, PARAM, templateNo);
+ }
+
+ /**
+ * 构建缓存
+ * @param cacheKey
+ * @param dtos
+ */
+ private void buildCache(String cacheKey, List dtos){
+ stringRedisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(dtos), TEMPLATE_PARAM_CACHE_SECONDS, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 构建参数
+ * @param param
+ * @return
+ */
+ private TemplateParamDto build(MessageTemplateParam param){
+ return TemplateParamDto.builder()
+ .templateNo(param.getTemplateNo())
+ .paramName(param.getParamName())
+ .paramOrder(param.getParamOrder())
+ .build();
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/RetryStrategyImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/RetryStrategyImpl.java
new file mode 100644
index 00000000..3ffcb704
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/RetryStrategyImpl.java
@@ -0,0 +1,82 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.constans.CommonConstants;
+import cn.axzo.msg.notices.common.domain.MessageContext;
+import cn.axzo.msg.notices.manager.api.RetryStrategy;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 重试策略实现类
+ *
+ * @author zhaoyong_sh
+ * @see RetryStrategyImpl
+ * @since 2021-05-19 10:42
+ */
+@Slf4j
+@Service("retryStrategy")
+public class RetryStrategyImpl implements RetryStrategy {
+
+ @Value("${notice.retry.rule}")
+ private String noticeRetryRule;
+
+ @Override
+ public List getRetryStrategy() {
+ List retryStrategyList = parseRetryStrategy(noticeRetryRule);
+ if(retryStrategyList.size() > CommonConstants.MAX_RETRY_COUNT) {
+ return retryStrategyList.subList(0, CommonConstants.MAX_RETRY_COUNT);
+ }
+ return retryStrategyList;
+ }
+
+ @Override
+ public Integer getNextNotifySecond(MessageContext context) {
+ if(context == null) {
+ return null;
+ }
+ if(context.getRetryCount() == null) {
+ return null;
+ }
+ if(StringUtils.isEmpty(context.getNotifyRule())) {
+ return null;
+ }
+ String notifyRule = context.getNotifyRule();
+ final List notifyRules = Lists.newArrayList();
+ Splitter.on(CommonConstants.COMMA_SYMBOL).split(notifyRule).forEach(e -> notifyRules.add(Integer.parseInt(e)));
+ log.info("notify message get notify rule {}", notifyRules.toString());
+ if(context.getRetryCount() >= notifyRules.size()) {
+ return null;
+ }
+ return notifyRules.get(context.getRetryCount());
+ }
+
+ /**
+ * 解析重试策略
+ * @param notifyRule
+ * @return
+ */
+ private List parseRetryStrategy(String notifyRule) {
+ List delaySeconds = Lists.newArrayList();
+ for(String strategy : notifyRule.split(CommonConstants.COMMA_SYMBOL)){
+ try {
+ int delaySecond = Integer.parseInt(strategy);
+ delaySeconds.add(delaySecond);
+ } catch (Exception e) {
+ delaySeconds.clear();
+ break;
+ }
+ }
+ if(CollectionUtils.isEmpty(delaySeconds)){
+ return Lists.newArrayList(30, 60, 60);
+ }
+ return delaySeconds;
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/SmsSendManagerComposite.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/SmsSendManagerComposite.java
new file mode 100644
index 00000000..c1a47dab
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/SmsSendManagerComposite.java
@@ -0,0 +1,232 @@
+package cn.axzo.msg.notices.manager;
+
+import cn.axzo.msg.notices.common.domain.ServiceContext;
+import cn.axzo.msg.notices.common.domain.ServiceContextHolder;
+import cn.axzo.msg.notices.common.enums.ChannelHandlerEnum;
+import cn.axzo.msg.notices.common.enums.ReturnCodeEnum;
+import cn.axzo.msg.notices.common.exception.BizException;
+import cn.axzo.msg.notices.dao.entity.MessageChannelLog;
+import cn.axzo.msg.notices.manager.api.SmsSendManager;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.response.BatchMessageSendResponseDto;
+import cn.axzo.msg.notices.manager.api.dto.response.SendSmsCommonResponseDto;
+import cn.azxo.framework.common.utils.LogUtil;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+
+/**
+ * 消息发送聚合类
+ *
+ * @author zhaoyong
+ * @see SmsSendManagerComposite
+ * @since 2021-08-19 10:51
+ */
+@Slf4j
+@Component("smsSendManagerComposite")
+public class SmsSendManagerComposite implements SmsSendManager, ApplicationContextAware {
+
+ private ApplicationContext applicationContext;
+
+ @Override
+ public SendSmsCommonResponseDto sendMessage(MessageSendRequestDto request) {
+ // 根据渠道码获取实现类
+ ChannelHandlerEnum handler = ChannelHandlerEnum.getByCode(request.getChannelCode());
+ BizException.error(handler != null, ReturnCodeEnum.SYSTEM_ERROR,
+ "不支持的渠道码:" + request.getChannelCode());
+
+ SmsSendManager sendManager = applicationContext.getBean(handler.getMessage(), SmsSendManager.class);
+
+ // 渲染请求
+ renderRequest(request);
+
+ // 服务上下文
+ ServiceContextHolder.set(new ServiceContext());
+
+ try {
+ // 发送短信
+ SendSmsCommonResponseDto response = sendManager.sendMessage(request);
+
+ // 保存渠道日志
+ saveMessageChannelLog(request, ServiceContextHolder.get().getChannelResponse());
+
+ // 响应结果
+ return response;
+ } catch (BizException e) {
+ LogUtil.error("SmsSendManagerComposite#sendMessage is BizException", e);
+ // 保存渠道日志
+ saveMessageChannelLog(request, e);
+ throw e;
+ } catch (Exception e) {
+ LogUtil.error("SmsSendManagerComposite#sendMessage is Exception", e);
+ // 保存渠道日志
+ saveMessageChannelLog(request, e.getMessage());
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "system error");
+ } finally {
+ ServiceContextHolder.cleanUp();
+ }
+ }
+
+ @Override
+ public BatchMessageSendResponseDto sendBatchMessage(BatchMessageSendRequestDto requestDto) {
+ // 指定渠道
+ ChannelHandlerEnum handler = ChannelHandlerEnum.CHUANG_LAN;
+
+ // 根据渠道码获取实现类
+ SmsSendManager smsSendManager = applicationContext.getBean(handler.getMessage(), SmsSendManager.class);
+
+ // 服务上下文
+ ServiceContextHolder.set(new ServiceContext());
+ try {
+ // 发送短信
+ BatchMessageSendResponseDto response = smsSendManager.sendBatchMessage(requestDto);
+
+ // 保存渠道日志
+ saveMessageChannelLog(requestDto, ServiceContextHolder.get().getChannelResponse());
+
+ // 响应结果
+ return response;
+ } catch (BizException e) {
+ LogUtil.error("SmsSendManagerComposite#sendBatchMessage is BizException", e);
+ // 保存渠道日志
+ saveMessageChannelLog(requestDto, e);
+ throw e;
+ } catch (Exception e) {
+ LogUtil.error("SmsSendManagerComposite#sendBatchMessage is Exception", e);
+ // 保存渠道日志
+ saveMessageChannelLog(requestDto, e.getMessage());
+ throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "system error");
+ } finally {
+ ServiceContextHolder.cleanUp();
+ }
+ }
+
+ /**
+ * 渲染请求
+ * @param request
+ */
+ private void renderRequest(MessageSendRequestDto request) {
+ // 获取模板参数
+ Map templateMap = request.getTemplateMap();
+
+ // 处理短信字符串变量参数超长问题
+ Map renderTemplateMap = handleSmsParamsSize(templateMap);
+
+ // 修改模板参数
+ request.setTemplateMap(renderTemplateMap);
+ }
+
+ /**
+ * 处理短信字符串变量参数超长问题
+ * @param templateMap
+ * @return
+ */
+ private Map handleSmsParamsSize(Map templateMap) {
+ if (CollectionUtils.isEmpty(templateMap)){
+ return templateMap;
+ }
+ Iterator> entries = templateMap.entrySet().iterator();
+
+ while (entries.hasNext()) {
+ Entry entry = entries.next();
+ Object value = entry.getValue();
+ String key = entry.getKey();
+ if (Objects.nonNull(value)){
+ if (value instanceof String){
+ String handledStr = handleSmsVariableSize(String.valueOf(value));
+ templateMap.put(key,handledStr);
+ }
+ }
+ }
+ return templateMap;
+ }
+
+ /**
+ * 处理短信参数长度
+ * @param str
+ * @return
+ */
+ private String handleSmsVariableSize(String str) {
+ if (str != null) {
+ int size = str.length();
+ if ( size <= 25 ) {
+ return str;
+ }
+ return str.substring(0, 22) + "...";
+ }
+ return "";
+ }
+
+ /**
+ * 保存单条短信渠道日志
+ * @param requestDto
+ * @param response
+ * @param response
+ */
+ private void saveMessageChannelLog(MessageSendRequestDto requestDto, Object response) {
+ MessageChannelLog log = new MessageChannelLog();
+ log.setAppNo(requestDto.getAppCode());
+ log.setAppRequestNo(requestDto.getAppRequestNo());
+ log.setMessageOrderNo(requestDto.getRequestChannelNo());
+ log.setTargetAddress(requestDto.getPhoneNo());
+ log.setUpdateAt(new Date());
+ log.setCreateAt(new Date());
+ String responseData = getResponseData(response);
+ log.setResponseData(responseData);
+ log.insert();
+ }
+
+
+
+ /**
+ * 保存批量短信渠道日志
+ * @param requestDto
+ * @param response
+ */
+ private void saveMessageChannelLog(BatchMessageSendRequestDto requestDto, Object response) {
+ MessageChannelLog log = new MessageChannelLog();
+ log.setAppNo(requestDto.getAppCode());
+ log.setAppRequestNo(requestDto.getAppRequestNo());
+ log.setMessageOrderNo(requestDto.getRequestChannelNo());
+ log.setTargetAddress(requestDto.getMessageKey());
+ log.setUpdateAt(new Date());
+ log.setCreateAt(new Date());
+ String responseData = getResponseData(response);
+ log.setResponseData(responseData);
+ log.insert();
+ }
+
+ /**
+ * 获取响应数据
+ * @param response
+ * @return
+ */
+ private String getResponseData(Object response){
+ if(response instanceof BizException) {
+ BizException exception = BizException.class.cast(response);
+ if(exception.getData() != null) {
+ return JSON.toJSONString(exception.getData());
+ } else {
+ return JSON.toJSONString(exception.getMessage());
+ }
+ } else {
+ return JSON.toJSONString(response);
+ }
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/converter/ChuangLanBatchMessageRequestDtoConverter.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/converter/ChuangLanBatchMessageRequestDtoConverter.java
new file mode 100644
index 00000000..9e2d06c0
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/converter/ChuangLanBatchMessageRequestDtoConverter.java
@@ -0,0 +1,37 @@
+package cn.axzo.msg.notices.manager.converter;
+
+import cn.axzo.msg.notices.dao.entity.BatchMessage;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.SmsContentDto;
+import com.alibaba.fastjson.JSON;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+
+import java.util.List;
+
+/**
+ * @Classname ChuangLanBatchMessageRequestDtoConverter
+ * @Author: szg
+ * @Date: 2021年08月10日 11:51
+ * @Description:
+ */
+@Component
+public class ChuangLanBatchMessageRequestDtoConverter implements
+ Converter {
+
+ @Override
+ public BatchMessageSendRequestDto convert(BatchMessage source) {
+ Assert.notNull(source, "source must not be null");
+ BatchMessageSendRequestDto requestDto = new BatchMessageSendRequestDto();
+ requestDto.setAppCode(source.getAppNo());
+ requestDto.setAppRequestNo(source.getRequestNo());
+ requestDto.setRequestChannelNo(source.getMessageOrderNo());
+ requestDto.setInnerTemplateNo(source.getTemplateNo());
+ requestDto.setBatchNo(source.getBatchNo());
+ List dtos = JSON
+ .parseArray(source.getSmsContent(), SmsContentDto.class);
+ requestDto.setSmsContentDtos(dtos);
+ return requestDto;
+ }
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/converter/ChuangLanSmsResponseDtoToVoConverter.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/converter/ChuangLanSmsResponseDtoToVoConverter.java
new file mode 100644
index 00000000..267c868e
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/converter/ChuangLanSmsResponseDtoToVoConverter.java
@@ -0,0 +1,31 @@
+package cn.axzo.msg.notices.manager.converter;
+
+import cn.axzo.msg.notices.integration.dto.response.ChuangLanSmsResponse;
+import cn.axzo.msg.notices.manager.api.dto.response.BatchMessageSendResponseDto;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+
+/**
+ * DTO -> VO
+ *
+ * @author zhaoyong
+ * @see ChuangLanSmsResponseDtoToVoConverter
+ * @since 2021-08-07 20:32
+ */
+@Component
+public class ChuangLanSmsResponseDtoToVoConverter implements Converter {
+
+ @Override
+ public BatchMessageSendResponseDto convert(ChuangLanSmsResponse source) {
+ Assert.notNull(source, "source must not be null");
+ BatchMessageSendResponseDto response = new BatchMessageSendResponseDto();
+ response.setCode(source.getCode());
+ response.setErrorMsg(source.getErrorMsg());
+ response.setSuccessNum(source.getSuccessNum());
+ response.setFailNum(source.getFailNum());
+ response.setMsgId(source.getMsgId());
+ response.setTime(source.getTime());
+ return response;
+ }
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/ApiRequestLogAspect.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/ApiRequestLogAspect.java
new file mode 100644
index 00000000..7caeb0b0
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/ApiRequestLogAspect.java
@@ -0,0 +1,61 @@
+package cn.axzo.msg.notices.manager.support;
+
+import cn.axzo.msg.notices.common.annotation.ApiRequestLog;
+import cn.axzo.msg.notices.dao.entity.MessageRequestLog;
+import cn.axzo.msg.notices.manager.api.MessageRequestLogManager;
+import cn.axzo.msg.notices.manager.api.dto.request.BaseRequestDto;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 切面日志实现类
+ *
+ * @author zhaoyong_sh
+ * @see ApiRequestLogAspect
+ * @since 2021-05-28 10:45
+ */
+@Aspect
+@Slf4j
+@Component
+public class ApiRequestLogAspect {
+
+ @Resource(name = "messageRequestLogManager")
+ private MessageRequestLogManager messageRequestLogManager;
+
+ @Around("@annotation(apiRequestLog)")
+ public Object methodHandler(ProceedingJoinPoint jp, ApiRequestLog apiRequestLog) throws Throwable {
+ Object[] params = jp.getArgs();
+ Object param = params[0];
+ Signature signature = jp.getSignature();
+ // 方法名
+ String methodName = signature.getName();
+ // 类名
+ String typeName = signature.getDeclaringType().getSimpleName();
+ log.info("保存请求日志:{}.{} Begin Request : {}", typeName, methodName, JSON.toJSONString(param));
+ // 保存requestLog
+ BaseRequestDto baseRequestDto = BeanUtil.copyProperties(param, BaseRequestDto.class);
+ MessageRequestLog requestLog = new MessageRequestLog();
+ requestLog.setAppNo(baseRequestDto.getAppCode());
+ requestLog.setRequestNo(baseRequestDto.getRequestNo());
+ requestLog.setMethodName(methodName);
+ requestLog.setRequestBody(JSON.toJSONString(param));
+ Long requestLogId = messageRequestLogManager.saveRequestLog(requestLog);
+ log.info("执行方法");
+ Object result = jp.proceed();
+ if(result != null) {
+ messageRequestLogManager.updateRequestLog(JSON.toJSONString(result), requestLogId);
+ log.info("返回Controller应答:{}", JSONUtil.toJsonStr(result));
+ }
+ return result;
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/ChuangLanMessageContentSupport.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/ChuangLanMessageContentSupport.java
new file mode 100644
index 00000000..25aa84a8
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/ChuangLanMessageContentSupport.java
@@ -0,0 +1,162 @@
+package cn.axzo.msg.notices.manager.support;
+
+import cn.axzo.msg.notices.common.enums.ReturnCodeEnum;
+import cn.axzo.msg.notices.common.exception.BizException;
+import cn.axzo.msg.notices.dao.entity.ChannelMessageTemplate;
+import cn.axzo.msg.notices.manager.api.MessageTemplateParamManager;
+import cn.axzo.msg.notices.manager.api.dto.request.BatchMessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.SmsContentDto;
+import cn.axzo.msg.notices.manager.api.dto.response.TemplateParamDto;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 创兰消息内部解析类
+ *
+ * @author zhaoyong
+ * @see ChuangLanMessageContentSupport
+ * @since 2021-08-19 10:14
+ */
+@Component("chuangLanMessageContentSupport")
+public class ChuangLanMessageContentSupport {
+
+ @Resource(name = "messageTemplateParamManager")
+ private MessageTemplateParamManager messageTemplateParamManager;
+
+ /**
+ * 获取单条消息内容
+ * @param requestDto
+ * @param hasParam
+ * @return
+ */
+ public String getSingleSmsContent(MessageSendRequestDto requestDto
+ , ChannelMessageTemplate template, boolean hasParam){
+ if(hasParam) {
+ return getSingleVariableSmsContent(requestDto, template);
+ } else {
+ return getSingleCommonSmsContent(requestDto);
+ }
+ }
+
+ /**
+ * 获取批量消息内容
+ * @param requestDto
+ * @param hasParam
+ * @return
+ */
+ public String getBatchSmsContent(BatchMessageSendRequestDto requestDto
+ , ChannelMessageTemplate template, boolean hasParam){
+ if(hasParam) {
+ return getBatchVariableSmsContent(requestDto, template);
+ } else {
+ return getBatchCommonSmsContent(requestDto);
+ }
+ }
+
+ /**
+ * 获取相同内容变量接口消息内容
+ * @param requestDto
+ * @return
+ */
+ private String getSingleVariableSmsContent(MessageSendRequestDto requestDto, ChannelMessageTemplate template){
+ // 查询消息模板中的变量名称列表
+ List messageTemplateParams = messageTemplateParamManager.getByCode(template.getInnerTemplateNo());
+ BizException.error(CollectionUtils.isNotEmpty(messageTemplateParams),
+ ReturnCodeEnum.SYSTEM_ERROR, "变量模板顺序参数不能为空");
+
+ // 把对象转换成变量名称字符串列表
+ List paramNames = messageTemplateParams.stream().map(v -> v.getParamName())
+ .collect(Collectors.toList());
+
+ // 定义单条消息中参数列表
+ List singleMessageParams = new ArrayList<>();
+ // 第一个变量一定是手机号
+ String phoneNo = requestDto.getPhoneNo();
+ singleMessageParams.add(phoneNo);
+ // 按照数据库定义的顺序查询模板变量的值
+ for (String paramName : paramNames) {
+ // 获取业务方传入的变量值
+ Object paramValue = requestDto.getTemplateMap().get(paramName);
+ BizException.error(paramValue != null, ReturnCodeEnum.INVALID_PARAMETER, paramName + "不能为空");
+ // 添加到单条消息中参数列表
+ singleMessageParams.add(paramValue.toString());
+ }
+ // 单条消息以逗号拼接成消息体
+ return singleMessageParams.stream().collect(Collectors.joining(","));
+ }
+
+ /**
+ * 获取相同内容群发接口消息内容
+ * @param requestDto
+ * @return
+ */
+ private String getSingleCommonSmsContent(MessageSendRequestDto requestDto) {
+ return requestDto.getPhoneNo();
+ }
+
+ /**
+ * 获取相同内容变量接口消息内容
+ * @param requestDto
+ * @return
+ */
+ private String getBatchVariableSmsContent(BatchMessageSendRequestDto requestDto, ChannelMessageTemplate template){
+ // 查询消息模板中的变量名称列表
+ List messageTemplateParams = messageTemplateParamManager.getByCode(template.getInnerTemplateNo());
+ BizException.error(CollectionUtils.isNotEmpty(messageTemplateParams),
+ ReturnCodeEnum.SYSTEM_ERROR, "变量模板顺序参数不能为空");
+
+ // 把对象转换成变量名称字符串列表
+ List paramNames = messageTemplateParams.stream().map(v -> v.getParamName())
+ .collect(Collectors.toList());
+
+ // 获取请求参数短信内容列表
+ List dtos = requestDto.getSmsContentDtos();
+
+ // 定义单条消息列表,列表内容为 手机号,变量值1,变量值2,变量值3...
+ List singleMessages = new ArrayList<>();
+
+ // 遍历请求参数短信内容列表
+ for (SmsContentDto dto : dtos) {
+ // 定义单条消息中参数列表
+ List singleMessageParams = new ArrayList<>();
+ // 第一个变量一定是手机号
+ String phoneNo = dto.getPhoneNo();
+ singleMessageParams.add(phoneNo);
+ JSONObject templateParams = JSON.parseObject(dto.getTemplateParams());
+ // 按照数据库定义的顺序查询模板变量的值
+ for (String paramName : paramNames) {
+ // 获取业务方传入的变量值
+ String paramValue = templateParams.getString(paramName);
+ // 添加到单条消息中参数列表
+ singleMessageParams.add(paramValue);
+ }
+ // 单条消息以逗号拼接成消息体
+ String singleMessage = singleMessageParams.stream().collect(Collectors.joining(","));
+ singleMessages.add(singleMessage);
+ }
+ // 批量消息以分号拼接
+ return singleMessages.stream().collect(Collectors.joining(";"));
+ }
+
+ /**
+ * 获取相同内容群发接口消息内容
+ * @param requestDto
+ * @return
+ */
+ private String getBatchCommonSmsContent(BatchMessageSendRequestDto requestDto) {
+ // 获取请求参数短信内容列表
+ List dtos = requestDto.getSmsContentDtos();
+
+ // 相同内容群发接口以逗号拼接手机号
+ return dtos.stream().map(v -> v.getPhoneNo()).collect(Collectors.joining(","));
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/ConversionServiceConfig.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/ConversionServiceConfig.java
new file mode 100644
index 00000000..6af5ba9e
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/ConversionServiceConfig.java
@@ -0,0 +1,27 @@
+package cn.axzo.msg.notices.manager.support;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.core.convert.support.GenericConversionService;
+
+import java.util.List;
+
+/**
+ * 自动转换配置类
+ *
+ * @author zhaoyong_sh
+ * @see ConversionServiceConfig
+ * @since 2021-05-27 18:26
+ */
+@Configuration
+public class ConversionServiceConfig {
+
+ @Bean("genericConversionService")
+ public GenericConversionService genericConversionService(List converters){
+ GenericConversionService conversionService = new GenericConversionService();
+ converters.forEach(converter -> conversionService.addConverter(converter));
+ return conversionService;
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/PushOperationAspect.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/PushOperationAspect.java
new file mode 100644
index 00000000..4ac0cc21
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/PushOperationAspect.java
@@ -0,0 +1,99 @@
+package cn.axzo.msg.notices.manager.support;
+
+import cn.axzo.log.platform.client.LogPlatClient;
+import cn.axzo.log.platform.client.model.OperateLogReq;
+import cn.axzo.msg.notices.common.annotation.PushOperation;
+import com.alibaba.fastjson.JSON;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * @author wangli
+ * @since 2022/12/22 10:38
+ */
+@Aspect
+@Component
+public class PushOperationAspect {
+ private static final Logger log = LoggerFactory.getLogger(PushOperationAspect.class);
+ @Autowired
+ private LogPlatClient logPlatClient;
+
+ @Pointcut("@annotation(cn.axzo.msg.notices.common.annotation.PushOperation)")
+ public void pointcut() {
+ }
+
+ @Before("@annotation(operation)")
+ public void before(JoinPoint point, PushOperation operation) {
+ try {
+ OperateLogReq req = OperateLogReq.builder()
+ .serviceName(getHeader("server-app-id"))
+ .featureName(operation.value())
+ .operateTime(new Date())
+ .identityId(0L)
+ .identityUserName("")
+ .identityType(0)
+ .operateBefore("{}")
+ .operateParam(buildRequest(point).toString())
+ .operateAfter("{}")
+ .workspaceId(0L)
+ .operateType(1)
+ .build();
+ logPlatClient.createOperateLog(req);
+ }catch (Exception e){
+ log.warn("无法正常调用日志管理服务: {}", e.getMessage());
+ }
+ }
+
+ /**
+ * 获取Http头中的header
+ *
+ * @return String
+ */
+ public static String getHeader(String headerName) {
+ HttpServletRequest request = getRequest();
+ return Objects.requireNonNull(request).getHeader(headerName);
+ }
+
+ /**
+ * 获取HttpRequest
+ *
+ * @return HttpServletRequest
+ */
+ public static HttpServletRequest getRequest() {
+ ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ if (Objects.nonNull(requestAttributes)) {
+ return requestAttributes.getRequest();
+ }
+ return null;
+ }
+
+ private static StringBuilder buildRequest(JoinPoint point) {
+ LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
+ String[] parameterNames = u.getParameterNames(((MethodSignature) point.getSignature()).getMethod());
+ Object[] args = point.getArgs();
+ StringBuilder sb = new StringBuilder();
+ if (args != null && parameterNames != null) {
+ for (int i = 0; i < args.length; i++) {
+ sb.append(parameterNames[i]);
+ sb.append("=");
+ sb.append(JSON.toJSONString(args[i]));
+ }
+ }
+ return sb;
+ }
+
+}
diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/UserCellphoneProperties.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/UserCellphoneProperties.java
new file mode 100644
index 00000000..9c56559a
--- /dev/null
+++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/notices/manager/support/UserCellphoneProperties.java
@@ -0,0 +1,34 @@
+package cn.axzo.msg.notices.manager.support;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 用户手机配置类
+ *
+ * @author zhaoyong
+ * @see UserCellphoneProperties
+ * @since 2021-07-12 16:34
+ */
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "user.cellphone")
+@RefreshScope
+public class UserCellphoneProperties {
+
+ /**
+ * 白名单
+ */
+ private List whitelist = new ArrayList<>();
+
+ /**
+ * 黑名单
+ */
+ private List blacklist = new ArrayList<>();
+
+}
diff --git a/msg-notices/msg-notices-service-api/pom.xml b/msg-notices/msg-notices-service-api/pom.xml
new file mode 100644
index 00000000..b3797524
--- /dev/null
+++ b/msg-notices/msg-notices-service-api/pom.xml
@@ -0,0 +1,44 @@
+
+
+
+ msg-notices
+ cn.axzo.msgcenter
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ cn.axzo.msg.notices.service.api
+ msg-notices-service-api
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ cn.axzo.msg.notices.common
+ msg-notices-common
+
+
+ cn.axzo.msg.notices.manager.api
+ msg-notices-manager-api
+
+
+ cn.axzo.msg.notices.manager.api
+ msg-notices-manager-api
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.common
+ msg-notices-common
+ 1.0.0-SNAPSHOT
+ compile
+
+
+
\ No newline at end of file
diff --git a/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/MessageCallbackService.java b/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/MessageCallbackService.java
new file mode 100644
index 00000000..c741b0e4
--- /dev/null
+++ b/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/MessageCallbackService.java
@@ -0,0 +1,29 @@
+package cn.axzo.msg.notices.service.api;
+
+import cn.axzo.msg.notices.manager.api.dto.request.AliMessageCallbackRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.ChuangLanSmsReportRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.response.AliCallbackResponseDto;
+import cn.axzo.msg.notices.manager.api.dto.response.ChuangLanCallbackResponseDto;
+
+import java.util.List;
+
+/**
+ * 消息回调处理
+ */
+public interface MessageCallbackService {
+
+ /**
+ * 阿里云短信回调处理
+ * @param request
+ * @return
+ */
+ AliCallbackResponseDto aliCallbackHandle(List request);
+
+ /**
+ * 创蓝短信回调处理
+ * @param request
+ * @return
+ */
+ ChuangLanCallbackResponseDto chuangLanCallbackHandle(ChuangLanSmsReportRequestDto request);
+
+}
diff --git a/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/MessageService.java b/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/MessageService.java
new file mode 100644
index 00000000..621cec7f
--- /dev/null
+++ b/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/MessageService.java
@@ -0,0 +1,26 @@
+package cn.axzo.msg.notices.service.api;
+
+import cn.axzo.msg.notices.manager.api.dto.request.SendBatchMessageRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.SendMessageRequestDto;
+
+/**
+ * 消息服务
+ * @Author: LiuYang
+ * @Date: 2021/5/20 13:53
+ */
+public interface MessageService {
+
+ /**
+ * 发送消息
+ * @param request
+ * @return
+ */
+ void sendMessage(SendMessageRequestDto request);
+
+ /**
+ * 批量发送短信
+ * @param request
+ */
+ void sendBatchMessage(SendBatchMessageRequestDto request);
+
+}
diff --git a/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/PlatService.java b/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/PlatService.java
new file mode 100644
index 00000000..badf9941
--- /dev/null
+++ b/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/PlatService.java
@@ -0,0 +1,32 @@
+package cn.axzo.msg.notices.service.api;
+
+
+import cn.axzo.msg.notices.common.lang.Page;
+import cn.axzo.msg.notices.manager.api.dto.request.plat.CreateTemplateRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.plat.QueryTemplateRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.response.plat.QueryTemplateResponseDto;
+
+public interface PlatService {
+
+ /*
+ * 创建短信模板
+ */
+ void createTemplate(CreateTemplateRequestDto request);
+
+ /**
+ * 通过短信模板获取模板信息
+ */
+ QueryTemplateResponseDto getByTemplateNo(String templateNo);
+
+ /**
+ * 分页查询
+ * @param request
+ * @return
+ */
+ Page list(QueryTemplateRequestDto request);
+
+ /*
+ * 删除短信模板
+ */
+ void delete(String templateNo);
+}
diff --git a/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/TaskService.java b/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/TaskService.java
new file mode 100644
index 00000000..01449419
--- /dev/null
+++ b/msg-notices/msg-notices-service-api/src/main/java/cn/axzo/msg/notices/service/api/TaskService.java
@@ -0,0 +1,61 @@
+package cn.axzo.msg.notices.service.api;
+
+import cn.azxo.framework.common.model.JobPageRequest;
+
+/**
+ * 定时任务服务类
+ *
+ * @author zhaoyong_sh
+ * @see TaskService
+ * @since 2021-05-19 15:47
+ */
+public interface TaskService {
+
+ /**
+ * 处理短信发送异常(阿里云)
+ * @param request
+ */
+ void aliYunProcessSendMessageException(JobPageRequest request);
+
+ /**
+ * 发送中的短信补偿(阿里云)
+ * @param request
+ */
+ void aliYunMessageProcessingHandle(JobPageRequest request);
+
+ /**
+ * 短信拆分发送批次
+ * @param request
+ */
+ void batchMessageRequestSplitHandle(JobPageRequest request);
+
+ /**
+ * 短信发送批次拆分
+ */
+ void batchMessageSendSplitHandle(JobPageRequest request);
+
+ /**
+ * 按照批次批量发送消息
+ * @param request
+ */
+ void batchSendMessage(JobPageRequest request);
+
+ /**
+ * 实时批量消息请求拆分补偿任务
+ * @param request
+ */
+ void realBatchMessageRequestSplitCompensation(JobPageRequest request);
+
+ /**
+ * 实时批量消息拆分补偿任务
+ * @param request
+ */
+ void realBatchMessageSplitCompensation(JobPageRequest request);
+
+ /**
+ * 批量请求计数补偿
+ * @param request
+ */
+ void batchMessageRequestCountCompensation(JobPageRequest request);
+
+}
diff --git a/msg-notices/msg-notices-service/pom.xml b/msg-notices/msg-notices-service/pom.xml
new file mode 100644
index 00000000..4623dad4
--- /dev/null
+++ b/msg-notices/msg-notices-service/pom.xml
@@ -0,0 +1,79 @@
+
+
+
+ msg-notices
+ cn.axzo.msgcenter
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ cn.axzo.msg.notices.service
+ msg-notices-service
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ cn.axzo.msg.notices.service.api
+ msg-notices-service-api
+
+
+ cn.axzo.msg.notices.manager
+ msg-notices-manager
+
+
+ org.springframework.cloud
+ spring-cloud-context
+
+
+ cn.axzo.msg.notices.service.api
+ msg-notices-service-api
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.dao
+ msg-notices-dao
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.manager.api
+ msg-notices-manager-api
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.manager.api
+ msg-notices-manager-api
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.integration
+ msg-notices-integration
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.manager
+ msg-notices-manager
+ 1.0.0-SNAPSHOT
+ compile
+
+
+ cn.axzo.msg.notices.manager
+ msg-notices-manager
+ 1.0.0-SNAPSHOT
+ compile
+
+
+
+
\ No newline at end of file
diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/notices/service/MessageCallbackServiceImpl.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/notices/service/MessageCallbackServiceImpl.java
new file mode 100644
index 00000000..39045235
--- /dev/null
+++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/notices/service/MessageCallbackServiceImpl.java
@@ -0,0 +1,280 @@
+package cn.axzo.msg.notices.service;
+
+import cn.axzo.msg.notices.common.constans.ChuangLanConstants;
+import cn.axzo.msg.notices.common.domain.BatchMessageCountContext;
+import cn.axzo.msg.notices.common.enums.BatchMessageStatusEnum;
+import cn.axzo.msg.notices.common.enums.MessageSendTypeEnum;
+import cn.axzo.msg.notices.common.enums.MessageStatusEnum;
+import cn.axzo.msg.notices.dao.entity.BatchMessage;
+import cn.axzo.msg.notices.dao.entity.Message;
+import cn.axzo.msg.notices.dao.entity.MessageRedo;
+import cn.axzo.msg.notices.dao.repository.BatchMessageDao;
+import cn.axzo.msg.notices.dao.repository.MessageChannelLogDao;
+import cn.axzo.msg.notices.dao.repository.MessageDao;
+import cn.axzo.msg.notices.manager.api.MessageManager;
+import cn.axzo.msg.notices.manager.api.MessageRedoManger;
+import cn.axzo.msg.notices.manager.api.dto.request.AliMessageCallbackRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.ChuangLanSmsReportRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.response.AliCallbackResponseDto;
+import cn.axzo.msg.notices.manager.api.dto.response.ChuangLanCallbackResponseDto;
+import cn.axzo.msg.notices.service.api.MessageCallbackService;
+import cn.azxo.framework.common.utils.LogUtil;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionSynchronizationAdapter;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.transaction.support.TransactionTemplate;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author: szg
+ * @Date: 2021/5/28 15:49
+ * @Description: 处理回执消息
+ */
+@Slf4j
+@Service("messageCallbackService")
+public class MessageCallbackServiceImpl implements MessageCallbackService {
+
+ @Resource(name = "messageManager")
+ private MessageManager messageManager;
+
+ @Resource(name = "messageRedoManger")
+ private MessageRedoManger messageRedoManger;
+
+ @Resource(name = "messageDao")
+ private MessageDao messageDao;
+
+ @Resource(name = "messageChannelLogDao")
+ private MessageChannelLogDao messageChannelLogDao;
+
+ @Resource(name = "batchMessageDao")
+ private BatchMessageDao batchMessageDao;
+
+ @Resource(name = "transactionTemplate")
+ private TransactionTemplate transactionTemplate;
+
+ @Override
+ public AliCallbackResponseDto aliCallbackHandle(List request) {
+ log.info("MessageCallbackServiceImpl.aliCallbackHandle callback request {}", JSON.toJSONString(request));
+ if (CollectionUtils.isEmpty(request)) {
+ log.info("MessageCallbackServiceImpl.aliCallbackHandle callback request is null");
+ return AliCallbackResponseDto.success();
+ }
+
+ for (AliMessageCallbackRequestDto messageInfo : request) {
+ if (Objects.isNull(messageInfo)) {
+ log.info("MessageCallbackServiceImpl.aliCallbackHandle callback message is null");
+ continue;
+ }
+ log.info("MessageCallbackServiceImpl.aliCallbackHandle callback message is {}", JSON.toJSONString(messageInfo));
+ String messageStatus = MessageStatusEnum.getSuccessCode(messageInfo.getSuccess());
+
+ try {
+ transactionTemplate.executeWithoutResult(status -> {
+ Message message =
+ messageManager.queryMessageByMessageOrderNoAndPhoneNumber(
+ messageInfo.getOut_id(), messageInfo.getBiz_id(), messageInfo.getPhone_number());
+ if (Objects.nonNull(message)) {
+ // 第一次回调
+ log.info("MessageCallbackServiceImpl.aliCallbackHandle callback message is first");
+ messageManager.updateProcessingMessageStatusById(message.getId(), messageStatus);
+ } else {
+ log.info("MessageCallbackServiceImpl.aliCallbackHandle callback message is retry");
+ // 重试
+ sendRetryHandle(messageInfo, messageStatus);
+ }
+ });
+ } catch (Exception e) {
+ LogUtil.error("MessageCallbackServiceImpl.aliCallbackHandle is error", e);
+ }
+ }
+ return AliCallbackResponseDto.success();
+ }
+
+ @Override
+ public ChuangLanCallbackResponseDto chuangLanCallbackHandle(
+ ChuangLanSmsReportRequestDto request) {
+ if (Objects.isNull(request)) {
+ log.info("MessageCallbackServiceImpl.chuangLanCallbackHandle request is null");
+ return ChuangLanCallbackResponseDto.success();
+ }
+ log.info("MessageCallbackServiceImpl.chuangLanCallbackHandle request is {}", JSON.toJSONString(request));
+
+ try {
+ if(MessageSendTypeEnum.SINGLE.getCode().equals(request.getUid())) {
+ transactionTemplate.executeWithoutResult(status -> {
+ Message message = messageDao
+ .getByChannelMsgId(request.getMsgid(), request.getMobile());
+ if (Objects.isNull(message)) {
+ log.info("创蓝短信回调 MessageCallbackServiceImpl.chuangLanCallbackHandle message is null");
+ return;
+ }
+ String messageStatus = MessageStatusEnum.FAIL.getCode();
+ if (Objects.equals(request.getStatus(), ChuangLanConstants.MESSAGE_CALLBACK_SUCCESS_STATUS)) {
+ messageStatus = MessageStatusEnum.SUCCESS.getCode();
+ }
+ messageDao
+ .updateStatusAndRemarkById(message.getId(), messageStatus, request.getStatusDesc());
+
+ messageChannelLogDao.updateCallbackDate(JSON.toJSONString(request), message.getMessageOrderNo());
+ });
+ } else {
+ transactionTemplate.executeWithoutResult(status -> {
+ BatchMessage batchMessage = batchMessageDao.getByChannelMsgIdAndLock(request.getMsgid());
+ if (Objects.isNull(batchMessage)) {
+ log.info("MessageCallbackServiceImpl.chuangLanCallbackHandle batchMessage is null");
+ return;
+ }
+ log.info("MessageCallbackServiceImpl.chuangLanCallbackHandle batchMessage is {}",
+ JSON.toJSONString(batchMessage));
+ //回调成功处理
+ Message message = messageDao
+ .getByBatchNoAndPhone(batchMessage.getBatchNo(), request.getMobile());
+ if (Objects.isNull(message)) {
+ log.info("创蓝短信回调 MessageCallbackServiceImpl.chuangLanCallbackHandle message is null");
+ return;
+ }
+ //更新message 和 batchMessage 表
+ updateMessageAndBatchMessage(request, message, batchMessage);
+ });
+ }
+ } catch (Exception e) {
+ LogUtil.error("MessageCallbackServiceImpl.chuangLanCallbackHandle is error", e);
+ }
+
+ return ChuangLanCallbackResponseDto.success();
+ }
+
+ /**
+ * 修改 batch_message 和 message
+ * @param request
+ * @param message
+ * @param batchMessage
+ */
+ private void updateMessageAndBatchMessage(ChuangLanSmsReportRequestDto request, Message message,
+ BatchMessage batchMessage) {
+ log.info("MessageCallbackServiceImpl.updateMessageAndBatchMessage batchMessage is {}",
+ batchMessage);
+ log.info("MessageCallbackServiceImpl.updateMessageAndBatchMessage message is {}", message);
+ //处理message相关
+ handleMessageAndBatchMessageInfo(request, message, batchMessage);
+ //当前批次已经全部回调完成发送消息更新上游状态
+ if (Objects.equals(batchMessage.getBatchSize(),
+ batchMessage.getSuccessCount() + batchMessage.getFailCount())) {
+ //事务提交后发送消息
+ log.info(
+ "MessageCallbackServiceImpl.updateMessageAndBatchMessage 消息批次处理完成发送mq消息 batchMessage is {}",
+ JSON.toJSONString(batchMessage));
+ doAfterCommit(batchMessage);
+ }
+ }
+
+ /**
+ * 事务提交后操作(必须依赖事务)
+ *
+ * @param batchMessage
+ */
+ private void doAfterCommit(BatchMessage batchMessage) {
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
+ @Override
+ public void afterCommit() {
+ sendCountMessageToMq(batchMessage);
+ }
+ });
+ }
+
+ /**
+ * 发送消息到 MQ
+ * @param batchMessage
+ */
+ private void sendCountMessageToMq(BatchMessage batchMessage) {
+ BatchMessageCountContext context = new BatchMessageCountContext();
+ context.setAppCode(batchMessage.getAppNo());
+ context.setAppRequestNo(batchMessage.getRequestNo());
+ context.setBatchNo(batchMessage.getBatchNo());
+ context.setSuccessNum(batchMessage.getSuccessCount());
+ context.setFailNum(batchMessage.getFailCount());
+ // remove rocketmq
+ }
+
+ /**
+ * 处理 batch_message 和 message
+ * @param request
+ * @param message
+ * @param batchMessage
+ */
+ private void handleMessageAndBatchMessageInfo(ChuangLanSmsReportRequestDto request,
+ Message message,
+ BatchMessage batchMessage) {
+ Integer successCount = 0;
+ Integer failCount = 1;
+ String messageStatus = MessageStatusEnum.FAIL.getCode();
+ if (Objects.equals(request.getStatus(), ChuangLanConstants.MESSAGE_CALLBACK_SUCCESS_STATUS)) {
+ messageStatus = MessageStatusEnum.SUCCESS.getCode();
+ successCount = 1;
+ failCount = 0;
+ }
+
+ successCount = batchMessage.getSuccessCount() + successCount;
+ failCount = batchMessage.getFailCount() + failCount;
+
+ //上层发送mq消息时会用到
+ batchMessage.setSuccessCount(successCount);
+ batchMessage.setFailCount(failCount);
+
+ //处理BatchMessage状态
+ Integer batchMessageStatus = handBatchMessageStatus(batchMessage, failCount,successCount);
+ boolean updateRes = messageDao
+ .updateStatusAndRemarkById(message.getId(), messageStatus, request.getStatusDesc());
+ //更新BachMessage
+ if (updateRes) {
+ batchMessageDao
+ .updateBachMessageInfoById(batchMessage.getId(), batchMessageStatus, successCount,
+ failCount);
+ }
+ }
+
+ /**
+ * 修改 batch_message 状态
+ * @param batchMessage
+ * @param failCount
+ * @param successCount
+ * @return
+ */
+ private Integer handBatchMessageStatus(BatchMessage batchMessage, Integer failCount,
+ Integer successCount) {
+
+ Integer batchMessageStatus = BatchMessageStatusEnum.PARTIAL_SUCCESS.getCode();
+ if (Objects.equals(successCount, batchMessage.getBatchSize())) {
+ //全部成功
+ batchMessageStatus = BatchMessageStatusEnum.SEND_SUCCESS.getCode();
+ } else if (Objects.equals(failCount, batchMessage.getBatchSize())) {
+ //还未全部完成回调 部分成功
+ batchMessageStatus = BatchMessageStatusEnum.ALL_FAILED.getCode();
+ }
+ return batchMessageStatus;
+ }
+
+ /**
+ * 消息重试
+ * @param messageInfo
+ * @param status
+ */
+ private void sendRetryHandle(AliMessageCallbackRequestDto messageInfo, String status) {
+ MessageRedo messageRedo =
+ messageRedoManger.queryMessageRedoByRedoOrderNoAndPhoneNumber(
+ messageInfo.getOut_id(), messageInfo.getBiz_id(), messageInfo.getPhone_number());
+ if (Objects.nonNull(messageRedo)) {
+ messageRedoManger
+ .updateMessageRedoStatusById(messageRedo.getId(), MessageStatusEnum.EXCEPTION.getCode(),
+ status);
+ messageManager.updateMessageStatusByMessageOrderNo(messageRedo.getMessageOrderNo(), status);
+ }
+ }
+
+}
diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/notices/service/MessageServiceImpl.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/notices/service/MessageServiceImpl.java
new file mode 100644
index 00000000..90fbfe76
--- /dev/null
+++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/notices/service/MessageServiceImpl.java
@@ -0,0 +1,502 @@
+package cn.axzo.msg.notices.service;
+
+import cn.axzo.msg.notices.common.annotation.ApiRequestLog;
+import cn.axzo.msg.notices.common.constans.CommonConstants;
+import cn.axzo.msg.notices.common.domain.BatchMessageSendContext;
+import cn.axzo.msg.notices.common.domain.MessageContext;
+import cn.axzo.msg.notices.common.enums.*;
+import cn.axzo.msg.notices.common.exception.BizException;
+import cn.axzo.msg.notices.common.utils.DateUtils;
+import cn.axzo.msg.notices.dao.entity.*;
+import cn.axzo.msg.notices.dao.repository.MessageAppDao;
+import cn.axzo.msg.notices.integration.client.DingDingClient;
+import cn.axzo.msg.notices.manager.api.*;
+import cn.axzo.msg.notices.manager.api.dto.request.MessageSendRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.SendBatchMessageRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.SendMessageRequestDto;
+import cn.axzo.msg.notices.manager.api.dto.request.SmsContentDto;
+import cn.axzo.msg.notices.manager.api.dto.response.SendSmsCommonResponseDto;
+import cn.axzo.msg.notices.manager.api.dto.response.TemplateParamDto;
+import cn.axzo.msg.notices.manager.support.UserCellphoneProperties;
+import cn.axzo.msg.notices.service.api.MessageService;
+import cn.azxo.framework.common.logger.MethodAroundLog;
+import cn.azxo.framework.common.utils.LogUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.PhoneUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.stream.Collectors;
+
+/**
+ * 消息服务
+ *
+ * @Author: LiuYang
+ * @Date: 2021/5/20 18:23
+ */
+@Slf4j
+@Service
+@RefreshScope
+public class MessageServiceImpl implements MessageService, EnvironmentAware {
+
+ @Resource(name = "messageAppDao")
+ private MessageAppDao messageAppDao;
+
+ @Resource(name = "messageTemplateManager")
+ private MessageTemplateManager messageTemplateManager;
+
+ @Resource(name = "messageManager")
+ private MessageManager messageManager;
+
+ @Resource(name = "messageChannelRoute")
+ private MessageChannelRouter messageChannelRouter;
+
+ @Resource(name = "retryStrategy")
+ private RetryStrategy retryStrategy;
+
+ @Resource(name = "smsSendManagerComposite")
+ private SmsSendManager smsSendManagerComposite;
+
+ @Resource(name = "batchMessageRequestManger")
+ private BatchMessageRequestManger batchMessageRequestManger;
+
+ @Resource(name = "dingDingClient")
+ private DingDingClient dingDingClient;
+
+ @Resource(name = "userCellphoneProperties")
+ private UserCellphoneProperties userCellphoneProperties;
+
+ @Value("${prod.profile.string:master}")
+ private String prodProfileString;
+
+ @Value("${enable.send.single.message:0}")
+ private Integer enableSendSingleMessage;
+
+ @Value("${enable.send.batch.message:1}")
+ private Integer enableSendBatchMessage;
+
+ private Environment environment;
+
+ @Override
+ @ApiRequestLog
+ @MethodAroundLog(source = "Controller", target = "Service", value = "发送单条短信")
+ public void sendMessage(SendMessageRequestDto request) {
+ log.info("[MessageServiceImpl#sendMessage] request starting {}", JSON.toJSONString(request));
+
+ try {
+ // 检查上游是否可调用
+ checkAppCode(request.getAppCode());
+
+ //手机号格式校验
+ boolean isLegalPhone = PhoneUtil.isPhone(request.getPhoneNo());
+ BizException.error(isLegalPhone, ReturnCodeEnum.INVALID_PARAMETER, "非法的手机号:" + request.getPhoneNo());
+
+ // 查询并校验
+ MessageTemplate messageTemplate = messageTemplateManager
+ .queryAndCheckInnerTemplate(request.getTemplateNo());
+
+ // 通过路由获取可用消息渠道
+ String condition = getChannelRouteCondition(request);
+ MessageChannel messageChannel = messageChannelRouter.route(condition);
+ BizException.error(messageChannel != null, ReturnCodeEnum.MESSAGE_CHANNEL_NOT_VALID);
+ log.info("[MessageServiceImpl#sendMessage] 选择渠道为 {}", JSON.toJSONString(messageChannel));
+
+ // 生成短信记录
+ Message message = initMessage(request, messageChannel, messageTemplate);
+ log.info("[MessageServiceImpl#sendMessage] 生成短信模板 {}", JSON.toJSONString(message));
+
+ // 保存消息
+ messageManager.saveMessage(message);
+
+ // 如果模拟发短信成功,则直接设置状态并为成功
+ if (shouldSkip(request)) {
+ successMessageAndSendDingDing(request, message, messageTemplate);
+ return;
+ }
+
+ // 获取真实短信模板
+ ChannelMessageTemplate channelTemplate = messageTemplateManager
+ .queryChannelTemplate(request.getTemplateNo(), messageChannel.getChannelCode());
+
+ // 发送短信
+ try {
+ MessageSendRequestDto dto = new MessageSendRequestDto();
+ dto.setAppCode(request.getAppCode());
+ dto.setChannelCode(message.getChannelCode());
+ dto.setPhoneNo(message.getTargetAddress());
+ dto.setInnerTemplateNo(messageTemplate.getTemplateNo());
+ dto.setTemplateNo(channelTemplate.getTemplateNo());
+ dto.setTemplateMap(request.getParams());
+ dto.setAppRequestNo(message.getRequestNo());
+ dto.setRequestChannelNo(message.getMessageOrderNo());
+ SendSmsCommonResponseDto response = smsSendManagerComposite.sendMessage(dto);
+ messageManager.updateToProcessing(response.getBizId(), response.getRequestId(), message.getId());
+ } catch (BizException e) {
+ messageManager.updateToFail(message.getId());
+ throw e;
+ }
+ } catch (Exception e) {
+ dingDingClient.notifySingleMessage(request.getTemplateNo(), request.getRequestNo(), e.getMessage());
+ throw e;
+ }
+ }
+
+ @Override
+ @MethodAroundLog(source = "Controller", target = "Service", value = "发送批量短信", requestExcludeName = {"smsContentDtos"})
+ public void sendBatchMessage(SendBatchMessageRequestDto request) {
+ // 检查上游是否可调用
+ checkAppCode(request.getAppCode());
+
+ // 过滤重复手机号
+ List filterContentDtos = filterMobileRepeated(request);
+
+ // 获取重复手机号条数
+ int repeatNum = getRepeatedNum(request, filterContentDtos);
+
+ // 查询并校验
+ MessageTemplate messageTemplate = messageTemplateManager.queryAndCheckInnerTemplate(request.getTemplateNo());
+
+ // 验证请求参数
+ if(messageTemplate.hasParam()) {
+ checkTemplateParam(request);
+ }
+
+ // 保存批量短信请求
+ BatchMessageRequest entity = saveBatchMessageRequest(request, filterContentDtos, repeatNum);
+
+ // 是否允许发送批量消息
+ if(YesNoEnum.NO.getCode().equals(enableSendBatchMessage)) {
+ // 更新批量消息请求为成功
+ batchMessageRequestManger.updateRequestSuccess(CommonConstants.MOCK_CHANNEL, entity.getId());
+ return;
+ }
+
+ // 实时直接发送 MQ
+ if(BatchSendTypeEnum.isRealtime(request.getSendType())) {
+ sendToMQ(request);
+ }
+ }
+
+ /**
+ * 设置消息成功,如果是验证码消息发送钉钉消息
+ * @param request
+ * @param message
+ * @param template
+ */
+ private void successMessageAndSendDingDing(SendMessageRequestDto request,
+ Message message, MessageTemplate template) {
+ message.setStatus(MessageStatusEnum.SUCCESS.getCode());
+ message.setChannelCode(CommonConstants.MOCK_CHANNEL);
+ message.setChannelName(CommonConstants.MOCK_CHANNEL);
+ message.updateById();
+
+ String messageContent = parse(template.getTemplateContent(), request.getParams());
+ dingDingClient.notifyMockMessage(request.getPhoneNo(), template.getTitle(), messageContent);
+ }
+
+ /**
+ * 过滤重复手机号数据
+ * @param request
+ */
+ private List filterMobileRepeated(SendBatchMessageRequestDto request) {
+ List contentDtos = request.getSmsContentDtos();
+ if(CollectionUtils.isEmpty(contentDtos)) {
+ throw new BizException(ReturnCodeEnum.INVALID_PARAMETER, "短信内容不能为空");
+ }
+ return contentDtos.stream()
+ .filter(distinctByKey(dto -> dto.getPhoneNo()))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * 过滤函数
+ * @param keyExtractor
+ * @param
+ * @return
+ */
+ private Predicate distinctByKey(Function super T, ?> keyExtractor) {
+ Map