package net.shapelight.common.utils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import net.shapelight.modules.sys.entity.SysDeptEntity; import org.apache.commons.lang.StringUtils; import javax.validation.constraints.NotNull; import java.lang.reflect.Field; import java.util.*; public class TreeUtils { /*public static boolean isEmpty(String str) { if (str != null && !"".equals(str.trim())) { return false; } return true; }*/ /** * 集合转树结构 * * @param collection 目标集合 * @param clazz 集合元素类型 * @param * @return */ public static Collection toTree(@NotNull Collection collection, @NotNull Class clazz) { return toTree(collection, null, null, null, clazz); } /** * 集合转树结构,注意,使用此方法,则集合元素必须继承ITree接口 * * @param collection 目标集合 * @param * @return */ public static Collection toTree(@NotNull Collection collection) { try { if (collection == null || collection.isEmpty()) return null;// 如果目标集合为空,直接返回一个空树 // 找出所有的根节点 Collection roots = null; if (collection.getClass().isAssignableFrom(Set.class)) roots = new HashSet<>(); else roots = new ArrayList<>(); for (T tree : collection) { Object o = ITree.class.getMethod("getParent").invoke(tree); if (o instanceof String) { if (StringUtils.isEmpty((String) o)) { roots.add(tree); } } else if (o == null) { roots.add(tree); } } // 从目标集合移除所有的根节点 collection.removeAll(roots); // 为根节点添加孩子节点 for (T tree : roots) { addChild(tree, collection); } return roots; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 集合转树结构 * * @param collection 目标集合 * @param id 被依赖字段名称 * @param parent 依赖字段名称 * @param children 子节点集合属性名称 * @param clazz 集合元素类型 * @param * @return */ public static Collection toTree(@NotNull Collection collection, String id, String parent, String children, @NotNull Class clazz) { try { if (collection == null || collection.isEmpty()) return null;// 如果目标集合为空,直接返回一个空树 if (StringUtils.isEmpty(id)) id = "id";// 如果被依赖字段名称为空则默认为id if (StringUtils.isEmpty(parent)) parent = "parent";// 如果依赖字段为空则默认为parent if (StringUtils.isEmpty(children)) children = "children";// 如果子节点集合属性名称为空则默认为children Collection roots = null;// 初始化根节点集合 if (collection.getClass().isAssignableFrom(Set.class)) roots = new HashSet<>();// 如果目标节点是一个set集合,则初始化根节点集合为hashset else roots = new ArrayList<>();// 否则初始化为Arraylist, // 这里集合初始化只分2中,要么是hashset,要么ArrayList,因为这两种最常用,其他不常用的摒弃 Field idField = null; try { idField = clazz.getDeclaredField(id);// 获取依赖字段 } catch (NoSuchFieldException e1) { idField = clazz.getSuperclass().getDeclaredField(id); } Field parentField = null; try { parentField = clazz.getDeclaredField(parent);// 获取被依赖字段 } catch (NoSuchFieldException e1) { parentField = clazz.getSuperclass().getDeclaredField(parent); } Field childrenField = null;// 获取孩子字段 try { childrenField = clazz.getDeclaredField(children); } catch (NoSuchFieldException e1) { childrenField = clazz.getSuperclass().getDeclaredField(children); } // 设置为可访问 idField.setAccessible(true); parentField.setAccessible(true); childrenField.setAccessible(true); // 找出所有的根节点 /*for (T c : collection) { Object o = parentField.get(c); if (o instanceof String) { if (StringUtils.isEmpty((String) o)) {// 如果父节点为空则说明是根节点,添加到根节点集合 roots.add(c); } } else { if (o == null) { roots.add(c); } } }*/ for (T c : collection) { Object o = parentField.get(c); if (o instanceof Long) { if (((Long)o).longValue() == 0L) {// 如果父节点为空则说明是根节点,添加到根节点集合 roots.add(c); } } else { if (o == null) { roots.add(c); } } } // 从目标集合移除所有根节点 collection.removeAll(roots); for (T c : roots) {// 遍历根节点,依次添加子节点 addChild(c, collection, idField, parentField, childrenField); } // 关闭可访问 idField.setAccessible(false); parentField.setAccessible(false); childrenField.setAccessible(false); return roots; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } public static void addChild(T tree, Collection collection) { try { Object id = ITree.class.getMethod("getId").invoke(tree); Collection children = (Collection) ITree.class.getMethod("getChildren").invoke(tree); for (T cc : collection) { Object o = ITree.class.getMethod("getParent").invoke(cc); if (id.equals(o)) {// 如果当前节点的被依赖值和目标节点的被依赖值相等,则说明,当前节点是目标节点的子节点 if (children == null) {// 如果目标节点的孩子集合为null,初始化目标节点的孩子集合 if (collection.getClass().isAssignableFrom(Set.class)) {// 如果目标集合是一个set集合,则初始化目标节点的孩子节点集合为set children = new HashSet<>(); } else children = new ArrayList<>();// 否则初始化为list } // 将当前节点添加到目标节点的孩子节点 children.add(cc); // 重设目标节点的孩子节点集合,这里必须重设,因为如果目标节点的孩子节点是null的话,这样是没有地址的,就会造成数据丢失,所以必须重设,如果目标节点所在类的孩子节点初始化为一个空集合,而不是null,则可以不需要这一步,因为java一切皆指针 ITree.class.getMethod("setChildren", Collection.class).invoke(tree, children); // 递归添加孩子节点 addChild(cc, collection); } } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 为目标节点添加孩子节点,此方法为私有,不能为公开,否则类修改信息无法恢复,后面有公开方法,其专门为目标节点添加子节点 * * @param c 目标节点 * @param collection 目标集合 * @param idField * @param parentField * @param childrenField * @param * @throws IllegalAccessException */ private static void addChild(@NotNull T c, @NotNull Collection collection, @NotNull Field idField, @NotNull Field parentField, @NotNull Field childrenField) throws IllegalAccessException { Object id = idField.get(c);// 获取目标节点的被依赖值 Collection children = (Collection) childrenField.get(c);// 获取目标节点的孩子列表 for (T cc : collection) {// 遍历目标集合 Object o = parentField.get(cc);// 获取当前节点的依赖值 if (id.equals(o)) {// 如果当前节点的被依赖值和目标节点的被依赖值相等,则说明,当前节点是目标节点的子节点 if (children == null) {// 如果目标节点的孩子集合为null,初始化目标节点的孩子集合 if (collection.getClass().isAssignableFrom(Set.class)) {// 如果目标集合是一个set集合,则初始化目标节点的孩子节点集合为set children = new HashSet<>(); } else children = new ArrayList<>();// 否则初始化为list } // 将当前节点添加到目标节点的孩子节点 children.add(cc); // 重设目标节点的孩子节点集合,这里必须重设,因为如果目标节点的孩子节点是null的话,这样是没有地址的,就会造成数据丢失,所以必须重设,如果目标节点所在类的孩子节点初始化为一个空集合,而不是null,则可以不需要这一步,因为java一切皆指针 childrenField.set(c, children); // 递归添加孩子节点 addChild(cc, collection, idField, parentField, childrenField); } } // 特别说明:大家可以看到此递归没有明显出口,其出口就是是否当前节点的依赖值和目标节点的被依赖值一样,一样就递归,不一样进不了if,自然出递归 // 此工具类自我感觉是最简单的,最实用的工具类,我看网上许多人写的,都是云的雾的,本来也想借鉴,但是实在没一个能看的感觉思路清晰,没办法,自己动手造轮子 } /** * 为目标节点添加孩子 * * @param c 目标节点 * @param collection 目标集合 * @param id 被依赖字段名 * @param parent 依赖字段名 * @param children 孩子节点字段名 * @param clazz 集合元素所在类别 * @param */ public static void addChild(@NotNull T c, @NotNull Collection collection, String id, String parent, String children, @NotNull Class clazz) { try { if (collection == null || collection.isEmpty()) return;// 如果目标集合为空,直接返回一个空树 if (StringUtils.isEmpty(id)) id = "id";// 如果被依赖字段名称为空则默认为id if (StringUtils.isEmpty(parent)) parent = "parent";// 如果依赖字段为空则默认为parent if (StringUtils.isEmpty(children)) children = "children";// 如果子节点集合属性名称为空则默认为children Field idField = null; try { idField = clazz.getDeclaredField(id);// 获取依赖字段 } catch (NoSuchFieldException e1) { idField = clazz.getSuperclass().getDeclaredField(id); } Field parentField = null; try { parentField = clazz.getDeclaredField(parent);// 获取被依赖字段 } catch (NoSuchFieldException e1) { parentField = clazz.getSuperclass().getDeclaredField(parent); } Field childrenField = null;// 获取孩子字段 try { childrenField = clazz.getDeclaredField(children); } catch (NoSuchFieldException e1) { childrenField = clazz.getSuperclass().getDeclaredField(children); } // 设置为可访问 idField.setAccessible(true); parentField.setAccessible(true); childrenField.setAccessible(true); addChild(c, collection, idField, parentField, childrenField); // 关闭可访问 idField.setAccessible(false); parentField.setAccessible(false); childrenField.setAccessible(false); } catch (Exception e) { throw new RuntimeException(e); } } /** * 为目标节点添加孩子 * * @param c 目标节点 * @param collection 目标集合 * @param clazz 集合元素所在类型 * @param */ public static void addChild(@NotNull T c, @NotNull Collection collection, @NotNull Class clazz) { addChild(c, collection, null, null, null, clazz); } /** - listToTree -

方法说明

- 将JSONArray数组转为树状结构 - @param arr 需要转化的数据 - @param id 数据唯一的标识键值 - @param pid 父id唯一标识键值 - @param child 子节点键值 - @return JSONArray */ public static JSONArray listToTree(JSONArray arr, String id, String pid, String child){ JSONArray r = new JSONArray(); JSONObject hash = new JSONObject(); //将数组转为Object的形式,key为数组中的id for(int i=0;i list = new ArrayList<>(); list.add(new Menu(1, 100)); list.add(new Menu(2, 100)); list.add(new Menu(3, 100)); list.add(new Menu(4, 1)); list.add(new Menu(5, 1)); list.add(new Menu(6, 1)); list.add(new Menu(7, 2)); list.add(new Menu(8, 2)); list.add(new Menu(9, 3)); list.add(new Menu(10, 4)); list.add(new Menu(11, 7)); list.add(new Menu(12, 5)); list.add(new Menu(13, 10)); list.add(new Menu(14, 8)); list.add(new Menu(15, 11)); list.add(new Menu(16, 12)); list.add(new Menu(17, 13)); List deptList = new ArrayList<>(); SysDeptEntity s = new SysDeptEntity(); s.setDeptId(2L); s.setParentId(7L); s.setName("系统管理"); deptList.add(s); s = new SysDeptEntity(); s.setDeptId(6L); s.setParentId(2L); deptList.add(s); s = new SysDeptEntity(); s.setDeptId(8L); s.setParentId(6L); deptList.add(s); s = new SysDeptEntity(); s.setDeptId(9L); s.setParentId(8L); deptList.add(s); //Collection

menus = TreeUtils.toTree(list, null, null, null, Menu.class); //System.out.println(JSON.toJSONString(menus)); //Collection depts = TreeUtils.toTree(deptList, "deptId", "parentId", "childrenList", SysDeptEntity.class); //System.out.println(JSON.toJSONString(depts)); /*List deptList = new ArrayList<>(); SysDeptEntity s = new SysDeptEntity(); s.setDeptId(2L); s.setParentId(7L); s.setName("系统管理"); deptList.add(s); s = new SysDeptEntity(); s.setDeptId(6L); s.setParentId(2L); s.setName("用户管理"); deptList.add(s);*/ System.out.println(JSON.toJSONString(deptList)); JSONArray deptTree = listToTree(JSONArray.parseArray(JSON.toJSONString(deptList)),"deptId","parentId","childrenList"); System.out.println(JSON.toJSONString(deptTree)); System.out.println(JSON.toJSONString(list)); JSONArray listTree = listToTree(JSONArray.parseArray(JSON.toJSONString(list)),"id","parent","children"); System.out.println(JSON.toJSONString(listTree)); } } class Menu { private Integer id; private Integer parent; private List children; public Menu() { } public Menu(Integer id, Integer parent) { this.id = id; this.parent = parent; } public List getChildren() { return children; } public void setChildren(List children) { this.children = children; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getParent() { return parent; } public void setParent(Integer parent) { this.parent = parent; } }