java遞歸查找樹的子節點,java集合快速構建成樹形json

 2023-10-01 阅读 28 评论 0

摘要:文章目錄1 場景1.1 面對問題1.2 實現目標2 代碼結構圖3 實現效果3.1 調用3.2 結果4 實現代碼4.1 JSON轉換器4.2 節點4.3 節點實例4.4 根節點選擇器4.5 節點轉換器4.6 樹4.7 樹構建器4.8 Easyui節點實例 1 場景 1.1 面對問題 java中,經常會需要構建樹形結構的jsonÿ

文章目錄

      • 1 場景
        • 1.1 面對問題
        • 1.2 實現目標
      • 2 代碼結構圖
      • 3 實現效果
        • 3.1 調用
        • 3.2 結果
      • 4 實現代碼
        • 4.1 JSON轉換器
        • 4.2 節點
        • 4.3 節點實例
        • 4.4 根節點選擇器
        • 4.5 節點轉換器
        • 4.6 樹
        • 4.7 樹構建器
        • 4.8 Easyui節點實例

1 場景

1.1 面對問題

java中,經常會需要構建樹形結構json,如構建一個省市區的樹形結構。

此處情況,有如下幾個情況需要解決:

  • 需要根據不同的前端組件,來定義不同格式的json(如easyui、ext里面的tree結構均不同)。如切換組件,原代碼不適用
  • 樹形結構,需手動組裝,如不同的樹形結構太多,則會花較多的時間來組裝不同業務的樹形結構
  • 手動實現,代碼較復雜,容易出問題
  • 如讓java中的實體類實現定義的樹形結構的接口,代碼侵入性太強

1.2 實現目標

java遞歸查找樹的子節點、這里實現一個代碼工具,各位朋友可以參考下,實現如下功能:

  • 實現樹形結構的快速構建
  • 定義不同樹類型的實現,可切換樹形結構簡單
  • 系統實體類無需實現自定義接口,代碼無侵入性
  • 使用類適配器,可隨意自行擴展

2 代碼結構圖

代碼結構圖.png

3 實現效果

依賴model:

package com.sa.example.tree.bean;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** 區域信息*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Area {private String areaCode;private String areaName;private Integer order;private String parentCode;}

3.1 調用

