Java通过注解实现构建树结构工具类

 更新时间:2026年05月18日 08:51:02   作者:RainCity  
在Java中,注解是一种元数据,可以提供有关代码的附加信息,通过使用注解可以在代码中添加配置信息、验证条件、文档和其他信息,本文我们就来看如何使用注解实现构建树结构吧

前言

在Java中,注解是一种元数据,可以提供有关代码的附加信息。通过使用注解,可以在代码中添加配置信息、验证条件、文档和其他信息,这使得代码更易于理解和维护。在本文中,我将介绍如何使用Java注解构建树结构工具类。

话不多说,现在开搞======================>

枚举类

标识字段的数据类型

	public enum DataType {
	    /** long */
	    LONG,
	
	    /** string */
	    STRING,
	
	    /** LIST */
	    LIST,
	}
	

注解

标识字段为主键

	
	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.FIELD)
	public @interface PrimaryKey {
	
	    /** 字段数据类型默认为 long */
	    DataType dataType() default DataType.LONG;
	}
	

标识字段为父id

	
	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.FIELD)
	public @interface ParentKey {
	    
	    /** 字段数据类型默认为 long */
	    DataType dataType() default DataType.LONG;
	}
	

标识字段为子集

	
	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.FIELD)
	public @interface ChildrenKey {
	
	    /** 字段数据类型默认为 List */
	    DataType dataType() default DataType.LIST;
	}
	

获取注解标识的字段值

public class AnnotationUtil {

    /**
     * 获取注解 annotation 标识的字段值
     * @param t entity
     * @param annotation 注解
     * @return java.lang.Object
     */
    public static <T> Object getFieldValue(T t, Class<? extends Annotation> annotation) throws IllegalAccessException {
        Object fieldValue = null;
        Class<?> clazz = t.getClass();
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if(field.isAnnotationPresent(annotation)){
                field.setAccessible(true);
                fieldValue = field.get(t);
                break;
            }
        }
        return fieldValue;
    }
}

构建树结构工具类

public class TreeUtils {
    private static final Logger log = LoggerFactory.getLogger(TreeUtils.class);

    /**
     * 构建前端所需要树结构,主键为 Long 时
     * @param tList 数据集
     * @return java.util.List<T> 树结构列表
     */
    public static <T> List<T> buildLongTree(List<T> tList) {
        try {
            List<T> returnList = new ArrayList<>();
            //主键id集合
            List<Long> tempList = new ArrayList<>();
            for (T t : tList) {
                Long primaryId = (Long) AnnotationUtil.getFieldValue(t, PrimaryKey.class);
                tempList.add(primaryId);
            }
            for (T t : tList) {
                // 如果是顶级节点, 遍历该父节点的所有子节点
                Long parentId = (Long) AnnotationUtil.getFieldValue(t, ParentKey.class);
                if (!tempList.contains(parentId)) {
                    recursionLong(tList, t);
                    returnList.add(t);
                }
            }
            if (returnList.isEmpty()) {
                returnList = tList;
            }
            return returnList;
        } catch (Exception e) {
            log.error("树结构转换失败:{}", e.getMessage());
            return tList;
        }
    }

    /**
     * 构建前端所需要树结构,主键为 String 时
     * @param tList 数据集
     * @return java.util.List<T> 树结构列表
     */
    public static <T> List<T> buildStringTree(List<T> tList) {
        try {
            List<T> returnList = new ArrayList<>();
            List<String> tempList = new ArrayList<>();
            for (T t : tList) {
                String primaryId = (String) AnnotationUtil.getFieldValue(t, PrimaryKey.class);
                tempList.add(primaryId);
            }
            for (T t : tList) {
                // 如果是顶级节点, 遍历该父节点的所有子节点
                String parentId = (String) AnnotationUtil.getFieldValue(t, ParentKey.class);
                if (!tempList.contains(parentId)) {
                    recursionString(tList, t);
                    returnList.add(t);
                }
            }
            if (returnList.isEmpty()) {
                returnList = tList;
            }
            return returnList;
        } catch (IllegalAccessException e) {
            log.error("树结构转换失败:{}", e.getMessage());
            return tList;
        }
    }

