考虑到应用系统会大量使用树形结构来表现数据,因此,提供一个通用树形标签供大家使用。
一、原始树形组件
关于树组件的实现有很多方式,此处使用著名的webfx-xtree实现,一个基于AJAX实现的树形菜单。它的原理就是每次都只加载当前结点下的所有结点,而对开发人员来说,就是只需要按一定的格式,生成一段XML代码。具体可参考http://webfx.eae.net/dhtml/xtree/index.html。
本文对树形组件做了一些别要的修改和扩充,修改后的树组件文末提供下载,解压后放在您的web文件夹common下面。
下文的重点是:通过提供一个jsp taglib,简化树结构的实现。
二、数据库设计
       要实现数据的树形级别关系,在数据库设计中,某个数据实体(一条行记录),有且只有唯一的父实体元素与之对应即可。如机构表sysorg中,字段parentOrgId(可任意命名)为父机构ID,与机构本身的orgId构成树节点的父子关系。
       通常,我们设置根节点的ID为“0”,这样,一级节点的父ID为“0”。
       当节点ID无子节点(不是任何一个元素的父节点),此时此节点为最终节点,通常称之为叶节点(叶子)。
三、实体对象(VO)实现ITreeNode接口
       ValueObject对象需要implements树节点接口com.basic.common.taglib.tree .ITreeNode。
       分别实现如下三个方法:
       //父节点ID
       public String getParentId();
       //节点ID
       public String getNodeId();
       //节点名
       public String getNodeName();
四、实现ITreeService接口
       一个任意的JAVA类,实现com.basic.common.taglib.tree.ITreeService的对象查找接口。
       接口方法:
       public List findAllRecords();
       public ITreeNode findByNodeId(String nodeId);
       实现该方法时候应注意:
1. 排除deleteFlag=’1’的记录。
2. 当结果集非常大,考虑到性能优化,可对结果集做缓存处理。(可暂不考虑实现,以后统一处理)。
五、注册树组件
       在com.basic.common.taglib.tree.TreeUtil类中,维护treeMap静态变量,定义对应treeType的树名和ITreeService实现类。       
六、在jsp中引入标签
       <%@taglib uri="/WEB-INF/tag.tld" prefix="tag"%>
       <tag:tree treeName="机构" root="<%=node%>" selectType="checkbox" selectAll="true"              treeService="<%=orgService%>"/>
       对各属性说明如下:
    
        
            | Attribute | Desc | Required | 
        
            | treeName | 树名                             | true | 
        
            | root | 展现的起始节点     如不指定,从根节点展示整个树形结构 | false | 
        
            | selectType | 选择方式 checkbox or radio | false | 
        
            | selectAll | 勾选父节点时,自动选择所有子节点 只有当selectType为checkbox时该属性方生效  默认为false | false | 
        
            | checkedId | 标识哪些节点被选中 内容为以“ ,”分隔的nodeId串 | false | 
        
            | treeService | ITreeService接口的实现类实例 | true | 
        
            | treeSql | 直接构造树形sql | false | 
        
            | lazy | 是否延迟加载 就是在点击某节点的时候,才load子节点 | false | 
        
            | selectParent | 对checkbox或者radio而言 当选择的子,是否自动勾选对应的所有的父 | False | 
    
1. 点击某一个节点时,触发函数selectNode()。
       atree.getSelected()返回当前点击的节点对象node,node.value和node.text为对应的节点ID和节点名。
       自行在javascript中重写selectNode函数。
2. 当使用勾选时,atree.getSelectedChildNodes()返回当前勾选的节点集合。
3. 在页面中双击鼠标左键(ondblclick)时,会自动展开或收缩当前树。
七、直接使用SQL语句构造树
       实现ITreeService和ItreeNode接口来构造树,相对有点麻烦。
       利用SqlTreeService可以直接通过sql语句来构造树,以机构为例,该SQL语句写法如下:
       select orgid as nodeid,orgname as nodename,parentorgid as parentid from sysorg where deleteflag='0'  
      请注意红色字符的写法。
       对某些实体,没有对应的父ID,parentid的构造语句为:‘0’as parentid
       这时,标签的引用变为:
       <hnisi:tree treeName="×××" treeService="<%=new SqlTreeService("your sql")%>"/> 
八、在javascript中引用树选择对话框
1、 在jsp中引入JS文件:
       <script src="<%=request.getContextPath()%>/js/COMMON.js"></script>
2、 在javascript中,定义要引用的Tree对象
3、 Tree对象有如下属性:
           this.treeType = null;//树类型 sysorg 。。。
        this.rootId = null;//树根
        this.checkedId = null;//选中的节点ID,“,”分隔
        this.selectType = null;//checkbox or radio
        this.selectAll = null;//是否自动选择所有子节点
        this.width = null;//对话框的宽度
        this.height = null;//对话框的高度
        this.params = null;//附加参数值,用于TreeService的构造函数
        this.sql = null;//根据特定sql语句直接构造树
    this.treeName = null;//树显示名   
    其中treeType和sql至少设置一个,分别代表两种的典型构造树的方式:一种属性实现ITreeService和ItreeNode两个接口,然后在TreeUtil.java中注册树组件,比较清晰,可以灵活的做一些复杂处理,但稍嫌复杂;另一种是直接传递SQL语句构造树组件,使用起来比较简单,无需实现相关结构,无需注册树组件,但灵活性相对欠缺。
    
    获取树选择器的返回值,可直接调用COMMON.Js的getValues(tree)方法,返回数组Array,Array[0]为逗号分隔的ID串,Array[1]为逗号分隔的NAME串。
九、文件下载和部署
1、 修改后的webfx-xtree组件,下载,解压后放于your web/common目录下。
2、 Java source,下载。
3、 在web.xml中部署一个servlet,用来生成tree xml
    
        
            | <servlet>        <servlet-name>treexml</servlet-name>        <servlet-class>               com.basic.common.taglib.tree.TreeXmlServlet        </servlet-class> </servlet> <servlet-mapping>        <servlet-name>treexml</servlet-name>        <url-pattern>/treexml</url-pattern> </servlet-mapping> |