package com.sa.example.tree.test;import com.sa.example.tree.*;
import com.sa.example.tree.ext.EasyuiNode;
import com.sa.example.tree.bean.Area;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;import java.util.ArrayList;
import java.util.List;public class TreeParseTest {@Testpublic void testParse(){// 節點轉換器(將任意對象轉換為樹節點)NodeConvert departmentConverter = new NodeConvert<Area>() {@Overridepublic Node convert(Area area) {// 根據實體的屬性,補充到對應的NodeInstance對象上(轉換為EasyUi)NodeInstance instance = new EasyuiNode();instance.setParentCode(area.getParentCode());instance.setCode(area.getAreaCode());instance.setName(area.getAreaName());instance.setOrder(area.getOrder());// 根據實際業務,配置其他屬性....../*instance.setCss("icon-value");instance.setChecked(true);instance.setState("opened");instance.putExtMap("aa", "aaVaule");*/return instance;}};// 默認根節點選擇器(確定根節點)RootSelector defaultSelector = new RootSelector() {@Overridepublic boolean select(Node node) {if (node != null && StringUtils.isEmpty(node.getParentCode())) {return true;}return false;}};List<Area> areaList = new ArrayList<>();areaList.add(new Area("130000000000", "河北", 2, ""));areaList.add(new Area("130100000000", "石家莊", 1, "130000000000"));areaList.add(new Area("130400000000", "邯鄲", 2, "130000000000"));areaList.add(new Area("370000000000", "山東", 1, ""));areaList.add(new Area("370100000000", "濟南", 1, "370000000000"));areaList.add(new Area("370200000000", "青島", 2, "370000000000"));areaList.add(new Area("370202000000", "市南", 2, "370200000000"));areaList.add(new Area("370203000000", "市北", 3, "370200000000"));TreeBuilder<Area> treeBuilder = new TreeBuilder<>(departmentConverter, defaultSelector);Tree tree = treeBuilder.build(areaList);System.out.println(tree.toJson());}
}

3.2 結果

[{"children": [{"id": "370100000000","text": "濟南"}, {"children": [{"id": "370202000000","text": "市南"}, {"id": "370203000000","text": "市北"}],"id": "370200000000","text": "青島"}],"id": "370000000000","text": "山東"
}, {"children": [{"id": "130100000000","text": "石家莊"}, {"id": "130400000000","text": "邯鄲"}],"id": "130000000000","text": "河北"
}]

4 實現代碼

maven依賴:

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.11</version>
</dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.73</version>
</dependency>

4.1 JSON轉換器

/*** JSON轉換器*/
public interface JsonParser {/*** 生成JSON對象* @return JSON對象*/JSONObject toJson();}

4.2 節點

package com.sa.example.tree;import java.util.List;
import java.util.Map;/*** 節點*/
public interface Node extends JsonParser, Comparable<Node> {/*** 獲取節點代碼** @return*/String getCode();/*** 獲取節點名稱** @return*/String getName();/*** 獲取節點排序** @return*/Integer getOrder();/*** 獲取節點樣式** @return*/String getCss();/*** 獲取節點狀態** @return*/String getState();/*** 獲取節點復選狀態** @return*/Boolean getChecked();/*** 擴展屬性** @return*/Map<String, Object> getExtMap();/*** 獲取父節點代碼** @return*/String getParentCode();/*** 獲取子節點集合** @return*/List<Node> getChildList();@Overridedefault int compareTo(Node o) {return this.getOrder().compareTo(o.getOrder());}/*** 添加子節點** @param node 子節點*/void addChildNode(Node node);/*** 設置額外屬性* @param key* @param value*/void putExtMap(String key, Object value);
}

4.3 節點實例

package com.sa.example.tree;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Node實例*/
public abstract class NodeInstance implements Node {/*** 節點代碼*/private String code;/*** 節點名稱*/private String name;/*** 節點排序*/private Integer order;/*** 節點樣式*/private String css;/*** 節點狀態*/private String state;/*** 節點復選狀態*/private Boolean checked;/*** 擴展屬性*/private Map<String, Object> extMap;/*** 父節點代碼*/private String parentCode;/*** 子節點集合*/private List<Node> childList;@Overridepublic void addChildNode(Node node) {if (childList == null) {childList = new ArrayList<>();}childList.add(node);}@Overridepublic List<Node> getChildList() {return childList;}@Overridepublic void putExtMap(String key, Object value) {if (extMap == null) {extMap = new HashMap<>();}extMap.put(key, value);}@Overridepublic String getCode() {return code;}public void setCode(String code) {this.code = code;}@Overridepublic String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic Integer getOrder() {return order;}public void setOrder(Integer order) {this.order = order;}@Overridepublic String getCss() {return css;}public void setCss(String css) {this.css = css;}@Overridepublic String getState() {return state;}public void setState(String state) {this.state = state;}@Overridepublic Boolean getChecked() {return checked;}public void setChecked(Boolean checked) {this.checked = checked;}@Overridepublic String getParentCode() {return parentCode;}public void setParentCode(String parentCode) {this.parentCode = parentCode;}@Overridepublic Map<String, Object> getExtMap() {return extMap;}
}

4.4 根節點選擇器

package com.sa.example.tree;/*** 根節點選擇器*/
public interface RootSelector {/*** 選擇節點為根節點* @param node 被選擇節點* @return true:選擇為根節點;false:不選擇為根節點*/boolean select(Node node);}

4.5 節點轉換器

/*** 節點轉換器*/
public interface NodeConvert<T> {/*** 實體轉換為節點* @param t* @return*/Node convert(T t);}

4.6 樹

package com.sa.example.tree;import com.alibaba.fastjson.JSONArray;
import org.apache.commons.collections4.CollectionUtils;import java.util.List;/*** 樹*/
public class Tree {/*** 根節點*/private List<Node> nodeList;public Tree() {}public void setNodeList(List<Node> nodeList) {this.nodeList = nodeList;}public String toJson() {JSONArray jsonArray = new JSONArray();if (CollectionUtils.isNotEmpty(nodeList)) {for (Node node : nodeList) {jsonArray.add(node.toJson());}}return jsonArray.toJSONString();}
}

4.7 樹構建器

package com.sa.example.tree;import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;/*** 樹構建器** @param <T>*/
public class TreeBuilder<T> {/*** 節點轉換器*/private NodeConvert<T> nodeConvert;/*** 根節點選擇器*/private RootSelector rootSelector;public TreeBuilder(NodeConvert nodeConvert, RootSelector rootSelector) {this.nodeConvert = nodeConvert;this.rootSelector = rootSelector;}/*** 初始化節點列表** @return*/protected List<Node> initNodeList(List<T> list) {List<Node> nodeList = new ArrayList<>();if (CollectionUtils.isNotEmpty(list)) {for (T model : list) {nodeList.add(nodeConvert.convert(model));}}return nodeList;}/*** 構建節點結構** @param nodeList* @return*/protected List<Node> buildNodeStructure(List<Node> nodeList) {List<Node> rootList = new ArrayList<>();if (CollectionUtils.isNotEmpty(nodeList)) {// 1、構建root節點Iterator<Node> iterator = nodeList.iterator();while (iterator.hasNext()) {Node node = iterator.next();if (rootSelector.select(node)) {rootList.add(node);iterator.remove();}}// 2、循環查找子節點for (Node rootNode : rootList) {this.buildChildNode(rootNode, nodeList);}}return rootList;}/*** 構建子節點(反復調用)** @param parentNode     父節點* @param originNodeList 自己節點列表*/protected void buildChildNode(Node parentNode, List<Node> originNodeList) {if (CollectionUtils.isNotEmpty(originNodeList)) {Iterator<Node> iterator = originNodeList.iterator();while (iterator.hasNext()) {Node node = iterator.next();if (StringUtils.equals(parentNode.getCode(), node.getParentCode())) {parentNode.addChildNode(node);iterator.remove();// 迭代調用this.buildChildNode(node, originNodeList);}}}}/*** 節點集合排序** @param nodeList* @return*/protected void sortNodeList(List<Node> nodeList) {if (CollectionUtils.isNotEmpty(nodeList)) {Collections.sort(nodeList);for (Node node : nodeList) {if (CollectionUtils.isNotEmpty(node.getChildList())) {this.sortNodeList(node.getChildList());}}}}/*** 構建樹** @param list* @return*/public Tree build(List<T> list) {List<Node> nodeList = this.initNodeList(list);List<Node> buildNodeList = this.buildNodeStructure(nodeList);this.sortNodeList(buildNodeList);Tree tree = new Tree();tree.setNodeList(buildNodeList);return tree;}}

4.8 Easyui節點實例

實例繼承自“節點實例NodeInstance”,此類實例可根據實際要求自行定義和擴展

package com.sa.example.tree.ext;import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sa.example.tree.Node;
import com.sa.example.tree.NodeInstance;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;import java.util.List;
import java.util.Map;/*** Easyui節點實例*/
public class EasyuiNode extends NodeInstance {@Overridepublic JSONObject toJson() {JSONObject jsonObject = new JSONObject();// ==========【(1)組裝必有屬性】==========jsonObject.put("id", this.getCode());jsonObject.put("text", this.getName());// ==========【(2)組裝可選屬性】==========String css = this.getCss();if (StringUtils.isNotEmpty(css)) {jsonObject.put("iconCls", css);}String state = this.getState();if (StringUtils.isNotEmpty(state)) {jsonObject.put("state", state);}Boolean checked = this.getChecked();if (checked != null) {jsonObject.put("checked", checked);}Map<String, Object> extMap = this.getExtMap();if (MapUtils.isNotEmpty(extMap)) {JSONObject attributesObject = new JSONObject();for (Map.Entry<String, Object> entry : extMap.entrySet()) {attributesObject.put(entry.getKey(), entry.getValue());}jsonObject.put("attributes", attributesObject);}// ==========【(3)組裝子節點】==========List<Node> childList = this.getChildList();if (CollectionUtils.isNotEmpty(childList)) {JSONArray jsonArray = new JSONArray();for (Node child : childList) {jsonArray.add(child.toJson());}jsonObject.put("children", jsonArray);}return jsonObject;}   
}

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/109439.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息