nodesNameBySeq:待分组的节点名称.将树节点对应的实体类的成员名称放到此数组里面,顺序是{"根节点","子节点1","子节点2"...}
data:数据列表,List<实体类> data ;
编写原理:
1).首先用groupByNodeName将数据分组
用Java中的Field进行字段比较,来获得相对应的成员字段,以及成员变量的名称,这里要用getDeclaredFields方法来获得,否则,private声明的成员是无法得到Field的
将得到的fieldIndex全部放到数组中保存,便于以后的使用,field[fieldIndex]可以得到相应的字段
2).构造一个tree的json形式的类:里面有几个重要的成员:{id,text,state}这种形式用JsonObject.fromObject(jsonObj}能直接转换为tree所需要的json,并且,这个类中要有一
个children字段,保存子节点的数据
3).recursiveTree方法
# 此方法内要递归遍历树,返回一个list,list中是一个JsonTreeObj自定义的一个类,其中的children还可以保存一个JsonTreeObj,这样就可以实现嵌套
#在递归之前,首先要有一个成员变量(全局变量)来记录要分组的节点索引
先进行一次分组,得到的map就是JsonTreeObj,通过构造方法可以实现转换,这样,转换过来的JsonTreeObj才是我们的Tree-json,但这只是一次调用
是否再次分组,要用事先准备好的 fieldIndex长度或者nodesNameBySeq进行判断,如果要继续分组,那么需要移除map中每条数据中的list并重新分组成map.
即:用新分组的List替换以前未分组的List
返回之后,返回分组好的JsonTreeObj数据,此时的list差不多和需要的json相仿但是,还要做下字符串的调整
4).replaceText
用此方法来替换最深层节点的文本,否则字段中无text,会出现undefine
1)要构造的树
2)要构造的json
[
{
"children": [
{
"children": [
{
"children": [
{
"address": "bj",
"text": "id1",
"name": "wang'ao1",
"occupation": "student"
}
],
"id": "0.5715806450144063",
"state": "closed",
"text": "student"
}
],
"id": "0.4010186645348438",
"state": "closed",
"text": "bj"
},
{
"children": [
{
"children": [
{
"address": "bj11",
"text": "id12",
"name": "wang'ao1",
"occupation": "student"
}
],
"id": "0.188373241944635",
"state": "closed",
"text": "student"
},
{
"children": [
{
"address": "bj11",
"text": "id11",
"name": "wang'ao1",
"occupation": "teacher"
}
],
"id": "0.9566645560486874",
"state": "closed",
"text": "teacher"
}
],
"id": "0.6062106288555755",
"state": "closed",
"text": "bj11"
}
],
"id": "0.6856242232995936",
"state": "closed",
"text": "wang'ao1"
},
{
"children": [
{
"children": [
{
"children": [
{
"address": "bj",
"text": "id1",
"name": "wang'ao",
"occupation": "student"
}
],
"id": "0.5044856120294572",
"state": "closed",
"text": "student"
}
],
"id": "0.2021652373692504",
"state": "closed",
"text": "bj"
},
{
"children": [
{
"children": [
{
"address": "bj11",
"text": "id12",
"name": "wang'ao",
"occupation": "student"
}
],
"id": "0.7096934456298796",
"state": "closed",
"text": "student"
},
{
"children": [
{
"address": "bj11",
"text": "id11",
"name": "wang'ao",
"occupation": "teacher"
}
],
"id": "0.8679325026402117",
"state": "closed",
"text": "teacher"
}
],
"id": "0.6940289758188156",
"state": "closed",
"text": "bj11"
}
],
"id": "0.08304442224761122",
"state": "closed",
"text": "wang'ao"
}
]
3)实体类
/**
* @author wang'ao
*
*/
public class TestEntity {
private String name ;
private String ids ;
private String address ;
private String occupation ;
public String getOccupation() {
return occupation;
}
public void setOccupation(String occupation) {
this.occupation = occupation;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIds() {
return ids;
}
public void setId(String ids) {
this.ids = ids;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public TestEntity(String name, String ids, String address, String occupation) {
super();
this.name = name;
this.ids = ids;
this.address = address;
this.occupation = occupation;
}
@Override
public String toString() {
return "TestEntity [name=" + name + ", id=" + ids + ", address="
+ address + "]";
}
}
4)测试
/**
* @author wang'ao
*
*/
public class Test {
public static void main(String[] args) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
TestEntity te1 = new TestEntity("wang'ao","id1","bj","student") ;
TestEntity te2 = new TestEntity("wang'ao","id11","bj11","teacher") ;
TestEntity te3 = new TestEntity("wang'ao","id12","bj11","student") ;
TestEntity te4 = new TestEntity("wang'ao1","id1","bj","student") ;
TestEntity te5 = new TestEntity("wang'ao1","id11","bj11","teacher") ;
TestEntity te6 = new TestEntity("wang'ao1","id12","bj11","student") ;
List
/**
*
* @version V1.0
*/
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.sf.json.JSONArray;
/**
* 用途:json树的数据生成类
* 描述:将数据列表转换成相应的tree所必需的JSON格式
* 说明:N级节点树,默认树节点是关闭的
*
* @author wang'ao
*
*/
public class JsonTreeHelper {
/**
* 用于页面传递JSON数据的类,id:xx text:xx children:xx
* 将从数据库查询到的数据,用这个类进行打包,而可以将这个类直接转换成 指定的格式的JSON字符串
*
* tip:如有需要,直接继承,并添加一个自定义字段
*
* @author wang'ao
*
*/
public static class JsonTreeObj {
/** 必需的id **/
private String id;
/** 显示的节点文本 **/
private String text;
/** 是否是关闭状态 **/
private String state;
/** 子 **/
private List children;
/**
*
* @param text
* 节点的文本名字
* @param children
* 内部节点集合
*/
public JsonTreeObj(String rootNode, List children) {
/** 保证id不重复 **/
this.id = Math.random() + "";
this.state = "closed";
this.text = rootNode;
this.children = children;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public List getChildren() {
return children;
}
public void setChildren(List children) {
this.children = children;
}
}
/**
* 用途:转换tree形式数据 用例: 实体类:class People{private String name ;private String
* hometown ;private String occupation ; set...;get...}
* 调用方法:getTreeJsonStr(new String[]{"hometown","occupation"},data);
* 说明:表示以hometown为根节点,occupation字段为子节点所构成的树
*
* @param nodesNameBySeq
* 树节点名字数组 {"根节点","子节点1","子节点2",...} ,此处的名字应是对应的实体类的成员名.
* 如:有一个成员{private String type ;} 根节点是"type"
* @param data
* 数据
* @return tree形式的JSON数据
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static String getTreeJsonStr(String[] nodesNameBySeq,List data) throws IllegalArgumentException,
IllegalAccessException {
int[] fieldIndex = new int[nodesNameBySeq.length];
// 优化标记
int end = 0;
Field[] fields = data.get(0).getClass().getDeclaredFields();
for (int i = 0; i < nodesNameBySeq.length; i++) {
for (int j = 0; j < fields.length; j++) {
if (nodesNameBySeq[i].equals(fields[j].getName())) {
fieldIndex[i] = j;
end++;
if (end == nodesNameBySeq.length)
break;
}
}
}
// 替换成text字段
return replaceText(JSONArray
.fromObject(recursiveTree(data, fieldIndex)).toString(),
nodesNameBySeq[nodesNameBySeq.length - 1], "text");
}
/**
* 将数据根据根节点进行分组
*
* @param fieldIndex
* 根节点成员字段所对应折field索引
* @param list
* 数据列表
* @return 分组好的map数据
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
private static Map> groupByNodeName(
Integer fieldIndex, List list)
throws IllegalArgumentException, IllegalAccessException {
// 准备集合
Map> readyMap = new HashMap>();
for (int i = 0; i < list.size(); i++) {
java.lang.reflect.Field[] field = (java.lang.reflect.Field[]) list
.get(i).getClass().getDeclaredFields();
field[fieldIndex].setAccessible(true);
List find = readyMap.get(field[fieldIndex].get(list.get(i))
.toString());
if (readyMap.isEmpty() || find == null) {
List similar = new ArrayList();
similar.add(list.get(i));
readyMap.put(field[fieldIndex].get(list.get(i)).toString(),
similar);
} else {
find.add(list.get(i));
readyMap.put(field[fieldIndex].get(list.get(i)).toString(),
find);
}
}
return readyMap;
}
private static int fIndex = 0;
/**
* 遍历所有节点(递归调用)
*
* @param data
* @param fieldIndexF
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
private static List recursiveTree(List data,
int[] fieldIndexF) throws IllegalArgumentException,
IllegalAccessException {
// 先进行一次分组
Map> firstGroupedData = groupByNodeName(
fieldIndexF[fIndex], data);
List jsonTrees = new ArrayList();
// 第一次分组的数据
Iterator>> it = firstGroupedData
.entrySet().iterator();
int i = 0;
List list;
// 遍历map
while (it.hasNext()) {
Map.Entry> entry = it.next();
jsonTrees.add(new JsonTreeObj(entry.getKey(), entry.getValue()));
if (fieldIndexF.length > 1 && fIndex < fieldIndexF.length - 2) {
fIndex++;
// **.clear()方法要清除指针,所以要用new方法实例化
list = new ArrayList(entry.getValue());
jsonTrees.get(i).getChildren().clear();
jsonTrees.get(i).getChildren()
.addAll((recursiveTree(list, fieldIndexF)));
}
i++;
}
fIndex--;
return jsonTrees;
}
/**
* 将JSON串中的字符替换,如:"post" -> "text" ,这样可以正常显示文本,否则 undefine
*
* @param src
* 源JSON
* @param replace
* 要替换的字段
* @param changedTxt
* 替换之后的字段
* @return 替换完成之后的字段
*/
private static String replaceText(String src, String replace,
String changedTxt) {
return src.replaceAll("\"" + replace + "\"", "\"" + changedTxt + "\"");
}
}