zTree联想终极篇-->将存储树形数据表封装成自定义TreeNode-->将自定义TreeNode解析成JSON树形字串

写了一个早上,终于实现,现在分享如下:

所有功能一个TreeNode完成,如下图:


TreeNode代码如下,你不要错过:)

package model;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/** 自定义的树节点 */
public class TreeNode {

	
	// 节点携带的值
	private Map tag;

	// 儿子节点
	private List nodes;

	/** 节点信息键值对,该属性不会为空指针,但可能没有键值对存在[就是map.size()==0] */
	public Map getTag() {
		if (tag == null)
			tag = new HashMap();
		return tag;
	}

	public void setTag(Map tag) {
		this.tag = tag;
	}

	/** 获得所有子节点,该属性不会为空指针,但可能没有集合元素存在 */
	public List getNodes() {
		if (nodes == null)
			nodes = new ArrayList();
		return nodes;
	}

	public void setNodes(List nodes) {

		this.nodes = nodes;
	}

	public TreeNode(Map tag, List nodes) {
		super();
		this.tag = tag;
		this.nodes = nodes;
	}

	public TreeNode() {
		super();
	}

	public TreeNode(Map tag) {
		super();
		this.tag = tag;
	}

	/**
	 * 
	 * 		将当前TreeNode解析为JSON字串 构造的目标格式示例: 
	 * 		{ 
	 * 			id:1, 
	 * 			name:'手机', 
	 * 			nodes:[
	 * 				{id:11,name:'诺基亚'}, 
	 * 				{id:12,name:'三星',nodes:[
	 * 					{id:121,name:'I9000(联通版)'},
	 * 					{id:122,name:'I9000(移动版)'},
	 * 					{id:123,name:'Galaxy Naos'}
	 * 				]},
	 * 				{id:13,name:'索爱'}
	 * 			]
	 * 		}
	 * 
* */ private String toJson() { // if (this.getNodes().size() == 0) // throw new RuntimeException("节点不能没有任何属性"); return parseTreeNode(this); } /** * 将对象集合解析为json格式的树形脚本 * @param 集合成员类型 * @param entities 待解析的集合,必须具备有效值 * @param key 对象的唯一标识属性,必须具备有效值 * @param parentKey 父对象的唯一标识属性,必须具备有效值 * @param fieldPropertyMap java对象属性名到json对象属性名的映射,比如java对象的属性名是code,对应解析后的json对象的属性名是id * @param parseCallBack 解析回调函数,用于扩展树节点的属性,有了这个接口给开发这个一个可以自定义树形节点特殊属性的机会 * @param parseFields 需要解析的字段,没有传递就解析对象的所有属性 * @return json格式的树形脚本 * 例如结果如下格式: *
 		
	 * 		[
	 * 				{id:11,name:'诺基亚'}, 
	 * 				{id:12,name:'三星',nodes:[
	 * 					{id:121,name:'I9000(联通版)'},
	 * 					{id:122,name:'I9000(移动版)'},
	 * 					{id:123,name:'Galaxy Naos'}
	 * 				]},
	 * 				{id:13,name:'索爱'},
	 * 				{id:14,name:'TCL'},
	 * 				{id:15,name:'摩托罗拉'}
	 * 		]
	 * 使用示范如下:
	 *	 * //用一个集合模拟数据表的内容,也就是一下集合的内容完全可以查询自数据库
	 *		List treeList = new ArrayList();
	 *		treeList.add(new SysFunction("L01", null, "营销管理","没有"));		
	 *		treeList.add(new SysFunction("L02",null,"客户管理","没有"));
	 *		treeList.add(new SysFunction("L03",null,"服务管理","没有"));	
	 *	 	//营销管理的子功能
	 *		treeList.add(new SysFunction("L0101","L01","创建销售机会","没有"));
	 *		treeList.add(new SysFunction("L0102","L01","指派销售机会","没有"));
	 *		treeList.add(new SysFunction("L0103","L01","制定开发计划","没有"));
	 *		treeList.add(new SysFunction("L0104","L01","执行开发计划","没有"));
	 *		//指派销售机会的子功能		
	 *		treeList.add(new SysFunction("L010201","L0102","经理指派","没有"));
	 *		treeList.add(new SysFunction("L010202","L0102","主管指派","没有"));				
	 *		//客户管理的子功能
	 *		treeList.add(new SysFunction("L0201","L02","客户信息管理","没有"));
	 *		treeList.add(new SysFunction("L0202","L02","客户流失管理","没有"));
	 *		//服务管理子功能
	 *		treeList.add(new SysFunction("L0301","L03","咨询服务管理","没有"));
	 *		treeList.add(new SysFunction("L0302","L03","投诉服务管理","没有"));
	 *		treeList.add(new SysFunction("L0303","L03","查询服务管理","没有"));
	 *		
	 *		try {
	 *		Properties p = new Properties();
 	 *		p.setProperty("code", "id");//将SysFunction对象里的属性名“code”映射到json对象里的属性名“id”
	 *		p.setProperty("title", "name");//将SysFunction对象里的属性名“title”映射到json对象里的属性名“name”
	 *		
	 *		//开始调用解析函数,第五个参数是一个匿名内部类
	 *		return
	 *			TreeNode.parseListToJsonTree(
	 *					treeList,
	 *					"code",
	 *					"parentCode",
	 *					p,
	 *					new TreeNode.IParseTreeNodeCallBack() {			
	 *							public void processTreeNode(TreeNode node) {
	 *									node.getTag().put("open",true);//向节点追加一个属性,表示要zTree展开这个节点
	 *									node.getTag().put("click","alert('"+node.getTag().get("id")+"')");//向节点追加一个属性click,表示要求zTree的节点具有响应点击事件的能力
	 *							}
	 *					},
	 *					"code",					//java对象SysFunction里要code属性参与解析
	 *					"parentCode",		//java对象SysFunction里要parentCode属性参与解析
	 *					"title"						//java对象SysFunction里要title属性参与解析
	 *			);
	 *	} catch (Exception e) {
	 *		e.printStackTrace();
	 *	} 
	 * 
* @throws SecurityException java反射异常 * @throws NoSuchFieldException java反射异常 * @throws IllegalArgumentException java反射异常 * @throws IllegalAccessException java反射异常 */ public static String parseListToJsonTree(List entities, String key, String parentKey, Properties fieldPropertyMap,IParseTreeNodeCallBack parseCallBack,String...parseFields) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { if (entities==null || entities.size()==0 || null==key || "".equals(key) || null==parentKey || "".equals(parentKey)) throw new RuntimeException("参数不是有效值,分析失败"); if (fieldPropertyMap==null) fieldPropertyMap = new Properties(); List nodes = new ArrayList(); //将这个集合封装成Map Map treeNodeMap = new HashMap(); Class classzz = entities.get(0).getClass(); Field keyField = classzz.getDeclaredField(key); Field parentKeyField = classzz.getDeclaredField(parentKey); keyField.setAccessible(true);//设置可以访问私有字段 parentKeyField.setAccessible(true);//设置可以访问私有字段 String keyJsonPropertyName = "";//key的json属性 String parentKeyJsonPropertyName="";//parentKey的json属性 //处理key if (fieldPropertyMap.containsKey(key))//如果包含对key的名称映射 keyJsonPropertyName = fieldPropertyMap.getProperty(key);//如果包含key映射就用映射名字作json对象属性名 else keyJsonPropertyName = keyField.getName();//如果不包含key映射就用字段名作json对象属性名 //同上处理parentKey if (fieldPropertyMap.containsKey(parentKey))//如果包含对key的名称映射 parentKeyJsonPropertyName = fieldPropertyMap.getProperty(parentKey); else parentKeyJsonPropertyName = parentKeyField.getName(); //下面的循环完成两个功能: // 1.将所有对象封装成Map里面的键值对,且值是TreeNode类型 // //2.将没有父节点的TreeNode添加到根节点rootNode for(E e:entities){ TreeNode node = new TreeNode(); //处理关键属性 //处理key node.getTag().put(keyJsonPropertyName, keyField.get(e)); //同上处理parentKey node.getTag().put(parentKeyJsonPropertyName,parentKeyField.get(e)); //处理其它属性 if (parseFields==null || parseFields.length==0){ for(Field field: classzz.getDeclaredFields()){ field.setAccessible(true);//设置可以访问私有字段 if (fieldPropertyMap.containsKey(field.getName()))//如果map中包含名字映射 node.getTag().put(fieldPropertyMap.getProperty(field.getName()), field.get(e)); else node.getTag().put(field.getName(),field.get(e));//不包含名字映射则使用字段本身的名字作json对象属性 } } else { for(String fieldName: parseFields){ Field field = classzz.getDeclaredField(fieldName); field.setAccessible(true);//设置可以访问私有字段 if (fieldPropertyMap.containsKey(field.getName()))//如果map中包含名字映射 node.getTag().put(fieldPropertyMap.getProperty(field.getName()), field.get(e)); else node.getTag().put(field.getName(),field.get(e));//不包含名字映射则使用字段本身的名字作json对象属性 } } if (parseCallBack!=null)//判断回调是否为空 parseCallBack.processTreeNode(node);//回调 treeNodeMap.put(keyField.get(e).toString(),node); } //下面的代码建立节点之间的从属关系 for(int i=0;i 集合成员类型 * @param entities 待解析的集合,必须具备有效值 * @param key 对象的唯一标识属性,必须具备有效值 * @param parentKey 父对象的唯一标识属性,必须具备有效值 * @param fieldPropertyMap java对象属性名到json对象属性名的映射,比如java对象的属性名是code,对应解析后的json对象的属性名是id * @return json格式的树形脚本 * 例如结果如下格式: *
 		
	 * 		[
	 * 				{id:11,name:'诺基亚'}, 
	 * 				{id:12,name:'三星',nodes:[
	 * 					{id:121,name:'I9000(联通版)'},
	 * 					{id:122,name:'I9000(移动版)'},
	 * 					{id:123,name:'Galaxy Naos'}
	 * 				]},
	 * 				{id:13,name:'索爱'},
	 * 				{id:14,name:'TCL'},
	 * 				{id:15,name:'摩托罗拉'}
	 * 		]
	 * 使用示范如下:
	 *	 * //用一个集合模拟数据表的内容,也就是一下集合的内容完全可以查询自数据库
	 *		List treeList = new ArrayList();
	 *		treeList.add(new SysFunction("L01", null, "营销管理","没有"));		
	 *		treeList.add(new SysFunction("L02",null,"客户管理","没有"));
	 *		treeList.add(new SysFunction("L03",null,"服务管理","没有"));	
	 *	 	//营销管理的子功能
	 *		treeList.add(new SysFunction("L0101","L01","创建销售机会","没有"));
	 *		treeList.add(new SysFunction("L0102","L01","指派销售机会","没有"));
	 *		treeList.add(new SysFunction("L0103","L01","制定开发计划","没有"));
	 *		treeList.add(new SysFunction("L0104","L01","执行开发计划","没有"));
	 *		//指派销售机会的子功能		
	 *		treeList.add(new SysFunction("L010201","L0102","经理指派","没有"));
	 *		treeList.add(new SysFunction("L010202","L0102","主管指派","没有"));				
	 *		//客户管理的子功能
	 *		treeList.add(new SysFunction("L0201","L02","客户信息管理","没有"));
	 *		treeList.add(new SysFunction("L0202","L02","客户流失管理","没有"));
	 *		//服务管理子功能
	 *		treeList.add(new SysFunction("L0301","L03","咨询服务管理","没有"));
	 *		treeList.add(new SysFunction("L0302","L03","投诉服务管理","没有"));
	 *		treeList.add(new SysFunction("L0303","L03","查询服务管理","没有"));
	 *		
	 *		try {
	 *		Properties p = new Properties();
 	 *		p.setProperty("code", "id");//将SysFunction对象里的属性名“code”映射到json对象里的属性名“id”
	 *		p.setProperty("title", "name");//将SysFunction对象里的属性名“title”映射到json对象里的属性名“name”
	 *		
	 *		//开始调用解析函数
	 *		return
	 *			TreeNode.parseListToJsonTree(treeList, "code","parentCode",p);
	 *	} catch (Exception e) {
	 *		e.printStackTrace();
	 *	} 
	 * 
* @throws SecurityException java反射异常 * @throws NoSuchFieldException java反射异常 * @throws IllegalArgumentException java反射异常 * @throws IllegalAccessException java反射异常 */ public static String parseListToJsonTree(List entities, String key, String parentKey, Properties fieldPropertyMap) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { return parseListToJsonTree(entities,key,parentKey,fieldPropertyMap,null); } /** * 将对象集合解析为json格式的树形脚本 * @param 集合成员类型 * @param entities 待解析的集合,必须具备有效值 * @param key 对象的唯一标识属性,必须具备有效值 * @param parentKey 父对象的唯一标识属性,必须具备有效值 * @return json格式的树形脚本 * 例如结果如下格式: *
 		
	 * 		[
	 * 				{id:11,name:'诺基亚'}, 
	 * 				{id:12,name:'三星',nodes:[
	 * 					{id:121,name:'I9000(联通版)'},
	 * 					{id:122,name:'I9000(移动版)'},
	 * 					{id:123,name:'Galaxy Naos'}
	 * 				]},
	 * 				{id:13,name:'索爱'},
	 * 				{id:14,name:'TCL'},
	 * 				{id:15,name:'摩托罗拉'}
	 * 		]
	 * 使用示范如下:
	 *	 * //用一个集合模拟数据表的内容,也就是一下集合的内容完全可以查询自数据库
	 *		List treeList = new ArrayList();
	 *		treeList.add(new SysFunction("L01", null, "营销管理","没有"));		
	 *		treeList.add(new SysFunction("L02",null,"客户管理","没有"));
	 *		treeList.add(new SysFunction("L03",null,"服务管理","没有"));	
	 *	 	//营销管理的子功能
	 *		treeList.add(new SysFunction("L0101","L01","创建销售机会","没有"));
	 *		treeList.add(new SysFunction("L0102","L01","指派销售机会","没有"));
	 *		treeList.add(new SysFunction("L0103","L01","制定开发计划","没有"));
	 *		treeList.add(new SysFunction("L0104","L01","执行开发计划","没有"));
	 *		//指派销售机会的子功能		
	 *		treeList.add(new SysFunction("L010201","L0102","经理指派","没有"));
	 *		treeList.add(new SysFunction("L010202","L0102","主管指派","没有"));				
	 *		//客户管理的子功能
	 *		treeList.add(new SysFunction("L0201","L02","客户信息管理","没有"));
	 *		treeList.add(new SysFunction("L0202","L02","客户流失管理","没有"));
	 *		//服务管理子功能
	 *		treeList.add(new SysFunction("L0301","L03","咨询服务管理","没有"));
	 *		treeList.add(new SysFunction("L0302","L03","投诉服务管理","没有"));
	 *		treeList.add(new SysFunction("L0303","L03","查询服务管理","没有"));
	 *		
	 *		try {	
	 *				//开始调用解析函数
	 *			return
	 *				TreeNode.parseListToJsonTree(treeList, "code","parentCode");
	 *	} catch (Exception e) {
	 *		e.printStackTrace();
	 *	} 
	 * 
* @throws SecurityException java反射异常 * @throws NoSuchFieldException java反射异常 * @throws IllegalArgumentException java反射异常 * @throws IllegalAccessException java反射异常 */ public static String parseListToJsonTree(List entities, String key, String parentKey) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { return parseListToJsonTree(entities,key,parentKey,null,null); } /** *
	 * 		将当前TreeNode解析为JSON字串 构造的目标格式示例: 
	 * 		{ 
	 * 			id:1, 
	 * 			name:'手机', 
	 * 			nodes:[
	 * 				{id:11,name:'诺基亚'}, 
	 * 				{id:12,name:'三星',nodes:[
	 * 					{id:121,name:'I9000(联通版)'},
	 * 					{id:122,name:'I9000(移动版)'},
	 * 					{id:123,name:'Galaxy Naos'}
	 * 				]},
	 * 				{id:13,name:'索爱'}
	 * 			]
	 * 		}
	 * 
* */ private String parseTreeNode(TreeNode node) { if (node == null) throw new RuntimeException("节点不能为空"); StringBuilder nodeBuilder = new StringBuilder("{");// JSON对象开始 // 把Map中的键值对构造成json对象属性 for (Map.Entry kvp : node.getTag().entrySet()) { if (kvp.getValue()==null || kvp.getValue().getClass() == String.class) nodeBuilder.append(kvp.getKey() + ":\"" + kvp.getValue() + "\","); else nodeBuilder.append(kvp.getKey() + ":" + kvp.getValue() + ","); } // 构造子节点 nodeBuilder.append("nodes:["); // 子节点开始 for (TreeNode cnode : node.getNodes()) { if (cnode == null) continue; nodeBuilder.append(parseTreeNode(cnode) + ",");// 递归调用ParseTreeNode返回一个完整的JSON字串:"{属性1:value,属性2:value}" } if (nodeBuilder.charAt(nodeBuilder.length() - 1) == ',')// 去掉末尾逗号 nodeBuilder.deleteCharAt(nodeBuilder.length() - 1); nodeBuilder.append("]"); // 子节点结束 nodeBuilder.append("}"); // JSON对象结束 return nodeBuilder.toString(); } /** * 向指定节点及其子孙节点添加一个属性 * * @author jiang * @param node * 被放置属性的节点 * @param isrecursive * 是否递归[当前节点的子孙节点]放置属性 * @param entries * 放置的属性键值对 */ private void _putProperty(TreeNode node, Boolean isrecursive, Map.Entry... entries) { if (entries != null) for (Map.Entry entry : entries) { node.getTag().put(entry.getKey(), entry.getValue()); } if (!isrecursive) return; for (TreeNode n : node.getNodes()) { _putProperty(n, isrecursive, entries); } } /** * 向指定节点及其子孙节点添加一个属性 * * @author jiang * @param node * 被放置属性的节点 * @param isrecursive * 是否递归[当前节点的子孙节点]放置属性 * @param entries * 放置的属性键值对 */ public void putProperty(Boolean isrecursive, Map.Entry... entries) { _putProperty(this, isrecursive, entries); } public interface IParseTreeNodeCallBack{ void processTreeNode(TreeNode node); } }


 
  

我的测试代码如下:

package biz;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import model.TreeNode;

/**
 * 系统功能对象
 * */
class SysFunction {
	
	private String code;
	private String parentCode;
	private String title;
	private String desc;	

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	/**功能编号*/
	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}
	/**父级功能编号*/
	public String getParentCode() {
		return parentCode;
	}

	public void setParentCode(String parentCode) {
		this.parentCode = parentCode;
	}
	/**功能名称,现在树上的节点文本*/
	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}
	
	public SysFunction(String code, String parentCode, String title) {
		super();
		this.code = code;
		this.parentCode = parentCode;
		this.title = title;
	}

	public SysFunction(String code, String parentCode, String title,String desc) {
		super();
		this.code = code;
		this.parentCode = parentCode;
		this.title = title;
		this.desc = desc;
	}

	public SysFunction() {
		super();
	}
}


public class TreeNodeService {
	
	public String getTree(){
//这里用一个集合模拟数据表的内容,也就是一下集合的内容完全可以查询自数据库
//存储树形的数据表应该满足以下基本机构:
/*CREATE TABLE JTREE
(
CODE INT PRIMARY KEY,//当前节点的ID,这个是必须字段,名字无所谓
PARENT_CODE INT REFERENCES JTREE(CODE),//当前节点的父节点ID,这个是必须字段,且必须符合父子引用关系,名字无所谓
TITLE VARCHAR2(32),//节点显示的文本
...,//节点其它信息
...//节点其它信息
);*/
		List treeList = new ArrayList();
		treeList.add(new SysFunction("L01", null, "营销管理","没有"));		
		treeList.add(new SysFunction("L02",null,"客户管理","没有"));
		treeList.add(new SysFunction("L03",null,"服务管理","没有"));		
		//营销管理的子功能
		treeList.add(new SysFunction("L0101","L01","创建销售机会","没有"));
		treeList.add(new SysFunction("L0102","L01","指派销售机会","没有"));
		treeList.add(new SysFunction("L0103","L01","制定开发计划","没有"));
		treeList.add(new SysFunction("L0104","L01","执行开发计划","没有"));
		//指派销售机会的子功能		
		treeList.add(new SysFunction("L010201","L0102","经理指派","没有"));
		treeList.add(new SysFunction("L010202","L0102","主管指派","没有"));				
		//客户管理的子功能
		treeList.add(new SysFunction("L0201","L02","客户信息管理","没有"));
		treeList.add(new SysFunction("L0202","L02","客户流失管理","没有"));
		//服务管理子功能
		treeList.add(new SysFunction("L0301","L03","咨询服务管理","没有"));
		treeList.add(new SysFunction("L0302","L03","投诉服务管理","没有"));
		treeList.add(new SysFunction("L0303","L03","查询服务管理","没有"));
		
		try {
			Properties p = new Properties();
			p.setProperty("code", "id");//将SysFunction对象里的属性名“code”映射到json对象里的属性名“id”
			p.setProperty("title", "name");//将SysFunction对象里的属性名“title”映射到json对象里的属性名“name”
			
			//开始调用解析函数,第五个参数是一个匿名内部类
			return
				TreeNode.parseListToJsonTree(treeList, "code","parentCode",p,new TreeNode.IParseTreeNodeCallBack() {
				
				public void processTreeNode(TreeNode node) {
					node.getTag().put("open",true);//向节点追加一个属性,表示要zTree展开这个节点
					node.getTag().put("click","alert('"+node.getTag().get("id")+"')");//向节点追加一个属性click,表示要求zTree的节点具有响应点击事件的能力
				}
			});
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "[]";
		
	}

}

JSP页面如何使用这个测试呢:

注意id为“treeDemo3"的代码

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@page import="biz.TreeNodeService"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>



	
		
		
		
  		
  		
  		
		
	
	
		

        运行结果,如下图:

        点击节点执行click事件弹出当前节点的编号,参考前面的代码如何实现:

        TreeNode.parseListToJsonTree(treeList, "code","parentCode",p,new TreeNode.IParseTreeNodeCallBack() {
        				
        				public void processTreeNode(TreeNode node) {
        					node.getTag().put("open",true);//向节点追加一个属性,表示要zTree展开这个节点
        					node.getTag().put("click","alert('"+node.getTag().get("id")+"')");//向节点追加一个属性click,表示要求zTree的节点具有响应点击事件的能力
        				}
        			});

        大功告成!!!



         
          
         
          
         
          
         
          
         
          
         
          
         
          
         
          
         
          
         
          
         
          
         
          
         
          
         
          
         
          
         
         

        你可能感兴趣的:(RIA)