公司需要对接第三方数据,同步对方的部门组织数据,众所周知递归遍历数据容易出现栈溢出,所以我自己写了个工具,根据 id、parentId 拆解数据结构,实现数据遍历排序。
代码如下:
- 部门机构的VO类
@Getter
@Setter
@Builder
public class PhxDeptSyncReqVO {
private String thirdId;
private String parentThirdId;
private String name;
}
- 排序方法.
- 思路是这样的,首先将 deptList 集合拆分成 deptIdMap、deptParentIdMap, 然后根据规则找到 root 节点,按照 root 节点来遍历拼装完整的 dept Tree。
@Slf4j
public class OuSortV2Util {
public static List<PhxDeptSyncReqVO> sort(List<PhxDeptSyncReqVO> ouList) {
List<String> thirdIdList = ouList.stream().map(PhxDeptSyncReqVO::getThirdId).distinct().collect(Collectors.toList());
log.info("获取元素的id: thirdIdListSize:{}", thirdIdList);
List<String> parentIdList = ouList.stream().map(PhxDeptSyncReqVO::getParentThirdId).distinct().collect(Collectors.toList());
log.info("获取元素的parentId: parentIdListSize:{}", parentIdList.size());
List<String> rootParentIdList = new ArrayList<>();
parentIdList.stream()
.distinct()
.forEach(item -> {
if (StringUtils.isBlank(item)) {
rootParentIdList.add(item);
log.info("找到parentId为空的root节点");
} else if (item.equals("0")) {
rootParentIdList.add(item);
log.info("找到parentId为0空的root节点");
} else if (!thirdIdList.contains(item)) {
rootParentIdList.add(item);
log.info("找到parentId为{}空的root节点", item);
}
});
log.info("按规则提取出rootId:rootParentIdListSize:{}", rootParentIdList.size());
return sort(ouList, rootParentIdList, null, null, null);
}
public static List<PhxDeptSyncReqVO> sort(List<PhxDeptSyncReqVO> ouList, List<String> rootParentIdList) {
return sort(ouList, rootParentIdList, null, null, null);
}
public static List<PhxDeptSyncReqVO> sort(List<PhxDeptSyncReqVO> ouList, List<String> rootParentIdList, List<String> excludeParentIdList, Boolean containsSub) {
return sort(ouList, rootParentIdList, excludeParentIdList, containsSub, null);
}
/**
* 部门排序
*
* @param ouList 部门列表
* @param rootParentIdList 部门根节点id列表
* @param excludeParentIdList 需要剔除的节点的 parentId 列表
* @param containsSub 剔除的节点是否包含子节点
* @param excludeIdList 需要剔除的节点的 id 列表
* @return 排序后的数据
*/
public static List<PhxDeptSyncReqVO> sort(List<PhxDeptSyncReqVO> ouList, List<String> rootParentIdList, List<String> excludeParentIdList, Boolean containsSub, List<String> excludeIdList) {
if (CollectionUtil.isEmpty(ouList) || CollectionUtil.isEmpty(rootParentIdList)) {
log.error("数据不能为空:ouListSize:{}, rootParentIdListSize:{}", ouList.size(), rootParentIdList.size());
return ouList;
}
//根据 parentId 将部门数据分组
Map<String, List<PhxDeptSyncReqVO>> ouMapList = convert2Map(ouList, "parentThirdId");
//过滤 excludeParentId
ouFilter(ouMapList, excludeParentIdList, containsSub, excludeIdList);
//获取 root 部门的列表
List<PhxDeptSyncReqVO> rootOuList = getRootOuList(ouMapList, rootParentIdList);
//部门最终排序后的结果集
List<PhxDeptSyncReqVO> sortedList = new ArrayList<>();
//遍历 root 节点
for (PhxDeptSyncReqVO rootOu : rootOuList) {
//写入 root 节点
sortedList.add(rootOu);
//找出 root 的子节点,然后使用子节点的 orgNum 向 MapList 中获取数据
List<String> childIdList = new ArrayList<>();
childIdList.add(rootOu.getThirdId());
while (CollectionUtil.isNotEmpty(childIdList)) {
//获取map中的数据,添加到 sortedList 队列中
List<PhxDeptSyncReqVO> childOrgList = getChildList(ouMapList, childIdList);
sortedList.addAll(childOrgList);
//更新子节点查询列表,查询下一级的子节点
childIdList = new ArrayList<>();
for (PhxDeptSyncReqVO childOrg : childOrgList) {
childIdList.add(childOrg.getThirdId());
}
}
}
//打印找不到的部门
printNotExistsData(ouMapList);
return sortedList;
}
/**
* 打印找不到父节点的,无法进行排序的数据
*
* @param ouMapList 数据集合
*/
private static void printNotExistsData(Map<String, List<PhxDeptSyncReqVO>> ouMapList) {
for (Iterator<Map.Entry<String, List<PhxDeptSyncReqVO>>> it = ouMapList.entrySet().iterator(); it.hasNext(); ) {
for (PhxDeptSyncReqVO ou : it.next().getValue()) {
log.error("部门数据同步异常,id为:{} 的部门:{}, 父节点:id={} 不存在",
ou.getThirdId(), ou.getName(), ou.getParentThirdId());
}
}
}
/**
* 获取子节点列表
*
* @param ouMapList 部门分组集合
* @param childOrgNumList 子节点id列表
* @return 子节点列表
*/
private static List<PhxDeptSyncReqVO> getChildList(Map<String, List<PhxDeptSyncReqVO>> ouMapList, List<String> childOrgNumList) {
List<PhxDeptSyncReqVO> childOrgList = new ArrayList<>();
for (String childOrgNum : childOrgNumList) {
if (!ouMapList.containsKey(childOrgNum)) {
continue;
}
childOrgList.addAll(ouMapList.get(childOrgNum));
ouMapList.remove(childOrgNum);
}
return childOrgList;
}
/**
* 获取根节点列表
*
* @param ouMapList 部门分组集合
* @param rootIdList 根节点id列表
* @return 根节点列表
*/
private static List<PhxDeptSyncReqVO> getRootOuList(Map<String, List<PhxDeptSyncReqVO>> ouMapList, List<String> rootIdList) {
List<PhxDeptSyncReqVO> rootOuList = new ArrayList<>();
for (Iterator<Map.Entry<String, List<PhxDeptSyncReqVO>>> it = ouMapList.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, List<PhxDeptSyncReqVO>> item = it.next();
String parentId = item.getKey();
if (rootIdList.contains(parentId)) {
//找出 root 节点,添加到集合中
rootOuList.addAll(ouMapList.get(parentId));
it.remove();
}
}
return rootOuList;
}
/**
* 根据 parentId 将 ouList 分组,转换成 MapList
*
* @param ouList 部门数据
* @return MapList, Key=parentId
*/
private static Map<String, List<PhxDeptSyncReqVO>> convert2Map(List<PhxDeptSyncReqVO> ouList, String groupKeyName) {
//根据parent_id 分组
List<List<PhxDeptSyncReqVO>> ouListGroup = CollectionUtil.groupByField(ouList, groupKeyName);
//以 parent_id 为 Key,将 ouList 转为 MapList
Map<String, List<PhxDeptSyncReqVO>> ouMapList = new HashMap<>();
for (List<PhxDeptSyncReqVO> itemList : ouListGroup) {
PhxDeptSyncReqVO item = itemList.get(0);
ouMapList.put(item.getParentThirdId(), itemList);
}
return ouMapList;
}
/**
* 数据过滤,过滤掉 excludeParentIdList 指定的节点及其子节点。
*
* @param ouMapList 组织机构map
* @param excludeParentIdList 需要过滤的parentId
* @param containsSub 是否过滤子节点
* @param excludeIdList 需要过滤的 id
*/
private static void ouFilter(Map<String, List<PhxDeptSyncReqVO>> ouMapList, List<String> excludeParentIdList, Boolean containsSub, List<String> excludeIdList) {
if (MapUtil.isEmpty(ouMapList)) {
return;
}
if (CollectionUtil.isNotEmpty(excludeIdList)) {
ouFilterById(ouMapList, excludeIdList);
}
if (CollectionUtil.isNotEmpty(excludeParentIdList)) {
ouFilterByParentId(ouMapList, excludeParentIdList, containsSub);
}
}
/**
* 根据指定的 parentId 过滤数据
*/
private static void ouFilterByParentId(Map<String, List<PhxDeptSyncReqVO>> ouMapList, List<String> excludeParentIdList, Boolean containsSub) {
//从参数中获取要移除的部门id,遍历移除
for (String excludeItem : excludeParentIdList) {
//获取子节点
List<PhxDeptSyncReqVO> excludeItemList = ouMapList.get(excludeItem);
if (CollectionUtil.isEmpty(excludeItemList)) {
continue;
}
//移除当前节点
ouMapList.remove(excludeItem);
if (!containsSub) {
//不移除子节点
continue;
}
//遍历当前节点的子节点,并依次移除
Iterator<PhxDeptSyncReqVO> iterator = excludeItemList.iterator();
while (iterator.hasNext()) {
PhxDeptSyncReqVO next = iterator.next();
//先从迭代器中移除,防止循环遍历
iterator.remove();
//查询是否有子节点
List<PhxDeptSyncReqVO> ouList = ouMapList.get(next.getThirdId());
if (CollectionUtil.isEmpty(ouList)) {
continue;
}
//删除数据
ouMapList.remove(next.getThirdId());
//将需要删除的节点写入list
excludeItemList.addAll(ouList);
//重置迭代器
iterator = excludeItemList.iterator();
}
}
}
/**
* 根据指定的 id 过滤数据
*/
private static void ouFilterById(Map<String, List<PhxDeptSyncReqVO>> ouMapList, List<String> excludeIdList) {
//根据指定的id过滤部门
for (Map.Entry<String, List<PhxDeptSyncReqVO>> item : ouMapList.entrySet()) {
Iterator<PhxDeptSyncReqVO> iterator = item.getValue().iterator();
while (iterator.hasNext()) {
PhxDeptSyncReqVO next = iterator.next();
if (excludeIdList.contains(next.getThirdId())) {
iterator.remove();
}
}
}
}
}