diff --git a/inside-notices/pom.xml b/inside-notices/pom.xml
index fc0a36ac..7d64c516 100644
--- a/inside-notices/pom.xml
+++ b/inside-notices/pom.xml
@@ -110,6 +110,11 @@
1.0.0-SNAPSHOT
compile
+
+
+ cn.axzo.pokonyan
+ pokonyan
+
\ No newline at end of file
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java
index 564597ea..9fdc269d 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java
@@ -29,9 +29,8 @@ public class MessageTemplateController implements MessageTemplateClient {
@Override
public CommonResponse save(MessageTemplateCreateRequest request) {
- MessageTemplateCreateParam param = MessageTemplateCreateParam.from(request);
- messageTemplateNewService.createTemplate(param);
- return CommonResponse.success(param.getTemplateCode());
+ return CommonResponse.success(
+ messageTemplateNewService.createTemplate(MessageTemplateCreateParam.from(request)));
}
@Override
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PendingMessageNewController.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PendingMessageNewController.java
index 90d07020..f825ad98 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PendingMessageNewController.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PendingMessageNewController.java
@@ -1,6 +1,6 @@
package cn.axzo.msg.center.message.controller;
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
+import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeStatisticDTO;
import cn.axzo.msg.center.message.domain.dto.PendingMessageDTO;
import cn.axzo.msg.center.message.domain.param.MessageGroupNodeStatisticParam;
import cn.axzo.msg.center.message.domain.param.PendingMessagePushParam;
@@ -36,10 +36,10 @@ public class PendingMessageNewController implements PendingMessageClient {
@Override
public CommonResponse> groupStatistic(MessageGroupNodeStatisticRequest request) {
- List groupNodes = pendingMessageNewService
+ List groupNodes = pendingMessageNewService
.groupStatistic(MessageGroupNodeStatisticParam.from(request));
return CommonResponse.success(groupNodes.stream()
- .map(MessageGroupNodeDTO::toResponse)
+ .map(MessageGroupNodeStatisticDTO::toResponse)
.collect(Collectors.toList())
);
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/GroupTreeNodePathDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/GroupTreeNodePathDTO.java
new file mode 100644
index 00000000..ad2d43b4
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/GroupTreeNodePathDTO.java
@@ -0,0 +1,58 @@
+package cn.axzo.msg.center.message.domain.dto;
+
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import com.alibaba.fastjson.JSON;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+@Setter
+@Getter
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+public class GroupTreeNodePathDTO implements Serializable {
+
+ private static final long serialVersionUID = -6325338437781927201L;
+
+ private static final String NODE_NAME_PATH_SPLITER = "/";
+ private static final String NODE_CODE_PATH_SPLITER = ":";
+
+ /**
+ * 结点编码
+ */
+ private String nodeCode;
+ /**
+ * 结点名称格式的路径
+ */
+ private String nodeNamePath;
+ /**
+ * 结点编码格式的路径
+ */
+ private String nodeCodePath;
+
+ public static GroupTreeNodePathDTO of(String nodeCode, Collection nodes) {
+ String nodeNamePath = formatPath(GroupTreeNodeDTO::getNodeName, nodes, NODE_NAME_PATH_SPLITER);
+ String nodeCodePath = formatPath(GroupTreeNodeDTO::getNodeCode, nodes, NODE_CODE_PATH_SPLITER);
+ return new GroupTreeNodePathDTO(nodeCode, nodeNamePath, nodeCodePath);
+ }
+
+ private static String formatPath(Function pathFunc, Collection nodes,
+ String spliter) {
+ return nodes.stream().map(pathFunc).collect(Collectors.joining(spliter));
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeDTO.java
deleted file mode 100644
index 37bd6303..00000000
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeDTO.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package cn.axzo.msg.center.message.domain.dto;
-
-import cn.axzo.core.utils.converter.BeanConverter;
-import cn.axzo.msg.center.domain.entity.MessageGroupNode;
-import cn.axzo.msg.center.service.enums.MessageGroupNodeCategoryEnum;
-import cn.axzo.msg.center.service.pending.response.MessageGroupNodeResponse;
-import com.alibaba.fastjson.JSON;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-
-import java.io.Serializable;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @description
- * 消息分类结点DTO
- *
- * @author cold_blade
- * @date 2023/9/26
- * @version 1.0
- */
-@Setter
-@Getter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MessageGroupNodeDTO implements Serializable {
-
- private static final long serialVersionUID = 5171436359992401120L;
-
- /**
- * 结点类型
- * GENERAL_MESSAGE_CENTER: 消息中心
- * GENERAL_MESSAGE_MODULE: 消息模块
- * GENERAL_MESSAGE_CATEGORY: 消息分类
- * PENDING_MESSAGE_CENTER: 待办中心
- * PENDING_MESSAGE_MODULE: 待办模块
- * PENDING_MESSAGE_CATEGORY: 待办分类
- */
- private MessageGroupNodeCategoryEnum category;
- /**
- * 结点名称
- */
- private String nodeName;
- /**
- * 结点编码
- */
- private String nodeCode;
- /**
- * 父节点编码
- */
- private String parentNodeCode;
- /**
- * 结点对应的代办数量
- */
- private Integer pendingCount;
- /**
- * 子节点列表
- */
- private List children;
-
- public static MessageGroupNodeDTO from(MessageGroupNode groupNode) {
- return MessageGroupNodeDTO.builder()
- .category(groupNode.getCategory())
- .nodeName(groupNode.getName())
- .nodeCode(groupNode.getCode())
- .parentNodeCode(groupNode.getParentCode())
- .build();
- }
-
- public MessageGroupNodeResponse toResponse() {
- MessageGroupNodeResponse response = BeanConverter.convert(this, MessageGroupNodeResponse.class);
- List children = this.children.stream()
- .map(MessageGroupNodeDTO::toResponse).collect(Collectors.toList());
- response.setNodeChildren(children);
- return response;
- }
-
- @Override
- public String toString() {
- return JSON.toJSONString(this);
- }
-}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeStatisticDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeStatisticDTO.java
new file mode 100644
index 00000000..f5cef354
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeStatisticDTO.java
@@ -0,0 +1,76 @@
+package cn.axzo.msg.center.message.domain.dto;
+
+import cn.axzo.basics.common.model.IBaseTree;
+import cn.axzo.core.utils.converter.BeanConverter;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import cn.axzo.msg.center.service.pending.response.MessageGroupNodeResponse;
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @description
+ * 消息分类结点DTO
+ *
+ * @author cold_blade
+ * @date 2023/9/26
+ * @version 1.0
+ */
+@Setter
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MessageGroupNodeStatisticDTO implements IBaseTree, Serializable {
+
+ private static final long serialVersionUID = 5171436359992401120L;
+
+ /**
+ * 树结点
+ */
+ private GroupTreeNodeDTO treeNode;
+ /**
+ * 子节点列表
+ */
+ private List nodeChildren;
+ /**
+ * 结点对应的代办数量
+ */
+ private Integer pendingCount;
+
+ public static MessageGroupNodeStatisticDTO of(GroupTreeNodeDTO groupNode) {
+ return MessageGroupNodeStatisticDTO.builder()
+ .treeNode(groupNode)
+ .build();
+ }
+
+ public MessageGroupNodeResponse toResponse() {
+ MessageGroupNodeResponse response = BeanConverter.convert(this, MessageGroupNodeResponse.class);
+ List children = this.nodeChildren.stream()
+ .map(MessageGroupNodeStatisticDTO::toResponse).collect(Collectors.toList());
+ response.setNodeChildren(children);
+ return response;
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+
+ @Override
+ public String getNodeCode() {
+ return treeNode.getNodeCode();
+ }
+
+ @Override
+ public String getParentNodeCode() {
+ return treeNode.getParentNodeCode();
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateCreateParam.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateCreateParam.java
index b1151d5d..c516a122 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateCreateParam.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateCreateParam.java
@@ -1,10 +1,10 @@
package cn.axzo.msg.center.message.domain.param;
import cn.axzo.msg.center.service.dto.MessageRouterButtonDTO;
-import cn.axzo.msg.center.service.dto.MessageRouterDTO;
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
+import cn.axzo.msg.center.service.enums.PushTerminalEnum;
import cn.axzo.msg.center.service.template.request.MessageTemplateCreateRequest;
-import cn.axzo.msg.center.utils.UUIDUtil;
+import cn.axzo.msg.center.utils.JSONObjectUtil;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -36,9 +36,9 @@ public class MessageTemplateCreateParam implements Serializable {
*/
private String templateName;
/**
- * 系统自动生成的模板code
+ * 消息分类树的叶结点的结点编码列表
*/
- private String templateCode;
+ private List leafGroupNodes;
/**
* 所属消息类型
* GENERAL_MESSAGE: 普通消息
@@ -69,18 +69,25 @@ public class MessageTemplateCreateParam implements Serializable {
* 路由列表
*/
private List routers;
+ /**
+ * 推送终端配置
+ * B_ENTERPRISE_APP: B-安心筑企业版
+ * C_WORKER_APP: C-安心筑工人版
+ */
+ private List pushTerminals;
public static MessageTemplateCreateParam from(MessageTemplateCreateRequest request) {
return MessageTemplateCreateParam.builder()
.templateName(request.getTemplateName())
- .templateCode(UUIDUtil.uuidString())
.msgCategory(request.getCategory())
+ .leafGroupNodes(request.getLeafGroupNodes())
.title(request.getMsgTitle())
.content(request.getMsgContent())
- .cardContent(request.getMsgCardInfo())
+ .cardContent(JSONObjectUtil.checkAndReturn(request.getMsgCardInfo()))
.icon(request.getMsgIcon())
.operatorId(request.getOperatorId())
.routers(request.getRouters())
+ .pushTerminals(request.getPushTerminals())
.build();
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupNodeService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupNodeService.java
new file mode 100644
index 00000000..773a1d48
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupNodeService.java
@@ -0,0 +1,41 @@
+package cn.axzo.msg.center.message.service;
+
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * 消息分类结点管理
+ *
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+public interface MessageGroupNodeService {
+
+ /**
+ * 获取分类结点(叶结点)名称的路径
+ *
+ * @param leafGroupNodeCodes 分类结点(叶结点)的编码列表
+ * @return 分类结点(叶结点)名称的路径
+ */
+ Map leafGroupNodeNamePaths(Collection leafGroupNodeCodes);
+
+ /**
+ * 获取分类结点(叶结点)编码的路径
+ *
+ * @param leafGroupNodeCodes 分类结点(叶结点)的编码列表
+ * @return 分类结点(叶结点)编码的路径
+ */
+ Map leafGroupNodeCodePaths(Collection leafGroupNodeCodes);
+
+ /**
+ * 根据结点编码查询结点信息
+ *
+ * @param rootNodeCode 结点编码
+ * @return 结点信息
+ */
+ Optional queryRootNode(String rootNodeCode);
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupService.java
deleted file mode 100644
index 66dabe02..00000000
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupService.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package cn.axzo.msg.center.message.service;
-
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * 消息分类管理
- *
- * @author cold_blade
- * @date 2023/9/20
- * @version 1.0
- */
-public interface MessageGroupService {
-
- /**
- * 通过结点编码查询结点信息
- *
- * @param nodeCode 结点编码
- * @return 结点信息
- */
- Optional queryByNodeCode(String nodeCode);
-
- /**
- * 查询指定结点的字节的信息
- *
- * @param nodeCode 指定结点编码
- * @return 子节点列表信息
- */
- List listChildren(String nodeCode);
-
- /**
- * 模板关联分类
- *
- * @param templateNode 模板编码
- * @param pathList 分类path列表
- */
- void templateGroup(String templateNode, Collection pathList);
-}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupTreeNodeCacheService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupTreeNodeCacheService.java
new file mode 100644
index 00000000..2b283f46
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupTreeNodeCacheService.java
@@ -0,0 +1,53 @@
+package cn.axzo.msg.center.message.service;
+
+import cn.axzo.msg.center.message.domain.dto.GroupTreeNodePathDTO;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 消息分类树节点缓存管理
+ *
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+public interface MessageGroupTreeNodeCacheService {
+
+ /**
+ * 获取所有有效的分类结点树的根节点
+ *
+ * @return 树根节点列表
+ */
+ List listAllRootNodes();
+
+ /**
+ * 获取指定结点所在的树的根节点
+ *
+ * @param rootNodeCode 结点编码
+ * @return 根节点
+ */
+ Optional queryRootNode(String rootNodeCode);
+
+ /**
+ * 根据结点编码查询结点信息
+ *
+ * @param groupNodeCode 结点编码
+ * @return 结点信息
+ */
+ Optional queryNode(String groupNodeCode);
+
+ /**
+ * 获取叶结点对应的树的路径
+ *
+ * @param leafNodeCode 叶结点编码
+ * @return 路径
+ */
+ Optional queryLeafNodePath(String leafNodeCode);
+
+ /**
+ * 刷新缓存
+ */
+ void refreshCache();
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateGroupService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateGroupService.java
index f830e062..3ed0499d 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateGroupService.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateGroupService.java
@@ -1,5 +1,6 @@
package cn.axzo.msg.center.message.service;
+import java.util.Collection;
import java.util.List;
/**
@@ -18,4 +19,12 @@ public interface MessageTemplateGroupService {
* @return 模板编码列表
*/
List listMessageTemplateCodes(String groupNodeCode);
+
+ /**
+ * 模板关联分类
+ *
+ * @param templateNode 模板编码
+ * @param groupNodeCodes 分类结点编码列表
+ */
+ void templateGroup(String templateNode, Collection groupNodeCodes);
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateNewService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateNewService.java
index 6836bb14..9175cd74 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateNewService.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateNewService.java
@@ -20,7 +20,7 @@ public interface MessageTemplateNewService {
*
* @param param 模板内容参数
*/
- void createTemplate(MessageTemplateCreateParam param);
+ String createTemplate(MessageTemplateCreateParam param);
/**
* 通过模板编码查询模板信息
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/PendingMessageNewService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/PendingMessageNewService.java
index df132a34..be931eef 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/PendingMessageNewService.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/PendingMessageNewService.java
@@ -1,12 +1,11 @@
package cn.axzo.msg.center.message.service;
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
+import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeStatisticDTO;
import cn.axzo.msg.center.message.domain.dto.PendingMessageDTO;
import cn.axzo.msg.center.message.domain.param.MessageGroupNodeStatisticParam;
import cn.axzo.msg.center.message.domain.param.PendingMessagePushParam;
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
import cn.axzo.msg.center.service.pending.request.PendingMessagePageRequest;
-import cn.axzo.msg.center.service.pending.request.PendingMessagePushRequest;
import cn.axzo.msg.center.service.pending.response.PendingMessageResponse;
import cn.azxo.framework.common.model.Page;
@@ -22,7 +21,7 @@ import java.util.Optional;
*/
public interface PendingMessageNewService {
- List groupStatistic(MessageGroupNodeStatisticParam param);
+ List groupStatistic(MessageGroupNodeStatisticParam param);
/**
* 代办列表分页查询
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupNodeServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupNodeServiceImpl.java
new file mode 100644
index 00000000..77a9ac7a
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupNodeServiceImpl.java
@@ -0,0 +1,62 @@
+package cn.axzo.msg.center.message.service.impl;
+
+import cn.axzo.msg.center.message.domain.dto.GroupTreeNodePathDTO;
+import cn.axzo.msg.center.message.service.MessageGroupNodeService;
+import cn.axzo.msg.center.message.service.MessageGroupTreeNodeCacheService;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class MessageGroupNodeServiceImpl implements MessageGroupNodeService {
+
+ private final MessageGroupTreeNodeCacheService messageGroupTreeNodeCacheService;
+
+ @Override
+ public Map leafGroupNodeNamePaths(Collection leafGroupNodeCodes) {
+ if (CollectionUtils.isEmpty(leafGroupNodeCodes)) {
+ log.info("leafGroupNodeCodes is empty.");
+ return Collections.emptyMap();
+ }
+ return leafGroupNodeCodes.stream()
+ .map(messageGroupTreeNodeCacheService::queryLeafNodePath)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toMap(GroupTreeNodePathDTO::getNodeCode,
+ GroupTreeNodePathDTO::getNodeNamePath, (cur, pre) -> cur));
+ }
+
+ @Override
+ public Map leafGroupNodeCodePaths(Collection leafGroupNodeCodes) {
+ if (CollectionUtils.isEmpty(leafGroupNodeCodes)) {
+ log.info("leafGroupNodeCodes is empty.");
+ return Collections.emptyMap();
+ }
+ return leafGroupNodeCodes.stream()
+ .map(messageGroupTreeNodeCacheService::queryLeafNodePath)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toMap(GroupTreeNodePathDTO::getNodeCode,
+ GroupTreeNodePathDTO::getNodeCodePath, (cur, pre) -> cur));
+ }
+
+ @Override
+ public Optional queryRootNode(String rootNodeCode) {
+ return messageGroupTreeNodeCacheService.queryRootNode(rootNodeCode);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupServiceImpl.java
deleted file mode 100644
index 0ca69898..00000000
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupServiceImpl.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package cn.axzo.msg.center.message.service.impl;
-
-import cn.axzo.msg.center.dal.MessageGroupNodeDao;
-import cn.axzo.msg.center.dal.MessageTemplateGroupDao;
-import cn.axzo.msg.center.domain.entity.MessageGroupNode;
-import cn.axzo.msg.center.domain.entity.MessageTemplateGroup;
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
-import cn.axzo.msg.center.message.service.MessageGroupService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.stereotype.Service;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- * @author cold_blade
- * @date 2023/10/6
- * @version 1.0
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class MessageGroupServiceImpl implements MessageGroupService {
-
- private final MessageGroupNodeDao messageGroupNodeDao;
- private final MessageTemplateGroupDao messageTemplateGroupDao;
-
- @Override
- public Optional queryByNodeCode(String nodeCode) {
- if (StringUtils.isBlank(nodeCode)) {
- return Optional.empty();
- }
- MessageGroupNode groupNode = messageGroupNodeDao.lambdaQuery()
- .eq(MessageGroupNode::getCode, nodeCode)
- .eq(MessageGroupNode::getIsDelete, 0)
- .one();
- return Optional.ofNullable(groupNode).map(MessageGroupNodeDTO::from);
- }
-
- @Override
- public List listChildren(String nodeCode) {
- return messageGroupNodeDao.lambdaQuery()
- .eq(MessageGroupNode::getParentCode, nodeCode)
- .eq(MessageGroupNode::getIsDelete, 0)
- .list().stream()
- .map(MessageGroupNodeDTO::from)
- .collect(Collectors.toList());
- }
-
- @Override
- public void templateGroup(String templateNode, Collection pathList) {
- if (StringUtils.isBlank(templateNode)
- || CollectionUtils.isEmpty(pathList)) {
- return;
- }
- List rows = pathList.stream()
- .map(e -> {
- MessageTemplateGroup group = new MessageTemplateGroup();
- group.setTemplateCode(templateNode);
- group.setPath(e);
- return group;
- }).collect(Collectors.toList());
- messageTemplateGroupDao.saveBatch(rows);
- }
-}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java
new file mode 100644
index 00000000..ddb47614
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java
@@ -0,0 +1,185 @@
+package cn.axzo.msg.center.message.service.impl;
+
+import cn.axzo.basics.common.util.TreeUtil;
+import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
+import cn.axzo.msg.center.dal.MessageGroupNodeDao;
+import cn.axzo.msg.center.domain.entity.MessageGroupNode;
+import cn.axzo.msg.center.message.domain.dto.GroupTreeNodePathDTO;
+import cn.axzo.msg.center.message.service.MessageGroupTreeNodeCacheService;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import cn.axzo.pokonyan.config.redis.RedisUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.compress.utils.Lists;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class MessageGroupTreeNodeCacheServiceImpl implements MessageGroupTreeNodeCacheService {
+
+ private static final String CACHE_KEY = "msg-center:message:group:cache-key";
+ private static final String CACHE_VALUE = "msg-center:message:group:cache-val";
+ private static final long CACHE_KEY_TIMEOUT_DAYS = 1;
+
+ private final MessageGroupNodeDao messageGroupNodeDao;
+
+ private List allGroupTreeRootNodesCache = Collections.emptyList();
+ private List leafTreeNodePathsCache = Collections.emptyList();
+
+ @Override
+ public List listAllRootNodes() {
+ return getAllGroupTreeRootNodesCache();
+ }
+
+ @Override
+ public Optional queryRootNode(String rootNodeCode) {
+ if (StringUtils.isBlank(rootNodeCode)) {
+ log.info("rootNodeCode is blank.");
+ return Optional.empty();
+ }
+ return getAllGroupTreeRootNodesCache().stream()
+ .filter(e -> Objects.equals(e.getNodeCode(), rootNodeCode))
+ .findFirst();
+ }
+
+ @Override
+ public Optional queryNode(String groupNodeCode) {
+ if (StringUtils.isBlank(groupNodeCode)) {
+ log.info("groupNodeCode is blank.");
+ return Optional.empty();
+ }
+ return getAllGroupTreeRootNodesCache().stream()
+ .map(e -> findTreeNode(e, groupNodeCode))
+ .filter(Objects::nonNull)
+ .findFirst();
+ }
+
+ @Override
+ public Optional queryLeafNodePath(String leafNodeCode) {
+ if (StringUtils.isBlank(leafNodeCode)) {
+ log.info("leafNodeCode is blank.");
+ return Optional.empty();
+ }
+ return getLeafTreeNodePathsCache().stream()
+ .filter(e -> Objects.equals(e.getNodeCode(), leafNodeCode))
+ .findFirst();
+ }
+
+ @Override
+ public void refreshCache() {
+ // 清除redis中的缓存标识
+ RedisUtil.KeyOps.delete(CACHE_KEY);
+ // 清除本地缓存
+ allGroupTreeRootNodesCache = Collections.emptyList();
+ leafTreeNodePathsCache = Collections.emptyList();
+ }
+
+ private GroupTreeNodeDTO findTreeNode(GroupTreeNodeDTO root, String treeNodeCode) {
+ if (Objects.equals(root.getNodeCode(), treeNodeCode)) {
+ return root;
+ }
+ LinkedList queue = new LinkedList<>(root.getNodeChildren());
+ while (!queue.isEmpty()) {
+ GroupTreeNodeDTO node = queue.pop();
+ Optional childOp = node.getChild(treeNodeCode);
+ if (childOp.isPresent()) {
+ return childOp.get();
+ }
+ queue.addAll(node.getNodeChildren());
+ }
+ return null;
+ }
+
+ private List getAllGroupTreeRootNodesCache() {
+ if (RedisUtil.KeyOps.hasKey(CACHE_KEY)) {
+ // 其它结点进行了本地缓存,但是当前服务进程还未进行缓存
+ if (CollectionUtils.isEmpty(allGroupTreeRootNodesCache)) {
+ // 本地缓存初始化,不更新redis中的缓存标识
+ initialize(false);
+ }
+ } else {
+ // 本地缓存初始化并更新redis中的缓存标识
+ initialize(true);
+ }
+ return this.allGroupTreeRootNodesCache;
+ }
+
+ private List getLeafTreeNodePathsCache() {
+ if (RedisUtil.KeyOps.hasKey(CACHE_KEY)) {
+ // 其它结点进行了本地缓存,但是当前服务进程还未进行缓存
+ if (leafTreeNodePathsCache.isEmpty()) {
+ // 本地缓存初始化,不更新redis中的缓存标识
+ initialize(false);
+ }
+ } else {
+ // 本地缓存初始化并更新redis中的缓存标识
+ initialize(true);
+ }
+ return leafTreeNodePathsCache;
+ }
+
+ private synchronized void initialize(boolean refreshCache) {
+ List groupNodes = listAllValidNodesFromDB();
+ allGroupTreeRootNodesCache = TreeUtil.buildTree(groupNodes);
+ leafTreeNodePathsCache = allGroupTreeRootNodesCache.stream()
+ .flatMap(e -> parseRootNode(e).stream())
+ .collect(Collectors.toList());
+ if (refreshCache) {
+ RedisUtil.StringOps.setIfAbsent(CACHE_KEY, CACHE_VALUE, CACHE_KEY_TIMEOUT_DAYS, TimeUnit.DAYS);
+ }
+ }
+
+ private List listAllValidNodesFromDB() {
+ return messageGroupNodeDao.lambdaQuery()
+ .eq(MessageGroupNode::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .list().stream()
+ .map(this::convert)
+ .collect(Collectors.toList());
+ }
+
+ private GroupTreeNodeDTO convert(MessageGroupNode groupNode) {
+ return GroupTreeNodeDTO.builder()
+ .nodeName(groupNode.getName())
+ .nodeCode(groupNode.getCode())
+ .category(groupNode.getCategory())
+ .parentNodeCode(groupNode.getParentCode())
+ .isLeaf(groupNode.getIsLeaf())
+ .status(groupNode.getStatus())
+ .build();
+ }
+
+ private List parseRootNode(GroupTreeNodeDTO root) {
+ List paths = Lists.newArrayList();
+ LinkedList pathNodeStack = new LinkedList<>();
+ LinkedList stack = new LinkedList<>();
+ stack.push(root);
+ while (!stack.isEmpty()) {
+ GroupTreeNodeDTO node = stack.pop();
+ pathNodeStack.push(node);
+ if (CollectionUtils.isEmpty(node.getNodeChildren())) {
+ // 当前结点为树的叶结点(逻辑上的,有可能不是业务维度的叶结点)
+ paths.add(GroupTreeNodePathDTO.of(node.getNodeCode(), pathNodeStack));
+ pathNodeStack.pop();
+ } else {
+ stack.addAll(node.getNodeChildren());
+ }
+ }
+ return paths;
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateGroupServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateGroupServiceImpl.java
index cfcd1b34..24288fc0 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateGroupServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateGroupServiceImpl.java
@@ -2,14 +2,18 @@ package cn.axzo.msg.center.message.service.impl;
import cn.axzo.msg.center.dal.MessageTemplateGroupDao;
import cn.axzo.msg.center.domain.entity.MessageTemplateGroup;
+import cn.axzo.msg.center.message.service.MessageGroupNodeService;
import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -22,6 +26,7 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class MessageTemplateGroupServiceImpl implements MessageTemplateGroupService {
+ private final MessageGroupNodeService messageGroupNodeService;
private final MessageTemplateGroupDao messageTemplateGroupDao;
@Override
@@ -37,4 +42,22 @@ public class MessageTemplateGroupServiceImpl implements MessageTemplateGroupServ
.map(MessageTemplateGroup::getTemplateCode)
.collect(Collectors.toList());
}
+
+ @Override
+ public void templateGroup(String templateNode, Collection groupNodeCodes) {
+ if (StringUtils.isBlank(templateNode)
+ || CollectionUtils.isEmpty(groupNodeCodes)) {
+ return;
+ }
+ Map pathMap = messageGroupNodeService.leafGroupNodeCodePaths(groupNodeCodes);
+ List rows = groupNodeCodes.stream()
+ .filter(pathMap::containsKey)
+ .map(e -> {
+ MessageTemplateGroup group = new MessageTemplateGroup();
+ group.setTemplateCode(templateNode);
+ group.setPath(pathMap.get(e));
+ return group;
+ }).collect(Collectors.toList());
+ messageTemplateGroupDao.saveBatch(rows);
+ }
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java
index 5a149989..50da105e 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java
@@ -1,18 +1,24 @@
package cn.axzo.msg.center.message.service.impl;
-import cn.axzo.core.utils.converter.BeanConverter;
+import cn.axzo.basics.common.util.AssertUtil;
+import cn.axzo.msg.center.common.enums.ServiceErrorCodeEnum;
import cn.axzo.msg.center.dal.MessageBaseTemplateDao;
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
import cn.axzo.msg.center.message.domain.dto.RawMessageRouterDTO;
import cn.axzo.msg.center.message.domain.param.MessageTemplateCreateParam;
+import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
import cn.axzo.msg.center.message.service.MessageTemplateNewService;
import cn.axzo.msg.center.message.service.MessageTemplateRouterService;
+import cn.axzo.msg.center.utils.JSONObjectUtil;
+import cn.axzo.msg.center.utils.UUIDUtil;
+import cn.axzo.pokonyan.config.redis.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.List;
@@ -33,19 +39,24 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class MessageTemplateNewServiceImpl implements MessageTemplateNewService {
+ private static final String SAVE_TEMPLATE_MUTEX_KEY = "msg-center:template:save:%s";
+ private static final long TRY_LOCK_TIMEOUT_MILLS = 1000;
+ private static final int RETRY_CNT_MAX = 3;
+
private final MessageBaseTemplateDao messageBaseTemplateDao;
+ private final MessageTemplateGroupService messageTemplateGroupService;
private final MessageTemplateRouterService messageTemplateRouterService;
@Override
- public void createTemplate(MessageTemplateCreateParam param) {
- // TODO: [cold_blade] [P2] 模板与分类的关系
- messageBaseTemplateDao.save(convert(param));
- if (CollectionUtils.isNotEmpty(param.getRouters())) {
- List routers = param.getRouters().stream()
- .map(e -> RawMessageRouterDTO.from(e, param.getTemplateCode()))
- .collect(Collectors.toList());
- messageTemplateRouterService.batchInsert(routers);
- }
+ @Transactional(rollbackFor = Exception.class)
+ public String createTemplate(MessageTemplateCreateParam param) {
+ // 创建模板基础数据
+ String templateCode = saveTemplate(param);
+ // 创建模板的路由数据
+ saveTemplateRouters(param, templateCode);
+ // 创建模板与分类的关联关系数据
+ messageTemplateGroupService.templateGroup(templateCode, param.getLeafGroupNodes());
+ return templateCode;
}
@Override
@@ -87,12 +98,65 @@ public class MessageTemplateNewServiceImpl implements MessageTemplateNewService
.collect(Collectors.toList());
}
+ private String saveTemplate(MessageTemplateCreateParam param) {
+ String templateCode = UUIDUtil.uuidString();
+ MessageBaseTemplate template = convert(param);
+ boolean result = doSaveTemplate(template, templateCode);
+ int retryCnt = 0;
+ while (!result && retryCnt++ < RETRY_CNT_MAX) {
+ // 默认重试{@cod RETRY_CNT_MAX}次,若{@code RETRY_CNT_MAX}次后依然失败就报错
+ templateCode = UUIDUtil.uuidString();
+ result = doSaveTemplate(template, templateCode);
+ }
+ AssertUtil.isTrue(result, ServiceErrorCodeEnum.SYSTEM_BUSY.getDesc());
+ return templateCode;
+ }
+
+ private boolean doSaveTemplate(MessageBaseTemplate template, String templateCode) {
+ String requestId = UUIDUtil.uuidRawString();
+ try {
+ String opKey = String.format(SAVE_TEMPLATE_MUTEX_KEY, templateCode);
+ boolean lockResult = RedisUtil.LockOps.getLockUntilTimeout(opKey, requestId, TRY_LOCK_TIMEOUT_MILLS);
+ AssertUtil.isTrue(lockResult, ServiceErrorCodeEnum.SYSTEM_BUSY.getDesc());
+ if (isTemplateExist(templateCode)) {
+ return false;
+ }
+ template.setCode(templateCode);
+ messageBaseTemplateDao.save(template);
+ return true;
+ } finally {
+ RedisUtil.LockOps.releaseLock(SAVE_TEMPLATE_MUTEX_KEY, requestId);
+ }
+ }
+
+ private boolean isTemplateExist(String templateCode) {
+ return messageBaseTemplateDao.lambdaQuery()
+ .eq(MessageBaseTemplate::getCode, templateCode)
+ .eq(MessageBaseTemplate::getIsDelete, 0)
+ .count() > 0;
+ }
+
private MessageBaseTemplate convert(MessageTemplateCreateParam param) {
- MessageBaseTemplate template = BeanConverter.convert(param, MessageBaseTemplate.class);
+ MessageBaseTemplate template = new MessageBaseTemplate();
template.setName(param.getTemplateName());
- template.setCode(param.getTemplateCode());
+ template.setMsgCategory(param.getMsgCategory());
+ template.setTitle(param.getTitle());
+ template.setContent(param.getContent());
+ template.setCardContent(JSONObjectUtil.checkAndReturn(param.getCardContent()));
+ template.setIcon(param.getIcon());
+ template.setPushTerminal(JSONObjectUtil.toJSONString(param.getPushTerminals()));
template.setCreatorId(param.getOperatorId());
template.setUpdaterId(param.getOperatorId());
return template;
}
+
+ private void saveTemplateRouters(MessageTemplateCreateParam param, String templateCode) {
+ if (CollectionUtils.isEmpty(param.getRouters())) {
+ return;
+ }
+ List routers = param.getRouters().stream()
+ .map(e -> RawMessageRouterDTO.from(e, templateCode))
+ .collect(Collectors.toList());
+ messageTemplateRouterService.batchInsert(routers);
+ }
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/PendingMessageNewServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/PendingMessageNewServiceImpl.java
index fd9312ba..027e62d8 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/PendingMessageNewServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/PendingMessageNewServiceImpl.java
@@ -5,16 +5,17 @@ import cn.axzo.msg.center.common.exception.ServiceException;
import cn.axzo.msg.center.common.utils.PlaceholderResolver;
import cn.axzo.msg.center.dal.PendingMessageRecordDao;
import cn.axzo.msg.center.domain.entity.PendingMessageRecord;
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
+import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeStatisticDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
import cn.axzo.msg.center.message.domain.dto.PendingMessageDTO;
import cn.axzo.msg.center.message.domain.dto.RawMessageRouterDTO;
import cn.axzo.msg.center.message.domain.param.MessageGroupNodeStatisticParam;
import cn.axzo.msg.center.message.domain.param.PendingMessagePushParam;
-import cn.axzo.msg.center.message.service.MessageGroupService;
+import cn.axzo.msg.center.message.service.MessageGroupNodeService;
import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
import cn.axzo.msg.center.message.service.MessageTemplateNewService;
import cn.axzo.msg.center.message.service.PendingMessageNewService;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
import cn.axzo.msg.center.service.dto.IdentityDTO;
import cn.axzo.msg.center.service.dto.MessageRouterDTO;
import cn.axzo.msg.center.service.dto.PersonDTO;
@@ -29,6 +30,7 @@ import cn.axzo.msg.center.service.pending.response.PendingMessageResponse;
import cn.axzo.msg.center.utils.JSONObjectUtil;
import cn.axzo.msg.center.utils.MessageRouterUtil;
import cn.axzo.msg.center.utils.OrderFieldParseUtil;
+import cn.axzo.msg.center.utils.TreeHelperUtil;
import cn.axzo.msg.center.utils.UUIDUtil;
import cn.azxo.framework.common.model.Page;
import com.alibaba.fastjson.JSON;
@@ -45,10 +47,10 @@ import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.Stack;
import java.util.stream.Collectors;
/**
@@ -63,13 +65,13 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class PendingMessageNewServiceImpl implements PendingMessageNewService {
- private final MessageGroupService messageGroupService;
private final PendingMessageRecordDao pendingMessageRecordDao;
+ private final MessageGroupNodeService messageGroupNodeService;
private final MessageTemplateNewService messageTemplateNewService;
private final MessageTemplateGroupService messageTemplateGroupService;
@Override
- public List groupStatistic(MessageGroupNodeStatisticParam param) {
+ public List groupStatistic(MessageGroupNodeStatisticParam param) {
return param.getGroupNodeCodes().stream()
.flatMap(e -> statistic(e, param).stream())
.collect(Collectors.toList());
@@ -193,26 +195,23 @@ public class PendingMessageNewServiceImpl implements PendingMessageNewService {
return pendingMessage;
}
- private List statistic(String rootNodeCode, MessageGroupNodeStatisticParam param) {
- MessageGroupNodeDTO groupNode = messageGroupService.queryByNodeCode(rootNodeCode)
+ private List statistic(String rootNodeCode, MessageGroupNodeStatisticParam param) {
+ GroupTreeNodeDTO rootNode = messageGroupNodeService.queryRootNode(rootNodeCode)
.orElseThrow(() -> new ServiceException("groupNodeCode is invalid."));
- MessageGroupNodeDTO root = groupNode;
- Stack stack = new Stack<>();
- stack.push(groupNode);
- List children;
+ MessageGroupNodeStatisticDTO rootWrapper = TreeHelperUtil.wrapper(rootNode, MessageGroupNodeStatisticDTO::of);
+ LinkedList stack = new LinkedList<>();
+ stack.push(rootWrapper);
+ MessageGroupNodeStatisticDTO wrapper;
while (!stack.isEmpty()) {
- // TODO: [cold_blade] [P3] 优化树形分类结点的统计效率
- groupNode = stack.pop();
- statistic(groupNode, param);
- children = messageGroupService.listChildren(groupNode.getNodeCode());
- groupNode.setChildren(children);
- children.forEach(stack::push);
+ wrapper = stack.pop();
+ statistic(wrapper, param);
+ stack.addAll(wrapper.getNodeChildren());
}
// 外部传的是根节点,但是前端希望只返回根节点的字节的
- return root.getChildren();
+ return rootWrapper.getNodeChildren();
}
- private void statistic(MessageGroupNodeDTO groupNode, MessageGroupNodeStatisticParam param) {
+ private void statistic(MessageGroupNodeStatisticDTO groupNode, MessageGroupNodeStatisticParam param) {
List templateCodes = messageTemplateGroupService.listMessageTemplateCodes(groupNode.getNodeCode());
if (CollectionUtils.isEmpty(templateCodes)) {
groupNode.setPendingCount(0);
@@ -298,6 +297,7 @@ public class PendingMessageNewServiceImpl implements PendingMessageNewService {
}
private void buildTemplateInfo(PendingMessageRecord record, MessageTemplateDTO msgTemplate, String routeParam) {
+ // TODO:[cold_blade] [P3] 后续其它业务对接的时候,需要明确业务扩展字段和路由参数的分界
JSONObject routerParamObj = JSONObjectUtil.parseObject(routeParam);
String title = PlaceholderResolver
.getDefaultResolver().resolveByMap(msgTemplate.getTitle(), routerParamObj);
@@ -316,4 +316,9 @@ public class PendingMessageNewServiceImpl implements PendingMessageNewService {
record.setBizCategory(param.getBizCategory());
record.setBizExtParam(JSONObjectUtil.checkAndReturn(param.getBizExtParams()));
}
+
+ private static class GroupTreeNodeWrapper {
+ private GroupTreeNodeDTO treeNode;
+ private int pendingCnt;
+ }
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/utils/JSONObjectUtil.java b/inside-notices/src/main/java/cn/axzo/msg/center/utils/JSONObjectUtil.java
index d22d57cc..a5770691 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/utils/JSONObjectUtil.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/utils/JSONObjectUtil.java
@@ -4,8 +4,12 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
+import java.util.Collection;
+import java.util.Objects;
+
/**
* @author cold_blade
* @date 2023/10/13
@@ -14,6 +18,8 @@ import org.apache.commons.lang3.StringUtils;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class JSONObjectUtil {
private static final JSONObject EMPTY_JSON_OBJ = new JSONObject();
+ private static final String EMPTY_JSON_OBJ_STR = "{}";
+ private static final String EMPTY_JSON_ARR_STR = "[]";
/**
* 解析JSON字符串,若字符串格式不正确,抛异常
@@ -28,6 +34,20 @@ public final class JSONObjectUtil {
return JSON.parseObject(str);
}
+ public static String toJSONString(Object obj) {
+ if (Objects.isNull(obj)) {
+ return EMPTY_JSON_OBJ_STR;
+ }
+ return JSON.toJSONString(obj);
+ }
+
+ public static String toJSONString(Collection> objCollection) {
+ if (CollectionUtils.isEmpty(objCollection)) {
+ return EMPTY_JSON_ARR_STR;
+ }
+ return JSON.toJSONString(objCollection);
+ }
+
/**
* 校验字符串是否为有效的JSON字符串,若字符串格式不正确,抛异常
*
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/utils/TreeHelperUtil.java b/inside-notices/src/main/java/cn/axzo/msg/center/utils/TreeHelperUtil.java
new file mode 100644
index 00000000..0a8a57e0
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/utils/TreeHelperUtil.java
@@ -0,0 +1,44 @@
+package cn.axzo.msg.center.utils;
+
+import cn.axzo.basics.common.model.IBaseTree;
+import cn.axzo.basics.common.util.AssertUtil;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import com.google.common.collect.Maps;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/16
+ * @version 1.0
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class TreeHelperUtil {
+
+ public static , O> T wrapper(GroupTreeNodeDTO treeNode,
+ Function wrapperFunc) {
+ AssertUtil.notNull(treeNode, "treeNode is null");
+ AssertUtil.notNull(wrapperFunc, "wrapperFunc is null");
+
+ final Map convertMap = Maps.newHashMap();
+ T wrapper = wrapperFunc.apply(treeNode);
+ convertMap.put(treeNode, wrapper);
+ LinkedList treeNodeStack = new LinkedList<>();
+ treeNodeStack.push(treeNode);
+ while (!treeNodeStack.isEmpty()) {
+ treeNode = treeNodeStack.pop();
+ List children = treeNode.getNodeChildren();
+ convertMap.get(treeNode).setNodeChildren(children.stream()
+ .map(e -> convertMap.put(e, wrapperFunc.apply(e)))
+ .collect(Collectors.toList()));
+ treeNodeStack.addAll(children);
+ }
+ return wrapper;
+ }
+}
diff --git a/msg-center-api/src/main/java/cn/axzo/msg/center/service/dto/GroupNodeDTO.java b/msg-center-api/src/main/java/cn/axzo/msg/center/service/dto/GroupNodeDTO.java
deleted file mode 100644
index 256ada15..00000000
--- a/msg-center-api/src/main/java/cn/axzo/msg/center/service/dto/GroupNodeDTO.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package cn.axzo.msg.center.service.dto;
-
-import cn.axzo.msg.center.service.enums.MessageGroupNodeCategoryEnum;
-import cn.axzo.msg.center.service.enums.StatusEnum;
-import com.alibaba.fastjson.JSON;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.io.Serializable;
-
-/**
- * @description
- *
- * @author cold_blade
- * @date 2023/9/23
- * @version 1.0
- */
-@Setter
-@Getter
-public class GroupNodeDTO implements Serializable {
-
- private static final long serialVersionUID = -5935469947222698608L;
-
- /**
- * 模板分组结点名称
- */
- private String name;
- /**
- * 模板分组结点名称code
- */
- private String code;
- /**
- * 结点类型
- */
- private MessageGroupNodeCategoryEnum category;
- /**
- * 父节点
- */
- private String parentCode;
- /**
- * 是否为叶节点
- */
- private Integer isLeaf;
- /**
- * 状态
- */
- private StatusEnum status;
-
- @Override
- public String toString() {
- return JSON.toJSONString(this);
- }
-}
diff --git a/msg-center-api/src/main/java/cn/axzo/msg/center/service/dto/GroupTreeNodeDTO.java b/msg-center-api/src/main/java/cn/axzo/msg/center/service/dto/GroupTreeNodeDTO.java
new file mode 100644
index 00000000..187101b5
--- /dev/null
+++ b/msg-center-api/src/main/java/cn/axzo/msg/center/service/dto/GroupTreeNodeDTO.java
@@ -0,0 +1,71 @@
+package cn.axzo.msg.center.service.dto;
+
+import cn.axzo.basics.common.model.IBaseTree;
+import cn.axzo.msg.center.service.enums.MessageGroupNodeCategoryEnum;
+import cn.axzo.msg.center.service.enums.StatusEnum;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class GroupTreeNodeDTO implements IBaseTree, Serializable {
+
+ private static final long serialVersionUID = -3244632155934087302L;
+
+ /**
+ * 模板分组结点名称
+ */
+ private String nodeName;
+ /**
+ * 模板分组结点名称code
+ */
+ private String nodeCode;
+ /**
+ * 结点类型
+ */
+ private MessageGroupNodeCategoryEnum category;
+ /**
+ * 父节点
+ */
+ private String parentNodeCode;
+ /**
+ * 是否为叶节点
+ */
+ private Integer isLeaf;
+ /**
+ * 状态
+ */
+ private StatusEnum status;
+ /**
+ * 子节点列表
+ */
+ @Builder.Default
+ private List nodeChildren = Collections.emptyList();
+
+ public Optional getChild(String treeNodeCode) {
+ if (StringUtils.isBlank(treeNodeCode)) {
+ return Optional.empty();
+ }
+ return getNodeChildren().stream()
+ .filter(e -> Objects.equals(e.getNodeCode(), treeNodeCode))
+ .findFirst();
+ }
+}
diff --git a/msg-center-common/src/main/java/cn/axzo/msg/center/common/enums/ServiceErrorCodeEnum.java b/msg-center-common/src/main/java/cn/axzo/msg/center/common/enums/ServiceErrorCodeEnum.java
new file mode 100644
index 00000000..e84dab97
--- /dev/null
+++ b/msg-center-common/src/main/java/cn/axzo/msg/center/common/enums/ServiceErrorCodeEnum.java
@@ -0,0 +1,23 @@
+package cn.axzo.msg.center.common.enums;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+@Getter
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+public enum ServiceErrorCodeEnum {
+
+ SYSTEM_BUSY("E0002", "系统繁忙,请稍后重试"),
+
+ PARAM_IS_INVALID("E0020", "参数异常"),
+ ;
+
+ private final String code;
+ private final String desc;
+}