一般情况下,我们想要实现这种无限层级的树形结构,都是采用递归的方式,但是递归比较占用内存,也容易导致栈溢出,于是只能尝试其它的方法。
下面采用的方式,只需要一次集合的遍历就可以实现树形的结构。
先手动编造一个树形结构的数据:
这是一个无序的树形结构数据的 json 格式:
[{"nodeId" : "700","nodeDesc" : "节点700","parentNodeId" : ""},{"nodeId" : "300","nodeDesc" : "节点300","parentNodeId" : ""},{"nodeId" : "500","nodeDesc" : "节点500","parentNodeId" : ""},{"nodeId" : "100","nodeDesc" : "节点100","parentNodeId" : ""},{"nodeId" : "400","nodeDesc" : "节点400","parentNodeId" : ""},{"nodeId" : "800","nodeDesc" : "节点800","parentNodeId" : ""},{"nodeId" : "200","nodeDesc" : "节点200","parentNodeId" : ""},{"nodeId" : "700-001","nodeDesc" : "节点700-001","parentNodeId" : "700"},{"nodeId" : "700-002","nodeDesc" : "节点700-002","parentNodeId" : "700"},{"nodeId" : "700-003","nodeDesc" : "节点700-003","parentNodeId" : "700"},{"nodeId" : "700-004","nodeDesc" : "节点700-004","parentNodeId" : "700"},{"nodeId" : "700-005","nodeDesc" : "节点700-005","parentNodeId" : "700"},{"nodeId" : "700-006","nodeDesc" : "节点700-006","parentNodeId" : "700"},{"nodeId" : "700-003-002","nodeDesc" : "节点700-003-002","parentNodeId" : "700-003"},{"nodeId" : "700-003-001","nodeDesc" : "节点700-003-001","parentNodeId" : "700-003"},{"nodeId" : "700-003-002-001","nodeDesc" : "节点700-003-002-001","parentNodeId" : "700-003-002"},{"nodeId" : "700-003-002-003","nodeDesc" : "节点700-003-002-003","parentNodeId" : "700-003-002"},{"nodeId" : "700-003-002-002","nodeDesc" : "节点700-003-002-002","parentNodeId" : "700-003-002"},{"nodeId" : "300-001","nodeDesc" : "节点300-001","parentNodeId" : "300"},{"nodeId" : "300-001-001","nodeDesc" : "节点300-001-001","parentNodeId" : "300-001"},{"nodeId" : "300-001-001-001","nodeDesc" : "节点300-001-001-001","parentNodeId" : "300-001-001"},{"nodeId" : "300-001-001-001-001","nodeDesc" : "节点300-001-001-001-001","parentNodeId" : "300-001-001-001"},{"nodeId" : "300-001-001-001-001-001","nodeDesc" : "节点300-001-001-001-001-001","parentNodeId" : "300-001-001-001-001"},{"nodeId" : "500-003","nodeDesc" : "节点500-003","parentNodeId" : "500"},{"nodeId" : "500-001","nodeDesc" : "节点500-001","parentNodeId" : "500"},{"nodeId" : "500-002","nodeDesc" : "节点500-002","parentNodeId" : "500"},{"nodeId" : "500-003-001","nodeDesc" : "节点500-003-001","parentNodeId" : "500-003"},{"nodeId" : "800-001","nodeDesc" : "节点800-001","parentNodeId" : "800"},{"nodeId" : "100-002","nodeDesc" : "节点100-002","parentNodeId" : "100"},{"nodeId" : "100-001","nodeDesc" : "节点100-001","parentNodeId" : "100"},{"nodeId" : "200-001","nodeDesc" : "节点200-001","parentNodeId" : "200"},{"nodeId" : "400-003","nodeDesc" : "节点400-003","parentNodeId" : "400"},{"nodeId" : "400-002","nodeDesc" : "节点400-002","parentNodeId" : "400"},{"nodeId" : "400-001","nodeDesc" : "节点400-001","parentNodeId" : "400"},{"nodeId" : "100-002-002","nodeDesc" : "节点100-002-002","parentNodeId" : "100-002"},{"nodeId" : "100-002-001","nodeDesc" : "节点100-002-001","parentNodeId" : "100-002"},{"nodeId" : "300-001-001-001-001-002","nodeDesc" : "节点300-001-001-001-001-002","parentNodeId" : "300-001-001-001-001"},{"nodeId" : "300-001-001-002","nodeDesc" : "节点300-001-002","parentNodeId" : "300-001"}
]
我是在springBoot项目中测试的,通过前端页面展示数形结构的效果。
这是后端项目结构,前端使用的 ant-design Vue 版。
<template><div><a-tree:show-line="true":show-icon="true":tree-data="treeData":replaceFields="{children:'children', title:'nodeDesc', key:'nodeId' }"@select="onSelect"></a-tree></div>
</template><script>import { queryTreeNodeList } from '@/services/myExample';
import { message } from 'ant-design-vue';export default {name: 'lemonTree',data() {return {treeData: []}},created() {queryTreeNodeList().then(response =>{console.log(response, '====response====')this.treeData = response.data.data})},methods: {onSelect(selectedKeys, info) {console.log('selected', selectedKeys, info);// console.log('nodeDesc', info.selectedNodes[0].data.props.nodeDesc);message.info('您点击了:' + info.selectedNodes[0].data.props.nodeDesc);}}
}
</script><style scoped></style>
构建树形结构的核心业务代码,都写在了 service 层的这个方法里:
package com.concat.example.service;import com.alibaba.fastjson2.JSON;
import com.concat.example.entity.LemonTreeEntity;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;@Service
public class LemonTreeServiceImpl implements LemonTreeService {@Overridepublic List<LemonTreeEntity> queryAllNodeWithTreeStructure() {List<LemonTreeEntity> dataSource = initLemonTree();// 如果要得到有顺序树状数据结构,则先进行排序操作,并且后面可以通过循环这个有序的集合组装最终的树状结构的数据;List<LemonTreeEntity> lemonTreeNodeList = dataSource.stream().sorted(Comparator.comparing(LemonTreeEntity::getNodeId)).collect(Collectors.toList());// 建立每个节点的 map 映射,方便后面快速查找到对应的节点数据;Map<String, LemonTreeEntity> lemonTreeNodeMap = new HashMap<>();lemonTreeNodeList.stream().forEach(lemonTreeEntity -> {String nodeId = lemonTreeEntity.getNodeId();lemonTreeNodeMap.put(nodeId, lemonTreeEntity);});// 结果集;List<LemonTreeEntity> lemonTreeResult = new ArrayList<>();// 循环这个有序的集合,组装最终的树状结构的数据;lemonTreeNodeList.stream().forEach(lemonTreeEntity -> {String parentNodeId = lemonTreeEntity.getParentNodeId();if (StringUtils.isEmpty(parentNodeId)) {// 说明是树的根节点,直接放在集合中;lemonTreeResult.add(lemonTreeEntity);} else {// 其它都是子节点,需要将每个子节点放在对应的父节点的孩子集合中。LemonTreeEntity parentTreeNodeEntity = lemonTreeNodeMap.get(parentNodeId);List<LemonTreeEntity> children = parentTreeNodeEntity.getChildren();if (children == null) {children = new ArrayList<>();parentTreeNodeEntity.setChildren(children);}children.add(lemonTreeEntity);}});// String json = JSON.toJSONString(lemonTreeResult);
// System.out.println("json = " + json);return lemonTreeResult;}private List<LemonTreeEntity> initLemonTree() {File file = null;try {file = ResourceUtils.getFile("classpath:lemon_tree.json");} catch (FileNotFoundException e) {throw new RuntimeException(e);}String json = null;try {json = FileUtils.readFileToString(file, "UTF-8");} catch (IOException e) {throw new RuntimeException(e);}System.out.println("json = " + json);List<LemonTreeEntity> lemonTreeEntityList = JSON.parseArray(json, LemonTreeEntity.class);System.out.println("lemonTreeEntityList = " + lemonTreeEntityList);return lemonTreeEntityList;}
}
package com.concat.example.entity;import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@NoArgsConstructor
public class LemonTreeEntity {private String nodeId;private String nodeDesc;private String parentNodeId;private List<LemonTreeEntity> children;}
Web项目其它相关:
package com.concat.example.vo;import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;@Data
@Accessors(chain = true)
@NoArgsConstructor
public class MyResponseEntity<T> implements Serializable {private String code;private String message;private T data;}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.6.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.concat.example</groupId><artifactId>spring-initialize-template</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-initialize-template</name><description>Demo project for Spring Boot</description><properties><java.version>8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></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>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency><!-- 反序列化json字符串 --><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.14</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>