前言
公司前端需要调用Cascader级联选择器功能,我这边要给他出一个递归接口。突然想到之前看的jdk8新特性中的peek,发现这个方法完美契合递归,就尝试用peek写了一个树形结构。下面具体讲一下这个功能。
peek
java 8 stream作为流式操作有两种操作类型,中间操作和终止操作。而peek就属于中间操作。咱们来看下面的例子
java
Stream<String> stream = Stream.of("我", "是", "谁");
stream.peek(System.out::println);
这段代码本意是输出stream中的值,实际并没有任何输出。 中间操作是对数据的加工,注意,中间操作是lazy操作,并不会立马启动,需要等待终止操作才会执行。终止操作是stream的启动操作,只有加上终止操作,stream才会真正的开始执行。所以,peek是一个中间操作,所以上面的例子没有任何输出。
java
Stream<String> stream = Stream.of("我", "是", "谁");
stream.peek(System.out::println).collect(Collectors.toList());
.collect(Collectors.toList()) 就是一个最终操作,可以正常输出结果。之后的事情就好办了(具体peek方法的使用还需要各位自己查询资料,这里不做过多赘述)。
递归
前提条件
需要jkd8及以上版本
实体类
java
import lombok.Data;
import java.util.List;
@Data
public class TreeDto {
/**
* id
*/
public Long id;
/**
* 名称
*/
public String name;
/**
* 父id ,根节点为0
*/
public Long pid;
/**
* 子节点信息
*/
public List<TreeDto> childList;
//构造函数
public TreeDto(Long id, String name, Long pid, List<TreeDto> childList) {
this.id = id;
this.name = name;
this.pid = pid;
this.childList = childList;
}
}
调用
java
List<StaffFolder> staffFolders = staffFolderMapper.selectStaffFolderList(staffFolder);
List<TreeDto> treeDtos = staffFolders.stream()
.map(result -> new TreeDto(result.getId(), result.getName(), result.getPid(), null))
.collect(Collectors.toList());
List<TreeDto> collect = treeDtos.stream().filter(folder -> folder.getPid() == 0)
.peek(folder -> folder.setChildList(getChildrens(folder, treeDtos)))
.collect(Collectors.toList());
因一开始查询出的是StaffFolder数组,需要将其对应的字段参数赋值到TreeDto数组中,通过实体类中的构造函数进行赋值。 filter()筛选其中父类id为0的数据作为一级目录。然后在peek中进行子类赋值,因为peek作为中间操作,只有进行最终操作后才会输出,这就完美契合了递归的功能。
被调用
java
private static List<TreeDto> getChildrens(TreeDto treeDto,List<TreeDto> TreeDtos){
return TreeDtos.stream().filter(folder->Objects.equals(folder.getPid(),treeDto.getId()))
.peek(folder->folder.setChildList(getChildrens(folder,TreeDtos)))
.collect(Collectors.toList());
}
这里同理,将一级目录与数据传入,当父级id与id相同时,进行peek,之后循环调用自己return最终结果。
最终结果
java
{
"msg": null,
"code": 1,
"data": [
{
"id": 42,
"name": "北京云梦智能科技有限公司",
"pid": 0,
"childList": [
{
"id": 49,
"name": "客户文件",
"pid": 42,
"childList": []
},
{
"id": 52,
"name": "文件夹",
"pid": 42,
"childList": []
}
]
},
{
"id": 43,
"name": "共享文件夹",
"pid": 0,
"childList": [
{
"id": 50,
"name": " 客户资源",
"pid": 43,
"childList": []
},
{
"id": 51,
"name": "模板大纲",
"pid": 43,
"childList": []
}
]
},
{
"id": 48,
"name": "公函文件夹",
"pid": 0,
"childList": []
}
]
}
有时候前端希望"childList": []
没有子级是返回null,当返回空数组时,前端会出现可以点击下级,而下级没有数据的情况。当然这个要看前端用的什么组件了。 我这举个简单的例子,扩展一下思路,各位有更好的方法就当我没说
java
private static List<TreeDto> getChildrens(TreeDto treeDto,List<TreeDto> TreeDtos){
return TreeDtos.stream().filter(folder->Objects.equals(folder.getPid(),treeDto.getId()))
.peek(folder->folder.setChildList(getChildrens(folder,TreeDtos).size()>0?getChildrens(folder,TreeDtos):null))
.collect(Collectors.toList());
}
通过简单的三目运算符,当返回值为空数组时,将null赋值。
扩展
功能
查询组织及下级组织人员数量
java
/**
* 核算组织人数
*
* @param id
* @return
*/
public Long getPeopleNum(Long id) {
//上方遍历出了组织树
List<OrganizationTreeDto> organizationTreeDtos = organizationTree(id);
List<EmployeeEntity> list = new ArrayList<>();
//总人数
Long sumDepAllCount = 0L;
if (organizationTreeDtos.size() > 0) {
for (OrganizationTreeDto organizationTreeDto : organizationTreeDtos) {
//查询组织人员关联表
LambdaQueryWrapper<EmployeeAndOrganizationEntity> entityLambdaQueryWrapper = new LambdaQueryWrapper<>();
entityLambdaQueryWrapper.eq(EmployeeAndOrganizationEntity::getOrganizationId, organizationTreeDto.getId());
List<EmployeeAndOrganizationEntity> employeeAndOrganizationEntities = employeeAndOrganizationMapper.selectList(entityLambdaQueryWrapper);
//存在下级组织
if (organizationTreeDto.getChildList().size() != 0) {
//递归返回人员数量
Long childListNum = getChildListNum(organizationTreeDto.getChildList(), 0L);
//加入总人数
sumDepAllCount = sumDepAllCount + childListNum;
}
//组织下有人员关联
if (employeeAndOrganizationEntities.size()>0) {
for (EmployeeAndOrganizationEntity employeeAndOrganizationEntity : employeeAndOrganizationEntities) {
LambdaQueryWrapper<EmployeeEntity> employeeEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
employeeEntityLambdaQueryWrapper.eq(EmployeeEntity::getId, employeeAndOrganizationEntity.getEmployeeId());
Long aLong = employeeMapper.selectCount(employeeEntityLambdaQueryWrapper);
sumDepAllCount = sumDepAllCount + aLong;
}
}
}
}
return sumDepAllCount;
}
/**
* 核算组织下级人数
*
* @param childList
* @param sumDepAllCount
* @return
*/
private Long getChildListNum(List<OrganizationTreeDto> childList, Long sumDepAllCount) {
for (OrganizationTreeDto organizationTreeDto : childList) {
LambdaQueryWrapper<EmployeeAndOrganizationEntity> entityLambdaQueryWrapper = new LambdaQueryWrapper<>();
entityLambdaQueryWrapper.eq(EmployeeAndOrganizationEntity::getOrganizationId, organizationTreeDto.getId());
List<EmployeeAndOrganizationEntity> employeeAndOrganizationEntities = employeeAndOrganizationMapper.selectList(entityLambdaQueryWrapper);
if (organizationTreeDto.getChildList().size() != 0) {
getChildListNum(organizationTreeDto.getChildList(), sumDepAllCount);
}
if (employeeAndOrganizationEntities.size()>0) {
for (EmployeeAndOrganizationEntity employeeAndOrganizationEntity : employeeAndOrganizationEntities) {
LambdaQueryWrapper<EmployeeEntity> employeeEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
employeeEntityLambdaQueryWrapper.eq(EmployeeEntity::getId, employeeAndOrganizationEntity.getEmployeeId());
Long aLong = employeeMapper.selectCount(employeeEntityLambdaQueryWrapper);
sumDepAllCount = sumDepAllCount + aLong;
}
}
}
return sumDepAllCount;
}