149 lines
4.7 KiB
Markdown
149 lines
4.7 KiB
Markdown
# 树形结构转换工具类
|
|
|
|
## 功能介绍
|
|
- 将 A类的List数组快速转换为 B类型 List 的树形结构列表
|
|
|
|
## 实现原理
|
|
- 主要使用到Java反射机制,将A类中的字段拷贝到B类中,并且根据A类中id 与 pid之间的关系快速构建树形结构
|
|
- 设置配置类,更方便的实现A类与B类之前转换的需要,配置类包含有id字段与pid字段之间自定义设置,A类中需要转换到B类中的字段,以及是需要Spring 中 BeanUtils直接copy,以及如果使用了BeanUtil后需要排除的字段
|
|
|
|
## 代码展示
|
|
```java
|
|
/**
|
|
* @author Clay
|
|
* @date 2022/11/16
|
|
*/
|
|
public class TreeUtil {
|
|
|
|
private static TreeConfig config;
|
|
|
|
private static Class<?> targetClass;
|
|
|
|
/**
|
|
* 构建tree结构
|
|
*
|
|
* @param list
|
|
* @param target
|
|
* @param node
|
|
* @param <T>
|
|
* @return
|
|
*/
|
|
public static <T> List<T> build(List<?> list, Class<T> target, Node node) {
|
|
//初始化config
|
|
config = new TreeConfig();
|
|
//将目标class对象设置为全局对象
|
|
TreeUtil.targetClass = target;
|
|
//提供给实现类对config进行修改
|
|
node.build(config);
|
|
//获取到最小的
|
|
Object min = list.stream().min(Comparator.comparing(object -> getParentId(object).toString())).get();
|
|
//获取到最小的父级id
|
|
Object minPid = getParentId(min);
|
|
//将数据通过他们的各自的父id进行分组
|
|
Map<Object, List<Object>> listMap = list.stream().collect(Collectors.groupingBy(object -> getParentId(object)));
|
|
//最终开始进行tree的构建
|
|
return getChildren(listMap, minPid);
|
|
}
|
|
|
|
/**
|
|
* 获取到子节点
|
|
*
|
|
* @param listMap
|
|
* @param parentId
|
|
* @param <T>
|
|
* @return
|
|
*/
|
|
private static <T> List<T> getChildren(Map<Object, List<Object>> listMap, Object parentId) {
|
|
//获取到缓存中的list
|
|
List<?> objects = listMap.get(parentId);
|
|
if (chickList(objects)) {
|
|
return null;
|
|
}
|
|
listMap.remove(parentId);
|
|
//遍历数组,并将对象一一的转换
|
|
List<Object> collect = objects.stream().map(object ->
|
|
conversion(object, listMap)).collect(Collectors.toList());
|
|
return (List<T>) collect;
|
|
}
|
|
|
|
/**
|
|
* 对象直接的字段进行转换
|
|
*
|
|
* @param object
|
|
* @param listMap
|
|
* @param <T>
|
|
* @return
|
|
*/
|
|
private static <T> T conversion(Object object, Map<Object, List<Object>> listMap) {
|
|
try {
|
|
Object targetObject = targetClass.newInstance();
|
|
//相同字段名称直接赋值
|
|
if (config.isCopy()){
|
|
BeanUtils.copyProperties(object, targetObject);
|
|
}
|
|
//不同字段名进行赋值
|
|
for (Map.Entry<String, String> entry : config.getMapper().entrySet()) {
|
|
String targetKey = entry.getKey();
|
|
String sourceKey = entry.getValue();
|
|
Object value = ReflectUtils.invokeGetter(object, sourceKey);
|
|
Object[] args = new Object[]{value};
|
|
ReflectUtils.invokeSetter(targetObject, targetKey, args);
|
|
}
|
|
//设置子节点
|
|
Object id = ReflectUtils.invokeGetter(object, config.getIdField());
|
|
List<Object> children = getChildren(listMap, id);
|
|
if (!chickList(children)) {
|
|
ReflectUtils.invokeSetter(targetObject, config.getChildrenField(), new Object[]{children});
|
|
}
|
|
//设置完毕后,将需要排除的字段进行置空
|
|
for (String key : config.getExclude()) {
|
|
ReflectUtils.invokeSetNull(targetObject, key);
|
|
}
|
|
//返回结果
|
|
return (T) targetObject;
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查list是否为空
|
|
*
|
|
* @param objects
|
|
* @return
|
|
*/
|
|
private static boolean chickList(List<?> objects) {
|
|
return null == objects || objects.isEmpty();
|
|
}
|
|
|
|
/**
|
|
* 获取到父级id
|
|
*
|
|
* @param object
|
|
* @return
|
|
*/
|
|
private static Object getParentId(Object object) {
|
|
try {
|
|
return ReflectUtils.invokeGetter(object, config.getParentField());
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
}
|
|
```
|
|
## 使用demo
|
|
```java
|
|
@Override
|
|
public List<DeptVo> selectDeptTree(String deptName, Integer state) {
|
|
List<Dept> deptList = deptMapper.selectDeptList(deptName, state);
|
|
return TreeUtil.build(deptList,DeptVo.class,(config)->{
|
|
config.setIdField("deptId");
|
|
config.setMapper("key","deptId");
|
|
config.setExclude("phone");
|
|
});
|
|
}
|
|
```
|
|
|
|
|