    /**
     * 递归设置子集数据,主键为 Long 时
     * @param list 数据集合
     * @param o 对象
     */
    private static <T> void recursionLong(List<T> list, Object o) throws IllegalAccessException {
        // 得到子节点列表
        List<T> childList = getLongChildList(list, o);
        invokeChildrenList(o, childList);

        for (Object oChild : childList) {
            if (getLongChildList(list, oChild).size() > 0) {
                recursionLong(list, oChild);
            }
        }
    }

    /**
     * 递归设置子集数据,主键为 String 时
     * @param list 数据集合
     * @param o 对象
     */
    private static <T> void recursionString(List<T> list, Object o) throws IllegalAccessException {
        // 得到子节点列表
        List<T> childList = getStringChildList(list, o);
        invokeChildrenList(o, childList);

        for (Object oChild : childList) {
            if (getStringChildList(list, oChild).size() > 0) {
                recursionString(list, oChild);
            }
        }
    }

    /**
     * 得到子节点列表,主键为 Long 时
     * @param list 数据
     * @param object entity
     * @return java.util.List<T>
     */
    private static <T> List<T> getLongChildList(List<T> list, Object object) throws IllegalAccessException {
        Long primaryId = (Long) AnnotationUtil.getFieldValue(object, PrimaryKey.class);

        List<T> objects = new ArrayList<>();
        for (T o : list) {
            Long parentId = (Long) AnnotationUtil.getFieldValue(o, ParentKey.class);
            if (null != parentId && parentId.longValue() == primaryId.longValue()) {
                objects.add(o);
            }
        }
        return objects;
    }

    /**
     * 得到子节点列表,主键为 String 时
     * @param list 数据
     * @param object entity
     * @return java.util.List<T>
     */
    private static <T> List<T> getStringChildList(List<T> list, Object object) throws IllegalAccessException {
        String primaryId = (String) AnnotationUtil.getFieldValue(object, PrimaryKey.class);

        List<T> objects = new ArrayList<>();
        for (T o : list) {
            String parentId = (String) AnnotationUtil.getFieldValue(o, ParentKey.class);
            if (null != parentId && parentId.equals(primaryId)) {
                objects.add(o);
            }
        }
        return objects;
    }

    /**
     * 通过反射设置子集数据
     * @param o 对象
     * @param childList 子集数据
     */
    private static <T> void invokeChildrenList(Object o, List<T> childList) {
        Class<?> clazz = o.getClass();
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if(field.isAnnotationPresent(ChildrenKey.class)){
                field.setAccessible(true);
                ReflectUtils.invokeSetter(o, field.getName(), childList);
                break;
            }
        }
    }

}

测试一下

部门 dept 类

// 此处使用lombok减少代码
@Data
public class Dept implements Serializable {
    private static final long serialVersionUID = -1L;

    /**
     * 部门ID
     * 如果数据类型为字符串,则 @PrimaryKey(dataType = DataType.STRING)
     */  
    @PrimaryKey
    private Long deptId;

    /** 
     * 父部门ID
     * 如果数据类型为字符串,则 @ParentKey(dataType = DataType.STRING)
     */
    @ParentKey
    private Long parentId;

    /** 部门名称 */
    private String deptName;

    /** 子部门 */
    @ChildrenKey
    private List<Dept> children = new ArrayList<>();

	/** 加一个有参构造,方便测试 */
    public Dept(Long deptId, Long parentId, String deptName) {
        this.deptId = deptId;
        this.parentId = parentId;
        this.deptName = deptName;
    }
}
@Test
public void test(){
    List<Dept> deptList = new ArrayList<>();
    deptList.add(new Dept(1L, 0L, "部门0-1"));
    deptList.add(new Dept(2L, 0L, "部门0-2"));
    deptList.add(new Dept(3L, 1L, "部门1-1"));
    deptList.add(new Dept(4L, 1L, "部门1-2"));
    deptList.add(new Dept(5L, 2L, "部门2-1"));
    deptList.add(new Dept(6L, 2L, "部门2-2"));
    deptList.add(new Dept(7L, 3L, "部门1-1-1"));
    deptList.add(new Dept(8L, 3L, "部门1-1-2"));
    deptList.add(new Dept(9L, 6L, "部门2-2-1"));
    deptList.add(new Dept(10L, 6L, "部门2-2-2"));
    List<Dept> depts = TreeUtils.buildLongTree(deptList);
    System.out.println(JSON.toJSONString(depts));
}

结果打印:

