一、三层架构代码
可能很多人都没写过关于tree的代码,今天我来演示一下,步骤很全,放心观看。
首先来看element-ui官网关于tree的示例:
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
<script>
export default {
data() {
return {
data: [{
label: '一级 1',
children: [{
label: '二级 1-1',
children: [{
label: '三级 1-1-1'
}]
}]
}, {
label: '一级 2',
children: [{
label: '二级 2-1',
children: [{
label: '三级 2-1-1'
}]
}, {
label: '二级 2-2',
children: [{
label: '三级 2-2-1'
}]
}]
}, {
label: '一级 3',
children: [{
label: '二级 3-1',
children: [{
label: '三级 3-1-1'
}]
}, {
label: '二级 3-2',
children: [{
label: '三级 3-2-1'
}]
}]
}],
defaultProps: {
children: 'children',
label: 'label'
}
};
},
methods: {
handleNodeClick(data) {
console.log(data);
}
}
};
</script>
可以看得出来其底层为:
[{
label: '一级 1',
children: [{
label: '二级 1-1',
children: [{
label: '三级 1-1-1'
}]
}]
}]
这么一看是不是清晰明了?那么我们该返回什么样的数据是不是也清楚明白了?
话不多说我们来看后端与数据库,首先是数据库:
对应的是 部门ID、 部门名称 、 部门层级 、 上级部门ID
接着来看实体类:(有lombok记得装)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DepartmentDTO {
private Integer departmentId; // ID
private String dname; // 部门名称
private Integer dindex; // 所属级别
private Integer dparent; // 上级部门ID
List<DepartmentDTO> dchildren; // 下级部门集合
}
这里dchildren正好对应的是子节点,可以无限的递归下去。也符合上面官网给出的示例。思想也很简单,如果是子节点就用dchildren.add添加进去即可。
然后看controller与service层代码:
@GetMapping("/getDepartmentTree")
public Result getCategory(){
List<DepartmentDTO> departmentDTOS = departmentService.quertListTree();
return Result.success(departmentDTOS);
}
public interface DepartmentService {
public List<DepartmentDTO> quertListTree();
}
@Mapper
public interface DepartmentMapper {
@Select("select department_id, dname, dindex, dparent from department order by dparent")
List<DepartmentDTO> queryList();
}
接下来是重头戏,看业务层的代码:
- //获取全部的部门数据
List<DepartmentDTO> departments = departmentMapper.queryList();
这一步就是从mapper层中获取数据库中的数据,然后封装到List<DepartmentDTO> departments中 - //初始化每个部门儿子节点
for (DepartmentDTO department : departments) {
department.setDchildren(new ArrayList<>());
}
这一步很重要,第一步获取的数据中是没有儿子节点的,也就说List<DepartmentDTO> departments中每一个部门的dchildren就将为null,这是mybatis的正常操作,对于没有的数据就映射为null,但是list集合如果为null的话,add的时候就会报空指针异常,所以需要进行初始化,用setDchildren(new ArrayList<>())来重新创建 ArrayList集合来进行add操作。 - 然后就没啥东西了,如果看得懂但是不理解可以学一下java的引用传递机制。
@Override
public List<DepartmentDTO> quertListTree() {
//获取全部的部门数据
List<DepartmentDTO> departments = departmentMapper.queryList();
//初始化每个部门儿子节点
for (DepartmentDTO department : departments) {
department.setDchildren(new ArrayList<>());
}
// 传递一个空的 将要返回的集合
List<DepartmentDTO> resuletDeptDTOs = new ArrayList<>();
// 开始构建树
for (DepartmentDTO dept : departments) {
// 1. 如果获取的dparent 为 0 则是第一层节点 直接放进resuletDeptDTOs中
if(dept.getDparent().equals(0)){
resuletDeptDTOs.add(dept);
}else {
// 2. 如果不是0 则至少是一个子节点或者是孙子节点
// 3. 找到当前循环的dept的父亲节点
// 4. 根据java的引用传递机制,你这里修改了其实是修改了引用,你后面获取到的就是有子节点的数据,不必担心,如果不理解可以去看看引用传递机制
DepartmentDTO fatherDept = findDepartmentDTOById(departments, dept.getDparent());
if(fatherDept!=null){
fatherDept.getDchildren().add(dept);
}
}
}
return resuletDeptDTOs;
}
private static DepartmentDTO findDepartmentDTOById(List<DepartmentDTO> dtoList, Integer id) {
for (DepartmentDTO dto : dtoList) {
if (dto.getDepartmentId().equals(id)) {
return dto;
}
}
return null;
}
最后来看看前端:
<template>
<div>
<div>
<h1>树形结构图实验开始</h1>
</div>
<div>
<el-tree :data="treedata" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</div>
</div>
</template>
<script>
export default {
data() {
return {
treedata:[],
defaultProps: {
children: 'dchildren',
label: 'dname'
}
};
},
methods: {
handleNodeClick(data) {
console.log(data);
},
getAllClothesByUserID() {
this.$axios.get('/admin/department/getDepartmentTree').then(res => {
if (res.data.code === 1) {
console.log(res.data.data);
this.treedata=res.data.data;
}
})
},
},
mounted() {
this.getAllClothesByUserID();
}
};
</script>
<style>
</style>
运行结果:
二、test模拟:
public class StringTest {
public static void main(String[] args) {
List<DepartmentDTO> departments = Arrays.asList(
new DepartmentDTO(19, "精工汽车", 1, 0,new ArrayList<>()),
new DepartmentDTO(18, "精工底盘", 2, 19,new ArrayList<>()),
new DepartmentDTO(17, "精工压铸", 2, 19,new ArrayList<>()),
new DepartmentDTO(16, "泰州底盘", 3, 18,new ArrayList<>()),
new DepartmentDTO(15, "徐水底盘", 3, 18,new ArrayList<>()),
new DepartmentDTO(14, "荆门压铸", 3, 17,new ArrayList<>()),
new DepartmentDTO(13, "徐水压铸", 3, 17,new ArrayList<>()),
new DepartmentDTO(12, "徐水制造部", 4, 15,new ArrayList<>())
);
// 构建部门树
List<DepartmentDTO> departmentTree = buildDepartmentTree(departments);
printDepartmentTree(departmentTree, 0);
}
private static List<DepartmentDTO> buildDepartmentTree(List<DepartmentDTO> departments) {
// 1. 创建一个新的返回集合
List<DepartmentDTO> resultDeptDTOs = new ArrayList<>();
for(int i=0;i<departments.size();i++){
if(departments.get(i).getDparent()==0){
resultDeptDTOs.add(departments.get(i));
}else {
DepartmentDTO chileDTO = findDTO(departments,departments.get(i).getDparent());
chileDTO.getDchildren().add(departments.get(i));
}
}
return resultDeptDTOs;
}
private static DepartmentDTO findDTO(List<DepartmentDTO> departments,Integer id){
for (DepartmentDTO department : departments) {
if(department.getDepartmentId()==id){
return department;
}
}
return null;
}
private static void printDepartmentTree(List<DepartmentDTO> departments, int level) {
for (DepartmentDTO department : departments) {
for (int i = 0; i < level; i++) {
System.out.print(" ");
}
System.out.println(department.getDname());
printDepartmentTree(department.getDchildren(), level + 1);
}
}
}