封装树形工具类,将list转化为树形结构

工具类

后续将继续优化

public class TreeUtils {

    private static final String ROOT_ID = "0";
    private static final String GET = "get";
    private static final String SET = "set";

    /**
     * 私有构造器
     */
    private TreeUtils() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * 使用递归方法建树
     * (如果项目中的各个表的id、父id、封装子对象的list名称均是固定,则可以再次简化,将反射获取属性的过程直接写
     * 死,这样调用时只需传list即可)
     * @param list         需要转化树形的list
     * @param idName       实体类中id的属性名(首字母需要大写,例如属性为id,则传Id)
     * @param parentIdName 实体类中父id的属性名(首字母需要大写,例如属性为parentId,则传ParentId)
     * @param childrenName 实体类中封装树形的子list方法名(首字母需要大写,例如属性为list,则传List)
     * @return 树形list
     */
    public static <T> List<T> buildByRecursive(List<T> list, String idName, String parentIdName, String childrenName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        List<T> result = new ArrayList<>();
        //遍历封装pid=0的
        for (T t : list) {
            //根据反射,获取父id的值
            String pId = reflect(t.getClass(), GET + parentIdName, t).toString();
            //如果pd=0,即是首层
            if (ROOT_ID.equals(pId)) {
                //递归查询并封装子对象
                result.add(findChildren(t, list, idName, parentIdName, childrenName));
            }
        }
        return result;
    }

    /**
     * 递归查找子节点
     *
     * @param idName       实体类中id的属性名(首字母需要大写)
     * @param parentIdName 实体类中父id的属性名(首字母需要大写)
     * @param bean
     * @param beans
     * @return
     */
    public static <T> T findChildren(T bean, List<T> beans, String idName, String parentIdName, String childrenName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //获取bean的id, bean.getId()
        String id = bean.getClass().getMethod(GET + idName).invoke(bean).toString();
        //获取bean用来封装子对象的list, bean.getList()
        List<T> children = (List) reflect(bean.getClass(), GET + childrenName, bean);
        //递归遍历
        for (T it : beans) {
            //根据反射,获取it的pId的值 it.getParentId()
            String parentId = it.getClass().getMethod(GET + parentIdName).invoke(it).toString();
            //如果是其子对象
            if (id.equals(parentId)) {
                //如果封装子对象的list为空,则创建
                if (children == null) {
                    bean.getClass().getMethod(SET + childrenName, List.class).invoke(bean, new ArrayList<>());
                }
                //重新获取子对象的list
                children = (List) reflect(bean.getClass(), GET + childrenName, bean);
                //继续递归遍历
                children.add(findChildren(it, beans, idName, parentIdName, childrenName));
            }
        }
        return bean;
    }

    /**
     * 根据反射获取属性值
     *
     * @param clazz      实体类名
     * @param methodName 方法名
     * @param t          对象
     * @param <T>        对象类
     * @return
     */
    public static <T> Object reflect(Class clazz, String methodName, T t) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        return clazz.getMethod(methodName).invoke(t);
    }

}

测试

数据库结构
在这里插入图片描述

实体类


```java
/**
 * 角色
 *
 */
@Data
public class SysRoleEntity implements Serializable {
	/**
	 * 角色ID
	 */
	@TableId
	private Long roleId;
	/**
	 * 父类ID
	 */
	private Long parentId;
	/**
	 * 角色名称
	 */
	private String roleName;
	/**
	 * 封装子角色的list
	 */
	private List<SysRoleEntity> children;

}

测试方法

@GetMapping("/test")
	public List<SysRoleEntity> test() throws Exception{
		//第一步查询所有数据(普通的查询所有,就不再一层一层的向下写了)
		List<SysRoleEntity> list = sysRoleService.selectAll();
		//调用工具转化为树形
		List<SysRoleEntity> result = buildByRecursive(list, "RoleId", "ParentId", "Children");
		return result;
	}

结果

[{
		"roleId": 1,
		"parentId": 0,
		"roleName": "技术部总监",
		"children": [{
				"roleId": 4,
				"parentId": 1,
				"roleName": "JAVA开发",
				"children": [{
						"roleId": 12,
						"parentId": 4,
						"roleName": "JAVA大牛"
					},
					{
						"roleId": 13,
						"parentId": 4,
						"roleName": "java菜鸟"
					}
				]
			},
			{
				"roleId": 5,
				"parentId": 1,
				"roleName": "IOS开发"
			},
			{
				"roleId": 6,
				"parentId": 1,
				"roleName": "安卓开发"
			},
			{
				"roleId": 7,
				"parentId": 1,
				"roleName": "前端开发"
			}
		]
	},
	{
		"roleId": 2,
		"parentId": 0,
		"roleName": "人事部总监",
		"children": [{
				"roleId": 8,
				"parentId": 2,
				"roleName": "人事专员"
			},
			{
				"roleId": 9,
				"parentId": 2,
				"roleName": "前台"
			}
		]
	},
	{
		"roleId": 3,
		"parentId": 0,
		"roleName": "财务总监",
		"children": [{
				"roleId": 10,
				"parentId": 3,
				"roleName": "会计"
			},
			{
				"roleId": 11,
				"parentId": 3,
				"roleName": "出纳"
			}
		]
	}
]

可以看到,子角色已经封装到父角色下。

结尾

实际就是一个通用的递归封装对象,后续将继续进行优化,如果有大佬有更好的方法欢迎告知。

发布了11 篇原创文章 · 获赞 12 · 访问量 4119

猜你喜欢

转载自blog.csdn.net/qq_38991369/article/details/102727114