最近在做小需求的時(shí)候,需要用到目錄樹(shù),特地寫了一個(gè)基于java的實(shí)現(xiàn)。
由于需求原因,目前只實(shí)現(xiàn)了讀部分的功能——如何將平面節(jié)點(diǎn)build成樹(shù)。動(dòng)態(tài)新增,刪除等功能尚未實(shí)現(xiàn)。
目錄結(jié)構(gòu)概念:
Node:目錄節(jié)點(diǎn),具備節(jié)點(diǎn)屬性信息
NodeStore:平面目錄節(jié)點(diǎn)持久化接口,提供方法如下:
public List findByType(String type); -- 根據(jù)目錄類型,獲取該類型下所有的節(jié)點(diǎn)(平面節(jié)點(diǎn))
public void add(T node);--將增加節(jié)點(diǎn)持久化
public void update(T node);--將修改節(jié)點(diǎn)持久化
public void delete(T node);--刪除節(jié)點(diǎn)
public void move(T src, T target); --將移動(dòng)節(jié)點(diǎn)持久化
NodeStore是一個(gè)接口,可以基于DB實(shí)現(xiàn),也可以基于XML實(shí)現(xiàn),或則其他你需要的方式。
Tree:目錄樹(shù),主要職責(zé):
通過(guò)NodeStore load某一類型目錄的所有平面節(jié)點(diǎn),build成樹(shù);
根據(jù)節(jié)點(diǎn)id號(hào),查找相應(yīng)的節(jié)點(diǎn)信息
動(dòng)態(tài)新增,修改,刪除,移動(dòng)節(jié)點(diǎn),通過(guò)NodeStore將變化持久化;
目錄結(jié)構(gòu)實(shí)現(xiàn)類圖:(目前只實(shí)現(xiàn)了讀方法)
附上Node,Tree類的核心代碼
Node.java
1 public class Node implements Serializable, Comparable {
2
3 private static final long serialVersionUID = 8085266615416399579L;
4
5 private Integer id; // id號(hào)
6 private Integer parentId;// 父親id號(hào)
7 private String name;// 目錄名
8 private String description;// 目錄描述
9 private String type;// 目錄類型
10
11 private Node parent;// 父親
12 private List children;// 兒子
13
14 /**
15 * 添加子節(jié)點(diǎn),并且建立與當(dāng)前節(jié)點(diǎn)的父子關(guān)系
16 *
17 * @param child 兒子節(jié)點(diǎn)
18 */
19 public void addChild(Node child) {
20 if (child == null) {
21 return;
22 }
23 // 設(shè)置當(dāng)前節(jié)點(diǎn)為child的父節(jié)點(diǎn)
24 child.setParent(this);
25 // 當(dāng)前節(jié)點(diǎn)增加child為兒子節(jié)點(diǎn)
26 if (getChildren() == null) {
27 setChildren(new ArrayList());
28 }
29 getChildren().add(child);
30 }
31
32 /**
33 * 刪除子節(jié)點(diǎn),并且建立與當(dāng)前節(jié)點(diǎn)的父子關(guān)系
34 *
35 * @param child 兒子節(jié)點(diǎn)
36 */
37 public void removeChild(Node child) {
38 if (child == null) {
39 return;
40 }
41 // 將child節(jié)點(diǎn)的父節(jié)點(diǎn)清空
42 child.setParent(null);
43 if (getChildren() == null) {
44 return;
45 }
46 // 當(dāng)前節(jié)點(diǎn)刪除child這個(gè)兒子節(jié)點(diǎn)
47 getChildren().remove(child);
48 }
49
50 /**
51 * 得到全路徑
52 *
53 * @param sep 分隔符號(hào)
54 * @return
55 */ 56 public String getPathName(String sep) {
57 String pathName = getName();
58 if (getParent() != null) {
59 pathName = getParent().getPathName(sep) + sep + pathName;
60 }
61 return pathName;
62 }
63
64 /**
65 * 判斷是否root節(jié)點(diǎn)
66 *
67 * @return
68 */
69 public boolean isRootNode() {
70 return getParentId() == -1;
71 }
72
73 /**
74 * 判斷是否是葉子節(jié)點(diǎn)
75 *
76 * @return
77 */
78 public boolean isEndNode() {
79 return getChildren() == null || getChildren().isEmpty();
80 }
81
82 /**
83 * 對(duì)當(dāng)前節(jié)點(diǎn)的兒子節(jié)點(diǎn)進(jìn)行排序
84 */
85 public void sortChildren() {
86 if (isEndNode()) {
87 return;
88 }
89 Collections.sort(getChildren());
90 }
91
92 /**
93 * 對(duì)當(dāng)前節(jié)點(diǎn)的所有兒子節(jié)點(diǎn)進(jìn)行排序
94 */
95 public void sortAllChidren() {
96 if (isEndNode()) {
97 return;
98 }
99 List children = getChildren();
100 Collections.sort(children);
101 for (Node child : children) {
102 child.sortAllChidren();
103 }
104 }
105
106 /**
107 * 將虛擬目錄轉(zhuǎn)換成JSONObject對(duì)象
108 *
109 * 本身轉(zhuǎn)換包含id、name兩個(gè)屬性,子節(jié)點(diǎn)轉(zhuǎn)換為children屬性的數(shù)組
110 *
111 *
112 * @return
113 */
114 public JSONObject toJson() {
115 JSONObject jsonObject = new JSONObject();
116 try {
117 jsonObject.put("id", id);
118 jsonObject.put("name", name);
119 if (!isEndNode()) {
120 JSONArray jsonArray = new JSONArray();
121 for (Node child : getChildren()) {
122 jsonArray.put(child.toJson());
123 }
124 jsonObject.put("children", jsonArray);
125 }
126 } catch (JSONException e) {
127 // ignore
128 }
129 return jsonObject;
130 } 131
132 @Override
133 public int compareTo(Node o) {
134 return this.getId().compareTo(o.getId());
135 }
136
137 }
Tree.java:
1 public class Tree {
2
3 private String type;
4 private Node root; // root節(jié)點(diǎn)
5 private Map nodeHolder = new HashMap();// 節(jié)點(diǎn)持有器
6
7 private NodeStore nodeStore;
8
9 /**
10 * 將平面的node list構(gòu)建成樹(shù)
11 *
12 * @throws TreeException
13 */
14 public void build() throws TreeException {
15 List nodes = nodeStore.findByType(type);
16 // 如果nodes為空,則不做任何處理
17 if (nodes == null || nodes.isEmpty()) {
18 return;
19 }
20 // 設(shè)置root和node持有器
21 for (T node : nodes) {
22 if (node.isRootNode()) {
23 this.root = node;
24 }
25 nodeHolder.put(node.getId(), node);
26 }
27
28 // 如果root為空,則build失敗了
29 if (root == null) {
30 throw new TreeException("no root node found.");
31 }
32
33 // 建立節(jié)點(diǎn)之前關(guān)系
34 for (T node : nodes) {
35 if (node.isRootNode()) {
36 continue;
37 }
38 Node parent = getNodeById(node.getParentId());
39 if (parent == null) {
40 throw new TreeException("no parent node found.current node id is:" + node.getId());
41 }
42 parent.addChild(node);
43 }
44
45 // 排序
46 root.sortAllChidren();
47 }
48
49 /**
50 * 得到root節(jié)點(diǎn)
51 *
52 * @return
53 */
54 public Node getRoot() {
55 return root;
56 }
57
58 /**
59 * 根據(jù)id得到對(duì)應(yīng)節(jié)點(diǎn)
60 *
61 * @param id
62 * @return
63 */
64 public Node getNodeById(Integer id) {
65 return nodeHolder.get(id);
66 }
67
68 public void setType(String type) {
69 this.type = type;
70 }
71
72 public void setNodeStore(NodeStore nodeStore) {
73 this.nodeStore = nodeStore;
74 }
75
76 }
由于需求原因,目前只實(shí)現(xiàn)了讀部分的功能——如何將平面節(jié)點(diǎn)build成樹(shù)。動(dòng)態(tài)新增,刪除等功能尚未實(shí)現(xiàn)。
目錄結(jié)構(gòu)概念:
Node:目錄節(jié)點(diǎn),具備節(jié)點(diǎn)屬性信息
NodeStore:平面目錄節(jié)點(diǎn)持久化接口,提供方法如下:
public List
public void add(T node);--將增加節(jié)點(diǎn)持久化
public void update(T node);--將修改節(jié)點(diǎn)持久化
public void delete(T node);--刪除節(jié)點(diǎn)
public void move(T src, T target); --將移動(dòng)節(jié)點(diǎn)持久化
NodeStore是一個(gè)接口,可以基于DB實(shí)現(xiàn),也可以基于XML實(shí)現(xiàn),或則其他你需要的方式。
Tree:目錄樹(shù),主要職責(zé):
通過(guò)NodeStore load某一類型目錄的所有平面節(jié)點(diǎn),build成樹(shù);
根據(jù)節(jié)點(diǎn)id號(hào),查找相應(yīng)的節(jié)點(diǎn)信息
動(dòng)態(tài)新增,修改,刪除,移動(dòng)節(jié)點(diǎn),通過(guò)NodeStore將變化持久化;
目錄結(jié)構(gòu)實(shí)現(xiàn)類圖:(目前只實(shí)現(xiàn)了讀方法)
附上Node,Tree類的核心代碼
Node.java
1 public class Node implements Serializable, Comparable
2
3 private static final long serialVersionUID = 8085266615416399579L;
4
5 private Integer id; // id號(hào)
6 private Integer parentId;// 父親id號(hào)
7 private String name;// 目錄名
8 private String description;// 目錄描述
9 private String type;// 目錄類型
10
11 private Node parent;// 父親
12 private List
13
14 /**
15 * 添加子節(jié)點(diǎn),并且建立與當(dāng)前節(jié)點(diǎn)的父子關(guān)系
16 *
17 * @param child 兒子節(jié)點(diǎn)
18 */
19 public void addChild(Node child) {
20 if (child == null) {
21 return;
22 }
23 // 設(shè)置當(dāng)前節(jié)點(diǎn)為child的父節(jié)點(diǎn)
24 child.setParent(this);
25 // 當(dāng)前節(jié)點(diǎn)增加child為兒子節(jié)點(diǎn)
26 if (getChildren() == null) {
27 setChildren(new ArrayList
28 }
29 getChildren().add(child);
30 }
31
32 /**
33 * 刪除子節(jié)點(diǎn),并且建立與當(dāng)前節(jié)點(diǎn)的父子關(guān)系
34 *
35 * @param child 兒子節(jié)點(diǎn)
36 */
37 public void removeChild(Node child) {
38 if (child == null) {
39 return;
40 }
41 // 將child節(jié)點(diǎn)的父節(jié)點(diǎn)清空
42 child.setParent(null);
43 if (getChildren() == null) {
44 return;
45 }
46 // 當(dāng)前節(jié)點(diǎn)刪除child這個(gè)兒子節(jié)點(diǎn)
47 getChildren().remove(child);
48 }
49
50 /**
51 * 得到全路徑
52 *
53 * @param sep 分隔符號(hào)
54 * @return
55 */ 56 public String getPathName(String sep) {
57 String pathName = getName();
58 if (getParent() != null) {
59 pathName = getParent().getPathName(sep) + sep + pathName;
60 }
61 return pathName;
62 }
63
64 /**
65 * 判斷是否root節(jié)點(diǎn)
66 *
67 * @return
68 */
69 public boolean isRootNode() {
70 return getParentId() == -1;
71 }
72
73 /**
74 * 判斷是否是葉子節(jié)點(diǎn)
75 *
76 * @return
77 */
78 public boolean isEndNode() {
79 return getChildren() == null || getChildren().isEmpty();
80 }
81
82 /**
83 * 對(duì)當(dāng)前節(jié)點(diǎn)的兒子節(jié)點(diǎn)進(jìn)行排序
84 */
85 public void sortChildren() {
86 if (isEndNode()) {
87 return;
88 }
89 Collections.sort(getChildren());
90 }
91
92 /**
93 * 對(duì)當(dāng)前節(jié)點(diǎn)的所有兒子節(jié)點(diǎn)進(jìn)行排序
94 */
95 public void sortAllChidren() {
96 if (isEndNode()) {
97 return;
98 }
99 List
100 Collections.sort(children);
101 for (Node child : children) {
102 child.sortAllChidren();
103 }
104 }
105
106 /**
107 * 將虛擬目錄轉(zhuǎn)換成JSONObject對(duì)象
108 *
109 * 本身轉(zhuǎn)換包含id、name兩個(gè)屬性,子節(jié)點(diǎn)轉(zhuǎn)換為children屬性的數(shù)組
110 *
111 *
112 * @return
113 */
114 public JSONObject toJson() {
115 JSONObject jsonObject = new JSONObject();
116 try {
117 jsonObject.put("id", id);
118 jsonObject.put("name", name);
119 if (!isEndNode()) {
120 JSONArray jsonArray = new JSONArray();
121 for (Node child : getChildren()) {
122 jsonArray.put(child.toJson());
123 }
124 jsonObject.put("children", jsonArray);
125 }
126 } catch (JSONException e) {
127 // ignore
128 }
129 return jsonObject;
130 } 131
132 @Override
133 public int compareTo(Node o) {
134 return this.getId().compareTo(o.getId());
135 }
136
137 }
Tree.java:
1 public class Tree
2
3 private String type;
4 private Node root; // root節(jié)點(diǎn)
5 private Map
6
7 private NodeStore
8
9 /**
10 * 將平面的node list構(gòu)建成樹(shù)
11 *
12 * @throws TreeException
13 */
14 public void build() throws TreeException {
15 List
16 // 如果nodes為空,則不做任何處理
17 if (nodes == null || nodes.isEmpty()) {
18 return;
19 }
20 // 設(shè)置root和node持有器
21 for (T node : nodes) {
22 if (node.isRootNode()) {
23 this.root = node;
24 }
25 nodeHolder.put(node.getId(), node);
26 }
27
28 // 如果root為空,則build失敗了
29 if (root == null) {
30 throw new TreeException("no root node found.");
31 }
32
33 // 建立節(jié)點(diǎn)之前關(guān)系
34 for (T node : nodes) {
35 if (node.isRootNode()) {
36 continue;
37 }
38 Node parent = getNodeById(node.getParentId());
39 if (parent == null) {
40 throw new TreeException("no parent node found.current node id is:" + node.getId());
41 }
42 parent.addChild(node);
43 }
44
45 // 排序
46 root.sortAllChidren();
47 }
48
49 /**
50 * 得到root節(jié)點(diǎn)
51 *
52 * @return
53 */
54 public Node getRoot() {
55 return root;
56 }
57
58 /**
59 * 根據(jù)id得到對(duì)應(yīng)節(jié)點(diǎn)
60 *
61 * @param id
62 * @return
63 */
64 public Node getNodeById(Integer id) {
65 return nodeHolder.get(id);
66 }
67
68 public void setType(String type) {
69 this.type = type;
70 }
71
72 public void setNodeStore(NodeStore nodeStore) {
73 this.nodeStore = nodeStore;
74 }
75
76 }

