Sometimes, our data is hierarchical. For example, the common three-level linkage between provinces and municipalities is one layer inside another, as shown below:

When we store data in the database, it is often in list form, as shown below:

Then when we query it from the database, When returning to the front end, when the front end needs to give a tree level, it may need to be recursively processed into a tree structure, so the following tool may be useful.
We define a Place object as above and add tool annotations:
@TreeKey unique identifier
@TreeParentKey identifies the parent node identification
@TreeChildren identifies the collection of descendant nodes
@Data
@Data
public class Place {
@TreeKey
private String id;
@TreeParentKey
private String parentId;
private String name;
@TreeChildren
private List<Place> children;
public Place(String id, String name, String parentId) {
this.id = id;
this.name = name;
this.parentId = parentId;
}
}Test:
public class Test {
public static void main(String[] args) {
List<Place> places = new ArrayList<>();
places.add(new Place("510000", "四川省", "0"));
places.add(new Place("510100", "成都市", "510000"));
places.add(new Place("510107", "武侯区", "510100"));
places.add(new Place("510116", "双流区", "510100"));
places.add(new Place("511600", "广安市", "510000"));
places.add(new Place("511603", "前锋区", "511600"));
places.add(new Place("511621", "岳池县", "511600"));
List<Place> treeList = TreeUtils.getTree(places, "0");
System.out.println(JSON.toJSONString(treeList));
}
}Final effect:

@TreeKey
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeKey {
}@TreeParentKey
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeParentKey {
}@TreeChildren
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeChildren {
}@TreeUtils
package com.csd.utils.tree;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* 递归求树形工具类
*
* @author Yuanqiang.Zhang
* @since 2023/3/8
*/
public class TreeUtils {
/**
* 集合转化为树形
*
* @param list 集合
* @param highestParentKey 最高层父节点值
* @param <T> 泛型
* @return 树形
*/
public static <T> List<T> getTree(List<T> list, Object highestParentKey) {
if (Objects.isNull(list) || list.isEmpty()) {
return Collections.emptyList();
}
Field key = null;
Field parentKey = null;
Field children = null;
Field[] fields = list.get(0).getClass().getDeclaredFields();
for (Field field : fields) {
if (Objects.isNull(key)) {
TreeKey treeKey = field.getAnnotation(TreeKey.class);
if (Objects.nonNull(treeKey)) {
key = field;
continue;
}
}
if (Objects.isNull(parentKey)) {
TreeParentKey treeParentKey = field.getAnnotation(TreeParentKey.class);
if (Objects.nonNull(treeParentKey)) {
parentKey = field;
continue;
}
}
if (Objects.isNull(children)) {
TreeChildren treeChildren = field.getAnnotation(TreeChildren.class);
if (Objects.nonNull(treeChildren)) {
children = field;
continue;
}
}
}
if (Objects.isNull(key) || Objects.isNull(parentKey) || Objects.isNull(children)) {
return Collections.emptyList();
}
key.setAccessible(true);
parentKey.setAccessible(true);
children.setAccessible(true);
// 获取最高层数据
List<T> highs = new ArrayList<>();
try {
for (T t : list) {
Object pk = parentKey.get(t);
if (getString(pk).equals(getString(highestParentKey))) {
highs.add(t);
}
}
// 获取最高层子孙节点
for (T t : highs) {
setChildren(list, t, key, parentKey, children);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return highs;
}
/**
* 获取子孙节点
*
* @param list 集合
* @param parent 父节点对象
* @param key 唯一属性
* @param parentKey 父唯一属性
* @param children 节点
* @param <T> 泛型
* @return 带有子孙集合的父节点对象
* @throws IllegalAccessException
*/
private static <T> T setChildren(List<T> list, T parent, Field key, Field parentKey, Field children) throws IllegalAccessException {
Object k = key.get(parent);
List<T> tempList = new ArrayList<>();
for (T t : list) {
Object pk = parentKey.get(t);
if (getString(k).equals(getString(pk))) {
tempList.add(setChildren(list, t, key, parentKey, children));
}
}
children.set(parent, tempList);
return parent;
}
/**
* 获取字符串
*
* @param o 值
* @return 字符串
*/
private static String getString(Object o) {
return Objects.isNull(o) ? "" : o.toString();
}
}The above is the detailed content of How to use recursion to implement a tree structure tool class in Java. For more information, please follow other related articles on the PHP Chinese website!