【java】实体类集合转树状结构

这里介绍一个将实体类数组通过父级id字段转换成树型结构的方法,一般主要还是便于接口数据返回后,前端可以直接使用和展示。
这里首先建一个基类,用于实现后面写的转换方法,然后让任意实体类继承这个类,再调用转换方法即可

import java.util.ArrayList;
import java.util.List;

/**
 * @author Wus
 * @since 2022/8/17-16:16
 */

public class TreeNode {
    private Object parentId;
    private List<TreeNode> children;
    private Object id;
    private Long weight;

    public void add(TreeNode node) {
        if (children == null) {
            children = new ArrayList<>();
        }
        children.add(node);
    }

    public Object getParentId() {
        return parentId;
    }

    public void setParentId(Object parentId) {
        this.parentId = parentId;
    }

    public List<TreeNode> getChildren() {
        return children;
    }

    public void setChildren(List<TreeNode> children) {
        this.children = children;
    }

    public Object getId() {
        return id;
    }

    public void setId(Object id) {
        this.id = id;
    }

    public Long getWeight() {
        return weight;
    }

    public void setWeight(Long weight) {
        this.weight = weight;
    }
}

下面这个就是转换方法,只要把集合传进去即可,默认根节点是root(String),null或者0(Integer),别忘了将idparentId属性是必须补充上的,weight主要用于排序,可以为null。

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Wus
 * @since 2022/8/17-16:12
 */
@Slf4j
public class TreeConvert {
    /**
     * 默认0,null,root是根节点
     *
     * @param origList 原始数据
     * @return 树结构数据
     */

    public static <T extends TreeNode> List<T> convert(List<T> origList) {
        // 用于保存当前 id 索引的实体类
        Map<Object, T> idEntities = new HashMap<>(5);
        // 暂存区, 用于保存没有找到父 id 的控件
        List<T> tempList = new ArrayList<>();
        // 最终生成结果
        List<T> result = new ArrayList<>();
        log.info("开始转换树形结构");
        log.info("原始数据为:{}", origList);
        for (T entity : origList) {
            // 获取 id, parentId, children
            Object id = entity.getId();
            Object parentId = entity.getParentId();
            idEntities.put(id, entity);
            if (ObjectUtils.isEmpty(parentId) || "root".equals(parentId) || parentId.equals(Integer.parseInt("0"))) {
                // 如果父 id 为空, 则实体类为第一层
                sortInsert(result, entity);
            } else {
                // 根据父 id 获取实体类
                T parentEntity = idEntities.get(parentId);
                if (parentEntity == null) {
                    // 没找到先放入暂存区
                    tempList.add(entity);
                } else {
                    // 父组件判断是否存在 children, 不存在新增, 存在则直接假如
                    setChildrenValue(entity, parentEntity);
                }
            }
        }
        // 处理暂存区, 暂存区的一定不为根节点, 所以它只要父节点存在, 那么此轮查询一定能找到父节点(上一轮已经将全部节点放入idEntities)
        for (T entity : tempList) {
            // 根据父id获取实体类
            T parentEntity = idEntities.get(entity.getParentId());
            // 父组件判断是否存在children, 并将entity加入children
            setChildrenValue(entity, parentEntity);

        }
        return result;
    }

    /**
     * 设置children
     * @param entity 子节点
     * @param parentEntity 父节点
     */
    private static <T extends TreeNode> void setChildrenValue(T entity, T parentEntity) {
        List<TreeNode> children = parentEntity.getChildren();
        List<T> childrenList;
        if (children == null) {
            childrenList = new ArrayList<>();
            sortInsert(childrenList, entity);
            parentEntity.setChildren((List<TreeNode>) childrenList);
        } else {
            sortInsert(children, entity);
        }
    }
    /**
     * 排序插入,依据weight属性
     */
    public static <T extends TreeNode> void sortInsert(List<T> list, T entity) {

        if (entity.getWeight() == null) {
            list.add(entity);
        } else {
            //weight转换为大数
            BigDecimal currentValue = new BigDecimal(entity.getWeight());
            if (list != null && list.size() != 0) {
                for (int i = 0; i < list.size(); i++) {
                    BigDecimal sortValue = new BigDecimal(list.get(i).getWeight());
                    if (currentValue.compareTo(sortValue) < 0) {
                        list.add(i, entity);
                        return;
                    }
                }
            }
            assert list != null;
            list.add(entity);
        }
    }
}

使用示例:

下面就做一个使用示例

