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了,重要的是思想。如果觉得好,请点个赞,推荐一下,右侧打赏一下更好了。~~~
  • 相关阅读:
    Android 3.0 r1 API中文文档(108) —— ExpandableListAdapter
    Android 3.0 r1 API中文文档(113) ——SlidingDrawer
    Android 3.0 r1 API中文文档(105) —— ViewParent
    Android 中文 API (102)—— CursorAdapter
    Android开发者指南(4) —— Application Fundamentals
    Android开发者指南(1) —— Android Debug Bridge(adb)
    Android中文API(115)——AudioFormat
    Android中文API(116)——TableLayout
    Android开发者指南(3) —— Other Tools
    Android中文API (110) —— CursorTreeAdapter
  • 原文地址:https://www.cnblogs.com/coder-lzh/p/8673156.html
Copyright © 2011-2022 走看看