java转树形结构工具类详解

本文实例为大家分享了java转树形结构工具类的具体代码,供大家参考,具体内容如下

import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.ToString;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author : liyk
 * @version 1.0
 * @date : 2020/6/9
 */
public class TreeUtil {

  /**
   * 将 List 转为树形结构
   *
   * @param origList     : 要转换的 List
   * @param idFieldName    : id字段名
   * @param parentIdFieldName : parentId 字段名
   * @param childrenFieldName : children 字段名
   * @param <T>        : 拥有父子结构的 Entity
   * @return : 树形结果
   * @throws Exception .
   */
  public static <T> List<T> convert(List<T> origList, String idFieldName,
                   String parentIdFieldName, String childrenFieldName) throws Exception {
    // 用于保存当前 id 索引的实体类
    Map<String, T> idMaps = new HashMap<>();
    // 暂存区, 用于保存没有找到父 id 的控件
    List<T> tempList = new ArrayList<>();
    List<T> result = new ArrayList<>();
    for (T entity : origList) {
      // 获取 id, parentId, children
      String id = Objects.toString(getFieldValue(entity, idFieldName), "");
      String parentId = Objects.toString(getFieldValue(entity, parentIdFieldName), "");
      if (StringUtils.isEmpty(id)) {
        throw new Exception("存在id为空的资料");
      }
      idMaps.put(id, entity);
      if (StringUtils.isEmpty(parentId)) {
        // 如果父 id 为空, 则实体类为第一层
        result.add(entity);
      } else {
        // 根据父 id 获取实体类
        T parentEntity = idMaps.get(parentId);
        if (parentEntity == null) {
          // 没找到先放入暂存区
          tempList.add(entity);
        } else {
          // 父组件判断是否存在 children, 不存在新增, 存在则直接假如
          setChildrenValue(childrenFieldName, entity, parentEntity);
        }
      }
    }
    // 处理暂存区, 暂存区的一定不为根节点, 所以它只要父节点存在, 那么此轮查询一定能找到父节点(上一轮已经将全部节点放入 idMaps)
    for (T entity : tempList) {
      // 获取 parentId
      String parentId = Objects.toString(getFieldValue(entity, parentIdFieldName), "");
      // 根据父id获取实体类
      T parentEntity = idMaps.get(parentId);
      if (parentEntity == null) {
        throw new Exception("存在孤立的子节点");
      } else {
        // 父组件判断是否存在children, 不存在新增, 存在则直接假如
        setChildrenValue(childrenFieldName, entity, parentEntity);
      }
    }
    return result;
  }

  private static <T> void setChildrenValue(String childrenFieldName, T entity, T parentEntity) throws Exception {
    Object children = getFieldValue(parentEntity, childrenFieldName);
    List<T> childrenList;
    if (children == null) {
      childrenList = new ArrayList<>();
      childrenList.add(entity);
      setFieldValue(parentEntity, childrenFieldName, childrenList);
    } else {
      List<T> childrenReal = (List<T>) children;
      childrenReal.add(entity);
    }
  }

  private static <T> Object getFieldValue(T entity, String fieldName) throws Exception {
    Field field = ReflectionUtils.findField(entity.getClass(), fieldName);
    if (field == null) {
      throw new Exception(String.format("字段名称[%s]不存在", fieldName));
    }
    boolean accessible = field.isAccessible();
    field.setAccessible(true);
    Object result = ReflectionUtils.getField(field, entity);
    field.setAccessible(accessible);
    return result;
  }

  private static <T> void setFieldValue(T entity, String fieldName, Object value) throws Exception {
    Field field = ReflectionUtils.findField(entity.getClass(), fieldName);
    if (field == null) {
      throw new Exception(String.format("字段名称[%s]不存在", fieldName));
    }
    boolean accessible = field.isAccessible();
    field.setAccessible(true);
    ReflectionUtils.setField(field, entity, value);
    field.setAccessible(accessible);
  }

