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

83 阅读3分钟

前言

在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注解构建树结构工具类的方法。使用注解可以为代码添加更多的语义信息,提高代码的可读性和可维护性

----------------------------------------------------------------------------THANKS !!!-----------------------------------------------------------------------