用richFaces的<rich:treeNode>标签开发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>的几个属性及深入理解递归的用法就可以了。希望参考本文档的读者能有所收获,谢谢。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值