java 转化为树工具类
Java 树状结构转化工具类
1:使用场景:菜单结构数(n级别)
2:数据库存储的往往的是一条条的数据,通过id,查询数据库的父类id进行获取子类数据,然后进行组装数据,数据曾经可能很多。
往往的解决思路是通过递归进行查询,递归中可能会写sql查询,效率极低。有需要的可以了解一下递归的时间复杂度和空间复杂度。
3:本工具类的优点在于以空间换时间的思路。通过查询出所需要的数据,将数据进行内存中处理,使用一层for结构,进行遍历循环,获取子类并进行组装数据
具体可以看代码
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; public class TreeUtils<T> { private final Map<Object, T> nodeMap = new HashMap<>(); private final List<T> root = new ArrayList<>(); private final List<T> baseRoot = new ArrayList<>(); private String childParamName = null; private String parentParamName = null; private String listParamName = null; private final List<T> listData; private final Class<?> aClass; private Method methodGet; private Method methodSet; /** * 初始化数据 * @param nodes */ public TreeUtils(List<T> nodes) { this.listData = nodes; aClass = nodes.get(0).getClass(); setBase(); listData.forEach(res -> nodeMap.put(getVal(res, parentParamName), res)); } /** * 转化为树,默认返回跟节点 */ public List<T> tree() { listData.forEach(one -> { T childData = nodeMap.get(getVal(one, childParamName)); if (childData != null) { setVal(childData, one); } else { baseRoot.add(one); } }); return getBaseRoot(); } /** * 转化为树,默认返回节点为base的节点树 */ public List<T> tree(Object base) { if (base == null) { return tree(); } listData.forEach(one -> { T childData = nodeMap.get(getVal(one, childParamName)); if (childData != null) { setVal(childData, one); } if (base.toString().equals(String.valueOf(getVal(one, parentParamName)))) { root.add(one); } }); return getRoot(); } private void setBase() { Field[] tableDoris = this.aClass.getDeclaredFields(); for (Field doris : tableDoris) { TreeUtil annotation = doris.getAnnotation(TreeUtil.class); if (annotation != null) { if (TreeType.id.name().equals(annotation.value().toString())) { parentParamName = doris.getName(); } else if (TreeType.parentId.name().equals(annotation.value().toString())) { childParamName = doris.getName(); } else if (TreeType.childList.name().equals(annotation.value().toString())) { listParamName = doris.getName(); } } } try { this.methodGet = aClass.getMethod("get" + getMethodName(listParamName)); this.methodGet.setAccessible(true); this.methodSet = aClass.getMethod("set" + getMethodName(listParamName), List.class); this.methodSet.setAccessible(true); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } private Object getVal(T t, String name) { // 获取单个属性 try { Field field = aClass.getDeclaredField(name); field.setAccessible(true); return field.get(t); } catch (Exception e) { throw new RuntimeException(e); } } @SuppressWarnings("unchecked") private void setVal(T t, T child) { // 获取单个属性 try { List<T> childData = null; Object obj = methodGet.invoke(t); if (obj instanceof List<?>) { childData = (List<T>) obj; } if (childData == null) { childData = new ArrayList<>(); } childData.add(child); methodSet.invoke(t, childData); } catch (Exception e) { throw new RuntimeException(e); } } private List<T> getBaseRoot() { return baseRoot; } private List<T> getRoot() { return root; } private static String getMethodName(String fieldName) { byte[] items = fieldName.getBytes(); items[0] = (byte) ((char) items[0] - 'a' + 'A'); return new String(items); } } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface TreeUtil { TreeType value(); } enum TreeType { //标识为id, id, //标识为父类id字段 parentId, //表示为结果存储对象 childList }
使用
加入注解
import lombok.Data; import java.util.List; /** * 视图实体类 * * @author Chill */ @Data public class TestTree { /** * 主键ID */ @TreeUtil(value = TreeType.id) private Long id; /** * 父节点ID */ @TreeUtil(value =TreeType.parentId) private Long parentId; /** * 子孙节点 */ @TreeUtil(value = TreeType.childList) private List<TestTree> children; }
测试
public static void main(String[] args) { List<TestTree> list1 = new ArrayList<>(); for (long i = 0; i < 10; i++) { TestTree menuVO = new TestTree(); menuVO.setId(i); menuVO.setParentId(i-1); list1.add(menuVO); } System.out.println( new TreeUtils<>(list1).tree()); }
效果
[TestTree(id=0, parentId=-1, children=[TestTree(id=1, parentId=0, children=[TestTree(id=2, parentId=1, children=[TestTree(id=3, parentId=2, children=[TestTree(id=4, parentId=3, children=[TestTree(id=5, parentId=4, children=[TestTree(id=6, parentId=5, children=[TestTree(id=7, parentId=6, children=[TestTree(id=8, parentId=7, children=[TestTree(id=9, parentId=8, children=null)])])])])])])])])])]