应用场景:
提示:此种写法只适用于数据量小的转换,数据量大时请移步另一个方案
[一次循环实现List转树形结构(不使用递归)](https://blog.csdn.net/weixin_37304961/article/details/128464604)
在后台开发中,很多情况下我们需要将数据库的List转成一个树形结构的JSON返回给前端,前端提交树形结构给后台,后台把树形结构转换成List来操作数据库,比如平常用到的菜单列表、地名区划列表、权限列表等。
最近在做人员权限,对树形结构的处理比较多,就在想能不能使用注解+反射写一个通用方法来解决树形结构的处理,查询网络资料整合,最后整理了一个通用方法。
注解:
定义Tree注解类,@Target申明注解可使用的位置,FIELD指成员变量。@Retention申明注解生命周期在运行时也生效。
@Target({ElementType.FIELD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Tree {
/**
* id : 主键
* parentId : 父节点
* childList : 子集
*/
String value();
}
工具类:
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @author: xiang
* @create: 2021/5/12
*/
public class TreeUtil {
/**
* 功能描述: <br>
* 〈获取节点总数量〉
* @param: * @param list
* @return: int
* @author: xiang
* @date: 2021/5/13 9:19
*/
public static <T> int getSize(List<T> list) throws IllegalAccessException {
int i = 0;
if (list == null || list.size() == 0) {
return i;
}
for (T tree : list) {
i++;
Field[] fields = tree.getClass().getDeclaredFields();
Field childList_field = null;
for (Field field : fields) {
if (field.getAnnotation(Tree.class) == null) {
continue;
} else if ("childList".equals(field.getAnnotation(Tree.class).value())) {
childList_field = field;
}
}
childList_field.setAccessible(true);
Object child = childList_field.get(tree);
if (child != null && ((List) childList_field.get(tree)).size() > 0) {
i = i + getSize((List<T>) childList_field.get(tree));
}
}
return i;
}
/**
* 功能描述: <br>
* 〈集合转树形结构〉
*
* @param _id
* @param: * @param list
* @return: java.util.List<T>
* @author: xiang
* @date: 2021/5/13 9:18
*/
public static <T> List<T> listToTree(List<T> list, String _id) throws IllegalAccessException {
if (list == null || list.size() == 0) {
return null;
}
ArrayList<T> tree = new ArrayList<>();
Field parent_field = null;
Field id_field = null;
Field childList_field = null;
for (T t : list) {
//获取父节点
Field[] fields = t.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(Tree.class) == null) {
continue;
} else if ("parentId".equals(field.getAnnotation(Tree.class).value())) {
parent_field = field;
} else if ("id".equals(field.getAnnotation(Tree.class).value())) {
id_field = field;
} else if ("childList".equals(field.getAnnotation(Tree.class).value())) {
childList_field = field;
}
}
if (parent_field == null || id_field == null || childList_field == null) {
throw new RuntimeException("无法获取到父子属性");
}
parent_field.setAccessible(true);
id_field.setAccessible(true);
childList_field.setAccessible(true);
Object obj_parentId = parent_field.get(t);
String parent_id = obj_parentId == null ? "0" : obj_parentId + "";
if (parent_id.equals(_id)) {
//获取ID
Object obj_id = id_field.get(t);
String id = obj_id == null ? "0" : obj_id + "";
//递归
List<T> back = listToTree(list, id);
childList_field.set(t, back);
tree.add(t);
}
}
return tree;
}
/**
* 功能描述: <br>
* 〈树形结构转集合〉
* @param: * @param treeList
* @return: java.util.List<T>
* @author: xiang
* @date: 2021/5/13 10:27
*/
public static <T> List<T> treeToList(List<T> treeList) throws IllegalAccessException {
if (treeList == null || treeList.size() == 0) {
return treeList;
}
List<T> list = new ArrayList<>();
for (T tree : treeList) {
list.add(tree);
Field[] fields = tree.getClass().getDeclaredFields();
Field childList_field = null;
for (Field field : fields) {
if (field.getAnnotation(Tree.class) == null) {
continue;
} else if ("childList".equals(field.getAnnotation(Tree.class).value())) {
childList_field = field;
}
}
childList_field.setAccessible(true);
Object child = childList_field.get(tree);
if (child != null && ((List) childList_field.get(tree)).size() > 0) {
list.addAll(treeToList((List<T>) childList_field.get(tree)));
}
childList_field.set(tree, null);
}
return list;
}
}
实体类:
只需要在父子及子集变量上加注解即可。
@Data
public class YtkBasePageroute {
@Tree("id")
private Integer id;
@Tree("parentId")
private Integer parentId;
private String name;
@Tree("childList")
private List<YtkBasePageroute> childList;
}
测试:
只需要在父子及子集变量上加注解即可。
public static void main(String[] args) {
List<YtkBasePageroute> list=new ArrayList<>();
for(int i = 0;i<1000;i++){
YtkBasePageroute ytkBasePageroute = new YtkBasePageroute();
ytkBasePageroute.setId(i+1);
ytkBasePageroute.setName("测试"+i);
if(i<100) {
ytkBasePageroute.setParentId(0);
}else if(i<200){
ytkBasePageroute.setParentId(i-99);
}else if(i<300){
ytkBasePageroute.setParentId(i-199);
}else if(i<400){
ytkBasePageroute.setParentId(i-299);
}else if(i<500){
ytkBasePageroute.setParentId(i-200);
}
else if(i<600){
ytkBasePageroute.setParentId(i-300);
}
else if(i<700){
ytkBasePageroute.setParentId(i-200);
}else if(i<1000){
ytkBasePageroute.setParentId((int)(Math.random()*60)+5);
}
list.add(ytkBasePageroute);
}
try {
List<YtkBasePageroute> treeList=TreeUtil.listToTree(list, "0");
List<YtkBasePageroute> ytkBasePagerouteList=TreeUtil.treeToList(treeList);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}