[{
	"deptId": 1,
	"parentId": 0,
	"deptName": "部门0-1",
	"children": [{
		"deptId": 3,
		"parentId": 1,
		"deptName": "部门1-1",
		"children": [{
			"deptId": 7,
			"parentId": 3,
			"deptName": "部门1-1-1",
			"children": []
		}, {
			"deptId": 8,
			"parentId": 3,
			"deptName": "部门1-1-2",
			"children": []
		}]
	}, {
		"deptId": 4,
		"parentId": 1,
		"deptName": "部门1-2",
		"children": []
	}]
}, {
	"deptId": 2,
	"parentId": 0,
	"deptName": "部门0-2",
	"children": [{
		"deptId": 5,
		"parentId": 2,
		"deptName": "部门2-1",
		"children": []
	}, {
		"deptId": 6,
		"parentId": 2,
		"deptName": "部门2-2",
		"children": [{
			"deptId": 9,
			"parentId": 6,
			"deptName": "部门2-2-1",
			"children": []
		}, {
			"deptId": 10,
			"parentId": 6,
			"deptName": "部门2-2-2",
			"children": []
		}]
	}]
}]

以上就是使用Java注解构建树结构工具类的方法。使用注解可以为代码添加更多的语义信息,提高代码的可读性和可维护性

到此这篇关于Java通过注解实现构建树结构工具类的文章就介绍到这了,更多相关Java构建树结构内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中ScheduledExecutorService的使用方法详解

    Java中ScheduledExecutorService的使用方法详解

    ScheduledExecutorService是ExecutorService的一个子接口,它主要用于在给定的延迟之后或周期性地执行任务,本文主要介绍了ScheduledExecutorService的使用方法,感兴趣的可以了解下
    2024-12-12
  • Java多线程 原子性操作类的使用

    Java多线程 原子性操作类的使用

    这篇文章主要介绍了Java多线程 原子性操作类的使用,在java5以后,我们接触到了线程原子性操作,也就是在修改时我们只需要保证它的那个瞬间是安全的即可,经过相应的包装后可以再处理对象的并发修改,本文总结一下Atomic系列的类的使用方法,下面一起进入文章了解详细内容
    2021-10-10
  • SpringBoot 工程中的异常处理方式

    SpringBoot 工程中的异常处理方式

    这篇文章主要介绍了SpringBoot 工程中的异常处理方式,帮助大家更好的理解和学习使用springboot框架,感兴趣的朋友可以了解下
    2021-02-02
  • SpringBoot密码加密的实现示例

    SpringBoot密码加密的实现示例

    本文主要介绍了SpringBoot密码加密的实现示例,包括引入依赖、配置加密工具、生成加密密钥、加密密码、配置解密,具有一定的参考价值,感兴趣的可以了解一下
    2024-08-08
  • IDEA提示内存不足 low memory的完美解决方法(亲测好用)

    IDEA提示内存不足 low memory的完美解决方法(亲测好用)

    这篇文章主要介绍了IDEA提示内存不足 low memory的完美解决方法(亲测好用),这里以IDEA2022版本为例,在IDE中 帮助(help)–>change memory setting(改变内存设置),具体设置办法文中给大家详细讲解,需要的朋友可以参考下
    2023-01-01
  • spring获取bean的源码解析

    spring获取bean的源码解析

    这篇文章主要介绍了spring获取bean的源码解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • java多线程之CyclicBarrier的使用方法

    java多线程之CyclicBarrier的使用方法

    这篇文章主要介绍了java多线程之CyclicBarrier的使用方法的相关资料,希望通过本文能帮助到大家,让大家理解掌握这部分内容,需要的朋友可以参考下
    2017-10-10
  • 基于MyBatis的数据持久化框架的使用详解

    基于MyBatis的数据持久化框架的使用详解

    Mybatis是一个优秀的开源、轻量级持久层框架,它对JDBC操作数据库的过程进行封装。本文将为大家讲解一下基于MyBatis的数据持久化框架的使用,感兴趣的可以了解一下
    2022-08-08
  • Spring Bean基本管理实例详解

    Spring Bean基本管理实例详解

    这篇文章主要介绍了Spring Bean基本管理,以实例形式较为详细的分析了Spring Bean的相关使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • java实现雪花算法ID生成器工具类

    java实现雪花算法ID生成器工具类

    本文主要介绍了java实现雪花算法ID生成器工具类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07

最新评论