将数据库中树类型的表递归转换为json字符串
需求:现在有很好的ext树,可以将数据库中的数据显示成很漂亮的树形,而一个瓶颈问题是怎么把数据库中查询得到的数据转换为json的字符串格式。这里的类就是把这样的一个数据类转换为json串。使用到了JsonUtil这个开源的json字符串转换类。
使用到了堆栈的数据结构。
下面是测试类:
1 package com;
2
3 public class Test {
4
5 /**
6 * @param args
7 */
8 public static void main(String[] args) {
9
10 TreeNode root = new TreeNode("root", "整个世界", null);
11 TreeNode node1 = new TreeNode("1", "太阳系", "root");
12 TreeNode node2 = new TreeNode("2", "地球", "1");
13 TreeNode node3 = new TreeNode("3", "火星", "1");
14 TreeNode node4 = new TreeNode("4", "亚洲", "2");
15 TreeNode node5 = new TreeNode("5", "非洲", "2");
16 TreeNode node6 = new TreeNode("6", "51号星球", "9");
17
18 Tree tree = new Tree();
19 tree.addNode(node1);
20 tree.addNode(node2);
21 tree.addNode(node3);
22 tree.addNode(node4);
23 tree.addNode(node5);
24 tree.addNode(node6);
25
26 System.out.println(tree.getTreeJson(tree, root));
27
28 }
29
30 }
31
自定义的类:TreeNode 类主要是包含的树的数据结构的必须的元素:id,name,parent(父亲节点id),print(一个辅助的属性,标志是否已经打印过)。
下面是具体TreeNode 类:
1 package com;
2
3 public class TreeNode {
4
5 private String id;
6
7 private String parent;
8
9 private String name;
10
11 private int print;
12
13 public TreeNode(String id, String name, String parent) {
14 this.id = id;
15 this.name = name;
16 this.parent = parent;
17 this.print = 0;
18 }
19
20 public String getId() {
21 return id;
22 }
23
24 public void setId(String id) {
25 this.id = id;
26 }
27
28 public String getParent() {
29 return parent;
30 }
31
32 public void setParent(String parent) {
33 this.parent = parent;
34 }
35
36 public String getName() {
37 return name;
38 }
39
40 public void setName(String name) {
41 this.name = name;
42 }
43
44 public int getPrint() {
45 return print;
46 }
47
48 public void setPrint(int print) {
49 this.print = print;
50 }
51
52 }
53
下面是最关键的Tree类,主要是把树的节点进行组装形成整个树型,然后再得到json串:
1 package com;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10
11 public class Tree {
12 // 一个关于父亲节点和所有孩子们的键值对
13 private HashMap parentMap = new HashMap();
14 // 一个关于节点id和节点对象的键值对
15 private HashMap nodeMap = new HashMap();
16 // 包含所有节点的list
17 private ArrayList nodeList = new ArrayList();
18
19 public void addNode(TreeNode node) {
20 nodeList.add(node);
21 nodeMap.put(node.getId(), node);
22 addParentMap(node.getParent(), node);
23 }
24
25 // 组装成一个节点与父亲id的map
26 private void addParentMap(String parentId, TreeNode node) {
27 List list = new ArrayList();
28 // 如果这个id下面的孩子们
29 if (!parentMap.containsKey(parentId)) {
30 list.add(node);
31 parentMap.put(parentId, list);
32 } else {
33 list = (ArrayList) parentMap.get(parentId);
34 list.add(node);
35 parentMap.put(parentId, list);
36 }
37 }
38
39 // 根据节点id得到节点
40 private TreeNode getNode(String id) {
41 return (TreeNode) nodeMap.get(id);
42 }
43
44 // 返回全部的父亲节点id组成的一个set
45 public Set getParentSet() {
46 Set parentSet = new HashSet();
47 Iterator it = nodeList.iterator();
48 while (it.hasNext()) {
49 TreeNode vo = (TreeNode) it.next();
50 parentSet.add(vo.getParent());
51 }
52 return parentSet;
53 }
54
55 // 查找孩子
56 public ArrayList getNodesByParentId(String parentId) {
57 return (ArrayList) parentMap.get(parentId);
58 }
59
60 // 设置第一层节点。主要把那些找不到父亲的节点主动的放在根节点下面。
61 private void setFistFloor(TreeNode root) {
62 Set parentSet = this.getParentSet();
63 String rootId = root.getId();
64 // 用来存放不存在的父亲节点的list
65 ArrayList notExitslist = new ArrayList();
66 // 下面查找所有的父节点字符串,如果不存在表明应该准备把这些父亲的孩子转存到虚根的下面,作为虚根的孩子
67 Object[] parents = parentSet.toArray();
68 for (int temp = 0; temp < parents.length; temp++) {
69 String tempId = parents[temp].toString();
70 // 下面找到所有的不存在的父亲节点,放在list里面。
71 if (this.getNode(tempId) == null && !tempId.equals(root.getId())) {
72 notExitslist.add(parents[temp].toString());
73 }
74 }
75 // 下面根据父亲孩子map找到所有的没有找到父亲节点的孩子们,将它们放到虚根的下面。。下面的是当有多个父亲节点不存在的时候进行更改父亲到虚根下面的操作。
76 Iterator it = notExitslist.iterator();
77 while (it.hasNext()) {
78 ArrayList list2 = getNodesByParentId(it.next().toString());
79 for (int temp = 0; temp < list2.size(); temp++) {
80 TreeNode tempNode = (TreeNode) list2.get(temp);
81 tempNode.setParent(rootId);
82 addParentMap(rootId, tempNode);
83 }
84 }
85 }
86
87 // 返回父亲与孩子们的映射关系
88 private Map getParentMap() {
89 return parentMap;
90 }
91
92 public String getTreeJson(Tree tree, TreeNode root) {
93 StringBuilder ans = new StringBuilder();
94 Set parentSet = tree.getParentSet();
95 Stack stack = new Stack();
96
97 stack.push(root);
98 tree.setFistFloor(root);
99 Map map = tree.getParentMap();
100 String result = "";
101 ans.append("[");
102 while (!stack.isEmpty()) {
103 TreeNode e = stack.top();
104
105 // 得到该父亲的孩子节点们
106 ArrayList childs = (ArrayList) map.get(e.getId());
107 Iterator cIt = childs.iterator();
108 // 设置一个堆栈是否改变的标志位
109 boolean stackChanged = false;
110 // 如果孩子节点循环未结束或者堆栈没有改变,就进行循环孩子节点的操作!
111 while (cIt.hasNext() && (!stackChanged)) {
112 // 得到孩子节点
113 TreeNode aChild = (TreeNode) cIt.next();
114 // 如果节点没有被打印出来就打印
115 if (aChild.getPrint() == 0) {
116 // 如果是树枝节点 ,就直接转换成为json字符串
117 if ((!parentSet.contains(aChild.getId()))) {
118 ans.append(JsonUtil.bean2json(aChild) + ",");
119 // 注意节点打印之后有一个逗号!
120 // ans.append(getExtNodeJsonStr(aChild) + ",");
121 // 设置节点被打印的标志位。
122 aChild.setPrint(1);
123 }
124 // 如果是非树枝节点就打印一部分字符串,同时入堆栈进行下次的循环
125 else if (parentSet.contains(aChild.getId())) {
126 // 使用了一个开源java类用来形成json串。
127 ans.append(JsonUtil.bean2json(aChild));
128 // ans.append(getExtNodeJsonStr(aChild));
129 ans.deleteCharAt(ans.lastIndexOf("}"));
130 ans.append(",\"children\":[");
131 // 设置该节点已经打印
132 aChild.setPrint(1);
133 // 将该节点推入堆栈
134 stack.push(aChild);
135 // 设置堆栈被修改了。将退出当次的while循环。
136 stackChanged = true;
137 break;
138 }
139 }
140 }
141
142 // 下面是进行的json数组封闭组串。
143 // 打印完一个父亲的全部孩子们的json串之后删除最后一个逗号。再加上一个"]".同时扔掉该父亲节点。
144 // 注意查询条件最后一个是因为没有打印root这个json串,所以没有必要在后面进行数组的封闭操作!
145 if ((!cIt.hasNext()) && stackChanged == false) {
146 // 注意打印完父亲之后要进行字符串的封闭操作。
147 if (e.getPrint() == 1) {
148 ans.deleteCharAt(ans.lastIndexOf(","));
149 ans.append("]},");
150 }
151 // 将打印完的父亲节点从堆栈中扔掉。
152 stack.pop();
153 }
154 }
155 // 下面进行整个字符串的封闭操作。
156 ans.deleteCharAt(ans.lastIndexOf(","));
157 ans.append("]");
158 result = ans.toString();
159 return result;
160 }
161
162 }
163
注意使用了一个开源的java类,jutil,主要用来形成一个java类的json串。
1 package com;
2
3 import java.beans.IntrospectionException;
4 import java.beans.Introspector;
5 import java.beans.PropertyDescriptor;
6 import java.math.BigDecimal;
7 import java.math.BigInteger;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 public class JsonUtil {
13
14 public static String object2json(Object obj) {
15 StringBuilder json = new StringBuilder();
16 if (obj == null) {
17 json.append("\"\"");
18 } else if (obj instanceof String || obj instanceof Integer
19 || obj instanceof Float || obj instanceof Boolean
20 || obj instanceof Short || obj instanceof Double
21 || obj instanceof Long || obj instanceof BigDecimal
22 || obj instanceof BigInteger || obj instanceof Byte) {
23 json.append("\"").append(string2json(obj.toString())).append("\"");
24 } else if (obj instanceof Object[]) {
25 json.append(array2json((Object[]) obj));
26 } else if (obj instanceof List) {
27 json.append(list2json((List<?>) obj));
28 } else if (obj instanceof Map) {
29 json.append(map2json((Map<?, ?>) obj));
30 } else if (obj instanceof Set) {
31 json.append(set2json((Set<?>) obj));
32 } else {
33 json.append(bean2json(obj));
34 }
35 return json.toString();
36 }
37
38 public static String bean2json(Object bean) {
39 StringBuilder json = new StringBuilder();
40 json.append("{");
41 PropertyDescriptor[] props = null;
42 try {
43 props = Introspector.getBeanInfo(bean.getClass(), Object.class)
44 .getPropertyDescriptors();
45 } catch (IntrospectionException e) {
46 }
47 if (props != null) {
48 for (int i = 0; i < props.length; i++) {
49 try {
50 String name = object2json(props[i].getName());
51 String value = object2json(props[i].getReadMethod().invoke(
52 bean));
53 json.append(name);
54 json.append(":");
55 json.append(value);
56 json.append(",");
57 } catch (Exception e) {
58 }
59 }
60 json.setCharAt(json.length() - 1, '}');
61 } else {
62 json.append("}");
63 }
64 return json.toString();
65 }
66
67 public static String list2json(List<?> list) {
68 StringBuilder json = new StringBuilder();
69 json.append("[");
70 if (list != null && list.size() > 0) {
71 for (Object obj : list) {
72 json.append(object2json(obj));
73 json.append(",");
74 }
75 json.setCharAt(json.length() - 1, ']');
76 } else {
77 json.append("]");
78 }
79 return json.toString();
80 }
81
82 public static String array2json(Object[] array) {
83 StringBuilder json = new StringBuilder();
84 json.append("[");
85 if (array != null && array.length > 0) {
86 for (Object obj : array) {
87 json.append(object2json(obj));
88 json.append(",");
89 }
90 json.setCharAt(json.length() - 1, ']');
91 } else {
92 json.append("]");
93 }
94 return json.toString();
95 }
96
97 public static String map2json(Map<?, ?> map) {
98 StringBuilder json = new StringBuilder();
99 json.append("{");
100 if (map != null && map.size() > 0) {
101 for (Object key : map.keySet()) {
102 json.append(object2json(key));
103 json.append(":");
104 json.append(object2json(map.get(key)));
105 json.append(",");
106 }
107 json.setCharAt(json.length() - 1, '}');
108 } else {
109 json.append("}");
110 }
111 return json.toString();
112 }
113
114 public static String set2json(Set<?> set) {
115 StringBuilder json = new StringBuilder();
116 json.append("[");
117 if (set != null && set.size() > 0) {
118 for (Object obj : set) {
119 json.append(object2json(obj));
120 json.append(",");
121 }
122 json.setCharAt(json.length() - 1, ']');
123 } else {
124 json.append("]");
125 }
126 return json.toString();
127 }
128
129 public static String string2json(String s) {
130 if (s == null)
131 return "";
132 StringBuilder sb = new StringBuilder();
133 for (int i = 0; i < s.length(); i++) {
134 char ch = s.charAt(i);
135 switch (ch) {
136 case '"':
137 sb.append("\\\"");
138 break;
139 case '\\':
140 sb.append("\\\\");
141 break;
142 case '\b':
143 sb.append("\\b");
144 break;
145 case '\f':
146 sb.append("\\f");
147 break;
148 case '\n':
149 sb.append("\\n");
150 break;
151 case '\r':
152 sb.append("\\r");
153 break;
154 case '\t':
155 sb.append("\\t");
156 break;
157 case '/':
158 sb.append("\\/");
159 break;
160 default:
161 if (ch >= '\u0000' && ch <= '\u001F') {
162 String ss = Integer.toHexString(ch);
163 sb.append("\\u");
164 for (int k = 0; k < 4 - ss.length(); k++) {
165 sb.append('0');
166 }
167 sb.append(ss.toUpperCase());
168 } else {
169 sb.append(ch);
170 }
171 }
172 }
173 return sb.toString();
174 }
175
还有一个自己写的堆栈类,比较简单:
1 package com;
2
3 import java.util.LinkedList;
4
5 public class Stack {
6 private LinkedList list = new LinkedList();
7
8 public void push(TreeNode v) {
9 list.addFirst(v);
10 }
11
12 public void push(Object v) {
13 list.addFirst(v);
14 }
15
16 public TreeNode top() {
17 return (TreeNode) list.getFirst();
18 }
19
20 public Object topObj() {
21 return list.getFirst();
22 }
23
24 public TreeNode pop() {
25 return (TreeNode) list.removeFirst();
26 }
27
28 public Object popObj() {
29 return list.removeFirst();
30 }
31
32 public String toString() {
33 return list.toString();
34 }
35
36 public boolean isEmpty() {
37 return list.isEmpty();
38 }
39 }
40