Merge branch 'feature/REQ-1465' of axzsource.com:universal/infrastructure/backend/msg-center-plat into dev
This commit is contained in:
commit
c7d351d784
@ -110,6 +110,11 @@
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.pokonyan</groupId>
|
||||
<artifactId>pokonyan</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -29,9 +29,8 @@ public class MessageTemplateController implements MessageTemplateClient {
|
||||
|
||||
@Override
|
||||
public CommonResponse<String> 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
|
||||
|
||||
@ -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<List<MessageGroupNodeResponse>> groupStatistic(MessageGroupNodeStatisticRequest request) {
|
||||
List<MessageGroupNodeDTO> groupNodes = pendingMessageNewService
|
||||
List<MessageGroupNodeStatisticDTO> groupNodes = pendingMessageNewService
|
||||
.groupStatistic(MessageGroupNodeStatisticParam.from(request));
|
||||
return CommonResponse.success(groupNodes.stream()
|
||||
.map(MessageGroupNodeDTO::toResponse)
|
||||
.map(MessageGroupNodeStatisticDTO::toResponse)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
@ -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<GroupTreeNodeDTO> 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<GroupTreeNodeDTO, String> pathFunc, Collection<GroupTreeNodeDTO> nodes,
|
||||
String spliter) {
|
||||
return nodes.stream().map(pathFunc).collect(Collectors.joining(spliter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -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<MessageGroupNodeDTO> 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<MessageGroupNodeResponse> children = this.children.stream()
|
||||
.map(MessageGroupNodeDTO::toResponse).collect(Collectors.toList());
|
||||
response.setNodeChildren(children);
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -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<MessageGroupNodeStatisticDTO, String>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5171436359992401120L;
|
||||
|
||||
/**
|
||||
* 树结点
|
||||
*/
|
||||
private GroupTreeNodeDTO treeNode;
|
||||
/**
|
||||
* 子节点列表
|
||||
*/
|
||||
private List<MessageGroupNodeStatisticDTO> 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<MessageGroupNodeResponse> 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();
|
||||
}
|
||||
}
|
||||
@ -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<String> leafGroupNodes;
|
||||
/**
|
||||
* 所属消息类型
|
||||
* GENERAL_MESSAGE: 普通消息
|
||||
@ -69,18 +69,25 @@ public class MessageTemplateCreateParam implements Serializable {
|
||||
* 路由列表
|
||||
*/
|
||||
private List<MessageRouterButtonDTO> routers;
|
||||
/**
|
||||
* 推送终端配置
|
||||
* B_ENTERPRISE_APP: B-安心筑企业版
|
||||
* C_WORKER_APP: C-安心筑工人版
|
||||
*/
|
||||
private List<PushTerminalEnum> 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();
|
||||
}
|
||||
|
||||
|
||||
@ -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<String, String> leafGroupNodeNamePaths(Collection<String> leafGroupNodeCodes);
|
||||
|
||||
/**
|
||||
* 获取分类结点(叶结点)编码的路径
|
||||
*
|
||||
* @param leafGroupNodeCodes 分类结点(叶结点)的编码列表
|
||||
* @return 分类结点(叶结点)编码的路径
|
||||
*/
|
||||
Map<String, String> leafGroupNodeCodePaths(Collection<String> leafGroupNodeCodes);
|
||||
|
||||
/**
|
||||
* 根据结点编码查询结点信息
|
||||
*
|
||||
* @param rootNodeCode 结点编码
|
||||
* @return 结点信息
|
||||
*/
|
||||
Optional<GroupTreeNodeDTO> queryRootNode(String rootNodeCode);
|
||||
}
|
||||
@ -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<MessageGroupNodeDTO> queryByNodeCode(String nodeCode);
|
||||
|
||||
/**
|
||||
* 查询指定结点的字节的信息
|
||||
*
|
||||
* @param nodeCode 指定结点编码
|
||||
* @return 子节点列表信息
|
||||
*/
|
||||
List<MessageGroupNodeDTO> listChildren(String nodeCode);
|
||||
|
||||
/**
|
||||
* 模板关联分类
|
||||
*
|
||||
* @param templateNode 模板编码
|
||||
* @param pathList 分类path列表
|
||||
*/
|
||||
void templateGroup(String templateNode, Collection<String> pathList);
|
||||
}
|
||||
@ -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<GroupTreeNodeDTO> listAllRootNodes();
|
||||
|
||||
/**
|
||||
* 获取指定结点所在的树的根节点
|
||||
*
|
||||
* @param rootNodeCode 结点编码
|
||||
* @return 根节点
|
||||
*/
|
||||
Optional<GroupTreeNodeDTO> queryRootNode(String rootNodeCode);
|
||||
|
||||
/**
|
||||
* 根据结点编码查询结点信息
|
||||
*
|
||||
* @param groupNodeCode 结点编码
|
||||
* @return 结点信息
|
||||
*/
|
||||
Optional<GroupTreeNodeDTO> queryNode(String groupNodeCode);
|
||||
|
||||
/**
|
||||
* 获取叶结点对应的树的路径
|
||||
*
|
||||
* @param leafNodeCode 叶结点编码
|
||||
* @return 路径
|
||||
*/
|
||||
Optional<GroupTreeNodePathDTO> queryLeafNodePath(String leafNodeCode);
|
||||
|
||||
/**
|
||||
* 刷新缓存
|
||||
*/
|
||||
void refreshCache();
|
||||
}
|
||||
@ -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<String> listMessageTemplateCodes(String groupNodeCode);
|
||||
|
||||
/**
|
||||
* 模板关联分类
|
||||
*
|
||||
* @param templateNode 模板编码
|
||||
* @param groupNodeCodes 分类结点编码列表
|
||||
*/
|
||||
void templateGroup(String templateNode, Collection<String> groupNodeCodes);
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ public interface MessageTemplateNewService {
|
||||
*
|
||||
* @param param 模板内容参数
|
||||
*/
|
||||
void createTemplate(MessageTemplateCreateParam param);
|
||||
String createTemplate(MessageTemplateCreateParam param);
|
||||
|
||||
/**
|
||||
* 通过模板编码查询模板信息
|
||||
|
||||
@ -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<MessageGroupNodeDTO> groupStatistic(MessageGroupNodeStatisticParam param);
|
||||
List<MessageGroupNodeStatisticDTO> groupStatistic(MessageGroupNodeStatisticParam param);
|
||||
|
||||
/**
|
||||
* 代办列表分页查询
|
||||
|
||||
@ -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<String, String> leafGroupNodeNamePaths(Collection<String> 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<String, String> leafGroupNodeCodePaths(Collection<String> 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<GroupTreeNodeDTO> queryRootNode(String rootNodeCode) {
|
||||
return messageGroupTreeNodeCacheService.queryRootNode(rootNodeCode);
|
||||
}
|
||||
}
|
||||
@ -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<MessageGroupNodeDTO> 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<MessageGroupNodeDTO> 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<String> pathList) {
|
||||
if (StringUtils.isBlank(templateNode)
|
||||
|| CollectionUtils.isEmpty(pathList)) {
|
||||
return;
|
||||
}
|
||||
List<MessageTemplateGroup> rows = pathList.stream()
|
||||
.map(e -> {
|
||||
MessageTemplateGroup group = new MessageTemplateGroup();
|
||||
group.setTemplateCode(templateNode);
|
||||
group.setPath(e);
|
||||
return group;
|
||||
}).collect(Collectors.toList());
|
||||
messageTemplateGroupDao.saveBatch(rows);
|
||||
}
|
||||
}
|
||||
@ -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<GroupTreeNodeDTO> allGroupTreeRootNodesCache = Collections.emptyList();
|
||||
private List<GroupTreeNodePathDTO> leafTreeNodePathsCache = Collections.emptyList();
|
||||
|
||||
@Override
|
||||
public List<GroupTreeNodeDTO> listAllRootNodes() {
|
||||
return getAllGroupTreeRootNodesCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GroupTreeNodeDTO> 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<GroupTreeNodeDTO> 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<GroupTreeNodePathDTO> 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<GroupTreeNodeDTO> queue = new LinkedList<>(root.getNodeChildren());
|
||||
while (!queue.isEmpty()) {
|
||||
GroupTreeNodeDTO node = queue.pop();
|
||||
Optional<GroupTreeNodeDTO> childOp = node.getChild(treeNodeCode);
|
||||
if (childOp.isPresent()) {
|
||||
return childOp.get();
|
||||
}
|
||||
queue.addAll(node.getNodeChildren());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<GroupTreeNodeDTO> getAllGroupTreeRootNodesCache() {
|
||||
if (RedisUtil.KeyOps.hasKey(CACHE_KEY)) {
|
||||
// 其它结点进行了本地缓存,但是当前服务进程还未进行缓存
|
||||
if (CollectionUtils.isEmpty(allGroupTreeRootNodesCache)) {
|
||||
// 本地缓存初始化,不更新redis中的缓存标识
|
||||
initialize(false);
|
||||
}
|
||||
} else {
|
||||
// 本地缓存初始化并更新redis中的缓存标识
|
||||
initialize(true);
|
||||
}
|
||||
return this.allGroupTreeRootNodesCache;
|
||||
}
|
||||
|
||||
private List<GroupTreeNodePathDTO> 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<GroupTreeNodeDTO> 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<GroupTreeNodeDTO> 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<GroupTreeNodePathDTO> parseRootNode(GroupTreeNodeDTO root) {
|
||||
List<GroupTreeNodePathDTO> paths = Lists.newArrayList();
|
||||
LinkedList<GroupTreeNodeDTO> pathNodeStack = new LinkedList<>();
|
||||
LinkedList<GroupTreeNodeDTO> 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;
|
||||
}
|
||||
}
|
||||
@ -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<String> groupNodeCodes) {
|
||||
if (StringUtils.isBlank(templateNode)
|
||||
|| CollectionUtils.isEmpty(groupNodeCodes)) {
|
||||
return;
|
||||
}
|
||||
Map<String, String> pathMap = messageGroupNodeService.leafGroupNodeCodePaths(groupNodeCodes);
|
||||
List<MessageTemplateGroup> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<RawMessageRouterDTO> 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<RawMessageRouterDTO> routers = param.getRouters().stream()
|
||||
.map(e -> RawMessageRouterDTO.from(e, templateCode))
|
||||
.collect(Collectors.toList());
|
||||
messageTemplateRouterService.batchInsert(routers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<MessageGroupNodeDTO> groupStatistic(MessageGroupNodeStatisticParam param) {
|
||||
public List<MessageGroupNodeStatisticDTO> 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<MessageGroupNodeDTO> statistic(String rootNodeCode, MessageGroupNodeStatisticParam param) {
|
||||
MessageGroupNodeDTO groupNode = messageGroupService.queryByNodeCode(rootNodeCode)
|
||||
private List<MessageGroupNodeStatisticDTO> statistic(String rootNodeCode, MessageGroupNodeStatisticParam param) {
|
||||
GroupTreeNodeDTO rootNode = messageGroupNodeService.queryRootNode(rootNodeCode)
|
||||
.orElseThrow(() -> new ServiceException("groupNodeCode is invalid."));
|
||||
MessageGroupNodeDTO root = groupNode;
|
||||
Stack<MessageGroupNodeDTO> stack = new Stack<>();
|
||||
stack.push(groupNode);
|
||||
List<MessageGroupNodeDTO> children;
|
||||
MessageGroupNodeStatisticDTO rootWrapper = TreeHelperUtil.wrapper(rootNode, MessageGroupNodeStatisticDTO::of);
|
||||
LinkedList<MessageGroupNodeStatisticDTO> 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<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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字符串,若字符串格式不正确,抛异常
|
||||
*
|
||||
|
||||
@ -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 <T extends IBaseTree<T, O>, O> T wrapper(GroupTreeNodeDTO treeNode,
|
||||
Function<GroupTreeNodeDTO, T> wrapperFunc) {
|
||||
AssertUtil.notNull(treeNode, "treeNode is null");
|
||||
AssertUtil.notNull(wrapperFunc, "wrapperFunc is null");
|
||||
|
||||
final Map<GroupTreeNodeDTO, T> convertMap = Maps.newHashMap();
|
||||
T wrapper = wrapperFunc.apply(treeNode);
|
||||
convertMap.put(treeNode, wrapper);
|
||||
LinkedList<GroupTreeNodeDTO> treeNodeStack = new LinkedList<>();
|
||||
treeNodeStack.push(treeNode);
|
||||
while (!treeNodeStack.isEmpty()) {
|
||||
treeNode = treeNodeStack.pop();
|
||||
List<GroupTreeNodeDTO> 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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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<GroupTreeNodeDTO, String>, 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<GroupTreeNodeDTO> nodeChildren = Collections.emptyList();
|
||||
|
||||
public Optional<GroupTreeNodeDTO> getChild(String treeNodeCode) {
|
||||
if (StringUtils.isBlank(treeNodeCode)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return getNodeChildren().stream()
|
||||
.filter(e -> Objects.equals(e.getNodeCode(), treeNodeCode))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user