前言:通常获取树结构我们很多都会用递归或者循环查询,数据量小的时候没什么问题,但是查询复杂度比较高,今天说的这个查询复杂度O(n)只使用一次循环就可以实现,我们进入实战。
一、实战
数据库我们使用h2 database 单元测试起来比较方便,我们先配置下数据库
server:
port: 8089
spring:
datasource:
url: jdbc:h2:~/meun
driver-class-name: org.h2.Driver
username: sa
password: 1234567
jpa:
database: h2
hibernate:
ddl-auto: update
show-sql: true
h2:
console:
path: /h2-console
enabled: true
配置很简单,需要说的就是 ~/meun 的意思是相对路径文件存储。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.32</version>
</dependency>
package com.example.demo.domain;
import lombok.Data;
import javax.persistence.*;
/**
* @author javacTree
* @description: 菜单实体
* @date 2021/11/29 9:52
*/
@Entity
@Data
@Table(name = "menu")
public class Menu {
@Id
private int id ;
private String name;
private String url;
private int pid;
private int sort;
}
定义实体类,和repo
package com.example.demo.mapper;
import com.example.demo.domain.Menu;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface MenuMapper extends JpaRepository<Menu,Long> {
}
表的创建项目启动的时候会自动创建,数据初始化的时候我们是需要写初始化脚本的。
这样我们启动下springboot 然后控制台访问 http://localhost:8089/h2-console/
输入配置文件中的密码
在这里面初始化数据
准备工作已经就绪,接下来重点来了。。。。。。
先新建一个menuTree
package com.example.demo.dto;
import com.example.demo.domain.Menu;
import lombok.Data;
import lombok.ToString;
import org.springframework.beans.BeanUtils;
import java.util.List;
/**
* @author javacTree
* @description: 树结构
* @date 2021/11/29 10:08
*/
@Data
@ToString
public class MenuTree {
private int id;
private String name;
private String url;
private int pid;
private List<MenuTree> children;
public MenuTree(Menu menu) {
BeanUtils.copyProperties(menu,this);
}
}
代码还是写在单元测试里面
@Autowired
private MenuMapper menuMapper;
@Test
public void treeMenu(){
List<Menu> allMenu = menuMapper.findAll();
List<MenuTree> result = getTreeMenu(allMenu);
System.out.println(JSONObject.toJSONString(result));
}
private List<MenuTree> getTreeMenu(List<Menu> allMenu) {
//快速查询引用缓存
Map<Integer,List<MenuTree>> hashMap = new HashMap<>();
//最终返回数据
List<MenuTree> result = new ArrayList<>();
for (Menu menu:allMenu) {
MenuTree menuTree = new MenuTree(menu);
List<MenuTree> children;
//查看父类对应的子类是否为空
if((children = hashMap.get(menuTree.getId()))==null){
children = new ArrayList<>();
hashMap.put(menuTree.getId(),children);
}
//引用赋值
menuTree.setChildren(children);
//是否是父类
if(menuTree.getPid()==-1){
result.add(menuTree);
}else{
//父类为空时,先将当前值缓存,等待父父类被初始化
if(hashMap.get(menuTree.getPid()) == null){
hashMap.put(menuTree.getPid(),new ArrayList<>());
}
//放到父类的孩子里面
hashMap.get(menuTree.getPid()).add(menuTree);
}
}
return result;
}
代码都有注释,就不解释了,最后我们看下运行结果
树结构就展示了,如果有排序,就在获取所有数据的时候按照排序取出,这个是我遇到过最喜欢的代码,非~常好用。