现在前端使用elementui中的tree组件,需要后端返回树结构的数据,但是数据库中存储的扁平化的数据,例如id,parentId。需要进行写个工具栏去进行统一处理。
首先引入了一个名为 buildTree 的通用方法,使用一个函数式接口 NodeMapper<T> 来映射不同类型的实体到 TreeVo 对象。
这使得在创建树形结构时只需编写一次通用逻辑,而不需要重复实现相似的代码。 映射逻辑: 在 buildTree 方法中,我们针对不同的实体类型使用一个 Lambda 表达式来指定如何从实体构建 TreeVo 对象。这为各种树结构的构建提供了灵活性。 提高了代码的可读性与可维护性。以后若有新的树形结构只需要简单地调用 buildTree 方法,并提供合适的映射逻辑即可。下面先给出工具类示例。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TreeVoUtils {
public static List<TreeVo> buildEquipmentTypeTree(List<EquipmentType> dataList) {
return buildTree(dataList, (item) -> new TreeVo() {{
setId(item.getId());
setParentId(item.getParentId());
setName(item.getName());
setNumber(item.getNumber());
setStatus(item.getStatus());
setRemark(item.getRemark());
}});
}
public static List<TreeVo> buildEquipmentKeyComponentsTree(List<EquipmentKeyComponents> dataList) {
return buildTree(dataList, (item) -> new TreeVo() {{
setId(item.getId());
setParentId(item.getParentId());
setName(item.getName());
setNumber(item.getNumber());
setChangeFrequency(item.getChangeFrequency());
setIsKey(item.getIsKey());
setRemark(item.getRemark());
}});
}
public static List<TreeVo> buildDocumentFolderTree(List<DocumentFolder> dataList) {
return buildTree(dataList, (item) -> new TreeVo() {{
setId(item.getId());
setParentId(item.getParentId());
setName(item.getName());
setRemark(item.getRemark());
}});
}
public static List<TreeVo> buildMaterialCategoryTree(List<MaterialCategory> dataList) {
return buildTree(dataList, (item) -> new TreeVo() {{
setId(item.getId());
setParentId(item.getParentId());
setName(item.getName());
setRemark(item.getRemark());
}});
}
private static <T> List<TreeVo> buildTree(List<T> dataList, NodeMapper<T> mapper) {
Map<Long, TreeVo> nodeMap = new HashMap<>();
List<TreeVo> roots = new ArrayList<>();
for (T item : dataList) {
TreeVo node = mapper.map(item);
nodeMap.put(node.getId(), node);
Long parentId = node.getParentId();
if (parentId == null) {
roots.add(node);
} else {
TreeVo parent = nodeMap.get(parentId);
if (parent != null) {
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
parent.getChildren().add(node);
}
}
}
return roots;
}
@FunctionalInterface
private interface NodeMapper<T> {
TreeVo map(T item);
}
}
@FunctionalInterface 注解和定义的 NodeMapper<T> 接口在上述代码中扮演了一个重要的角色,
@FunctionalInterface 注解 定义 @FunctionalInterface 是一个用于标记接口的注解,表示这个接口是一个函数式接口(Functional Interface)。 特性 函数式接口是只包含一个抽象方法的接口。这样的接口可以被隐式地转换为 Lambda 表达式或方法引用。 在编译时,如果接口中包含多个抽象方法,编译器会抛出错误,确保符合函数式接口的定义。
NodeMapper<T> 接口 定义 NodeMapper<T> 是一个泛型接口,定义了一个方法 map(T item),它接受一个类型为 T 的参数,并返回一个 TreeVo 类型的对象。 目的 这个接口的主要目的是为构建树形结构提供一种灵活的映射机制。它允许传入不同类型的实体对象(如 EquipmentType, EquipmentKeyComponents, DocumentFolder, MaterialCategory 等),并通过实现 map 方法来指定如何把这些实体对象转化为 TreeVo 对象。
这样,即使以后需要对映射逻辑进行更改或对其他类型进行映射,只需传入不同的 Lambda 表达式即可,保证了代码的灵活性和可扩展性。 总结 NodeMapper<T> 接口的定义及其作为函数式接口的使用,使得在构建树形结构时,可以灵活地处理多种不同类型的输入,提供了一种干净的方式来映射数据,减少了重复代码,同时增强了代码的可读性和维护性。