服务于区块链开拓者

www.zhidnet.com

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

简介
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.

posted on 2013-09-26 17:06  知点网  阅读(613)  评论(0编辑  收藏  举报