用richFaces的标签开发tree

  用richFaces的<rich:treeNode>标签开发tree
岳乡成

环境:jdk1.6.0、jboss-4.2.3.GA、jboss-seam-2.1.1.GA 、My-SQL-5.0.8

一、标签说明
1. 概要
树形组件是最常用的组件之一,richFaces也实现了树形结构。<rich:treeNode>,<rich:recursiveTree>都适用于具有递归类型的数据结构,<rich:treeNode>的自由度更高。如下图所示为一个用<rich:treeNode>做的Tree的示例。

                            <rich:treeNode>示例
2. 标签属性
属性名称 描述
var Request范围内地循环变量
value 要生成Tree的所有节点的值
nodeSelectListener 节点选中监听事件

二、示例开发
1. JSF Web页面
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:rich="http://richfaces.org/rich">
    <style>
        .col, .col2 {
            width:50%;
            vertical-align:top;
        }
    </style>
    <h:form>   
        <h:panelGrid columns="2" width="100%" columnClasses="col1,col2">      
            <rich:tree style="width:300px" nodeSelectListener="#{SimpleTreeBean.processSelection}"
                reRender="selectedNode" ajaxSubmitSelection="true"  switchType="client"
                value="#{SimpleTreeBean.treeNode}" var="item" ajaxKeys="#{null}">
            </rich:tree>
            <h:outputText escape="false" value="#{SimpleTreeBean.selectedNodeDescription}" id="selectedNode" />
        </h:panelGrid>
    </h:form>
</ui:composition>
<rich:tree>标签中的reRender属性表示动态刷新id="selectedNode"的区域,
其他属性请参考上面的属性说明。
#{SimpleTreeBean.processSelection}中的SimpleTreeBean表示要绑定的Session Bean的name。
2. Session Bean及接口
Session Bean接口SimpleTreeBeanImpl如下:
package org.domain.seam.session.simpletree.Impl;

import java.util.List;
import javax.ejb.Local;
import org.domain.seam.session.entitybean.Treedirectory;
import org.richfaces.event.NodeSelectedEvent;
import org.richfaces.model.TreeNode;
@Local
public interface SimpleTreeBeanImpl {   
    public void processSelection(NodeSelectedEvent event) ;  
    public TreeNode getTreeNode() ; 
    public String getNodeTitle();
public void destroy();
public void addNodes(TreeNode node, List<Treedirectory> rootNode);
public List<String> getSelectedNodeChildren();
public String getSelectedNodeDescription();
public String getLeftnodecontext(int treedirectoryid);
}
Session Bean SimpleTreeBean如下:
/**
* <p>WeeklyPlanAction</p>
*
*  版权 (c) 2009
*
* <p>CIB</p>
*
* 文件历史
* 日期                  作者            描述
* 2009-05-21        xiangcheng.yue      创建
*
*/
package org.domain.seam.session.simpletree;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.domain.seam.session.entitybean.Leftnodecontext;
import org.domain.seam.session.entitybean.Treedirectory;
import org.domain.seam.session.simpletree.Impl.SimpleTreeBeanImp;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.richfaces.component.html.HtmlTree;
import org.richfaces.event.NodeSelectedEvent;
import org.richfaces.model.TreeNode;
import org.richfaces.model.TreeNodeImpl;
/**
* 生成树目录结构,显示数据。
*
* @author xiangcheng.yue
* @version 1.0
*/
@Stateful
@Name("SimpleTreeBean")
/**
* 设置该Bean(SimpleTreeBean)的生命周期为Application,
* 目的是为了使该Bean在容器的整个生命周期一直存在。
*/
@Scope(ScopeType.APPLICATION)
public class SimpleTreeBean implements SimpleTreeBeanImp{
    /** 根节点标志常量.*/
    private static final int rootNodeFlag = 0;
/**实例化EntityManager。*/
@PersistenceContext
private EntityManager em;
/**生成的Tree。*/
    private TreeNode rootNode = null;
    /**选中节点的孩子结点List。*/
    private List<String> selectedNodeChildren = new ArrayList<String>();
    /**选中结点的名字。*/
    private String nodeTitle;
    /**选中结点的描述。*/
    private String selectedNodeDescription;
  
