生成树的工具类
1 1、 这里使用的是三个注解 2 3 @Target(ElementType.FIELD) 4 @Retention(RetentionPolicy.RUNTIME) 5 public @interface TreeId { 6 } 7 8 @Target(ElementType.FIELD) 9 @Retention(RetentionPolicy.RUNTIME) 10 public @interface TreeParentId { 11 } 12 13 @Target(ElementType.FIELD) 14 @Retention(RetentionPolicy.RUNTIME) 15 public @interface TreeChildrenList { 16 }
1 2. 对应的工具类 2 3 /** 4 * @author: 5 * @desc: 将数据组合成一棵树, 6 * 添加三个注解到 @TreeId @TreeParentId @TreeChildrenList 7 * 这三个注解分别表示 当前数据的 id 当前数据的上级数据id 存放当前数据的子节点集合 8 **/ 9 public class TreeUtils { 10 11 /** 12 * 构建树状结构 13 * 14 * @param list 原数据集 15 * @param clazz 数据实体 16 * @param <T> 泛型 17 * @return 树状结构 18 */ 19 public static <T> List<T> buildTree(List<T> list, @NotNull Class clazz) { 20 RequiredField requiredField = new RequiredField(clazz); 21 if (CollectionUtil.isEmpty(list) || ObjectUtil.isEmpty(requiredField)) { 22 return null; 23 } 24 // 判断 获取最上级数据的 id 25 List<Long> rootIdList = new ArrayList<>(); 26 for (T entity : list) { 27 try { 28 Object parentIdValue = requiredField.getParentId().get(entity); 29 if (ObjectUtil.isEmpty(parentIdValue) || parentIdValue.equals(0)) { 30 rootIdList.add((long) requiredField.getId().get(entity)); 31 } 32 } catch (IllegalAccessException e) { 33 throw new CustomException("构建树失败,请检查"); 34 } 35 } 36 if (CollectionUtil.isEmpty(rootIdList)) { 37 throw new CustomException("传递进来的数据不存在最上级节点,请检查!"); 38 } 39 40 return buildTree(list, clazz, rootIdList); 41 } 42 43 /** 44 * 构建树状结构 45 * 46 * @param list 原数据集 47 * @param parentId 父级字段名 48 * @param id id字段名 49 * @param children 子级字段名 50 * @param clazz 数据实体 51 * @param <T> 泛型 52 * @return 树状结构 53 */ 54 public static <T> List<T> buildTree(List<T> list, String parentId, String id, String children, @NotNull Class clazz) { 55 RequiredField requiredField = new RequiredField(id, parentId, children, clazz); 56 if (CollectionUtil.isEmpty(list) || ObjectUtil.isEmpty(requiredField)) { 57 return null; 58 } 59 // 判断判断 获取最上级数据的 id 60 List<Long> rootIdList = new ArrayList<>(); 61 for (T entity : list) { 62 try { 63 Object parentIdValue = requiredField.getParentId().get(entity); 64 if (ObjectUtil.isEmpty(parentIdValue) || parentIdValue.equals(0)) { 65 rootIdList.add((long) requiredField.getId().get(entity)); 66 } 67 } catch (IllegalAccessException e) { 68 throw new CustomException("构建树失败,请检查"); 69 } 70 } 71 if (CollectionUtil.isEmpty(rootIdList)) { 72 throw new CustomException("传递进来的数据不存在最上级节点,请检查!"); 73 } 74 75 return buildTree(list, clazz, rootIdList); 76 } 77 78 /** 79 * 获取指定指点下面的数据 返回的是数据集合。不是树 80 * 81 * @param list 原始数据 82 * @param clazz 数据实体类 83 * @param id 数据id 84 * @param <T> 泛型 85 * @return 返回结果 86 */ 87 public static <T> List<T> getListById(List<T> list, @NotNull Class clazz, @NotNull Long id, boolean containCurrentNode) { 88 List<Long> treeIdList = new ArrayList<>(); 89 treeIdList.add(id); 90 91 List<T> chidrenList = new ArrayList<>(); 92 List<T> treeList = TreeUtils.buildTree(list, clazz, treeIdList); 93 for (T tree : treeList) { 94 if (ObjectUtil.isNotEmpty(tree)) { 95 chidrenList.addAll(getChidrenList(tree, clazz)); 96 } 97 } 98 if (containCurrentNode && CollectionUtil.isNotEmpty(chidrenList)) { 99 chidrenList.addAll(treeList); 100 } 101 return chidrenList; 102 } 103 104 /** 105 * 获取某个树下面的所有子节点 106 * 107 * @param root 树节点 108 * @param clazz 数据实体 109 * @param <T> 泛型 110 * @return 返回子集合 111 */ 112 private static <T> List<T> getChidrenList(T root, @NotNull Class clazz) { 113 List<T> resultList = new ArrayList<>(); 114 RequiredField requiredField = new RequiredField(clazz); 115 Field childrenField = requiredField.getChildrenList(); 116 try { 117 List<T> childrenList = (List<T>) childrenField.get(root); 118 for (T entity : childrenList) { 119 if (ObjectUtil.isNotEmpty(entity)) { 120 resultList.addAll(getChidrenList(entity, clazz)); 121 } 122 } 123 resultList.addAll(childrenList); 124 } catch (IllegalAccessException e) { 125 throw new CustomException("构建树失败,请检查!"); 126 } 127 return resultList; 128 } 129 130 131 /** 132 * 构建树形状,获取当前id下面的树接待,包括当前节点 133 * 134 * @param list 原数据集 135 * @param clazz 数据实体 136 * @param treeIdList 当前id 137 * @param <T> 数据类型 138 * @return 树形状结构 139 */ 140 public static <T> List<T> buildTree(List<T> list, @NotNull Class clazz, List<Long> treeIdList) { 141 RequiredField requiredField = new RequiredField(clazz); 142 if (CollectionUtil.isEmpty(list) || ObjectUtil.isEmpty(requiredField) || CollectionUtil.isEmpty(treeIdList)) { 143 return null; 144 } 145 List<T> resultList = new ArrayList<>(treeIdList.size()); 146 try { 147 Iterator<T> iterator = list.iterator(); 148 while (iterator.hasNext()) { 149 T next = iterator.next(); 150 Object idValue = requiredField.getId().get(next); 151 if (treeIdList.contains(idValue)) { 152 resultList.add(next); 153 iterator.remove(); 154 continue; 155 } 156 } 157 if (CollectionUtil.isEmpty(resultList)) { 158 throw new CustomException("集合中不存在要查询的数据"); 159 } 160 for (T root : resultList) { 161 requiredField.getChildrenList().set(root, findChild(root, list, requiredField.getParentId(), requiredField.getId(), requiredField.getChildrenList())); 162 } 163 } catch (IllegalAccessException e) { 164 throw new CustomException("构建树失败,请检查"); 165 } 166 return resultList; 167 } 168 169 /** 170 * 构建树状结构 171 * 172 * @param list 数据集 173 * @param parentField 父级ID字段 174 * @param idField id字段 175 * @param childrenField 子集字段 176 * @param <T> 数据类型 177 * @return 树状结构 178 * @throws IllegalAccessException 异常 179 */ 180 public static <T> List<T> buildTree(List<T> list, Field parentField, Field idField, Field childrenField) { 181 List<T> result = new ArrayList<>(); 182 183 try { 184 Iterator<T> iterator = list.iterator(); 185 while (iterator.hasNext()) { 186 T root = iterator.next(); 187 iterator.remove(); 188 childrenField.set(root, findChild(root, list, parentField, idField, childrenField)); 189 // 刷新 iterator 190 iterator = list.iterator(); 191 result.add(root); 192 } 193 } catch (IllegalAccessException e) { 194 throw new CustomException("构建树失败,请检查"); 195 } 196 return result; 197 } 198 199 /** 200 * 查找子集 201 * 202 * @param root 节点 203 * @param list 所有集合 204 * @param parentField 父级字段 205 * @param idField id字段 206 * @param childrenField 子级字段 207 * @param <T> 208 * @return 子级集合 209 * @throws IllegalAccessException 异常信息 210 */ 211 private static <T> List<T> findChild(T root, List<T> list, Field parentField, Field idField, Field childrenField) 212 throws IllegalAccessException { 213 Object id = idField.get(root); 214 if (ObjectUtil.isEmpty(id)) { 215 throw new CustomException("类中存在相同字段,请检查!"); 216 } 217 List<T> children = new ArrayList<>(); 218 219 Iterator<T> iterator = list.iterator(); 220 while (iterator.hasNext()) { 221 T node = iterator.next(); 222 Object parentId = parentField.get(node); 223 224 if (id.equals(parentId)) { 225 iterator.remove(); 226 childrenField.set(node, findChild(node, list, parentField, idField, childrenField)); 227 // 刷新 iterator 228 iterator = list.iterator(); 229 children.add(node); 230 } 231 } 232 return children; 233 } 234 } 235 236 /** 237 * 必填字段 238 */ 239 class RequiredField { 240 private Field id; 241 private Field parentId; 242 private Field childrenList; 243 244 public RequiredField(@NotNull Class clazz) { 245 //1 获取类中是否拥有需要的三个注解 246 List<Field> fieldList = ReflectUtils.getAllField(clazz); 247 for (Field field : fieldList) { 248 if (ObjectUtil.isNotEmpty(field.getAnnotation(TreeId.class))) { 249 this.id = field; 250 this.id.setAccessible(true); 251 } 252 if (ObjectUtil.isNotEmpty(field.getAnnotation(TreeParentId.class))) { 253 this.parentId = field; 254 this.parentId.setAccessible(true); 255 } 256 if (ObjectUtil.isNotEmpty(field.getAnnotation(TreeChildrenList.class))) { 257 this.childrenList = field; 258 this.childrenList.setAccessible(true); 259 } 260 } 261 } 262 263 public RequiredField(String idField, String parentIdField, String childrenListField, @NotNull Class clazz) { 264 // 判断传入字段是否为空 265 if (StrUtil.isEmpty(idField) || StrUtil.isEmpty(parentIdField) || StrUtil.isEmpty(childrenListField)) { 266 throw new CustomException("必填字段不能为空!"); 267 } 268 try { 269 // 获取 id 字段, 从当前对象或其父类 270 this.id = clazz.getDeclaredField(idField); 271 this.id.setAccessible(true); 272 // 获取 parentId 字段, 从当前对象或其父类 273 this.parentId = clazz.getDeclaredField(parentIdField); 274 this.parentId.setAccessible(true); 275 // 获取 children 字段, 从当前对象或其父类 276 this.childrenList = clazz.getDeclaredField(childrenListField); 277 this.childrenList.setAccessible(true); 278 } catch (NoSuchFieldException e1) { 279 throw new CustomException("获取字段失败", e1); 280 } 281 } 282 283 public Field getId() { 284 return id; 285 } 286 287 public Field getParentId() { 288 return parentId; 289 } 290 291 public Field getChildrenList() { 292 return childrenList; 293 } 294 }