- 浏览: 1884665 次
- 性别:
- 来自: 合肥
文章分类
- 全部博客 (514)
- OPEN (41)
- WARN (33)
- EXPER (16)
- RESOURCE (7)
- TOOL (4)
- DWR (10)
- Struts1.x (10)
- Ibtais (18)
- MyEclipse (30)
- Sql Server (64)
- Tomcat (7)
- APACHE (4)
- JSP (18)
- SERVLET (6)
- ENGLISH (0)
- ECSide (8)
- JasperReports (7)
- JAVA (24)
- JS (42)
- XML (26)
- CVS (8)
- Mind (1)
- JQUERY (2)
- IBATIS (6)
- PROJECT (0)
- STRUTS2 (0)
- PROXOOL (0)
- SPRING (4)
- Hibernate (0)
- SSI (0)
- JBPM (11)
- FLEX (3)
- JSON (2)
- GWT (1)
- jeecms v3 (1)
- Flash (2)
- DATA (1)
- ORACLE (3)
- 查询oracle 中逗号分隔字符串中所有值 (1)
最新评论
-
小小西芹菜:
GoEasy web三步轻松实现web实时推送1. 引入goe ...
服务器推送技术 java -
kg_1997:
这个方法太棒了,可以不用to_date函数,实在是棒!!!
java/oracle日期处理 -
wodesunday:
:idea:
SQL的分段统计查询语句 -
wodesunday:
引用
SQL的分段统计查询语句 -
BlueSkator:
讲的有点浅,没有深入进去
tomcat需要的重新发布和重启服务器的几种情况
E3.Tree参考手册
(v1.0)
目录
简介 2
系统要求 2
新增功能 2
升级说明 2
样例部署 2
使用 4
Lib文件清单 4
使用taglib 4
添加JAR到classpath中 8
业务数据对象 8
控制器Servlet 9
JSP页面 11
web.xml配置 11
测试 12
体系结构 12
设计模型 13
API代码片段 20
排序 20
设置节点图标 21
节点过滤 22
构造混合节点树 23
构造动态树 25
自定义TreeBuilder 27
Taglib使用代码片段 27
简单树 27
设置节点图标 27
动态树 28
节点排序 28
反向排序 28
FAQ 29
简介
1. E3.Tree是E3平台下一个用于构造树型UI(menu,tree,outlookbar等)的的组件,
E3.Tree 特色
部署简单,只需要把相关jar放到WEB-INF/lib目录下即可
构造树,菜单等树型UI的开发模式一致,
提供了API和taglib 2种使用方式,使用简单,功能强大
能够很容易把现有的树型UI集成进来,现在支持的有:xtree, ext tree 和yui menu
功能丰富,现在支持的树有 普通树,radio树 ,checkbox树,动态树等
系统要求
JDK1.4X 或者以上版本
E3.tree 有2种使用方式,一种是直接调用API,另外一种是使用taglib,第一种方式只要求jsp1.2,servlet2.3即可。第2种方式需要jsp2.0 servlet2.4
新增功能
提供了taglib的方式来构造树型UI
升级说明
替换E3-Tree.jar
添加commons-beanutils-core.jar
样例部署
把e3.war 放到Tomcat's webapps 目录下,启动服务器,输入地址http://localhost:8080/e3 进入示例主页. 点级 E3.Tree 连接,即可看到示例程序.
示例组图:
使用
Lib文件清单
文件名 版本 说明
E3-Tree.jar 1.0 E3平台的树
E3-TemplateEngine.ja 1.0 E3平台的模板引擎Adapter
commons-logging.jar 1.04 Apache的commons log,
log4j-1.2.14.jar 1.2.14 Apache的log4j
commons-collections-2.1.1.jar 2.1.1 Apache的collections
velocity-1.4.jar 1.4 Apache的模板引擎
commons-beanutils-core.jar 1.6 Apache的BeanUtils,使用里面的PropertyUtils类.
使用taglib
我们先来看看怎么使用taglib.把下面内容命名为E3Tree.jsp,放到例子web应用目录下去,输入地址http://localhost:8080/e3/E3Tree.jsp 看看效果,如果你看到2棵树,说明程序正常没问题,否则请到e3群(21523645)里面问.
<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="e3" uri="/e3/tree/E3Tree.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv=Content-Type content="text/html; charset=utf-8">
<script>
function showSelectedNode(){
var selectModel= tree.getSelectionModel();
var selectNode = selectModel.getSelectedNode();
alert(selectNode.text + selectNode.id );
}
</script>
</HEAD>
<BODY>
<%
java.util.List datas = new java.util.ArrayList();
java.util.Map data = new java.util.HashMap();
data.put("id","10");
data.put("parentId", null );
data.put("name","总部");
datas.add( data );
java.util.Map data1 = new java.util.HashMap();
data1.put("id","1010");
data1.put("parentId", "10" );
data1.put("name","子公司1");
datas.add( data1 );
java.util.Map data2 = new java.util.HashMap();
data2.put("id","1020");
data2.put("parentId", "10" );
data2.put("name","子公司2");
datas.add( data2 );
pageContext.setAttribute("orgs", datas);
%>
<table>
<tr>
<td>
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<e3:tree var="org" items="orgs" builder="extTree">
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
action="javascript:showSelectedNode()"
/>
</e3:tree>
</td>
<td>
<e3:tree var="org" items="orgs" builder="xTree">
<e3:node id="B${org.id}" parentId="B${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
action="javascript:alert('test')"
/>
</e3:tree>
</td>
</tr>
</BODY>
</HTML>
使用taglib步骤
1. 声明taglib
<%@ taglib prefix="e3" uri="/e3/tree/E3Tree.tld" %>
2. 准备业务数据
java.util.List datas = new java.util.ArrayList();
java.util.Map data = new java.util.HashMap();
data.put("id","10");
data.put("parentId", null );
data.put("name","总部");
datas.add( data );
java.util.Map data2 = new java.util.HashMap();
data2.put("id","1020");
data2.put("parentId", "10" );
data2.put("name","子公司2");
datas.add( data2 );
业务数据可以保存在Map或者普通的JAVABEAN中.业务数据必须包含id,parentId,以及节点名称 信息。注意:并不要求他们的属性名是”id” “parented”,”name”,只需要包含了这些信息即可。Id代表节点主键,parentId代表父亲节点主键, name代表节点标题。 如你的业务对象属性名称是orgId, parentOrgId, orgName都可以.
3. 保存业务数据
pageContext.setAttribute("orgs", datas);
可以保存到(pageContext,request, session或application里)
4. 使用taglib显示树
<e3:tree var="org" items="orgs" builder="extTree">
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
action="javascript:showSelectedNode()"
/>
</e3:tree>
Tree标签属性
属性名称 属性类型 备注
var String 用于保存items元素
items String 是业务数据列表对象的key
builder String 用于构造树的builder对象(builder是什么下面会有介绍),可以选值有
[XTree, XLoadTree, RadioXTree, RadioXLoadTree, CheckXTree, CheckXLoadTree, CompositeXTree, CompositeXLoadTree, ExtTree, ExtLoadTree]
如果这些builder不能满足您的需求,你可以指定一个class,只要指定class实现了WebTreeBuilder接口即可.
comparator java.util.Comparator 排序器,用来对树的节点排序. 节点类型为
net.jcreate.e3.tree.support.WebTreeNode
sortProperty String 排序属性名称,默认是按节点的名称来排序的,如果要使用别的属性排序,则需要设置该值.:如果你的业务对象有排序属性时,则需要指定,如sortProperty=”orgOrder”. 注意:如果设置了comparator属性,那么该值无效.
reverse boolean 是否反向排序,默认false
node标签负责将业务对象转换成树节点对象.node taglib包含的常规属性有
属性名称 属性类型 备注
id String 节点id
parentId String 父亲节点id
name String 节点名称(标题)
icon String 节点图标
openIcon String 节点展开时的图标
action String 是单节点时的动作,可以是一个url也可以是javascript函数.如果是函数,则必须以javascript:开头.如:action=”javascript: alert(‘demo’)”
nodeProperty String 用于设置节点类型,有效值radio,checkbox和none, nodeProperty的默认值是none,表示节点旁边没有其他控件,为radio时,节点旁边会有个单选按纽,为checkbox时,节点旁边会有个checkbox按纽.
selected boolean 是否选种节点,只有当nodeProperty为radio或checkbox时才有效,默认值为false
disabled boolean 是否禁用节点,默认值为false
value String 节点帮定的值,只有当nodeProperty为radio或checkbox时才有效,默认值为空(长度为0的字符串)
dragable boolean 节点是否允许拖动,默认值为false
dropable boolean 是否允许停放拖动的节点,默认值为false
添加JAR到classpath中
现在来看调用API的使用方式.新建一个web项目,把Lib文件清单中的jar全部添加到classpath中
业务数据对象
package net.jcreate.e3.samples.tree;
public class Org {
private String id;
private String parentId;
private String name;
private int viewOrder;
public Org(){
}
public Org(String pId, String pParentId, String pName, int pViewOrder){
this.id = pId;
this.parentId = pParentId;
this.name = pName;
this.viewOrder = pViewOrder;
}
public int getViewOrder() {
return viewOrder;
}
public void setViewOrder(int viewOrder) {
this.viewOrder = viewOrder;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
}
控制器Servlet
package net.jcreate.e3.samples.tree;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.jcreate.e3.tree.Node;
import net.jcreate.e3.tree.TreeDirector;
import net.jcreate.e3.tree.TreeModel;
import net.jcreate.e3.tree.UncodeException;
import net.jcreate.e3.tree.UserDataUncoder;
import net.jcreate.e3.tree.support.AbstractWebTreeModelCreator;
import net.jcreate.e3.tree.support.DefaultTreeDirector;
import net.jcreate.e3.tree.support.WebTreeBuilder;
import net.jcreate.e3.tree.support.WebTreeNode;
import net.jcreate.e3.tree.xtree.XTreeBuilder;
public class TestServlet extends HttpServlet{
protected void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
//业务数据
List orgs = new ArrayList();
Org jcjtOrg = new Org("001",null,"进创集团", 1);
Org jcrjOrg = new Org("001001","001","进创软件", 1);
Org xrjOrg = new Org("0010010011","001001","X软件公司", 1);
Org yrjOrg = new Org("0010010012","001001","Y软件公司", 2);
Org zrjOrg = new Org("0010010013","001001","Z软件公司", 3);
orgs.add(jcjtOrg);
orgs.add(jcrjOrg);
orgs.add(xrjOrg);
orgs.add(yrjOrg);
orgs.add(zrjOrg);
//业务数据解码器,从业务数据中分解出id和parentid
UserDataUncoder orgUncoder = new UserDataUncoder(){
public Object getID(Object pUserData) throws UncodeException {
Org org = (Org)pUserData;
return org.getId();
}
public Object getParentID(Object pUserData) throws UncodeException {
Org org = (Org)pUserData;
return org.getParentId();
}
};
//Tree模型构造器,用于生成树模型
AbstractWebTreeModelCreator treeModelCreator =
new AbstractWebTreeModelCreator(){
//该方法负责将业务数据映射到树型节点
protected Node createNode(Object pUserData, UserDataUncoder pUncoder) {
Org org = (Org)pUserData;
WebTreeNode result = new WebTreeNode(org.getName(), "org" + org.getId());
//action是点击按纽执行的方法.可以是url,或者javascript函数
result.setAction("javascript:alert(' " + org.getName() + "')");
return result;
}
};
treeModelCreator.init(pRequest);
TreeModel treeModel = treeModelCreator.create(orgs,orgUncoder);
TreeDirector director = new DefaultTreeDirector();//构造树导向器
WebTreeBuilder treeBuilder = new XTreeBuilder();//构造树Builder
treeBuilder.init(pRequest);
director.build(treeModel, treeBuilder);//执行构造
String treeScript = treeBuilder.getTreeScript();//获取构造树的脚本
pRequest.setAttribute("treeScript", treeScript);//保存到request,以便页面使用
pRequest.getRequestDispatcher("XTree.jsp").forward(pRequest,pResponse);
}
}
上面代码构造是普通树,如果要构造带checkbox/radiobox的树,只需要将
WebTreeBuilder treeBuilder = new XTreeBuilder()
这行代码换成
WebTreeBuilder treeBuilder = new CheckXTreeBuilder ()
或
WebTreeBuilder treeBuilder = new RadioXTreeBuilder ()
即可
JSP页面
命名为XTree.jsp,放在web应用跟目录下(WEB-INF所在目录);
%@ page contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv=Content-Type content="text/html; charset=utf-8">
</HEAD>
<BODY>
<%= request.getAttribute("treeScript") %>
</BODY>
</HTML>
web.xml配置
把下面配置添加到web.xml文件
<listener> <listener-class>net.jcreate.e3.tree.loader.LoadResourcesListener</listener-class>
</listener>
<filter>
<filter-name>e3/characterEncodingFilter</filter-name>
<filter-class>net.jcreate.e3.web.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>e3/characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>net.jcreate.e3.samples.tree.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/testServlet</url-pattern>
</servlet-mapping>
测试
将web项目部署到Tomcat's webapps的test目录
输入地址 http://localhost:8080/test/testServlet 如果看到树,恭喜你成功了!
体系结构
db
xml
ldap
mem
灰色大框图里的部件是E3.Tree的,框外是E3.Tree需要的输入和输出
业务数据的来源会很多,常见的有db,xml,ldap和内存,所以对于数据如何获取,在E3.Tree里不做定义
业务数据以Collection的形式提交给E3.Tree
解码器:负责业务对象解码,分解出ID和parentID
模型构造器:使用解码器对业务数据进行处理,生成树模型
树模型:就是树的内存结构,可以有一个或者多个跟节点
树构造器:负责对树模型中的节点进行处理,将内存节点翻译成用于与构造特定树型UI的脚本.
导向器:负责树模型的节点遍历,驱动树构造器的处理.
排序器:负责节点的排序
访问器:负责节点过滤或者节点遍历.
设计模型
E3.Tree采用的核心设计模式是builder模式,如果您对builder还不大清楚,可以找gof设计模式树翻翻。
业务对象
具有树型属性(构造树型结构需要的属性)的业务数据对象,从这类对象中可以分解出ID,和parentID.这类业务对象通常是会下面几种结构中的一种.
如:
A{
Private String id;
Private String parentId ;
}
B{
Private String ID; //ID的值是 0000_0001, 0000_0001_0001这种形式
}
E3.Tree对业务数据的唯一要求就是:从业务对象中要能分解出ID和父亲ID。ID和parentID可以是任何数据类型
业务数据集
业务对象的集合,该集合里的业务对象是线型关系。彼此之间没关系.
由于业务数据的来源会很多,常见的有db,xml,ldap和内存,所以对于数据如何获取,在E3.Tree里不做定义.E3.Tree只要求以Collection的形式传递给TreeModelCreator即可.
节点Node
跟数据结构里的节点概念一致,包含的方法有
public interface Node {
//获取父亲节点
public Node getParent();
//设置父亲节点
public void setParent(Node pParent);
//设置业务对象
public void setUserData(Object pUserData);
//获取业务对象
public Object getUserData();
//获取所有儿子
public Iterator getChildren();
//删除儿子
public void detachNode(Node pNode);
//添加儿子
public void addNode(Node pNode);
//是否是叶子节点
public boolean isLeaf();
//是否是根节点
public boolean isRoot();
//儿子节点个数
public int getChildCount();
//获取指定位置节点,序号从0开始
public Node getChildAt(int pChildIndex);
//获取儿子节点的序号
public int getIndex(Node node);
}
树模型TreeModel
TreeModel 跟数据结构里的树的概念对应. TreeModel可以有一个跟节点也可以有多个跟节点,所以可以是树有可以是森林.
/**
* 树,森林
* @author new
*
*/
public interface TreeModel {
/**
* 获取跟节点,可以是多个跟节点.
* @return
*/
public Iterator getRootNodes();
}
解码器UserDataUncoder
负责业务对象解码,分解出ID和parentID. 如果分解过程出错,抛UncodeException或它的派生类异常.TreeModelCreator会使用它对业务对象进行解码(我把从业务对象中分解出ID和parentID的过程叫做解码)处理.
/**
* 负责业务对象解码,分解出ID和parentID
* @author new
*
*/
public interface UserDataUncoder {
public Object getID(Object pUserData) throws UncodeException;
public Object getParentID(Object pUserData) throws UncodeException;
}
树模型构造器TreeModelCreator
负责创建TreeModel对象.注意,存在2个create方法,请看注释,理解2种方法的区别.
/**
* 将业务数据构造成TreeModel
* @author new
*
*/
public interface TreeModelCreator {
/**
* 创建树模型
* @param pUserDatas 业务数据,至少要存在一个跟节点(不存在父亲节点的节点)
* 要求集合元素读必须实现Uncodable接口
* @return 返回根节点.
* @throws CreateTreeModelException 如果集合元素没有实现Uncodable接口,会抛出
* ClassCastException异常
*/
public TreeModel create(Collection pUserDatas) throws CreateTreeModelException;
/**
* 创建树模型
* @param pUserDatas 业务数据,至少要存在一个跟节点(不存在父亲节点的节点)
* @param pUncoder 解码器,对每个业务数据进行解码,返回主键对象和父亲主键对象.
* @return 返回根节点.
* @throws CreateTreeModelException
*/
public TreeModel create(Collection pUserDatas, UserDataUncoder pUncoder) throws CreateTreeModelException;
}
树构造器TreeBuilder
负责对树模型中的节点进行处理,将内存节点翻译成用于与构造特定树型UI的脚本.
TreeBuilder包含一系列树型UI构造过程方法。请看注释,理解各方法的含义.
public interface TreeBuilder {
/**
* 开始构造树
* @throws BuildTreeException
*/
public void buildTreeStart() throws BuildTreeException;
/**
* 结束构造树
* @throws BuildTreeException
*/
public void buildTreeEnd() throws BuildTreeException;
/**
* 开始构造普通节点(除跟节点之外的节点)
* @param pNode 当前节点
* @param pParentNode 父亲节点
* @param pLevel 节点级别,根节点为0级,根节点直接儿子节点为1级,依次类推,2,3,....
* @param pRow 在兄弟节点里的序号,第一个兄弟节点为0,第2个为1,第3个为2,依次类推.3,4....
* @throws BuildTreeException
*/
public void buildNodeStart(Node pNode, Node pParentNode, int pLevel, int pRow)
throws BuildTreeException;
/**
* 结束构造普通节点(除跟节点之外的节点)
* @param pNode 当前节点
* @param pParentNode 父亲节点
* @param pLevel 节点级别,根节点为0级,根节点直接儿子节点为1级,依次类推,2,3,....
* @param pRow 在兄弟节点里的序号,第一个兄弟节点为0,第2个为1,第3个为2,依次类推.3,4....
* @throws BuildTreeException
*/
public void buildNodeEnd(Node pNode, Node pParentNode, int pLevel, int pRow)
throws BuildTreeException;
/**
* 开始构造跟节点
* @param pRootNode 跟节点,非空
* @param pLevel 根节点级别
* @param pRow 在兄弟节点里的序号,第一个兄弟节点为0,第2个为1,第3个为2,依次类推.3,4....
* @throws BuildTreeException
*/
public void buildRootNodeStart(Node pRootNode,int pLevel, int pRow) throws BuildTreeException;
/**
* 结束构造跟节点
* @param pRootNode 跟节点,非空
* @param pLevel 根节点级别
* @param pRow 在兄弟节点里的序号,第一个兄弟节点为0,第2个为1,第3个为2,依次类推.3,4....
* @throws BuildTreeException
*/
public void buildRootNodeEnd(Node pRootNode, int pLevel, int pRow) throws BuildTreeException;
}
导向器TreeDirector
负责树模型的节点遍历,驱动树构造器的处理.
public interface TreeDirector {
/**
* 设置节点比较器
* @param pComparator 节点比较器,用于进行兄弟节点比较
*/
public void setComparator(Comparator pComparator);
/**
* 节点访问者
* @param pVisitor
*/
public void setNodeVisitor(NodeVisitor pVisitor);
/**
* build树
* @param pTree
* @param pTreeBuilder Tree构造器(非空)
* @throws BuildTreeException
*/
public void build(TreeModel pTree, TreeBuilder pTreeBuilder) throws BuildTreeException;
}
排序器Comparator
负责节点的排序处理.排序器是使用jdk自带的java.util.Comparator
访问器NodeVisitor
负责节点过滤或者节点遍历.
/**
* 在使用TreeBuilder构造节点前进行访问.可以通过NodeVisitor
* 设置Node的属性,过滤节点.当访问一个节点返回false时,
* 该节点和他所有儿子节点不会传递个TreeBuilder
* 节点访问.
* @author 黄云辉
*
*/
public interface NodeVisitor {
public boolean visit(Node pNode);
}
API代码片段
排序
节点默认是不排序,如果要排序,需要给导向器TreeDirector设置排序器.
net.jcreate.e3.tree.support.DefaultNodeComparator是E3.Tree内置的排序器,根据节点名称排序.
TreeDirector director = new DefaultTreeDirector();//构造树导向器
director.setComparator(new DefaultNodeComparator());
如果要根据特定属性排序,则需要自己实现排序器,通常只需要从
net.jcreate.e3.tree.support.AbstractNodeComparator派生即可
TreeDirector director = new DefaultTreeDirector();//构造树导向器
director.setComparator(new AbstractNodeComparator(){
protected Comparable getComparableProperty(Node pNode) {
Object userData = pNode.getUserData();//获取业务对象
Org org = (Org)userData;
return new Integer( org.getViewOrder() );
}
});
设置节点图标
设置节点图标
//Tree模型构造器,用于生成树模型
AbstractWebTreeModelCreator treeModelCreator =
new AbstractWebTreeModelCreator(){
//该方法负责将业务数据映射到树型节点
protected Node createNode(Object pUserData, UserDataUncoder pUncoder) {
Org org = (Org)pUserData;
WebTreeNode result = new WebTreeNode(org.getName(), "org" + org.getId());
result.setIcon(this.getUrl("/e3/samples/tree/Org.gif"));
result.setOpenIcon(this.getUrl("/e3/samples/tree/Org.gif"));
//action是点击按纽执行的方法.可以是url,或者javascript函数
result.setAction("javascript:alert(' " + org.getName() + "')");
return result;
}
};
类 net.jcreate.e3.tree.support. DefaultNode
属性 名称 备注
name 节点名称
类 net.jcreate.e3.tree.support.WebTreeNode
属性 名称 备注
id 节点ID 注意:该ID要是合法标识符号,因为TreeBuilder可能使用该ID作为js变量
icon 节点图标 收缩时图标
openIcon 打开时的图标 展开时图标
action 动作 单击节点时的动作,可以是javascript,也可以是超级连接 如: javascript:orgClick();
/e3/a.jsp
selected 是否被选种
disabled 是否被禁用
nodeProperty 节点属性 目前只有3种属性radio,checkbox和none
这个属性需特别说明:一个树的最终形态是由TreeBuilder来决定的。所以如果采用CheckXTreeBuilder或RadioXTreeBuilder构造树时 ,该属性是没有用的。只有当一棵树中既有check节点又有radio节点或普通节点时,该属性才有效.
类 net.jcreate.e3.tree.support. WebTreeDynamicNode
属性 名称 备注
subTreeURL 子树URL 负责导入子树的URL
节点过滤
过滤掉所有没有儿子节点的跟节点.返回false的节点以及他的儿子节点都会被过滤掉
director.setNodeVisitor(new NodeVisitor(){
public boolean visit(Node pNode) {
boolean noChildRoot = pNode.isRoot() && (pNode.getChildCount() == 0);
if (noChildRoot).{
return false;
} else {
return true;
}
}
});
设置所有叶子节点图标
director.setNodeVisitor(new NodeVisitor(){
public boolean visit(Node pNode) {
if (pNode.isLeaf() ){
result.setIcon(RequestUtil.getUrl("/e3/samples/tree/Org.gif", pRequest));
result.setOpenIcon(RequestUtil.getUrl("/e3/samples/tree/Org.gif", pRequest));
}
return true;
}
});
说明:RequestUtil的包名是net.jcreate.e3.tree.support
pRequest是HttpServletRequest对象,因为是在匿名类里使用,所以pRequest必须是final 类型的.否则编译不能通过.
构造混合节点树
这棵树有机构节点和用户节点,用户节点挂在机构下.用户有个属性指向所属机构.
混合节点的构造跟单节点的构造基本相同。就有一点要特别注意:因为是多节点,可能存在
主键冲突的问题,所以构造节点ID和做节点分解的时候,需要带上前缀.
public void showMixTree(final HttpServletRequest pRequest,
final HttpServletResponse pResponse) throws Exception{
//业务数据
List orgs = new ArrayList();
Org jcjtOrg = new Org("001",null,"进创集团", 1);
Org jcrjOrg = new Org("001001","001","进创软件", 1);
orgs.add(jcjtOrg);
orgs.add(jcrjOrg);
User huangy = new User("huangyh", "黄云辉", "001");//直属集团
User guohp = new User("guohp", "郭鸿鹏", "001");//直属集团
User caogp = new User("caogp", "曹高平", "001001");//进创软件
List users = new ArrayList();
users.add(huangy);
users.add(guohp);
users.add(caogp);
List allData = new ArrayList();
allData.addAll(orgs);
allData.addAll(users);
//业务数据解码器,从业务数据中分解出id和parentid
UserDataUncoder uncoder = new UserDataUncoder(){
final String USERID_PREFIX = "USER_";//为了避免用户ID和机构ID出现相同的情况,所以构造树时
//所有用户ID带个前缀.
public Object getID(Object pUserData) throws UncodeException {
if ( pUserData instanceof Org){
Org org = (Org)pUserData;
return org.getId();
}
if ( pUserData instanceof User ){
User user = (User)pUserData;
return USERID_PREFIX + user.getId();
}
throw new UncodeException("不支持的数据对象." + pUserData.getClass().getName());
}
public Object getParentID(Object pUserData) throws UncodeException {
if ( pUserData instanceof Org){
Org org = (Org)pUserData;
return org.getParentId();
}
if ( pUserData instanceof User ){
User user = (User)pUserData;
return user.getOrgId();
}
throw new UncodeException("不支持的数据对象." + pUserData.getClass().getName());
}
};
//Tree模型构造器,用于生成树模型
AbstractWebTreeModelCreator treeModelCreator =
new AbstractWebTreeModelCreator(){
//该方法负责将业务数据映射到树型节点
protected Node createNode(Object pUserData, UserDataUncoder pUncoder) {
if ( pUserData instanceof Org ){
Org org = (Org)pUserData;
WebTreeNode result = new WebTreeNode(org.getName(), "org" + org.getId());
result.setIcon(this.getUrl("/e3/samples/tree/Org.gif"));
result.setOpenIcon(this.getUrl("/e3/samples/tree/Org.gif"));
//action是点击按纽执行的方法.可以是url,或者javascript函数
result.setAction("javascript:alert(' " + org.getName() + "')");
return result;
}
if ( pUserData instanceof User ){
User user = (User)pUserData;
WebTreeNode result = new WebTreeNode(user.getName(), "user" + user.getId());
result.setIcon(this.getUrl("/e3/samples/tree/User.gif"));
result.setOpenIcon(this.getUrl("/e3/samples/tree/User.gif"));
//action是点击按纽执行的方法.可以是url,或者javascript函数
result.setAction("javascript:alert(' " + user.getName() + "')");
return result;
}
throw new UncodeException("不支持的数据对象." + pUserData.getClass().getName());
}
};
treeModelCreator.init(pRequest);
TreeModel treeModel = treeModelCreator.create(allData,uncoder);
TreeDirector director = new DefaultTreeDirector();//构造树导向器
WebTreeBuilder treeBuilder = new XTreeBuilder();//构造树Builder
treeBuilder.init(pRequest);
director.build(treeModel, treeBuilder);//执行构造
String treeScript = treeBuilder.getTreeScript();//获取构造树的脚本
pRequest.setAttribute("treeScript", treeScript);//保存到request,以便页面使用
pRequest.getRequestDispatcher("/e3/samples/tree/XTree.jsp").forward(pRequest,pResponse);
}
构造动态树
动态树的构造分2个过程,第一个过程构造顶层静态节点(第一次要显示的节点),第2个过程负责导入特定节点的儿子节点数据.
通常第一个过程只显示跟节点,下面的代码
public void showLoadTree(final HttpServletRequest pRequest,
final HttpServletResponse pResponse) throws Exception{
WebTreeDynamicNode rootNode = new WebTreeDynamicNode("进创集团", "org" + "001");
rootNode.setSubTreeURL(
RequestUtil.getUrl("/servlet/xtreeServlet?_actionType=" +
"loadSubOrgs&parentID=" + "001", pRequest));
DefaultTreeModel treeModel = new DefaultTreeModel();
treeModel.addRootNode(rootNode);
TreeDirector director = new DefaultTreeDirector();
director.setComparator(new DefaultNodeComparator());
WebTreeBuilder treeBuilder = new XLoadTreeBuilder();
treeBuilder.init(pRequest);
director.build(treeModel, treeBuilder);
String treeScript = treeBuilder.getTreeScript();
pRequest.setAttribute("treeScript", treeScript);
pRequest.getRequestDispatcher("/e3/samples/tree/XTree.jsp").forward(pRequest,pResponse);
}
说明:
1. 动态节点对象必须是WebTreeDynamicNode
2. setSubTreeURL方法用于设置导入儿子节点数据的url
下面这个方法用于生成儿子节点XML
public void loadSubOrgs(final HttpServletRequest pRequest,
final HttpServletResponse pResponse) throws Exception{
final String parentID = pRequest.getParameter("parentID");
TreeService treeService = TreeBeanFactory.getTreeService();
List subOrgs = treeService.getSubOrgs(parentID);
UserDataUncoder orgUncoder = new OrgUncoder();
AbstractWebTreeModelCreator treeModelCreator =
new AbstractWebTreeModelCreator(){
protected Node createNode(Object pUserData, UserDataUncoder pUncoder) {
Org org = (Org)pUserData;
WebTreeDynamicNode result = new WebTreeDynamicNode(org.getName(), "org" +org.getId());
result.setSubTreeURL(
getUrl("/servlet/xtreeServlet?_actionType=" +
"loadSubOrgs&parentID=" + org.getId()));
return result;
}
};
treeModelCreator.init(pRequest);
TreeModel treeModel = treeModelCreator.create(subOrgs,orgUncoder);
TreeDirector director = new DefaultTreeDirector();
director.setComparator(new DefaultNodeComparator());
WebTreeBuilder treeBuilder = new XLoadSubTreeBuilder();
treeBuilder.init(pRequest);
director.build(treeModel, treeBuilder);
String treeScript = treeBuilder.getTreeScript();
pResponse.setBufferSize(1024*10);
pResponse.setContentType("text/xml;charset=utf-8");
pResponse.getWriter().write(treeScript);
pResponse.flushBuffer();
return;
}
自定义TreeBuilder
Todo
Taglib使用代码片段
简单树
<e3:tree var="org" items="orgs" >
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"/>
</e3:tree>
设置节点图标
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<e3:tree var="org" items="orgs" >
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
/>
</e3:tree>
动态树
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<c:url var="subTree" value="/servlet/xtreeServlet?_actionType=loadExtSubOrgs&parentID=001"/>
<e3:tree var="org" items="orgs" builder="ExtLoadTree" >
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
subTreeURL="${subTree}"
cls="dynamic"
/>
</e3:tree>
节点排序
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<e3:tree var="org" items="orgs" sortProperty="viewOrder" >
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
/>
</e3:tree>
反向排序
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<e3:tree var="org" items="orgs" sortProperty="viewOrder" reverse="true">
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
/>
</e3:tree>
FAQ
1. 我用的web框架是struts/jsf/webwork/,可以用E3.Tree吗?
E3.Tree对Web 框架只有一个要求,就是能取到HttpServletRequest对象,只要满足这个要求,都可以使用.显然上面这几个框架都可以使用E3.Tree.
(v1.0)
目录
简介 2
系统要求 2
新增功能 2
升级说明 2
样例部署 2
使用 4
Lib文件清单 4
使用taglib 4
添加JAR到classpath中 8
业务数据对象 8
控制器Servlet 9
JSP页面 11
web.xml配置 11
测试 12
体系结构 12
设计模型 13
API代码片段 20
排序 20
设置节点图标 21
节点过滤 22
构造混合节点树 23
构造动态树 25
自定义TreeBuilder 27
Taglib使用代码片段 27
简单树 27
设置节点图标 27
动态树 28
节点排序 28
反向排序 28
FAQ 29
简介
1. E3.Tree是E3平台下一个用于构造树型UI(menu,tree,outlookbar等)的的组件,
E3.Tree 特色
部署简单,只需要把相关jar放到WEB-INF/lib目录下即可
构造树,菜单等树型UI的开发模式一致,
提供了API和taglib 2种使用方式,使用简单,功能强大
能够很容易把现有的树型UI集成进来,现在支持的有:xtree, ext tree 和yui menu
功能丰富,现在支持的树有 普通树,radio树 ,checkbox树,动态树等
系统要求
JDK1.4X 或者以上版本
E3.tree 有2种使用方式,一种是直接调用API,另外一种是使用taglib,第一种方式只要求jsp1.2,servlet2.3即可。第2种方式需要jsp2.0 servlet2.4
新增功能
提供了taglib的方式来构造树型UI
升级说明
替换E3-Tree.jar
添加commons-beanutils-core.jar
样例部署
把e3.war 放到Tomcat's webapps 目录下,启动服务器,输入地址http://localhost:8080/e3 进入示例主页. 点级 E3.Tree 连接,即可看到示例程序.
示例组图:
使用
Lib文件清单
文件名 版本 说明
E3-Tree.jar 1.0 E3平台的树
E3-TemplateEngine.ja 1.0 E3平台的模板引擎Adapter
commons-logging.jar 1.04 Apache的commons log,
log4j-1.2.14.jar 1.2.14 Apache的log4j
commons-collections-2.1.1.jar 2.1.1 Apache的collections
velocity-1.4.jar 1.4 Apache的模板引擎
commons-beanutils-core.jar 1.6 Apache的BeanUtils,使用里面的PropertyUtils类.
使用taglib
我们先来看看怎么使用taglib.把下面内容命名为E3Tree.jsp,放到例子web应用目录下去,输入地址http://localhost:8080/e3/E3Tree.jsp 看看效果,如果你看到2棵树,说明程序正常没问题,否则请到e3群(21523645)里面问.
<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="e3" uri="/e3/tree/E3Tree.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv=Content-Type content="text/html; charset=utf-8">
<script>
function showSelectedNode(){
var selectModel= tree.getSelectionModel();
var selectNode = selectModel.getSelectedNode();
alert(selectNode.text + selectNode.id );
}
</script>
</HEAD>
<BODY>
<%
java.util.List datas = new java.util.ArrayList();
java.util.Map data = new java.util.HashMap();
data.put("id","10");
data.put("parentId", null );
data.put("name","总部");
datas.add( data );
java.util.Map data1 = new java.util.HashMap();
data1.put("id","1010");
data1.put("parentId", "10" );
data1.put("name","子公司1");
datas.add( data1 );
java.util.Map data2 = new java.util.HashMap();
data2.put("id","1020");
data2.put("parentId", "10" );
data2.put("name","子公司2");
datas.add( data2 );
pageContext.setAttribute("orgs", datas);
%>
<table>
<tr>
<td>
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<e3:tree var="org" items="orgs" builder="extTree">
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
action="javascript:showSelectedNode()"
/>
</e3:tree>
</td>
<td>
<e3:tree var="org" items="orgs" builder="xTree">
<e3:node id="B${org.id}" parentId="B${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
action="javascript:alert('test')"
/>
</e3:tree>
</td>
</tr>
</BODY>
</HTML>
使用taglib步骤
1. 声明taglib
<%@ taglib prefix="e3" uri="/e3/tree/E3Tree.tld" %>
2. 准备业务数据
java.util.List datas = new java.util.ArrayList();
java.util.Map data = new java.util.HashMap();
data.put("id","10");
data.put("parentId", null );
data.put("name","总部");
datas.add( data );
java.util.Map data2 = new java.util.HashMap();
data2.put("id","1020");
data2.put("parentId", "10" );
data2.put("name","子公司2");
datas.add( data2 );
业务数据可以保存在Map或者普通的JAVABEAN中.业务数据必须包含id,parentId,以及节点名称 信息。注意:并不要求他们的属性名是”id” “parented”,”name”,只需要包含了这些信息即可。Id代表节点主键,parentId代表父亲节点主键, name代表节点标题。 如你的业务对象属性名称是orgId, parentOrgId, orgName都可以.
3. 保存业务数据
pageContext.setAttribute("orgs", datas);
可以保存到(pageContext,request, session或application里)
4. 使用taglib显示树
<e3:tree var="org" items="orgs" builder="extTree">
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
action="javascript:showSelectedNode()"
/>
</e3:tree>
Tree标签属性
属性名称 属性类型 备注
var String 用于保存items元素
items String 是业务数据列表对象的key
builder String 用于构造树的builder对象(builder是什么下面会有介绍),可以选值有
[XTree, XLoadTree, RadioXTree, RadioXLoadTree, CheckXTree, CheckXLoadTree, CompositeXTree, CompositeXLoadTree, ExtTree, ExtLoadTree]
如果这些builder不能满足您的需求,你可以指定一个class,只要指定class实现了WebTreeBuilder接口即可.
comparator java.util.Comparator 排序器,用来对树的节点排序. 节点类型为
net.jcreate.e3.tree.support.WebTreeNode
sortProperty String 排序属性名称,默认是按节点的名称来排序的,如果要使用别的属性排序,则需要设置该值.:如果你的业务对象有排序属性时,则需要指定,如sortProperty=”orgOrder”. 注意:如果设置了comparator属性,那么该值无效.
reverse boolean 是否反向排序,默认false
node标签负责将业务对象转换成树节点对象.node taglib包含的常规属性有
属性名称 属性类型 备注
id String 节点id
parentId String 父亲节点id
name String 节点名称(标题)
icon String 节点图标
openIcon String 节点展开时的图标
action String 是单节点时的动作,可以是一个url也可以是javascript函数.如果是函数,则必须以javascript:开头.如:action=”javascript: alert(‘demo’)”
nodeProperty String 用于设置节点类型,有效值radio,checkbox和none, nodeProperty的默认值是none,表示节点旁边没有其他控件,为radio时,节点旁边会有个单选按纽,为checkbox时,节点旁边会有个checkbox按纽.
selected boolean 是否选种节点,只有当nodeProperty为radio或checkbox时才有效,默认值为false
disabled boolean 是否禁用节点,默认值为false
value String 节点帮定的值,只有当nodeProperty为radio或checkbox时才有效,默认值为空(长度为0的字符串)
dragable boolean 节点是否允许拖动,默认值为false
dropable boolean 是否允许停放拖动的节点,默认值为false
添加JAR到classpath中
现在来看调用API的使用方式.新建一个web项目,把Lib文件清单中的jar全部添加到classpath中
业务数据对象
package net.jcreate.e3.samples.tree;
public class Org {
private String id;
private String parentId;
private String name;
private int viewOrder;
public Org(){
}
public Org(String pId, String pParentId, String pName, int pViewOrder){
this.id = pId;
this.parentId = pParentId;
this.name = pName;
this.viewOrder = pViewOrder;
}
public int getViewOrder() {
return viewOrder;
}
public void setViewOrder(int viewOrder) {
this.viewOrder = viewOrder;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
}
控制器Servlet
package net.jcreate.e3.samples.tree;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.jcreate.e3.tree.Node;
import net.jcreate.e3.tree.TreeDirector;
import net.jcreate.e3.tree.TreeModel;
import net.jcreate.e3.tree.UncodeException;
import net.jcreate.e3.tree.UserDataUncoder;
import net.jcreate.e3.tree.support.AbstractWebTreeModelCreator;
import net.jcreate.e3.tree.support.DefaultTreeDirector;
import net.jcreate.e3.tree.support.WebTreeBuilder;
import net.jcreate.e3.tree.support.WebTreeNode;
import net.jcreate.e3.tree.xtree.XTreeBuilder;
public class TestServlet extends HttpServlet{
protected void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
//业务数据
List orgs = new ArrayList();
Org jcjtOrg = new Org("001",null,"进创集团", 1);
Org jcrjOrg = new Org("001001","001","进创软件", 1);
Org xrjOrg = new Org("0010010011","001001","X软件公司", 1);
Org yrjOrg = new Org("0010010012","001001","Y软件公司", 2);
Org zrjOrg = new Org("0010010013","001001","Z软件公司", 3);
orgs.add(jcjtOrg);
orgs.add(jcrjOrg);
orgs.add(xrjOrg);
orgs.add(yrjOrg);
orgs.add(zrjOrg);
//业务数据解码器,从业务数据中分解出id和parentid
UserDataUncoder orgUncoder = new UserDataUncoder(){
public Object getID(Object pUserData) throws UncodeException {
Org org = (Org)pUserData;
return org.getId();
}
public Object getParentID(Object pUserData) throws UncodeException {
Org org = (Org)pUserData;
return org.getParentId();
}
};
//Tree模型构造器,用于生成树模型
AbstractWebTreeModelCreator treeModelCreator =
new AbstractWebTreeModelCreator(){
//该方法负责将业务数据映射到树型节点
protected Node createNode(Object pUserData, UserDataUncoder pUncoder) {
Org org = (Org)pUserData;
WebTreeNode result = new WebTreeNode(org.getName(), "org" + org.getId());
//action是点击按纽执行的方法.可以是url,或者javascript函数
result.setAction("javascript:alert(' " + org.getName() + "')");
return result;
}
};
treeModelCreator.init(pRequest);
TreeModel treeModel = treeModelCreator.create(orgs,orgUncoder);
TreeDirector director = new DefaultTreeDirector();//构造树导向器
WebTreeBuilder treeBuilder = new XTreeBuilder();//构造树Builder
treeBuilder.init(pRequest);
director.build(treeModel, treeBuilder);//执行构造
String treeScript = treeBuilder.getTreeScript();//获取构造树的脚本
pRequest.setAttribute("treeScript", treeScript);//保存到request,以便页面使用
pRequest.getRequestDispatcher("XTree.jsp").forward(pRequest,pResponse);
}
}
上面代码构造是普通树,如果要构造带checkbox/radiobox的树,只需要将
WebTreeBuilder treeBuilder = new XTreeBuilder()
这行代码换成
WebTreeBuilder treeBuilder = new CheckXTreeBuilder ()
或
WebTreeBuilder treeBuilder = new RadioXTreeBuilder ()
即可
JSP页面
命名为XTree.jsp,放在web应用跟目录下(WEB-INF所在目录);
%@ page contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv=Content-Type content="text/html; charset=utf-8">
</HEAD>
<BODY>
<%= request.getAttribute("treeScript") %>
</BODY>
</HTML>
web.xml配置
把下面配置添加到web.xml文件
<listener> <listener-class>net.jcreate.e3.tree.loader.LoadResourcesListener</listener-class>
</listener>
<filter>
<filter-name>e3/characterEncodingFilter</filter-name>
<filter-class>net.jcreate.e3.web.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>e3/characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>net.jcreate.e3.samples.tree.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/testServlet</url-pattern>
</servlet-mapping>
测试
将web项目部署到Tomcat's webapps的test目录
输入地址 http://localhost:8080/test/testServlet 如果看到树,恭喜你成功了!
体系结构
db
xml
ldap
mem
灰色大框图里的部件是E3.Tree的,框外是E3.Tree需要的输入和输出
业务数据的来源会很多,常见的有db,xml,ldap和内存,所以对于数据如何获取,在E3.Tree里不做定义
业务数据以Collection的形式提交给E3.Tree
解码器:负责业务对象解码,分解出ID和parentID
模型构造器:使用解码器对业务数据进行处理,生成树模型
树模型:就是树的内存结构,可以有一个或者多个跟节点
树构造器:负责对树模型中的节点进行处理,将内存节点翻译成用于与构造特定树型UI的脚本.
导向器:负责树模型的节点遍历,驱动树构造器的处理.
排序器:负责节点的排序
访问器:负责节点过滤或者节点遍历.
设计模型
E3.Tree采用的核心设计模式是builder模式,如果您对builder还不大清楚,可以找gof设计模式树翻翻。
业务对象
具有树型属性(构造树型结构需要的属性)的业务数据对象,从这类对象中可以分解出ID,和parentID.这类业务对象通常是会下面几种结构中的一种.
如:
A{
Private String id;
Private String parentId ;
}
B{
Private String ID; //ID的值是 0000_0001, 0000_0001_0001这种形式
}
E3.Tree对业务数据的唯一要求就是:从业务对象中要能分解出ID和父亲ID。ID和parentID可以是任何数据类型
业务数据集
业务对象的集合,该集合里的业务对象是线型关系。彼此之间没关系.
由于业务数据的来源会很多,常见的有db,xml,ldap和内存,所以对于数据如何获取,在E3.Tree里不做定义.E3.Tree只要求以Collection的形式传递给TreeModelCreator即可.
节点Node
跟数据结构里的节点概念一致,包含的方法有
public interface Node {
//获取父亲节点
public Node getParent();
//设置父亲节点
public void setParent(Node pParent);
//设置业务对象
public void setUserData(Object pUserData);
//获取业务对象
public Object getUserData();
//获取所有儿子
public Iterator getChildren();
//删除儿子
public void detachNode(Node pNode);
//添加儿子
public void addNode(Node pNode);
//是否是叶子节点
public boolean isLeaf();
//是否是根节点
public boolean isRoot();
//儿子节点个数
public int getChildCount();
//获取指定位置节点,序号从0开始
public Node getChildAt(int pChildIndex);
//获取儿子节点的序号
public int getIndex(Node node);
}
树模型TreeModel
TreeModel 跟数据结构里的树的概念对应. TreeModel可以有一个跟节点也可以有多个跟节点,所以可以是树有可以是森林.
/**
* 树,森林
* @author new
*
*/
public interface TreeModel {
/**
* 获取跟节点,可以是多个跟节点.
* @return
*/
public Iterator getRootNodes();
}
解码器UserDataUncoder
负责业务对象解码,分解出ID和parentID. 如果分解过程出错,抛UncodeException或它的派生类异常.TreeModelCreator会使用它对业务对象进行解码(我把从业务对象中分解出ID和parentID的过程叫做解码)处理.
/**
* 负责业务对象解码,分解出ID和parentID
* @author new
*
*/
public interface UserDataUncoder {
public Object getID(Object pUserData) throws UncodeException;
public Object getParentID(Object pUserData) throws UncodeException;
}
树模型构造器TreeModelCreator
负责创建TreeModel对象.注意,存在2个create方法,请看注释,理解2种方法的区别.
/**
* 将业务数据构造成TreeModel
* @author new
*
*/
public interface TreeModelCreator {
/**
* 创建树模型
* @param pUserDatas 业务数据,至少要存在一个跟节点(不存在父亲节点的节点)
* 要求集合元素读必须实现Uncodable接口
* @return 返回根节点.
* @throws CreateTreeModelException 如果集合元素没有实现Uncodable接口,会抛出
* ClassCastException异常
*/
public TreeModel create(Collection pUserDatas) throws CreateTreeModelException;
/**
* 创建树模型
* @param pUserDatas 业务数据,至少要存在一个跟节点(不存在父亲节点的节点)
* @param pUncoder 解码器,对每个业务数据进行解码,返回主键对象和父亲主键对象.
* @return 返回根节点.
* @throws CreateTreeModelException
*/
public TreeModel create(Collection pUserDatas, UserDataUncoder pUncoder) throws CreateTreeModelException;
}
树构造器TreeBuilder
负责对树模型中的节点进行处理,将内存节点翻译成用于与构造特定树型UI的脚本.
TreeBuilder包含一系列树型UI构造过程方法。请看注释,理解各方法的含义.
public interface TreeBuilder {
/**
* 开始构造树
* @throws BuildTreeException
*/
public void buildTreeStart() throws BuildTreeException;
/**
* 结束构造树
* @throws BuildTreeException
*/
public void buildTreeEnd() throws BuildTreeException;
/**
* 开始构造普通节点(除跟节点之外的节点)
* @param pNode 当前节点
* @param pParentNode 父亲节点
* @param pLevel 节点级别,根节点为0级,根节点直接儿子节点为1级,依次类推,2,3,....
* @param pRow 在兄弟节点里的序号,第一个兄弟节点为0,第2个为1,第3个为2,依次类推.3,4....
* @throws BuildTreeException
*/
public void buildNodeStart(Node pNode, Node pParentNode, int pLevel, int pRow)
throws BuildTreeException;
/**
* 结束构造普通节点(除跟节点之外的节点)
* @param pNode 当前节点
* @param pParentNode 父亲节点
* @param pLevel 节点级别,根节点为0级,根节点直接儿子节点为1级,依次类推,2,3,....
* @param pRow 在兄弟节点里的序号,第一个兄弟节点为0,第2个为1,第3个为2,依次类推.3,4....
* @throws BuildTreeException
*/
public void buildNodeEnd(Node pNode, Node pParentNode, int pLevel, int pRow)
throws BuildTreeException;
/**
* 开始构造跟节点
* @param pRootNode 跟节点,非空
* @param pLevel 根节点级别
* @param pRow 在兄弟节点里的序号,第一个兄弟节点为0,第2个为1,第3个为2,依次类推.3,4....
* @throws BuildTreeException
*/
public void buildRootNodeStart(Node pRootNode,int pLevel, int pRow) throws BuildTreeException;
/**
* 结束构造跟节点
* @param pRootNode 跟节点,非空
* @param pLevel 根节点级别
* @param pRow 在兄弟节点里的序号,第一个兄弟节点为0,第2个为1,第3个为2,依次类推.3,4....
* @throws BuildTreeException
*/
public void buildRootNodeEnd(Node pRootNode, int pLevel, int pRow) throws BuildTreeException;
}
导向器TreeDirector
负责树模型的节点遍历,驱动树构造器的处理.
public interface TreeDirector {
/**
* 设置节点比较器
* @param pComparator 节点比较器,用于进行兄弟节点比较
*/
public void setComparator(Comparator pComparator);
/**
* 节点访问者
* @param pVisitor
*/
public void setNodeVisitor(NodeVisitor pVisitor);
/**
* build树
* @param pTree
* @param pTreeBuilder Tree构造器(非空)
* @throws BuildTreeException
*/
public void build(TreeModel pTree, TreeBuilder pTreeBuilder) throws BuildTreeException;
}
排序器Comparator
负责节点的排序处理.排序器是使用jdk自带的java.util.Comparator
访问器NodeVisitor
负责节点过滤或者节点遍历.
/**
* 在使用TreeBuilder构造节点前进行访问.可以通过NodeVisitor
* 设置Node的属性,过滤节点.当访问一个节点返回false时,
* 该节点和他所有儿子节点不会传递个TreeBuilder
* 节点访问.
* @author 黄云辉
*
*/
public interface NodeVisitor {
public boolean visit(Node pNode);
}
API代码片段
排序
节点默认是不排序,如果要排序,需要给导向器TreeDirector设置排序器.
net.jcreate.e3.tree.support.DefaultNodeComparator是E3.Tree内置的排序器,根据节点名称排序.
TreeDirector director = new DefaultTreeDirector();//构造树导向器
director.setComparator(new DefaultNodeComparator());
如果要根据特定属性排序,则需要自己实现排序器,通常只需要从
net.jcreate.e3.tree.support.AbstractNodeComparator派生即可
TreeDirector director = new DefaultTreeDirector();//构造树导向器
director.setComparator(new AbstractNodeComparator(){
protected Comparable getComparableProperty(Node pNode) {
Object userData = pNode.getUserData();//获取业务对象
Org org = (Org)userData;
return new Integer( org.getViewOrder() );
}
});
设置节点图标
设置节点图标
//Tree模型构造器,用于生成树模型
AbstractWebTreeModelCreator treeModelCreator =
new AbstractWebTreeModelCreator(){
//该方法负责将业务数据映射到树型节点
protected Node createNode(Object pUserData, UserDataUncoder pUncoder) {
Org org = (Org)pUserData;
WebTreeNode result = new WebTreeNode(org.getName(), "org" + org.getId());
result.setIcon(this.getUrl("/e3/samples/tree/Org.gif"));
result.setOpenIcon(this.getUrl("/e3/samples/tree/Org.gif"));
//action是点击按纽执行的方法.可以是url,或者javascript函数
result.setAction("javascript:alert(' " + org.getName() + "')");
return result;
}
};
类 net.jcreate.e3.tree.support. DefaultNode
属性 名称 备注
name 节点名称
类 net.jcreate.e3.tree.support.WebTreeNode
属性 名称 备注
id 节点ID 注意:该ID要是合法标识符号,因为TreeBuilder可能使用该ID作为js变量
icon 节点图标 收缩时图标
openIcon 打开时的图标 展开时图标
action 动作 单击节点时的动作,可以是javascript,也可以是超级连接 如: javascript:orgClick();
/e3/a.jsp
selected 是否被选种
disabled 是否被禁用
nodeProperty 节点属性 目前只有3种属性radio,checkbox和none
这个属性需特别说明:一个树的最终形态是由TreeBuilder来决定的。所以如果采用CheckXTreeBuilder或RadioXTreeBuilder构造树时 ,该属性是没有用的。只有当一棵树中既有check节点又有radio节点或普通节点时,该属性才有效.
类 net.jcreate.e3.tree.support. WebTreeDynamicNode
属性 名称 备注
subTreeURL 子树URL 负责导入子树的URL
节点过滤
过滤掉所有没有儿子节点的跟节点.返回false的节点以及他的儿子节点都会被过滤掉
director.setNodeVisitor(new NodeVisitor(){
public boolean visit(Node pNode) {
boolean noChildRoot = pNode.isRoot() && (pNode.getChildCount() == 0);
if (noChildRoot).{
return false;
} else {
return true;
}
}
});
设置所有叶子节点图标
director.setNodeVisitor(new NodeVisitor(){
public boolean visit(Node pNode) {
if (pNode.isLeaf() ){
result.setIcon(RequestUtil.getUrl("/e3/samples/tree/Org.gif", pRequest));
result.setOpenIcon(RequestUtil.getUrl("/e3/samples/tree/Org.gif", pRequest));
}
return true;
}
});
说明:RequestUtil的包名是net.jcreate.e3.tree.support
pRequest是HttpServletRequest对象,因为是在匿名类里使用,所以pRequest必须是final 类型的.否则编译不能通过.
构造混合节点树
这棵树有机构节点和用户节点,用户节点挂在机构下.用户有个属性指向所属机构.
混合节点的构造跟单节点的构造基本相同。就有一点要特别注意:因为是多节点,可能存在
主键冲突的问题,所以构造节点ID和做节点分解的时候,需要带上前缀.
public void showMixTree(final HttpServletRequest pRequest,
final HttpServletResponse pResponse) throws Exception{
//业务数据
List orgs = new ArrayList();
Org jcjtOrg = new Org("001",null,"进创集团", 1);
Org jcrjOrg = new Org("001001","001","进创软件", 1);
orgs.add(jcjtOrg);
orgs.add(jcrjOrg);
User huangy = new User("huangyh", "黄云辉", "001");//直属集团
User guohp = new User("guohp", "郭鸿鹏", "001");//直属集团
User caogp = new User("caogp", "曹高平", "001001");//进创软件
List users = new ArrayList();
users.add(huangy);
users.add(guohp);
users.add(caogp);
List allData = new ArrayList();
allData.addAll(orgs);
allData.addAll(users);
//业务数据解码器,从业务数据中分解出id和parentid
UserDataUncoder uncoder = new UserDataUncoder(){
final String USERID_PREFIX = "USER_";//为了避免用户ID和机构ID出现相同的情况,所以构造树时
//所有用户ID带个前缀.
public Object getID(Object pUserData) throws UncodeException {
if ( pUserData instanceof Org){
Org org = (Org)pUserData;
return org.getId();
}
if ( pUserData instanceof User ){
User user = (User)pUserData;
return USERID_PREFIX + user.getId();
}
throw new UncodeException("不支持的数据对象." + pUserData.getClass().getName());
}
public Object getParentID(Object pUserData) throws UncodeException {
if ( pUserData instanceof Org){
Org org = (Org)pUserData;
return org.getParentId();
}
if ( pUserData instanceof User ){
User user = (User)pUserData;
return user.getOrgId();
}
throw new UncodeException("不支持的数据对象." + pUserData.getClass().getName());
}
};
//Tree模型构造器,用于生成树模型
AbstractWebTreeModelCreator treeModelCreator =
new AbstractWebTreeModelCreator(){
//该方法负责将业务数据映射到树型节点
protected Node createNode(Object pUserData, UserDataUncoder pUncoder) {
if ( pUserData instanceof Org ){
Org org = (Org)pUserData;
WebTreeNode result = new WebTreeNode(org.getName(), "org" + org.getId());
result.setIcon(this.getUrl("/e3/samples/tree/Org.gif"));
result.setOpenIcon(this.getUrl("/e3/samples/tree/Org.gif"));
//action是点击按纽执行的方法.可以是url,或者javascript函数
result.setAction("javascript:alert(' " + org.getName() + "')");
return result;
}
if ( pUserData instanceof User ){
User user = (User)pUserData;
WebTreeNode result = new WebTreeNode(user.getName(), "user" + user.getId());
result.setIcon(this.getUrl("/e3/samples/tree/User.gif"));
result.setOpenIcon(this.getUrl("/e3/samples/tree/User.gif"));
//action是点击按纽执行的方法.可以是url,或者javascript函数
result.setAction("javascript:alert(' " + user.getName() + "')");
return result;
}
throw new UncodeException("不支持的数据对象." + pUserData.getClass().getName());
}
};
treeModelCreator.init(pRequest);
TreeModel treeModel = treeModelCreator.create(allData,uncoder);
TreeDirector director = new DefaultTreeDirector();//构造树导向器
WebTreeBuilder treeBuilder = new XTreeBuilder();//构造树Builder
treeBuilder.init(pRequest);
director.build(treeModel, treeBuilder);//执行构造
String treeScript = treeBuilder.getTreeScript();//获取构造树的脚本
pRequest.setAttribute("treeScript", treeScript);//保存到request,以便页面使用
pRequest.getRequestDispatcher("/e3/samples/tree/XTree.jsp").forward(pRequest,pResponse);
}
构造动态树
动态树的构造分2个过程,第一个过程构造顶层静态节点(第一次要显示的节点),第2个过程负责导入特定节点的儿子节点数据.
通常第一个过程只显示跟节点,下面的代码
public void showLoadTree(final HttpServletRequest pRequest,
final HttpServletResponse pResponse) throws Exception{
WebTreeDynamicNode rootNode = new WebTreeDynamicNode("进创集团", "org" + "001");
rootNode.setSubTreeURL(
RequestUtil.getUrl("/servlet/xtreeServlet?_actionType=" +
"loadSubOrgs&parentID=" + "001", pRequest));
DefaultTreeModel treeModel = new DefaultTreeModel();
treeModel.addRootNode(rootNode);
TreeDirector director = new DefaultTreeDirector();
director.setComparator(new DefaultNodeComparator());
WebTreeBuilder treeBuilder = new XLoadTreeBuilder();
treeBuilder.init(pRequest);
director.build(treeModel, treeBuilder);
String treeScript = treeBuilder.getTreeScript();
pRequest.setAttribute("treeScript", treeScript);
pRequest.getRequestDispatcher("/e3/samples/tree/XTree.jsp").forward(pRequest,pResponse);
}
说明:
1. 动态节点对象必须是WebTreeDynamicNode
2. setSubTreeURL方法用于设置导入儿子节点数据的url
下面这个方法用于生成儿子节点XML
public void loadSubOrgs(final HttpServletRequest pRequest,
final HttpServletResponse pResponse) throws Exception{
final String parentID = pRequest.getParameter("parentID");
TreeService treeService = TreeBeanFactory.getTreeService();
List subOrgs = treeService.getSubOrgs(parentID);
UserDataUncoder orgUncoder = new OrgUncoder();
AbstractWebTreeModelCreator treeModelCreator =
new AbstractWebTreeModelCreator(){
protected Node createNode(Object pUserData, UserDataUncoder pUncoder) {
Org org = (Org)pUserData;
WebTreeDynamicNode result = new WebTreeDynamicNode(org.getName(), "org" +org.getId());
result.setSubTreeURL(
getUrl("/servlet/xtreeServlet?_actionType=" +
"loadSubOrgs&parentID=" + org.getId()));
return result;
}
};
treeModelCreator.init(pRequest);
TreeModel treeModel = treeModelCreator.create(subOrgs,orgUncoder);
TreeDirector director = new DefaultTreeDirector();
director.setComparator(new DefaultNodeComparator());
WebTreeBuilder treeBuilder = new XLoadSubTreeBuilder();
treeBuilder.init(pRequest);
director.build(treeModel, treeBuilder);
String treeScript = treeBuilder.getTreeScript();
pResponse.setBufferSize(1024*10);
pResponse.setContentType("text/xml;charset=utf-8");
pResponse.getWriter().write(treeScript);
pResponse.flushBuffer();
return;
}
自定义TreeBuilder
Todo
Taglib使用代码片段
简单树
<e3:tree var="org" items="orgs" >
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"/>
</e3:tree>
设置节点图标
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<e3:tree var="org" items="orgs" >
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
/>
</e3:tree>
动态树
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<c:url var="subTree" value="/servlet/xtreeServlet?_actionType=loadExtSubOrgs&parentID=001"/>
<e3:tree var="org" items="orgs" builder="ExtLoadTree" >
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
subTreeURL="${subTree}"
cls="dynamic"
/>
</e3:tree>
节点排序
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<e3:tree var="org" items="orgs" sortProperty="viewOrder" >
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
/>
</e3:tree>
反向排序
<c:url var="orgIcon" value="/e3/samples/tree/Org.gif"/>
<c:url var="userIcon" value="/e3/samples/tree/User.gif"/>
<e3:tree var="org" items="orgs" sortProperty="viewOrder" reverse="true">
<e3:node id="${org.id}" parentId="${org.parentId}" name="${org.name}"
icon="${orgIcon}"
openIcon="${userIcon}"
/>
</e3:tree>
FAQ
1. 我用的web框架是struts/jsf/webwork/,可以用E3.Tree吗?
E3.Tree对Web 框架只有一个要求,就是能取到HttpServletRequest对象,只要满足这个要求,都可以使用.显然上面这几个框架都可以使用E3.Tree.
发表评论
-
Apache FileUpload组件
2013-11-22 15:05 5453Apache FileUpload组件 在最初的 htt ... -
各种数据库对应的jar包、驱动类名和URL格式
2012-11-20 16:38 1522各种数据库对应的jar包、驱动类名和URL格式 2011 ... -
Java Web Start
2011-09-14 10:45 1355一.首先了解一下什么是java web start 1JNL ... -
The template at a glance一目了然的模板
2011-08-05 09:06 1503The template at a glance一目了然的模板 ... -
FreeMarker
2011-08-05 09:04 1132一目了然的数据模型 As you have seen, th ... -
jeecms v3
2011-07-04 15:28 1575好久没有逛jeecms的官方论坛了,今天去看了下,jeecms ... -
gwt整合ibatis
2011-07-02 09:42 2089最近整合gwt整合ibatis,常见错误 控制台报错: 一.N ... -
GWT RPC原理浅析(二)
2011-06-17 16:14 2859前一篇介绍了RPC大体的流程,核心方法是RemoteServi ... -
GWT RPC原理浅析
2011-06-17 15:26 5337GWT中前后台交互有多种方式,包括JSON,XML,RPC 其 ... -
五种开源协议
2011-04-25 14:54 1120五种开源协议(BSD,Apache,G ... -
JAVA代码调用客户端摄像头 初步探讨
2011-02-21 16:51 6764首先到sun下载最新的jmf,然后安装。 然后,说一下 ... -
tomcat部署jbpm项目 loader constraint violation
2011-02-11 14:22 1806当tomcat部署jbpm项目 时,启动项目控制台出错 ja ... -
e3.tree 1.5 发布,很好,很强大,有截图[转]
2010-12-07 14:14 1144E3.Tree是E3平台下一个用于构造树型UI(menu,tr ... -
在Action中获取ServletContext实例
2010-11-25 13:43 37731:在Action中获取servletContext的时候可以 ... -
Bean named 'sqlMapClient' must be of type [org.springframework.orm.ibatis.SqlMap
2010-11-22 09:57 4952在整合spring2.5和ibatis2,出现了ibatis的 ... -
spring,ibatis的笔记
2010-11-22 08:51 1050在上文中,我们把iface ... -
spring,ibatis的笔记
2010-11-22 08:51 978在上文中,我们把iface ... -
后台错误处理
2010-11-17 15:10 1332后台处理 if (!isTokenValid(request) ... -
struts1 和Spring整合jar包
2010-11-17 11:33 5020struts1 和Spring整合 struts1 和Spri ... -
spring 与struts的集成
2010-11-17 08:37 1287Struts与Spring的集成主要有两种方式,即Delega ...
相关推荐
【E3.Tree参考手册】是针对Java Web开发中一种用于构建树形结构的库的详细指南,特别适用于配合动态生成静态页的场景。在这样的应用中,E3.Tree能够一次性加载所有数据,优化了页面加载效率,提高了用户体验。 ### ...
总的来说,E3Tree参考手册是开发者使用E3Tree库的重要指南,它详细阐述了如何在实际项目中集成和使用E3Tree,无论是新手还是有经验的开发者,都能从中受益。通过遵循手册的步骤,开发者能够有效地利用E3Tree来处理和...
首先,我们来看看《E3Tree参考手册[1.5].doc》。这份文档通常会涵盖E3.tree的最新版本1.5的功能更新和改进,包括新引入的API、性能优化以及可能的bug修复。开发者可以通过这份手册了解到如何利用新特性来提升用户...
E3.Tree是一个在E3平台上构建树形UI(如菜单、树、外挂栏等)的组件。这个组件的特点在于其部署简便,...通过阅读E3.Tree的参考手册,可以获取更详细的使用指南和API文档,以帮助你更好地理解和运用E3.Tree的各种功能。
2. **编程环境**:Java开发环境,因为E3Tree参考手册中涉及到Java语言的使用。 3. **开发工具**:IDE(如Eclipse、IntelliJ IDEA)用于编写和调试代码。 4. **依赖库**:确保有JDK(Java Development Kit)安装并...
这个压缩包中的"文档架包"可能包括了使用E3table Etree树表控件的相关文档,如API参考、示例代码、用户手册等,帮助开发者理解和集成这个控件。这些文档通常会涵盖以下内容: 1. **安装与配置**:指导如何将E3table...
在提供的文件列表中,“E3Tree参考手册[1.5].doc”很可能是关于E3树组件的详细文档,里面应该包含了如何导入和使用jar文件的指导,以及如何配置和定制动态树和拖曳树的示例代码。而“ExtTreeTest.jsp”和...
开发E3树时,参考的文档可能包括《E3树开发手册》。这份手册会详细介绍E3树的原理、API使用方法、最佳实践以及常见问题解决方案。通过阅读和理解手册,开发者可以快速上手并熟练运用E3树。 **相关网页** 网络上...
参考文档"E3Tree参考手册[1.5].doc"很可能详细介绍了"e3tree"存储过程的使用方法、参数说明、示例和最佳实践。这通常是开发人员学习和调试存储过程的重要资源。 另外两个xml文件"sqlmap_TEvlRecord.xml"和"sqlmap_...
用户手册 RAR 4.00 控制台版本 欢迎使用 RAR 压缩文件管理器! 简介 RAR 是一个强力压缩工具,允许你管理和操作压缩文件。控制台 RAR 只支持 RAR 格式,带有的 ".rar" 扩展名的文件。ZIP 和其他...