优化组织机构树构建逻辑,修改为根据根节点展示多条数据,支持多级机构并提升性能

1. 重构`getTreeByNode`方法:
   - 新增父节点到子节点的映射表(parentToChildrenMap),通过预处理将子节点查找时间从O(n)优化为O(1)
   - 使用StringBuilder累加部门ID,避免字符串拼接的性能损耗
   - 提前将SysOrg转换为SysOrgVO并应用树形结构字段(id/title/key/value),减少重复转换操作

2. 新增`buildMultiLevelTree`方法:
   - 独立递归构建多级树的核心逻辑,提升代码可读性
   - 通过映射表快速获取子节点列表,支持任意层级的组织机构树构建
   - 对每层级子节点按sort字段排序,保持原有展示顺序

3. 移除原低效递归方法`getChildrenNode`,消除全量数据遍历的性能瓶颈

影响范围:组织机构树形查询接口(对应Controller的`/queryAll`端点),显著提升大数据量(20000+条)时的响应速度。
This commit is contained in:
刘倡
2025-06-19 18:22:56 +08:00
parent a44f07962d
commit 2101b352f4

View File

@ -22,9 +22,7 @@ import com.coscoshipping.ebtp.project.org.service.SysOrgService;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -50,8 +48,7 @@ public class SysOrgServiceImpl extends BaseServiceImpl<SysOrgMapper,SysOrg> imp
@Override
public List<SysOrgVO> getTreeByNode(SysOrg org) {
SysOrgVO sysOrgVO = new SysOrgVO();
List<SysOrg> sysOrgList = new ArrayList<>();
List<SysOrg> sysOrgList;
if (!StringUtils.isEmpty(org.getOrgName()) || !StringUtils.isEmpty(org.getOrgNum())){
SysOrgVO vo = BeanUtil.toBean(org, SysOrgVO.class);
IPage<SysOrg> page = this.getPage(vo);
@ -59,33 +56,77 @@ public class SysOrgServiceImpl extends BaseServiceImpl<SysOrgMapper,SysOrg> imp
return sysOrgList.stream().map(entity -> BeanUtil.toBean(entity, SysOrgVO.class)).collect(Collectors.toList());
} else {
sysOrgList = this.list();
//存储所有的部门ID
String allDepartmentId = "";
if (!CollectionUtils.isEmpty(sysOrgList)) {
//获取要查询的节点ID 如果为空则查询所有节点进行树形展示
String rootNode = StringUtils.isNotBlank(org.getOrgId()) ? org.getOrgId() : CommonUtil.ROOT_NODE;
allDepartmentId += rootNode;
List<SysOrgVO> sysOrgVOList = JsonUtils.jsonToList(sysOrgList, SysOrgVO.class);
//获取要查询的节点
sysOrgVO = sysOrgVOList.stream()
.filter(n -> StringUtils.equals(n.getUpOrgId(), rootNode))
.map(this::setInfoForTree)
.collect(Collectors.toList())
.get(0);
//递归查询节点信息
getChildrenNode(sysOrgVOList, sysOrgVO, allDepartmentId);
}
sysOrgVO.setAllDepartmentId(allDepartmentId);
List<SysOrgVO> voList = new ArrayList<>();
voList.add(sysOrgVO);
if (CollectionUtils.isEmpty(sysOrgList)) {
return voList;
}
// 预处理所有节点为SysOrgVO并构建子节点映射表
List<SysOrgVO> allOrgVOs = sysOrgList.stream()
.map(entity -> BeanUtil.toBean(entity, SysOrgVO.class))
.map(this::setInfoForTree) // 提前应用树形结构转换
.collect(Collectors.toList());
// 构建父节点到子节点的映射key: upOrgIdvalue: 子节点列表)
Map<String, List<SysOrgVO>> parentToChildrenMap = new HashMap<>();
String rootOrgCode = "10000000";
for (SysOrgVO orgVO : allOrgVOs) {
String parentId = StringUtils.isBlank(orgVO.getUpOrgId()) ? rootOrgCode : orgVO.getUpOrgId();
parentToChildrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(orgVO);
}
// 获取根节点ID
String rootNode = StringUtils.isNotBlank(org.getOrgId()) ? org.getOrgId() : rootOrgCode;
// 使用StringBuilder记录所有部门ID
StringBuilder allDepartmentIdBuilder = new StringBuilder(rootNode);
// 构建多级树结构(从根节点开始递归)
List<SysOrgVO> rootChildren = parentToChildrenMap.getOrDefault(rootNode, new ArrayList<>());
for (SysOrgVO rootChild : rootChildren) {
buildMultiLevelTree(rootChild, parentToChildrenMap, allDepartmentIdBuilder);
voList.add(rootChild);
}
// 设置全量部门ID
voList.forEach(vo -> vo.setAllDepartmentId(allDepartmentIdBuilder.toString()));
return voList;
}
}
/**
* 递归构建多级组织机构树结构
*
* @param currentNode 当前需要处理的组织机构节点
* @param parentToChildrenMap 父节点ID到子节点列表的映射表预处理结果用于O(1)时间查找子节点)
* @param allDepartmentIdBuilder 记录所有层级部门ID的字符串构建器按层级顺序累加
* @apiNote 通过递归方式为当前节点设置子节点,并继续处理子节点的子节点,最终形成完整的多级树结构。
* 依赖预处理的{@code parentToChildrenMap}提升查找子节点效率,避免重复遍历全量数据。
*/
private void buildMultiLevelTree(SysOrgVO currentNode,
Map<String, List<SysOrgVO>> parentToChildrenMap,
StringBuilder allDepartmentIdBuilder) {
// 从映射表直接获取当前节点的子节点O(1)
List<SysOrgVO> children = parentToChildrenMap.getOrDefault(currentNode.getOrgId(), new ArrayList<>());
// 排序
List<SysOrgVO> sortedChildren = children.stream()
.sorted(Comparator.comparing(SysOrgVO::getSort, Comparator.nullsLast(String::compareTo)))
.collect(Collectors.toList());
currentNode.setChildren(sortedChildren);
// 记录当前节点ID,累加所有层级ID
allDepartmentIdBuilder.append(",").append(currentNode.getOrgId());
// 递归处理子节点
for (SysOrgVO child : sortedChildren) {
buildMultiLevelTree(child, parentToChildrenMap, allDepartmentIdBuilder);
}
}
@Override
public Boolean insertByVo(SysOrgVO vo) {
vo.setOrgId(PropertyUtils.getSnowflakeId()).setCreateDate(LocalDateTime.now());
@ -165,37 +206,6 @@ public class SysOrgServiceImpl extends BaseServiceImpl<SysOrgMapper,SysOrg> imp
.setKey(orgVO.getOrgId())
.setValue(orgVO.getOrgId());
}
/**
* 递归查询部门信息树形展示
*
* @param sysOrgVOList 所有部门信息
* @param sysOrg 当前查询节点
*/
private void getChildrenNode(List<SysOrgVO> sysOrgVOList, SysOrgVO sysOrg, String allDepartmentId) {
List<SysOrgVO> childrenNodeList = new ArrayList<>();
for (SysOrgVO sysOrgVO : sysOrgVOList) {
//判断机构部门上级ID和当前节点ID是否相等
if (StringUtils.equals(sysOrg.getOrgId(), sysOrgVO.getUpOrgId())) {
childrenNodeList.add(sysOrgVO);
allDepartmentId += sysOrgVO.getOrgId();
getChildrenNode(sysOrgVOList, sysOrgVO, allDepartmentId);
}
}
//判断是否有下级节点
if (!CollectionUtils.isEmpty(childrenNodeList)) {
//根据sort排序
childrenNodeList = childrenNodeList
.stream()
.map(this::setInfoForTree)
.sorted(Comparator.comparing(SysOrgVO::getSort, Comparator.nullsLast(String::compareTo)))
.collect(Collectors.toList());
sysOrg.setChildren(childrenNodeList);
} else {
sysOrg.setChildren(ListUtil.empty());
}
}
private LambdaQueryWrapper<SysOrg> buildQueryWrapper(SysOrgVO vo) {
LambdaQueryWrapper<SysOrg> lqw = Wrappers.lambdaQuery();