【飞机专用地址:https://v.tnabors.com/】
今天北京下大雨,公司让居家办公,写完需求觉得没什么意思,然后看了一个别人写的接口,接口功能很简单就是将查询出来的数据展示为树形结构,数据库中的数据结构就是这个样子,每条数据都有一级编码、二级编码、三级编码、四级编码,然后将这四层转换为树形结构。
还有一个是我从网上找个,也是一个转树形结构的例子,这两个还有有点区别的,都记录一下吧平常都是做业务处理代码,感觉好久没写这种代码了,今天尝试写了,特此记录一下。横向结构1
数据库中存储大概是这种转换前:
转换为JSON转换后:
转换后上面是我删除数据后展示的结果,其实数据量有很多,我是为了展示层级关系下面是我思考后写的代码//这是数据库查询结果对应的类,分别与上面数据库截图中的数据字段相对应publicclass CsmpTreeData { 。
privateString csmpTreeId; privateString firstNodeId; privateString firstNodeName; private
String secondNodeId; privateString secondNodeName; privateString thirdNodeId; privateString
thirdNodeName; privateString forthNodeId; privateString forthNodeName; }//这个数据是返回前端的数据结构public
class CloudTreeNode { privateString nodeId; privateString nodeName; privateString level;
privateString parentNodeId; private List children; }//创建了一个工具类,对外提供一个方法,直接讲查询数据的list集合传进行就可以
publicclassTreeUtil{ //为什么要有这个map呢,我的想法是因为从数据库查询出来的结果是横向的结构//我是想在递归的时候根据递归的层级id去判断我我在横向的数据应该获取第几级数据
privatestaticfinal HashMap treeMap = newHashMap<>(); //还有一个问题,这里我为啥要拿两个字段拼接来作为分组条件呢,是因为我在写的过程中发现我虽然获取到了id
//但是name依然不好获取,这里我就直接将两个字段拼接到了一块static { //层级是1,我就应该查询的数据中去getFirstNodeId//层级是2,我就应该查询的数据中去getSecondNodeId
//... treeMap.put(1, (treeData) -> treeData.getFirstNodeId() + "," + treeData.getFirstNodeName()); treeMap.put(
2, (treeData) -> treeData.getSecondNodeId() + "," + treeData.getSecondNodeName()); treeMap.put(
3, (treeData) -> treeData.getThirdNodeId() + "," + treeData.getThirdNodeName()); treeMap.put(
4, (treeData) -> treeData.getForthNodeId() + "," + treeData.getForthNodeName()); } /** * @author
wangpeng * @version 1.0 * @apiNote ,这个方法是外部调用的方法,传入的数据是直接从数据库中查询的数据 * 构建树形结构 * @date
2023/7/31 4:59 下午 * @since JDK1.8 **/publicstaticList buildTreeNode(List
list) { ArrayList cloudTreeNode = new ArrayList<>(); if (CommonUtil.isNotNullList(
list)) { //这里是代表第一层的意思 int i = 1; //通过key获取对应的分组字段,这里是获取getFirstNodeId+"," + treeData.getFirstNodeName()
//说白了就是按一级编码分组 Map firstNode = list.stream().collect(Collectors.groupingBy(getFunction(i)));
for (Map.Entry entry : firstNode.entrySet()) { //将key进行分割,获取一级编码和一级名称
String[] idAndName = StringUtils.split(entry.getKey(), ","); String firstNodeId = idAndName[
超级加密线路:https://av1o.com/
0]; String firstNodeName = idAndName[1]; //这个是所有FirstNodeId等于当前一级编码的集合
List candidateTreeData = entry.getValue(); //创建最外层一级编码对象 CloudTreeNode firstTreeNode =
new CloudTreeNode(); firstTreeNode.setNodeId(firstNodeId); firstTreeNode.setNodeName(firstNodeName);
//设置层级 firstTreeNode.setLevel(i + ""); //构建子节点 firstTreeNode.setChildren(buildTreeNode(candidateTreeData, firstNodeId, i));
//将数据返回 cloudTreeNode.add(firstTreeNode); } } return cloudTreeNode; }
privatestaticList buildTreeNode(List treeData, String parentNodeId, int i) { ArrayList
list = new ArrayList<>(); ++i; //这个方法是一个递归方法,这里的i跟上面方法的意思是一样的,是层级的意思//我们通过层级id去查询map,然后拿到get第几层那个方法
Function function = getFunction(i); //没有层级后返nullif (Objects.isNull(function
)) returnnull; //这里跟一级一样,这里又是分组,假如是二级的话,则通过getSecondNodeId等来获取二级编码数据 Map nodes = treeData.stream().collect(Collectors.groupingBy(
function)); if (CommonUtil.checkMap(nodes)) { for (Map.Entry entry : nodes.entrySet()) {
//获取当前级别的nodeId String[] idAndName = StringUtils.split(entry.getKey(), ","); String nodeId = idAndName[
0]; String nodeName = idAndName[1]; //这里是当前级别的数据List candidateTreeData = entry.getValue(); CloudTreeNode cloudTreeNode =
new CloudTreeNode(); cloudTreeNode.setParentNodeId(parentNodeId); cloudTreeNode.setNodeId(nodeId); cloudTreeNode.setNodeName(nodeName);
//设置级别 cloudTreeNode.setLevel(i + ""); //递归调用,设置层级 cloudTreeNode.setChildren(buildTreeNode(candidateTreeData, nodeId, i));
list.add(cloudTreeNode); } } returnlist; } //这里是从map中获取对应的方法private
staticFunction getFunction(Integer currentId){ return treeMap.get(currentId); } }
˙横向结构2转换前:
转换后:
publicclass ProvinceTreeData { privateString id; privateString pid; private List children;
privateString name; }// list 是从数据库请求回来的数据// 构建前端所需要树publicstaticList buildProvinceTree(
List list){ // 获取根节点List root = list.stream().filter(item -> "0"
.equals(item.getPid())).collect(Collectors.toList()); // 根据pid进行分组 Map provinceTreeMap =
list.stream().collect(Collectors.groupingBy(ProvinceTreeData::getPid)); //先是拿根节点进行遍历 recursionFnTree(root,provinceTreeMap);
return root; } //当前是递归方法publicstatic void recursionFnTree(List list, Map
> provinceTreeMap){ for (ProvinceTreeData provinceTree: list) { //根据当前节点id,从provinceTreeMap中获取对应的子节点,因为provinceTreeMap中的key都是父节点
List childList = provinceTreeMap.get(provinceTree.getId()); //将查询的子节点赋值 provinceTree.setChildren(childList);
if (null != childList && 0
上面两种树形结构的原始数据还是有些差别的,对于这两种数据,以上都是我思考后的想法,对于这两个功能,大家有什么好的想法吗?
vpn官方地址:https://www.sandrakurvits.com/