zoukankan      html  css  js  c++  java
  • java的递归查询大体思路

    场景:递归查询是我们开发中很常见的,如果没有一个比较好的思路,这将会让我们很头疼。

    我这里介绍一个查询部门的例子,希望能给你一些启发

    部门sql

    -- ----------------------------
    --  Table structure for `sys_dept`
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_dept`;
    CREATE TABLE `sys_dept` (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '部门id',
      `name` varchar(20) NOT NULL DEFAULT '' COMMENT '部门名称',
      `parent_id` int(11) NOT NULL DEFAULT '0' COMMENT '上级部门id',
      `level` varchar(200) NOT NULL DEFAULT '' COMMENT '部门层级',
      `seq` int(11) NOT NULL DEFAULT '0' COMMENT '部门在当前层级下的顺序,由小到大',
      `remark` varchar(200) DEFAULT '' COMMENT '备注',
      `operator` varchar(20) NOT NULL DEFAULT '' COMMENT '操作者',
      `operate_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后一次操作时间',
      `operate_ip` varchar(20) NOT NULL DEFAULT '' COMMENT '最后一次更新操作者的ip地址',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4;
    
    -- ----------------------------
    --  Records of `sys_dept`
    -- ----------------------------
    BEGIN;
    INSERT INTO `sys_dept` VALUES ('1', '技术部', '0', '0', '1', '技术部', 'system', '2017-10-11 07:21:40', '127.0.0.1'), ('2', '后端开发', '1', '0.1', '1', '后端', 'system-update', '2017-10-12 07:56:16', '127.0.0.1'), ('3', '前端开发', '1', '0.1', '2', '', 'system-update', '2017-10-14 11:29:45', '127.0.0.1'), ('4', 'UI设计', '1', '0.1', '3', '', 'system', '2017-10-12 07:55:43', '127.0.0.1'), ('11', '产品部', '0', '0', '2', '', 'Admin', '2017-10-16 22:52:29', '0:0:0:0:0:0:0:1'), ('12', '客服部', '0', '0', '4', '', 'Admin', '2017-10-17 00:22:55', '0:0:0:0:0:0:0:1');
    COMMIT;
    View Code

     这个表最主要的是level,parentId这两个字段,比如说一个顶级部门开发部(顶级部门默认parentId为0),id为1,parentld为0,level为0

    然后开发部下面有后端开发,前端开发这些子部门。那这些子部门的parentId就为开发部的id 1 ,level就为他父level加父id,中间用逗号隔开。

    之所以要设计成这种形式,是因为我们下面会用到。

    SysDept.java
    package com.mmall.model;
    
    import lombok.Builder;
    
    import java.util.Date;
    @Builder
    public class SysDept {
        private Integer id;
    
        private String name;
    
        private Integer parentId;
    
        private String level;
    
        private Integer seq;
    
        private String remark;
    
        private String operator;
    
        private Date operateTime;
    
        private String operateIp;
    
        public SysDept() {
        }
    
        public SysDept(Integer id, String name, Integer parentId, String level, Integer seq, String remark, String operator, Date operateTime, String operateIp) {
            this.id = id;
            this.name = name;
            this.parentId = parentId;
            this.level = level;
            this.seq = seq;
            this.remark = remark;
            this.operator = operator;
            this.operateTime = operateTime;
            this.operateIp = operateIp;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name == null ? null : name.trim();
        }
    
        public Integer getParentId() {
            return parentId;
        }
    
        public void setParentId(Integer parentId) {
            this.parentId = parentId;
        }
    
        public String getLevel() {
            return level;
        }
    
        public void setLevel(String level) {
            this.level = level == null ? null : level.trim();
        }
    
        public Integer getSeq() {
            return seq;
        }
    
        public void setSeq(Integer seq) {
            this.seq = seq;
        }
    
        public String getRemark() {
            return remark;
        }
    
        public void setRemark(String remark) {
            this.remark = remark == null ? null : remark.trim();
        }
    
        public String getOperator() {
            return operator;
        }
    
        public void setOperator(String operator) {
            this.operator = operator == null ? null : operator.trim();
        }
    
        public Date getOperateTime() {
            return operateTime;
        }
    
        public void setOperateTime(Date operateTime) {
            this.operateTime = operateTime;
        }
    
        public String getOperateIp() {
            return operateIp;
        }
    
        public void setOperateIp(String operateIp) {
            this.operateIp = operateIp == null ? null : operateIp.trim();
        }
    }
    View Code

    这个是部门的表,但是我们通常返回给前端的不是这样的数据类型,我们需要new一个dto,DeptLevelDto.java

    增加一个属性List<DeptLevelDto>      ,    另外再增加一个方法,让查询出来的dept对象转换成deptDto,因为他俩基本上字段相同。

    DeptLevelDto.java

    package com.mmall.dto;
    
    import com.google.common.collect.Lists;
    import com.mmall.model.SysDept;
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import org.springframework.beans.BeanUtils;
    
    import java.util.List;
    
    @Getter
    @Setter
    @ToString
    public class DeptLevelDto extends SysDept {
    
        private List<DeptLevelDto> deptList = Lists.newArrayList();
    
        public static DeptLevelDto adapt(SysDept dept) {
            DeptLevelDto dto = new DeptLevelDto();
            BeanUtils.copyProperties(dept, dto);
            return dto;
        }
    }
    View Code

    基本上架子搭起来了,下面开始实现我们的逻辑   树形部门

    如何得到一个树形结构呢?递归,必须得。

    首先我们需要一个特殊的结构类型,类似于Map<String,List<Dept>>,为什么要这样的数据类型呢?因为我们要根据key为level,得到这个部门下面的子节点。

    举个例子:打比方说,我现在一个开发部的顶级对象,然后我可以得到开发部子节点的level(开发部的level+id),然后我根据子节点的level得到开发部下面的子节点List,如果list不为null,我就把list子节点add到开发部,然后再让遍历子节点,还是从新走这个方法。这就是递归。

    记住:递归一定要有结束条件,这里的结束条件就是查出的子节点不为null就跳出。

    准备条件:

    首先:我需要得到一个类似于Map<String,List<Dept>>  ,这个用 

    Multimap<String, DeptLevelDto> levelDeptMap = ArrayListMultimap.create();  为什么用它?

    然后还需要一个RootList<Dept>  这个是我们最开始遍历用的。因为遍历肯定是遍历根节点嘛。然后再一个一个挖挖挖~~

    然后递归就可以了。具体看代码

    SysTreeService.java
    package com.mmall.service;
    
    import com.google.common.collect.ArrayListMultimap;
    import com.google.common.collect.Lists;
    import com.google.common.collect.Multimap;
    import com.mmall.dao.SysDeptMapper;
    import com.mmall.dto.AclDto;
    import com.mmall.dto.AclModuleLevelDto;
    import com.mmall.dto.DeptLevelDto;
    import com.mmall.model.SysDept;
    import com.mmall.util.LevelUtil;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    /**
     * Created by 敲代码的卡卡罗特
     * on 2018/3/27 20:46.
     */
    @Service
    public class SysTreeService {
        @Resource
        private SysDeptMapper sysDeptMapper;
        public List<DeptLevelDto> deptTree() {
            //得到全部的部门对象
            List<SysDept> deptList = sysDeptMapper.getAllDept();
            //new一个返回前端的DeptLevelDto List
            List<DeptLevelDto> dtoList = Lists.newArrayList();
            for (SysDept dept : deptList) {
                DeptLevelDto dto = DeptLevelDto.adapt(dept);
                dtoList.add(dto);
            }
            
            return deptListToTree(dtoList);
        }
    
        public List<DeptLevelDto> deptListToTree(List<DeptLevelDto> deptLevelList) {
            //如果得到为null,直接返回null    List
            if (CollectionUtils.isEmpty(deptLevelList)) {
                return Lists.newArrayList();
            }
            //new一个我们需要的结构类型
            Multimap<String, DeptLevelDto> levelDeptMap = ArrayListMultimap.create();
            //new一个我们需要的rootList
            List<DeptLevelDto> rootList = Lists.newArrayList();
            //遍历上面所有的list部门对象,把level==0的放到rootList     同时也可以利用Multimap的特性得到key为level , 值为对象的 数据结构
            for (DeptLevelDto dto : deptLevelList) {
                levelDeptMap.put(dto.getLevel(), dto);
                if (LevelUtil.ROOT.equals(dto.getLevel())) {
                    rootList.add(dto);
                }
            }
    
            // 按照seq从小到大排序
            Collections.sort(rootList, new Comparator<DeptLevelDto>() {
                public int compare(DeptLevelDto o1, DeptLevelDto o2) {
                    return o1.getSeq() - o2.getSeq();
                }
            });
    
            // 递归生成树
            transformDeptTree(rootList, LevelUtil.ROOT, levelDeptMap);
            return rootList;
        }
    
        public void transformDeptTree(List<DeptLevelDto> deptLevelList, String level, Multimap<String, DeptLevelDto> levelDeptMap) {
            for (int i = 0; i < deptLevelList.size(); i++) {
                // 遍历该层的每个元素
                DeptLevelDto deptLevelDto = deptLevelList.get(i);
                // 处理当前层级的数据
                String nextLevel = LevelUtil.calculateLevel(level, deptLevelDto.getId());
                // 处理下一层
                List<DeptLevelDto> tempDeptList = (List<DeptLevelDto>) levelDeptMap.get(nextLevel);
                if (CollectionUtils.isNotEmpty(tempDeptList)) {
                    // 排序
                    Collections.sort(tempDeptList, deptSeqComparator);
                    // 设置下一层部门
                    deptLevelDto.setDeptList(tempDeptList);
                    // 进入到下一层处理
                    transformDeptTree(tempDeptList, nextLevel, levelDeptMap);
                }
            }
        }
        //排序方法
        public Comparator<DeptLevelDto> deptSeqComparator = new Comparator<DeptLevelDto>() {
            public int compare(DeptLevelDto o1, DeptLevelDto o2) {
                return o1.getSeq() - o2.getSeq();
            }
        };
    
    
      
    }
    View Code
    LevelUtil.java
    package com.mmall.util;
    
    import org.apache.commons.lang3.StringUtils;
    
    public class LevelUtil {
    
        public final static String SEPARATOR = ".";
    
        public final static String ROOT = "0";
    
        // 0
        // 0.1
        // 0.1.2
        // 0.1.3
        // 0.4
        public static String calculateLevel(String parentLevel, int parentId) {
            if (StringUtils.isBlank(parentLevel)) {
                return ROOT;
            } else {
                return StringUtils.join(parentLevel, SEPARATOR, parentId);
            }
        }
    }
    View Code
    这样就ok了,重要的是思想。如果觉得好,请点个赞,推荐一下,右侧打赏一下更好了。~~~
  • 相关阅读:
    Docker下安装redis
    Goodnotes5
    Notability
    浏览器好用的技术
    苹果平板上好用的软件推荐
    苹果平板爱思助手检验安兔兔
    积分超过排名的第一天
    卸载Windows控制面板的程序和功能中找不到的一些软件的方法
    怎样在GitHub上新建一个文件夹
    Vim的常用操作
  • 原文地址:https://www.cnblogs.com/coder-lzh/p/8673156.html
Copyright © 2011-2022 走看看