    public String getSelectedNodeDescription() {
return selectedNodeDescription;
}

public void setSelectedNodeDescription(String selectedNodeDescription) {
this.selectedNodeDescription = selectedNodeDescription;
}

public TreeNode getTreeNode() {
        if (rootNode == null) {
            loadTree();
        }     
        return rootNode;
    }
  
    public String getNodeTitle() {
        return nodeTitle;
    }

    public void setNodeTitle(String nodeTitle) {
        this.nodeTitle = nodeTitle;
    }
   
    public List<String> getSelectedNodeChildren() {
return selectedNodeChildren;
}

public void setSelectedNodeChildren(List<String> selectedNodeChildren) {
this.selectedNodeChildren = selectedNodeChildren;
}
    /**
     * @since 2009-05-19
     * 进入Tree页面时装入树所以的结点。
     * @return void
     * @throws 
     */
    private void loadTree() {
        rootNode = new TreeNodeImpl();
        /**通过根结点标志常量得到根节点list。*/
        List<Treedirectory> results = getClildNodeList(rootNodeFlag);
        if(results != null){
        /**设置根结点的描述。*/
            selectedNodeDescription = "";
        /**向每个根节点加孩子结点。*/
         addNodes(rootNode,results);
        }          
     }
    /**
     * @since 2009-05-19
     * 通过父节点得到该父结点的孩子结点list。
     * @return List<Treedirectory>
     * @throws 
     */
    public List<Treedirectory> getClildNodeList(int paratNode){
      List<Treedirectory> results = em.createQuery("select td from Treedirectory td where td.parentid=" + paratNode).getResultList();
      return results;
      }
    /**
     * @since 2009-05-19
     * 通过递归向每个节点添加孩子结点。
     * @return TreeNode node, List<Treedirectory> rootNode
     * @throws 
     */
     public void addNodes(TreeNode node, List<Treedirectory> rootNode) {
      /**递归的出口标示,如果某个节点为孩子结点,该标示由false变为true,进行下一节点孩子结点的递归添加。*/
      boolean end = false;
      while(!end){
      /**判断该节点是否有孩子结点。*/
      if(rootNode.size()>0){
      /**通过循环取出List<Treedirectory>中每个Treedirectory对象。*/
      for(int i = 0;i<rootNode.size();i++){
      /**实例化一个树的节点。*/
      TreeNodeImpl nodeImpl = new TreeNodeImpl();
      /**向该节点内设值。*/
      nodeImpl.setData(rootNode.get(i).getNodename());
      /**把节点加入树中,设置该节点的标志为该条数据在数据库中的Id。*/
      node.addChild(new Integer(rootNode.get(i).getId()), nodeImpl);
      /**递归调用。*/
      addNodes(nodeImpl, getClildNodeList(rootNode.get(i).getId()));
      }
      }
      end = true;
      }
    }
     /**
      * @since 2009-05-19
      * 通过treedirectory table的Id得到leftnodecontext table中的leftcontext字段的内容。
      * @return String
      * @throws 
      */
     public String getLeftnodecontext(int treedirectoryid){
    String leftnodecontext ="";
       List<Leftnodecontext> results = em.createQuery("select td from Leftnodecontext td where td.treedirectoryid =" + treedirectoryid).getResultList();
       if(results.size()>0){
       Leftnodecontext lnc = results.get(0);
       leftnodecontext = lnc.getLeftcontext();
       }
       return leftnodecontext;
       }
      /**
       * @since 2009-05-19
       * 点击每个结点触发的事件。
       * @return NodeSelectedEvent event
       * @throws
       */
    public void processSelection(NodeSelectedEvent event) {
    /**得到该Tree对象。*/
        HtmlTree tree = (HtmlTree) event.getComponent();
        /**得到点击的节点的值。*/
        nodeTitle = (String) tree.getRowData();
        /**清除selectedNodeChildren的内容。*/
        selectedNodeChildren.clear();
        TreeNode currentNode = tree.getModelTreeNode(tree.getRowKey());
        if (currentNode.isLeaf()){
        /**通过tree.getRowKey()得到该节点的Id。*/
        String[] s = tree.getRowKey().toString().split(":");
            int sLength = s.length;
            int treeNodeId = Integer.parseInt(s[sLength-1]);
            System.out.println("treeNodeId = "+treeNodeId);
            /**得到该叶子节点在leftnodecontext table中的leftcontext.*/
            String leftcontext = getLeftnodecontext(treeNodeId);
        selectedNodeDescription = nodeTitle + " is a leafnode,it context is:" + leftcontext;
            selectedNodeChildren.add((String)currentNode.getData());
        }else
           {
        selectedNodeDescription = nodeTitle + " is not leaf,it have children node:";
            Iterator<Map.Entry<Object, TreeNode>> it = currentNode.getChildren();
            while (it!=null &&it.hasNext()) {
                Map.Entry<Object, TreeNode> entry = it.next();
                selectedNodeChildren.add(entry.getValue().getData().toString());
                selectedNodeDescription = selectedNodeDescription + entry.getValue().getData().toString() + ";";
            }
        }
    }

@Remove
public void destroy() {
}
}
以上代码主要是通过递归生成一个Tree,代码中都加上了详细的注解,看代码时请参考注解。
3. Entity Bean如下:
Treedirectory如下:
package org.domain.seam.session.entitybean;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.jboss.seam.annotations.Name;

