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

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

部门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;

这个表最主要的是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();
}
}

这个是部门的表,但是我们通常返回给前端的不是这样的数据类型,我们需要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;
}
}

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

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

首先我们需要一个特殊的结构类型,类似于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();
}
}; }
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);
}
}
}
这样就ok了,重要的是思想。如果觉得好,请点个赞,推荐一下,右侧打赏一下更好了。~~~

java的递归查询大体思路的更多相关文章

  1. Java I/O编程思路

    我们在开发过程中不可避免遇到字符编码问题.遇到乱码问题的时候一定要保持清晰,网上很多关于字符编码集,这里我也就不介绍各种编码,这里我介绍自己编程中遇到字符编码问题时的思路. 乱码问题 无非就是 字节 ...

  2. java高并发解决思路

    一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构.性能的要求都很简单,随着互联网业务的不断丰富,网站 ...

  3. java中文件下载的思路(参考:孤傲苍狼)

    文件下载 文件下载功能是web开发中经常使用到的功能,使用HttpServletResponse对象就可以实现文件的下载 文件下载功能的实现思路: 1.获取要下载的文件的绝对路径 2.获取要下载的文件 ...

  4. Java应用性能瓶颈分析思路

    1 问题描述 因产品架构的复杂性,可能会导致性能问题的因素有很多.根据部署架构,大致的可以分为应用端瓶颈.数据库端瓶颈.环境瓶颈三大类.可以根据瓶颈的不同部位,选择相应的跟踪工具进行跟踪分析. 应用层 ...

  5. java画流程图【思路】

    java计算整数输入 <样例 画的第一张流程图 把脑子里的东西能清晰的表现出来 学编程必备

  6. Java进程故障排查思路及步骤

    故障场景 Java进程出现问题,通常表现出如下现象: Web应用响应时间长/超时,甚至不响应 CPU使用率极高/低,频繁出现Full GC,甚至OutOfMemoryError 响应时间长.超时,甚至 ...

  7. 整合shiro+jwt大体思路

    springboot整合shiro大体上的思路: 1.自定义一个类Realm extends AuthorizingRealm{} 主要是对token授权和认证 重写2个方法 doGetAuthori ...

  8. 如何写一个SSH项目(一)程序设计大体思路

    SSH:分别是指Spring,Struts,Hibernate. 后来Struts2代替了Struts,所以我们常说的SSH是指Spring,Struts2,Hibenate. 其中Spring一般用 ...

  9. Loadrunner脚本编程(1)-大体思路

    http://www.360doc.com/content/10/0806/13/1698198_44076570.shtml 就目前的了解.Loadrunner的脚本语言其实和C没什么区别.他内部的 ...

随机推荐

  1. HDOJ2025_查找最大元素

    一道简单题 HDOJ2025_查找最大元素 #include<stdio.h> #include<stdlib.h> #include<ctype.h> #incl ...

  2. CentOS查看版本及架构信息

    https://blog.csdn.net/shuaigexiaobo/article/details/78030008

  3. PRML读书笔记_绪论

    一.基本名词 泛化(generalization) 训练集所训练的模型对新数据的适用程度. 监督学习(supervised learning) 训练数据的样本包含输入向量以及对应的目标向量. 分类( ...

  4. php函数值传值/地址以及引用的用法

    博客摘自  奔跑的大白,网址: http://www.cnblogs.com/gauze/p/5568867.html 1.先来解释一下名词. 值传递(passl-by-value)过程中,被调函数的 ...

  5. c3算法详解

    c3 算法求某一类在多继承中的继承顺序:类的mro == [类] + [父类的继承顺序] + [父类2的继承顺序]如果从左到右的第一个类在后面的顺序中出现,那么就提取出来到mro顺序中[ABCD] + ...

  6. pxe+kickstart 自动化部署linux操作系统

    kickstart 是什么? 批量部署Linux服务器操作系统 运行模式: C/S client/server 服务器上要部署: DHCP tftp(非交互式文件共享) 安装系统的三个步骤: 1.加载 ...

  7. Java ThreadLocal 理解

    ThreadLocal 概念: ThreadLocal不是用来解决对象共享访问的问题,而主要是提供了保存对象的方法和避免参数传递的方便的对象访问方式. ThreadLocal并不是一个Thread,而 ...

  8. Ubuntu 16.04 root环境变量不生效问题解决方案

    在Ubuntu 16.04中配置JDK环境变量,但是在切换到root时不生效 . 在/etc/profile中添加如下: export JAVA_HOME=/opt/java/jdk1..0_151 ...

  9. 什么是Maven?

    绝大部分Maven用户都会说:Maven是一个“构建工具”——一个用来把源代码构建成可发布的构建的工具. 构建工程师和项目经理会说Maven是一个更复杂的东西:一个项目管理工具. Maven除了提供构 ...

  10. BZOJ5297 [CQOI2018] 交互网络 【MatrixTree定理】

    题目分析: 这题是一道板题,属于MatrixTree定理的简单拓展,邻接矩阵与有向图邻接矩阵一致,度数矩阵作为入度矩阵.然后高斯消元即可. 代码: #include<bits/stdc++.h& ...