  public static void main(String[] args) throws Exception {
    List<Demo> list = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
      Demo demo = new Demo(i, "一级节点" + i);
      list.add(demo);
    }
    for (int i = 5; i < 15; i++) {
      Demo demo = new Demo(i, i % 5, "二级节点" + i);
      list.add(demo);
    }
    for (int i = 15; i < 100; i++) {
      Demo demo = new Demo(i, i % 10 + 5, "三级节点" + i);
      list.add(demo);
    }
    Demo demo = new Demo(100, 102, "非法节点");
    list.add(demo);
    List<Demo> convert = TreeUtil.convert(list, "id", "pid", "children");
    String s = JSON.toJSONString(convert);
    System.out.println(s);
  }

}

@Data
@ToString
class Demo {
  private Integer id;
  private Integer pid;
  private String name;
  private List<Demo> children;

  public Demo(Integer id, Integer pid, String name) {
    this.id = id;
    this.pid = pid;
    this.name = name;
  }

  public Demo(Integer id, String name) {
    this.id = id;
    this.name = name;
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 使用递归算法结合数据库解析成Java树形结构的代码解析

    1.准备表结构及对应的表数据 a.表结构: create table TB_TREE ( CID NUMBER not null, CNAME VARCHAR2(50), PID NUMBER //父节点 ) b.表数据: insert into tb_tree (CID, CNAME, PID) values (1, '中国', 0); insert into tb_tree (CID, CNAME, PID) values (2, '北京市', 1); insert into tb_tree

  • JSON复杂数据处理之Json树形结构数据转Java对象并存储到数据库的实现

    在网站开发中经常遇到级联数据的展示,比如选择城市的时候弹出的省市县选择界面.很多前端制作人员习惯于从JSON中而不是从数据库中获取省市县数据.那么在选择了省市县中的某一个城市 ,存储到数据库中需要存储所选城市的代码.所以需要一个能将JSON数据(一般存储在javascript脚本中)结构全部导入到数据库中的功能. JSON的特点是支持层级结构.支持数组表示的对象 .下面的示例介绍如何将JSON的省市县数据保存到数据库中,实现原理非常简单,就是利用JSON的java工具包API,将层次结构的JSO

  • 解决java idea新建子目录时命名不是树形结构的问题

    问题再现 解决办法:点击设置,然后再点击Compact Middle Packages,如下图: 成功 补充知识:idea 2019.2 svn 忽略文件/目录 .idea *.iml target log 背景 idea 2019.2 不再支持忽略 svn 文件和目录的功能,我们可以使用小乌龟自带的功能来解决这个问题. 1. 在项目根目录的空白处,点击右键菜单 TortoiseSVN->Properties 2. New->Other 3. 选择svn:global-ignores 所有子目

  • Java递归遍历树形结构

    废话不多说了,直接给大家贴代码,具体代码如下所示: //菜单树形结构 public JSONArray treeMenuList(JSONArray menuList, int parentId) { JSONArray childMenu = new JSONArray(); for (Object object : menuList) { JSONObject jsonMenu = JSONObject.fromObject(object); int menuId = jsonMenu.ge

  • 使用递归删除树形结构的所有子节点(java和mysql实现)

    1.业务场景 有如下树形结构: +-0 +-1 +-2 +-4 +-5 +-3 如果删除某个父节点,则其子节点,以及其子节点的子节点,以此类推,需要全部删除. 2.Java实现 使用Map存储树形结构的数据,id为map的key,pid为树形结构的value. import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.uti

  • java、js中实现无限层级的树形结构方法(类似递归)

    js中: var zNodes=[ {id:0,pId:-1,name:"Aaaa"}, {id:1,pId:0,name:"A"}, {id:11,pId:1,name:"A1"}, {id:12,pId:1,name:"A2"}, {id:13,pId:1,name:"A3"}, {id:2,pId:0,name:"B"}, {id:21,pId:2,name:"B1&qu

  • Java创建树形结构算法实例代码

    在JavaWeb的相关开发中经常会涉及到多级菜单的展示,为了方便菜单的管理需要使用数据库进行支持,本例采用相关算法讲数据库中的条形记录进行相关组装和排序讲菜单组装成树形结构. 首先是需要的JavaBean import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import j

  • Java遍历输出指定目录、树形结构所有文件包括子目录下的文件

    下面通过一段代码介绍下Java输出指定目录.树形结构下的所有文件包括子目录中的文件的方法,并附有效果图. import java.io.File; public class ReadDirectory { // 文件所在的层数 private int fileLevel; /** * 生成输出格式 * @param name 输出的文件名或目录名 * @param level 输出的文件名或者目录名所在的层次 * @return 输出的字符串 */ public String createPri

  • Java数据封装树形结构代码实例

    这篇文章主要介绍了Java数据封装树形结构代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.实体类 @data public class PublishServiceType implements Comparable<PublishServiceType>{ /** * */ private static final long serialVersionUID = -3572108154932898825L; /* * @see

  • java转树形结构工具类详解

    本文实例为大家分享了java转树形结构工具类的具体代码,供大家参考,具体内容如下 import com.alibaba.fastjson.JSON; import lombok.Data; import lombok.ToString; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import java.lang.reflect.Field; impor

  • java中DateUtils时间工具类详解

    本文实例为大家分享了DateUtils时间工具类的具体代码,供大家参考,具体内容如下 package com.example.administrator.myapp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; /** * Date 工具类 * Created by lychun on 2017/12/07

  • java中文转拼音工具类详解

    本文实例为大家分享了java中文转拼音工具类的具体代码,供大家参考,具体内容如下 import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import net.sourceforge.

  • java数字转汉字工具类详解

    本文实例为大家分享了java数字转汉字工具类的具体代码,供大家参考,具体内容如下 /** * Created by 33303 on 2017/7/28. */ import java.math.BigDecimal; /** * 数字转换为汉语中人民币的大写<br> * */ public class NumberToCN { /** * 汉语中数字大写 */ private static final String[] CN_UPPER_NUMBER = { "零", &

  • Java身份证号码校验工具类详解

    本文实例为大家分享了Java身份证号码校验工具类的具体代码,供大家参考,具体内容如下 import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.regex.Pattern; public class IdcardVa

  • Java基础类之ArrayUtils工具类详解

    目录 1.引入pom依赖 2.ArrayUtils中的方法: 3.举例 总结 1.引入pom依赖 <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <

  • Java TimedCache 带时间缓存工具类详解使用

    简述 我们在工作中会碰到需要使用带过期时间的缓存场景.但是使用redis有太重了,毕竟缓存的数据很小,放在内存够够的.hutools提供了TimedCache时间缓存工具,可以实现该场景.下面使用到该组件,并为了适配工作场景,对该工具类做优化升级. Maven依赖 <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>

  • Java项目常见工具类详解

    目录 JWT工具类 MD5工具类 视频点播工具类 公共常量工具类 日期操作工具类 Http客户端工具类 获取IP工具类 JWT工具类 这里一共涉及四个方法: 传入用户信息获得token 传入token字符串判断token是否存在与有效 传入HttpServletRequest,通过获取Header中的token判断是否存在与有效 根据token获取用户id public class JwtUtils { //token过期时间 public static final long EXPIRE =

  • Java并发编程之Executors类详解

    一.Executors的理解 Executors类属于java.util.concurrent包: 线程池的创建分为两种方式:ThreadPoolExecutor 和 Executors: Executors(静态Executor工厂)用于创建线程池: 工厂和工具方法Executor , ExecutorService , ScheduledExecutorService , ThreadFactory和Callable在此包中定义的类: jdk1.8API中的解释如下: 二.Executors

  • Springboot Mybatis Plus自动生成工具类详解代码

    前言 代码生成器,也叫逆向工程,是根据数据库里的表结构,自动生成对应的实体类.映射文件和接口. 看到很多小伙伴在为数据库生成实体类发愁,现分享给大家,提高开发效率. 一.pom依赖 <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> &

随机推荐