@Entity
@Name("treedirectory")
public class Treedirectory implements Serializable
{
   private int id;
   private String nodename;
   private int parentid;
   private char leafflag;

   @Id @GeneratedValue
   public int getId()
   {
      return id;
   }
   public void setId(int id)
   {
      this.id = id;
   }
  
   public String getNodename() {
return nodename;
}
  
public void setNodename(String nodename) {
this.nodename = nodename;
}

public int getParentid() {
return parentid;
}

public void setParentid(int parentid) {
this.parentid = parentid;
}

public char getLeafflag() {
return leafflag;
}

public void setLeafflag(char leafflag) {
this.leafflag = leafflag;
}
   @Override
   public String toString()
   {
      return "Treedirectory(" + nodename + "," + parentid + "," + leafflag + ")";
   }
}
该Bean同数据库中的Treedirectory表相对应。


Leftnodecontext如下:
package org.domain.seam.session.entitybean;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.jboss.seam.annotations.Name;

@Entity
@Name("leftnodecontext")
public class Leftnodecontext implements Serializable
{
   private int id;
   private int treedirectoryid;
   private String leftcontext;
@Id @GeneratedValue
   public int getId()
   {
      return id;
   }
   public void setId(int id)
   {
      this.id = id;
   }
   public int getTreedirectoryid() {
return treedirectoryid;
}
public void setTreedirectoryid(int treedirectoryid) {
this.treedirectoryid = treedirectoryid;
}
public String getLeftcontext() {
   return leftcontext;
    }
    public void setLeftcontext(String leftcontext) {
   this.leftcontext = leftcontext;
}
   @Override
   public String toString()
   {
      return "Leftnodecontext(" + leftcontext + ")";
   }
}
该Bean同数据库中的Leftnodecontext表相对应。

4.添加jboss-web.xml配置文件。
richfaces 的 tree 选中节点等功能中需要用到 UI包中的 UITree 等,需要把richfaces-impl.jar,richfaces-ui.jar加到ear的jar的lib中,并在项目的web-inf中添加jboss-web.xml:

<!DOCTYPE jboss-web PUBLIC
    "-//JBoss//DTD Web Application 4.2//EN"
    "http://www.jboss.org/j2ee/dtd/jboss-web_4_2.dtd">

<jboss-web> 
    <class-loading java2ClassLoadingCompliance="false">
        <loader-repository>
            seam.jboss.org:loader=seamIntegration
            <loader-repository-config>java2ParentDelegation=false</loader-repository-config>
        </loader-repository>
    </class-loading>
</jboss-web>
5.小结。
    利用richFaces的<rich:treeNode>标签过程非常简单,只需要掌握<rich:treeNode>的几个属性及深入理解递归的用法就可以了。希望参考本文档的读者能有所收获,谢谢。

你可能感兴趣的:(bean,Web,jboss,Richfaces,seam)