MP - 加载数据库中树型数据(同步树)

本文介绍了如何使用Mybatis-Plus(MP)从数据库加载树型数据,适用于前端页面的分类树展示。通过分析数据表结构、使用场景,提出通过创建专门的VO类继承实体并实现树节点接口,利用BeanUtils进行数据复制,明确输入输出(根节点id),最终实现递归生成树结构的方法。
摘要由CSDN通过智能技术生成

MP - 加载数据库中树型数据(同步树)

  • 数据表结构
  • 使用场景
  • 分析与实现

一:数据表结构
  • Department

    • id
    • pid

    在这里插入图片描述

二:使用场景

在前端页面的分类树中:点击树节点,得到当前节点的所有子节点(树结构),展开分类树。

三:分析与实现
  • 环境

    • Mybatis-Plus 3.4.3
    • Java 8
  • 分析

    1> 由于实体对象中的部分字段与前端用于显示的数据字段名称不同 + 作为树节点应该作为树节点(遵循一种规范/接口),所以应该单独创建实体VO类用于与前端数据的交互;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class DepartmentTreeVO extends Department implements INode {
    
        // 展示内容
        private String label;
    
        // 子节点
        private List<? extends INode> children;
    
        // 标记是否有子节点
        private Boolean hasChildren;
    
        @Override
        public String getParentId() {
            return this.getPid();
        }
    }
    

    2> VO应该继承原有实体,并且实现INode树节点规范;

    public interface INode extends Serializable {
        String getId();
    
        String getParentId();
    
        List<? extends INode> getChildren();
    
        default Boolean getHasChildren() { return this.getChildren() != null && !this.getChildren().isEmpty();};
    }
    

    3> 为了方便VO与实体之间数据的拷贝,需要使用BeanUtils工具类完成Bean对象之间属性复制;

    import org.springframework.beans.BeanUtils;
    
    import java.util.Collections;
    import java.util.List;
    import java.util.stream.Collectors;
    
    public class XBeanUtil {
    
        /**
         * 复制bean的属性(使用到了spring框架中的BeanUtils)
         *
         * @param source 源 要复制的对象
         * @param target 目标 复制到此对象
         */
        public static void copyProperties(Object source, Object target) {
            BeanUtils.copyProperties(source, target);
        }
    
        /**
         * 复制对象
         *
         * @param source 源 要复制的对象
         * @param target 目标 复制到此对象
         * @param <T>
         * @return
         */
        public static <T> T copy(Object source, Class<T> target) {
            if(source == null || target == null){
                return null;
            }
            try {
                T newInstance = target.newInstance();
                BeanUtils.copyProperties(source, newInstance);
                return newInstance;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        /**
         * 复制list
         *
         * @param source
         * @param target
         * @param <T>
         * @param <K>
         * @return
         */
        public static <T, K> List<K> copyList(List<T> source, Class<K> target) {
            if (null == source || source.isEmpty()) {
                return Collections.emptyList();
            }
            return source.stream().map(e -> copy(e, target)).collect(Collectors.toList());
        }
    
    }
    

    4> 明确输入与输出

    • 输入:根节点id,这个根节点一般被定义为id=-1的虚拟节点
      • 数据库中pid=-1的记录都会被挂在最外层虚拟根节点上;
      • 虚拟根节点在数据库中并不存在,应该在形成树结构时(页面初始化时)手动初始化该节点,同时将其id置为-1并将下方节点挂在当前节点下面。
    • 输出:List
  • 实现

    1> 调用

    List<DepartmentTreeVO> result = buildTreeList("-1", departmentTreeVOList);
    

    2> 根据一个id获取其所有子节点:getChildNodes

    public List<DepartmentTreeVO> getChildNodes(String pid, List<DepartmentTreeVO> departments) {
            return departments.stream().filter(x -> pid.equals(x.getParentId())).collect(Collectors.toList());
        }
    

    3> 递归生成树结构

    /**
     * 构建树型数据集合
     *
     * @param pid 父节点pid(注:当前节点不会作为结果根节点)
     * @param list 所有节点数据(思想:从数据库中拿到所有数据,逻辑只做结构处理)
     * @return
     */
    public List<DepartmentTreeVO> buildTreeList(String pid, List<DepartmentTreeVO> list) {
        List<DepartmentTreeVO> childList = getChildNodes(pid, list);
        List<DepartmentTreeVO> departmentTreeVOList = new ArrayList<>();
    
        for (DepartmentTreeVO node : childList) {
            List<DepartmentTreeVO> children = buildTreeList(node.getId(), list);
            if (!children.isEmpty()) {
                node.setLabel(node.getDeptName());
                node.setHasChildren(true);
                node.setChildren(children);
            } else {
                node.setHasChildren(false);
            }
            departmentTreeVOList.add(node);
    
        }
    
        return departmentTreeVOList;
    }
    




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值