逻辑先行
具体分析
整个部门成树状图分布:如下图
在网页中实际显示的效果如下图:
数据库中部门的数据如下:
根据以上3张图,我们结合代码来理一理树状图显示的逻辑。
1. level是分层的逻辑点所在
根据观察,可知,顶层的parent_id=0,level=0,其对应的下级部门的level = parentLevel.parent_id。(这个等式非常重要,因为level是树状图形成的关键点)。
创建计算level的工具类
package com.xmcc.utils;
public class LevelUtil {
public final static String ROOT="0";
public final static String SEPARATOR=".";
public static String calculateLevel(String parentLevel,Integer parentId){
if(parentLevel==null){
return ROOT;
}
StringBuffer b = new StringBuffer();
b.append(parentLevel);
b.append(SEPARATOR);
b.append(parentId);
return b.toString();
}
}
2.根据树形图,创建dto实体类
1)先根据数据库的表格,创建与表格对应的实体类SysDept
package com.xmcc.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import java.util.Date;
@AllArgsConstructor
@NoArgsConstructor
@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 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();
}
}
2)根据上面3图可知,一个部门可能存在多个下级部门,即list集合。随即创建DeptTreeDto
package com.xmcc.dto;
import com.xmcc.model.SysDept;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
//注意,该实体类必须继承之前的实体类
public class DeptTreeDto extends SysDept {
// 用来存储下层数据
private List<DeptTreeDto> deptList=new ArrayList<>();
//将sysDept 封装成 DeptTreeDto
public static DeptTreeDto adapter(SysDept sysDept){
DeptTreeDto deptTreeDto = new DeptTreeDto();
//拷贝字段
BeanUtils.copyProperties(sysDept,deptTreeDto );
return deptTreeDto;
}
}
3.利用递归,生成部门树,将数据储存在 List< DeptTreeDto >
service层代码
//生成部门树
public List<DeptTreeDto> deptTree() {
//1、获取所有dept
List<SysDept> deptList = sysDeptMapper.findAll();
//2、存储所有部门的dto
List<DeptTreeDto> treeDtoList = new ArrayList<>();
//3、将dept 转换成 deptDto
for (SysDept sysDept : deptList) {
DeptTreeDto treeDto = DeptTreeDto.adapter(sysDept);
treeDtoList.add(treeDto);
}
//4、调用方法1
return deptDtoListToTree(treeDtoList);
}
//方法1: 将deptDto 封装成 tree
public List<DeptTreeDto> deptDtoListToTree(List<DeptTreeDto> treeDtoList) {
//1、如果没有部门,则返回一个空的list集合
if (treeDtoList == null) {
return new ArrayList<DeptTreeDto>();
}
/**
* Multimap:如果key值相同,将value值封装为一个集合
* 用于根据level封装部门,将同一层级的部门封装在一个集合里
*/
Multimap<String, DeptTreeDto> map = ArrayListMultimap.create();
//2、用于封装顶层部门
List<DeptTreeDto> rootList = new ArrayList<>();
//3、遍历集合并封装顶层
for (DeptTreeDto dto : treeDtoList) {
if (LevelUtil.ROOT.equals(dto.getLevel())) {
rootList.add(dto);
}
//4、封装各级部门
map.put(dto.getLevel(), dto);
}
//5、部门根据sep排序
Collections.sort(rootList, new seqRank());
//6、调用方法2,递归生成tree
recursionDeptTree(rootList, map);
return rootList;
}
//方法2:递归生成树
public void recursionDeptTree(List<DeptTreeDto> rootList, Multimap<String, DeptTreeDto> map) {
//1、遍历该层的每一个元素
for (DeptTreeDto dto : rootList) {
//2/处理当前层级的数据
//获取下一层的level
String nextLevel = LevelUtil.calculateLevel(dto.getLevel(), dto.getId());
//3、处理下一层(根据nextLevel 获取到了当前层的下一层数据)
List<DeptTreeDto> deptTreeDtos = (List<DeptTreeDto>) map.get(nextLevel);
if (deptTreeDtos != null) {
//部门根据sep排序
Collections.sort(deptTreeDtos, new seqRank());
//4、设置下一层部门
dto.setDeptList(deptTreeDtos);
//5、递归
recursionDeptTree(deptTreeDtos, map);
}
}
}