package com.java.utils;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.sf.entity.dto.BaseTree;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* 树形机构转化工具
* @author lizh
*/
public class TreeUtils<T extends BaseTree> {
/** 父级时分组会出现异常,给默认值 **/
private static final String DEFAULT_FIST_KEY = "[_0-_df_key_-0_]";
private TreeUtils(){}
/**
*集合转成树形结构
* @param cols 集合数据
* @return 返回树形列表
*/
public static<T> List<T> col2Tree(Collection<? extends BaseTree> cols){
return col2Tree(cols,false, null);
}
/**
*集合转成树形结构
* @param cols 集合数据
* @param isSort 是否排序
* @return 返回树形列表
*/
public static<T> List<T> col2Tree(Collection<? extends BaseTree> cols, boolean isSort){
return col2Tree(cols, isSort, false, null);
}
/**
*集合转成树形结构
* @param cols 集合数据
* @param rootParentIds 根节点上级Id
* @return 返回树形列表
*/
public static<T> List<T>col2Tree(Collection<? extends BaseTree> cols, Object[] rootParentIds){
return col2Tree(cols,false, rootParentIds);
}
/**
*集合转成树形结构
* @param cols 集合数据
* @param isSort 是否排序
* @param rootParentIds 根节点上级Id
* @return 返回树形列表
*/
public static<T> List<T> col2Tree(Collection<? extends BaseTree> cols, boolean isSort, Object[] rootParentIds){
return (List<T>)col2Tree((Collection<BaseTree>)cols, isSort, false, rootParentIds);
}
/**
*集合转成树形结构
* @param cols 集合数据
* @param isSort 是否排序
* @param isReversed 是否倒叙
* @param rootParentIds 根节点上级Id
* @return 返回树形列表
*/
public static<T> List<T> col2Tree(Collection<? extends BaseTree> cols, boolean isSort, boolean isReversed, Object[] rootParentIds){
return (List<T>)doCol2Tree((Collection<BaseTree>)cols, isSort, isReversed, rootParentIds);
}
/**
*集合转成树形结构
* @param cols 集合数据
* @param isSort 是否排序
* @param isReversed 是否倒叙
* @param rootParentIds 根节点上级Id
* @return 返回树形列表
*/
private static List<BaseTree> doCol2Tree(Collection<BaseTree> cols, boolean isSort, boolean isReversed, Object[] rootParentIds){
if(CollectionUtils.isEmpty(cols)){ return Collections.emptyList(); }
Set<Object> rootParentIdSet = ArrayUtils.isNotEmpty(rootParentIds) ?
Sets.newHashSet(rootParentIds) : Sets.newHashSet() ;
Map<Object,List<BaseTree>> nodeMap = cols.stream()
.filter( t -> Objects.nonNull(t) && !isRoot(rootParentIdSet, t.getParentId()))
.collect(Collectors.groupingBy(BaseTree::getParentId));
cols.forEach(ch -> ch.setChildren(nodeMap.get(ch.getId())));
List<BaseTree> resultList = cols.stream().filter(t -> isRoot(rootParentIdSet, t.getParentId())).collect(Collectors.toList());
if(isSort){ treeSort(resultList, false); }
return resultList;
}
/**
* list转树形结构,没有父级ID自动跳为一级菜单
* @param cols 源数据列表
* @param isSort 是否排序
* @param isReversed 是否倒叙
* @return 树形列表
*/
private static List<BaseTree> doAutoCol2Tree(Collection<BaseTree> cols, boolean isSort, boolean isReversed){
if(CollectionUtils.isEmpty(cols)){ return Collections.emptyList(); }
Map<Object,List<BaseTree>> nodeMap = cols.stream().filter(Objects::nonNull).map(t -> {
if(Objects.isNull(t.getParentId())){
t.setParentId(DEFAULT_FIST_KEY);
}
return t;
}).collect(Collectors.groupingBy(BaseTree::getParentId));
cols.forEach(ch -> {
ch.setChildren(nodeMap.get(ch.getId()));
nodeMap.remove(ch.getId());
});
List<Object> firstIds = new ArrayList<>();
nodeMap.values().forEach(lst -> lst.forEach(t -> firstIds.add(t.getId())));
List<BaseTree> resultList = cols.stream().filter(t ->{
if(firstIds.contains(t.getId())){
if(Objects.equals(DEFAULT_FIST_KEY,t.getParentId())){
t.setParentId(null);
}
return true;
}
return false;
}).collect(Collectors.toList());
if(isSort){ treeSort(resultList, isReversed);}
return resultList;
}
/**
* list转树形结构,没有父级ID自动跳为一级菜单
* @param cols 源数据列表
* @param isSort 是否排序
* @param isReversed 是否倒叙
* @return 树形列表
*/
public static<T> List<T> autoCol2Tree(Collection<? extends BaseTree> cols, boolean isSort, boolean isReversed){
return (List<T>) doAutoCol2Tree((Collection<BaseTree>) cols, isSort, isReversed);
}
/**
* list转树形结构,没有父级ID自动跳为一级菜单
* @param cols 源数据列表
* @param isSort 是否排序
* @return 树形列表
*/
public static<T> List<T> autoCol2Tree(Collection<? extends BaseTree> cols, boolean isSort){
return autoCol2Tree(cols,isSort,false);
}
/**
* list转树形结构,没有父级ID自动跳为一级菜单
* @param cols 源数据列表
* @return 树形列表
*/
public static<T> List<T> autoCol2Tree(Collection<? extends BaseTree> cols){
return autoCol2Tree((Collection)cols,false,false);
}
/** 判断是否为根节点 **/
private static boolean isRoot(Set<Object> rootParentIdSet, Object parentId){
return Objects.isNull(parentId) || rootParentIdSet.contains(parentId);
}
/** 对各级菜单进行排序 **/
private static void treeSort(List<BaseTree> treeList, boolean reversed){
if(CollectionUtils.isEmpty(treeList) || Objects.equals(treeList.size(),1)){ return; }
List<BaseTree> sortList = treeList.stream().sorted(
reversed ? Comparator.comparing(BaseTree::getSort).reversed():Comparator.comparing(BaseTree::getSort)
).collect(Collectors.toList());
treeList.clear();
treeList.addAll(sortList);
treeList.forEach(t -> treeSort(t.getChildren(),reversed));
}
public static void main(String[] args) {
BaseTree node1a = new BaseTree(1,null,"一级目录1",1);
BaseTree node2a = new BaseTree(2,"","一级目录2",2);
BaseTree node3a = new BaseTree(3,null,"一级目录3",3);
BaseTree node4a = new BaseTree(4,0,"一级目录4",4);
BaseTree node5a = new BaseTree(5,-1,"一级目录5",5);
BaseTree node21a = new BaseTree(6,1,"二级目录1",1);
BaseTree node22a = new BaseTree(7,1,"二级目录2",2);
BaseTree node23a = new BaseTree(8,1,"二级目录3",3);
BaseTree node24a = new BaseTree(9,2,"二级目录4",4);
BaseTree node25a = new BaseTree(10,3,"二级目录5",5);
BaseTree node31a = new BaseTree(11,8,"3级目录1",1);
BaseTree node32a = new BaseTree(12,8,"3级目录2",2);
BaseTree node33a = new BaseTree(13,10,"3级目录3",3);
BaseTree node34a = new BaseTree(14,100,"3级目录4",4);
BaseTree node35a = new BaseTree(15,16,"3级目录5",5);
BaseTree node41a = new BaseTree(16,15,"4级目录1",1);
BaseTree node42a = new BaseTree(17,11,"4级目录2",2);
BaseTree node43a = new BaseTree(18,15,"4级目录3",3);
BaseTree node44a = new BaseTree(19,11,"4级目录4",4);
BaseTree node54a = new BaseTree(20,17,"5级目录5",5);
BaseTree node55a = new BaseTree(21,18,"5级目录5",5);
BaseTree node61a = new BaseTree(22,21,"6级目录5",5);
List<BaseTree> lists = Lists.newArrayList(node3a,node1a,node2a,node5a,node4a,
node21a,node22a,node23a,node24a,node25a,
node31a,node32a,node33a,node34a,node35a,
node41a,node42a,node43a,node44a,
node54a,node55a,
node61a
);
System.out.println(JSON.toJSONString(col2Tree(lists,true,false, new Object[]{"",0,-1,null,100})));
System.out.println(JSON.toJSONString(autoCol2Tree(lists,true,false)));
}
}
package com.java.entity.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 树形基础类
* @author lizh
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class BaseTree implements Serializable {
private static final long serialVersionUID = 1L;
/** 本级ID **/
private Object id;
/** 父级ID **/
private Object parentId;
/** 本级名称 **/
private String name;
/** 排序号,越小越靠前 **/
private Integer sort;
/** 子级列表 **/
List<BaseTree> children;
public BaseTree(Object id, Object parentId, String name, Integer sort) {
this.id = id;
this.parentId = parentId;
this.name = name;
this.sort = sort;
}
}
若分享转发请附上原文地址。