首先继承TreeNode类,id,parentId,weight可以重新声明也可以super来用父类的属性。

import com.fasterxml.jackson.annotation.JsonFormat;
import com.wss.server.question.entity.QClassification;
import com.wss.witch.utils.tree.TreeConvert;
import com.wss.witch.utils.tree.TreeNode;
import io.swagger.annotations.ApiModelProperty;

import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Wus
 * @since 2022/8/17-16:19
 */

public class ClassQuestionTreeVo extends TreeNode implements Serializable {
    @Serial
    private static final long serialVersionUID = 22494L;
    @ApiModelProperty("分类id")
    private Integer qClassificationId;

    @ApiModelProperty("分类名")
    private String className;

    @ApiModelProperty("父级id")
    private Integer parentId;

    @ApiModelProperty("层级")
    private Integer level;

    @ApiModelProperty("创建时间")
    @JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    @ApiModelProperty("修改时间")
    @JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

    @ApiModelProperty("创建用户")
    private Long createUser;

    @ApiModelProperty("是否删除")
    private Integer isDelete;

    @ApiModelProperty("图标")
    private String logo;
    @ApiModelProperty("权重")
    private Long weight;

    /**
     * 初始化
     */
    public static ClassQuestionTreeVo init(QClassification qClassification) {
        ClassQuestionTreeVo treeVo = new ClassQuestionTreeVo();
        treeVo.setId(qClassification.getqClassificationId());
        treeVo.setParentId(qClassification.getParentId());
        treeVo.setqClassificationId(qClassification.getqClassificationId());
        treeVo.setClassName(qClassification.getClassName());
        treeVo.setLevel(qClassification.getLevel());
        treeVo.setCreateTime(qClassification.getCreateTime());
        treeVo.setUpdateTime(qClassification.getUpdateTime());
        treeVo.setCreateUser(qClassification.getCreateUser());
        treeVo.setIsDelete(qClassification.getIsDelete());
        treeVo.setLogo(qClassification.getLogo());
        return treeVo;
    }

    /**
     * 转换成树形结构
     */
    public static List<ClassQuestionTreeVo> convert(List<QClassification> qClassifications) throws Exception {
        ArrayList<ClassQuestionTreeVo> classQuestionTreeVos = new ArrayList<>();
        for (QClassification qClassification : qClassifications) {
            classQuestionTreeVos.add(init(qClassification));
        }
        return TreeConvert.convert(classQuestionTreeVos);
    }

    public Integer getqClassificationId() {
        return qClassificationId;
    }

    public void setqClassificationId(Integer qClassificationId) {
        this.qClassificationId = qClassificationId;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    @Override
    public Integer getParentId() {
        return parentId;
    }

    public void setParentId(Integer parentId) {
        this.parentId = parentId;
    }

    public Integer getLevel() {
        return level;
    }

    public void setLevel(Integer level) {
        this.level = level;
    }

    public LocalDateTime getCreateTime() {
        return createTime;
    }

    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }

    public LocalDateTime getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }

    public Long getCreateUser() {
        return createUser;
    }

    public void setCreateUser(Long createUser) {
        this.createUser = createUser;
    }

    public Integer getIsDelete() {
        return isDelete;
    }

    public void setIsDelete(Integer isDelete) {
        this.isDelete = isDelete;
    }

    public String getLogo() {
        return logo;
    }

    public void setLogo(String logo) {
        this.logo = logo;
    }

    @Override
    public Long getWeight() {
        return weight;
    }

    @Override
    public void setWeight(Long weight) {
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "ClassQuestionTreeVo{" +
                "qClassificationId=" + qClassificationId +
                ", className='" + className + '\'' +
                ", parentId=" + parentId +
                ", level=" + level +
                ", createTime=" + createTime +
                ", updateTime=" + updateTime +
                ", createUser=" + createUser +
                ", isDelete=" + isDelete +
                ", logo='" + logo  +
                ",id=" + super.getId() +
                ",weight=" + weight +
                '}';
    }
}

这一块有些其他类的细节就不放了,上主要是把数据库的实体类变成方便转换的类,然后通过TreeConvert.convert转换即可。

public static List<ClassQuestionTreeVo> convert(List<QClassification> qClassifications) throws Exception {
	ArrayList<ClassQuestionTreeVo> classQuestionTreeVos = new ArrayList<>();
    for (QClassification qClassification : qClassifications) {
		classQuestionTreeVos.add(init(qClassification));
    }
    return TreeConvert.convert(classQuestionTreeVos); //----------这是重点
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游码客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值