java-树状结构展示-递归查询
提供前端树形结构展示返回值
递归查询的时候千万不要多次查库,这样如果数据量大的时候特别影响性能,一定改成只查询一次库把数据放到缓存中继续递归操作。
查询结果
[{
"name": "节点1",
"id": 1,
"parentId": -1,
"children": [{
"name": "节点1-1",
"id": 4,
"parentId": 1,
"children": [{
"children": [],
"name": "节点1-1-1",
"id": 13,
"parentId": 4
},
{
"children": [],
"name": "节点1-1-2",
"id": 14,
"parentId": 4
},
{
"children": [],
"name": "节点1-1-3",
"id": 15,
"parentId": 4
}
]
},
{
"name": "节点1-2",
"id": 5,
"parentId": 1,
"children": [{
"children": [],
"name": "节点1-2-1",
"id": 16,
"parentId": 5
},
{
"children": [],
"name": "节点1-2-2",
"id": 17,
"parentId": 5
},
{
"children": [],
"name": "节点1-2-3",
"id": 18,
"parentId": 5
}
]
},
{
"name": "节点1-3",
"id": 6,
"parentId": 1,
"children": [{
"children": [],
"name": "节点1-3-1",
"id": 19,
"parentId": 6
},
{
"children": [],
"name": "节点1-3-2",
"id": 20,
"parentId": 6
},
{
"children": [],
"name": "节点1-3-3",
"id": 21,
"parentId": 6
}
]
}
]
},
{
"name": "节点2",
"id": 2,
"parentId": -1,
"children": [{
"children": [],
"name": "节点2-1",
"id": 7,
"parentId": 2
},
{
"children": [],
"name": "节点2-2",
"id": 8,
"parentId": 2
},
{
"children": [],
"name": "节点2-3",
"id": 9,
"parentId": 2
}
]
},
{
"name": "节点3",
"id": 3,
"parentId": -1,
"children": [{
"children": [],
"name": "节点3-1",
"id": 10,
"parentId": 3
},
{
"children": [],
"name": "节点3-2",
"id": 11,
"parentId": 3
},
{
"children": [],
"name": "节点3-3",
"id": 12,
"parentId": 3
}
]
}
]
pom.xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId>
<version>3.5.1</version>
</dependency>
控制层代码 Controller
import com.tree.entity.TreeVO;
import com.tree.service.TreeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class TreeController {
@Autowired
private TreeService treeService;
@GetMapping("/tree")
public List<TreeVO> selectList(@RequestParam(value = "parentId", required = false) Integer parentId) {
List<TreeVO> tagManageDTOList = treeService.selectTree(parentId);
return tagManageDTOList;
}
}
业务实现层代码 Service
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tree.entity.Tree;
import com.tree.entity.TreeVO;
import com.tree.mapper.TreeMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class TreeService {
@Autowired
private TreeMapper treeMapper;
/**
* 将数据库查出来的所有数据保存到缓存种,避免多次调用数据库
*/
private List<Tree> trees;
/**
* 查询树状结构
*
* @param parentId 根节点获取树分支,如果是0 获取所有根节点分支
* @return
*/
public List<TreeVO> selectTree(Integer parentId) {
//初始化数据
this.trees = treeMapper.selectList(new QueryWrapper<Tree>());
return getTree(parentId != null ? parentId : -1);
}
/**
* 获取树结构
*
* @param parentId
* @return
*/
private List<TreeVO> getTree(Integer parentId) {
List<TreeVO> selectListByParentIdList = selectListByParentId(parentId);
if (selectListByParentIdList.size() > 0) {
for (Integer i = 0; i < selectListByParentIdList.size(); i++) {
List<TreeVO> treeVOList = getTree(selectListByParentIdList.get(i).getId());
selectListByParentIdList.get(i).setChildren(treeVOList);
}
}
return selectListByParentIdList;
}
/**
* 根据parentId获取分支数量
*
* @param parentId
* @return
*/
private List<TreeVO> selectListByParentId(Integer parentId) {
List<TreeVO> treeVOList = new ArrayList<>();
this.trees.forEach(tree -> {
if (parentId == tree.getParentId()) {
TreeVO treeVO = new TreeVO();
BeanUtils.copyProperties(tree, treeVO);
treeVOList.add(treeVO);
}
});
return treeVOList;
}
}
数据存储对象 Mapper / DAO
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tree.entity.Tree;
import org.springframework.stereotype.Repository;
@Repository
public interface TreeMapper extends BaseMapper<Tree> {
}
实体类
Tree
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 数据库实体类
*/
@Data
@TableName("tree_table")
public class Tree {
private Integer id;
private String name;
/**
* 父id
*/
private Integer parentId;
}
TreeVO
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.util.List;
/**
* 返回结果实体类
*/
@Data
public class TreeVO {
private Integer id;
private String name;
/**
* 父id
*/
private Integer parentId;
/**
* 子属性
*/
private List<TreeVO> children;
}
sql语句
/*
Navicat MySQL Data Transfer
Source Server : 127.0.0.1
Source Server Version : 50717
Source Host : 127.0.0.1:3306
Source Database : demo
Target Server Type : MYSQL
Target Server Version : 50717
File Encoding : 65001
Date: 2022-11-09 10:15:11
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `tree_table`
-- ----------------------------
DROP TABLE IF EXISTS `tree_table`;
CREATE TABLE `tree_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`parent_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tree_table
-- ----------------------------
INSERT INTO `tree_table` VALUES ('1', '节点1', '-1');
INSERT INTO `tree_table` VALUES ('2', '节点2', '-1');
INSERT INTO `tree_table` VALUES ('3', '节点3', '-1');
INSERT INTO `tree_table` VALUES ('4', '节点1-1', '1');
INSERT INTO `tree_table` VALUES ('5', '节点1-2', '1');
INSERT INTO `tree_table` VALUES ('6', '节点1-3', '1');
INSERT INTO `tree_table` VALUES ('7', '节点2-1', '2');
INSERT INTO `tree_table` VALUES ('8', '节点2-2', '2');
INSERT INTO `tree_table` VALUES ('9', '节点2-3', '2');
INSERT INTO `tree_table` VALUES ('10', '节点3-1', '3');
INSERT INTO `tree_table` VALUES ('11', '节点3-2', '3');
INSERT INTO `tree_table` VALUES ('12', '节点3-3', '3');
INSERT INTO `tree_table` VALUES ('13', '节点1-1-1', '4');
INSERT INTO `tree_table` VALUES ('14', '节点1-1-2', '4');
INSERT INTO `tree_table` VALUES ('15', '节点1-1-3', '4');
INSERT INTO `tree_table` VALUES ('16', '节点1-2-1', '5');
INSERT INTO `tree_table` VALUES ('17', '节点1-2-2', '5');
INSERT INTO `tree_table` VALUES ('18', '节点1-2-3', '5');
INSERT INTO `tree_table` VALUES ('19', '节点1-3-1', '6');
INSERT INTO `tree_table` VALUES ('20', '节点1-3-2', '6');
INSERT INTO `tree_table` VALUES ('21', '节点1-3-3', '6');
application.yml
server:
port: 8888
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: root
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql日志
个人喜欢把实体类区分化,如果不喜欢区分,需要在 children 属性中添加 @TableField(exist = false) ,以免利用苞米豆查询报错
@TableField(exist = false)
private List<TreeVO> children;