Java 树状结构转化工具类
1:使用场景:菜单结构数(n级别)
2:数据库存储的往往的是一条条的数据,通过id,查询数据库的父类id进行获取子类数据,然后进行组装数据,数据曾经可能很多。
往往的解决思路是通过递归进行查询,递归中可能会写sql查询,效率极低。有需要的可以了解一下递归的时间复杂度和空间复杂度。
3:本工具类的优点在于以空间换时间的思路。通过查询出所需要的数据,将数据进行内存中处理,使用一层for结构,进行遍历循环,获取子类并进行组装数据
具体可以看代码
package org.springblade.common.utils; 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) { System.out.println(annotation.value()); 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 }View Code
使用
加入注解
@Data public class TestTree { /** * 主键ID */ @JsonSerialize(using = ToStringSerializer.class) @TreeUtil(value = TreeType.id) private Long id; /** * 父节点ID */ @JsonSerialize(using = ToStringSerializer.class) @TreeUtil(value =TreeType.parentId) private Long parentId; /** * 子孙节点 */ @JsonInclude(JsonInclude.Include.NON_EMPTY) @TreeUtil(value = TreeType.childList) private List<TestTree> children; }View Code
测试
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); list1.add(menuVO); } list1.get(0).setParentId(-1L); list1.get(1).setParentId(0L); list1.get(2).setParentId(1L); list1.get(3).setParentId(2L); list1.get(4).setParentId(3L); list1.get(5).setParentId(4L); list1.get(6).setParentId(5L); list1.get(7).setParentId(6L); list1.get(8).setParentId(7L); list1.get(9).setParentId(8L); List<TestTree> list2 = new TreeUtils<TestTree>(list1).tree(); System.out.println(list2); }View Code
效果
[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)])])])])])])])])])]
标签:java,get,List,private,id,转化,TestTree,parentId,为树 From: https://www.cnblogs.com/tdf-/p/17584541.html