`
过儿oO
  • 浏览: 54701 次
  • 性别: Icon_minigender_1
  • 来自: 大连
最近访客 更多访客>>
社区版块
存档分类
最新评论

JSF中Tree2组件使用方法

阅读更多
Tree2组件使用HTML表格将你的数据呈现为一个树。这个树是动态的:当用户点击它们时它们可以展开或者折叠。该组件同时支持客户端和服务端的交互方式,在客户端交互时使用了JavaScript。 在随后的例子中,每次用户的点击将产生一个Request / Response 周期,并在新的视图状态(View State)中重新呈现新的树结构。

  注:在后面的例子中只有可见的(已经展开的节点)数据被传送到客户端。而在第一个例子(客户端Tree),在每个HTML Response中,整个树都被发送到客户端浏览器。树的每个节点都包含了不少的HTML代码(假定每个节点200个字符,这个大小将取决于你希望在节点上显示的信息的量),这些信息将被传送到浏览器,其中包括了那些不可见的节点(没有展开的节点),因为它们的一个祖系节点被展开。如果你有一个深度有四层的树,平均每个结点拥有四个子结点,这时候你就需要传输10 + 102 + 103 + 104 = 11 110个节点,每个节点有200个字符,这个树总共就有2 222 000个字符,也就是2M的数据。这个例子将向用户说明,虽然纯客户端Tree会给客户端带来更好的用户体验,但随之而来的带宽问题迅速的增长。纯客户端的树适用于小型的树,或者在Intranet及宽带连接中使用的中型大小的树。对于大型的树,或者你需要照顾到一些低带宽的用户的需要时,你就需要使用服务端树。你可以通过<t:tree2>的clientSideToggle这个属性来选择你使用的是客户端的树或者服务端的树,<t:tree2>的clientSideToggle这个属性来选择你使用的是客户端的树或者服务端的树,<t:tree2 clientSideToggle="false" ...>将会使用服务端的树,属性值设为true将会使用客户端的树,默认值为true。

  Backing Bean:

  Tree2组件对Backing Bean中的一个TreeModel进行操作。通常情况,你只要把这个TreeModel绑定到这个组件上就可以了,就像这样:

<t:tree2 value="#{myHandler.treeModel}"

  下面需要建立一个类MyHandler,在faces-config.xml中的managed bean配置成myHandler,在例子中这个类提供了一个方法getTreeModel()用于返回一个TreeModel用于表示你的数据。

public class MyHandler {
 public TreeModel getTreeModel() {
  ......
 }
}

  TreeModel实际上是对TreeNode实例进行了一些简单的包装。

  TreeNode是一个接口,其中和tree2相关有四个方法:

String getType()
boolean isLeaf()
List getChildren()
int getChildCount()

  其它方法都没有什么用处了,可能会在今后的版本中取消。它们要求开发者在开发backing bean中做一些并不必要的操作。

  int getChildCount() 方法返回这个节点的子结点数量,这个方法了很容易的采用如下的方式实现:

public final int getChildCount() {
return getChildren().size();
}

  该方法的出现使得对于子结点的延迟加载变的可行。该方法的实现只需要返回该节点的子结点数量,而不需要返回每个子结点的实例。

  boolean isLeaf() 方法在该节点没有子节点的时候返回true。这样,一个很直截了当的实现可以这样:

public final boolean isLeaf() {
return getChildren().isEmpty();
}

  不管你提供了什么样的实现,在任何时间任何情况下你都得保持getChildren().isEmpty() ==> isLeaf()。isLeaf()方法实际上控制了节点被怎样呈现:是否被当做树叶节点(不能被继续展开)。

  String getType() 方法决定了用怎样的方式来呈现这个节点。在 JSF 页面中,可以在 <t:tree2> 的Tag 中嵌套facet,JSF将会选出与 getType() 方法返回值同名的 facet 用于呈现。如果该节点没有找到相符的 facet,将会导致一个错误,并且这个方法不会返回null。

  List getChildren() 方法返回一个 List,其中包含了该节点下所有的 TreeNode,这就表示这些节点将被呈现为该节点下的子结点。该 List 不能包含 null,如果该 List 的大小和getChildCount()不符,将会报错。子结点将按照它们在 List 中的顺序呈现出来。

  改变Tree中的内容

  (当展开树的节点时,在后台延迟加载)

  在邮件列表中有很多关于这项任务的问题和讨论,我(Marcel,一个 JSF 的初学者)在这里总结一下。如果你有更好的解决方案,请更新这些文字。

  在这里存在的一个问题就是我要这样把“+”图标去掉:

  · <t:tree2 ... showNav="false" ...>
 
  然后再让文件夹图标(代表包含子节点的节点)变的可点击:

  · <h:commandLink action="#{t.toggleExpanded}" actionListener="#{navigationBacker.processAction}">

  然后在 Java 代码中接受鼠标点击的事件。在 NavigationBacker.java 文件中的processAction(ActionEvent e) 方法里,我从 EJB3-persistency 中加载子结点的数据。

  不好的是“+”图标变的不可见,但是我现在没有办法获取点击“+”图标的事件。

  看起来在org.apache.myfaces.custom.tree2.HtmlTree.java这个文件里是通过注册了_expandControl = new HtmlCommandLink(); 从内部获取“+”的点击事件,但是我现在没有办法从我的代码中接受到这一事件。

  为了导航,我使用了含有entries的TreeNode.getIdentifier() (参见:#{node.identifier}),看起来就是这个样子:

  · db_id="car_id=7,person_id=2"

  这代表了后台数据库表的主键(我还没有找到一个更好的解决方案用于导航)

  程序代码如下:

  navigation.jsp

<t:tree2 id="serverTree" value="#{navigationBacker.treeData}"
var="node" varNodeToggler="t" clientSideToggle="false" showNav="false"
showRootNode="false">
<f:facet name="project-folder">
<h:panelGroup>
<h:commandLink action="#{t.toggleExpanded}" actionListener="#{navigationBacker.processAction}">
<t:graphicImage value="/images/yellow-folder-open.png"
rendered="#{t.nodeExpanded}" border="0" />
<t:graphicImage value="/images/yellow-folder-closed.png"
rendered="#{!t.nodeExpanded}" border="0" />
</h:commandLink>
<h:commandLink action="#{navigationBacker.toViewId}"
styleClass="#{t.nodeSelected ? 'documentSelected':'document'}"
actionListener="#{navigationBacker.nodeClicked}"
value="#{node.description}" immediate="true">
<f:param name="db_id" value="#{node.identifier}" />

</h:commandLink>
<h:outputText value=" (#{node.childCount})" styleClass="childCount"
rendered="#{!empty node.children}" />
</h:panelGroup>
</f:facet>
<f:facet name="person-folder">
<h:panelGroup>

  NavigationBacker.java

/** *//**
* 拦截节点被展开的事件,并加载额外的数据
* @param event
* @throws AbortProcessingException
*/
public void processAction(ActionEvent event) throws AbortProcessingException {
System.out.println("Entering processAction()");
UIComponent component = (UIComponent) event.getSource();
while (!(component != null && component instanceof HtmlTree)) {
 component = component.getParent();
}
if (component != null) {
 HtmlTree tree = (HtmlTree) component;
 TreeNodeBase node = (TreeNodeBase) tree.getNode();
 if (!tree.isNodeExpanded() && node.getChildren().size() == 0) {
  Map<String, String> map = splitKeyValues(node.getIdentifier()); // 一些辅助代码,用于将 "car_id=7" 或 "car_id=7&person_id=12" 拆分开
  this.car_id = map.get("car_id");
  if (this.car_id != null) {
   appendPersonsNodes(node); // 参见下面的例子
  }
  this.person_id = map.get("person_id");
  if (this.person_id != null) {
   appendLicensesNodes(node); // 没有显示
  }
 }
}
}

/** *//** 把当前car_id下的Person子结点加入导航中 */
private void appendPersonsNodes(TreeNodeBase carDetailNode) {
 VariableResolver resolver = FacesContext.getCurrentInstance().getApplication().getVariableResolver();
 PersonsTable personsTable = (PersonsTable) resolver.resolveVariable(FacesContext.getCurrentInstance(),
"personsTable");
 List<Person> personsList = personsTable.getCarPersons();
 for (Person o : personsList) {
  List<TreeNodeBase> list = carDetailNode.getChildren();
  list.add(new TreeNodeBase("person-folder", o.getDescription(),"person_id=" + o.getPersonId(), true));
 }
 System.out.println("NavigationBacker fetched " + personsList.size() + " Persons for carId=" + this.car_id);
}

  这里有一段辅助代码用于从 h:commandLink 中获取 f:param 用于多种用途。

/** *//**
* 当 JSF 组件 h:commandLink 包含有 f:param 成员, 这些 name-value 对被放到
* request 参数表中供后面的action handler使用。不幸的是,这样的用法不能用在
* h:commandButton上。我们没有办法把通过 button 来传递这些参数。
*
* 因为 Action Listeners 可以保证在 Action 方法前被执行到,所以 Action Listeners
* 可以调用该方法更新 Action 方法所需要的任何上下文。
*
* From http://cvs.sakaiproject.org/release/2.0.0/
* sakai2/gradebook/tool/src/java/org/sakaiproject/tool/gradebook/jsf/FacesUtil.java
* Educational Community License Version 1.0
*/
public static final Map getEventParameterMap(FacesEvent event) {
 Map<String, String> parameterMap = new HashMap<String, String>();
 List children = event.getComponent().getChildren();
 for (Iterator iter = children.iterator(); iter.hasNext();) {
  Object next = iter.next();
  if (next instanceof UIParameter) {
   UIParameter param = (UIParameter) next;
   parameterMap.put(param.getName(), "" + param.getValue());
  }
 }
 //System.out.println("parameterMap=" + parameterMap);
 return parameterMap;
}

  注:在上面的例子里,backing bean都存放于 session 作用域里,可以在WEB-INF/examples-config.xml 中进行配置。</t:tree2>
分享到:
评论

相关推荐

    深入讨论JSF中Tree2组件使用方法

    深入讨论JSF中Tree2组件使用方法。

    JSF生命周期及组件开发

    - **定义**: 在这一阶段,JSF框架从客户端接收到HTTP请求后,会解析请求中的视图标识符(View ID),并使用这个标识符找到相应的视图树(View Tree)。 - **视图实例化**: - **新视图**(New View): 如果视图不...

    JSF2新特性以及配置

    在JSF2中引入了许多新特性和改进,极大地提升了开发效率和用户体验。以下将详细介绍JSF2的新特性及其配置。** 1. **Faces Servlet自动注册**:在JSF2中,Faces Servlet不再需要在web.xml中手动配置。它现在会自动...

    jsf需要全部包

    2. **JSF组件库**: - JSF标准组件库(JavaServer Faces Core Components):提供基本的HTML元素和交互控件,如按钮、输入框、表单等。 - Apache MyFaces或Mojarra:JSF的两个主要实现,它们扩展了标准组件库,...

    jsf常用文档datatable行样式,frameset及树型目录dtree,jsf滚动组件

    在JSF中,虽然主要关注组件的交互,但可以通过嵌入HTML元素来使用frameset。然而,现代Web开发中,frameset已逐渐被iframe所取代,因为iframe提供了更好的灵活性和更好的SEO支持。 - **DTREE(Dynamic Tree)**:...

    jsf常用控件的使用

    本文将深入探讨JSF中的一些常见控件及其使用方法,旨在帮助开发者更好地理解和应用这些控件。 1. **输入控件**: - `h:inputText`:用于创建简单的文本输入字段,可以与Bean中的属性绑定,处理用户输入的数据。 -...

    JSF FacesContext 详解

    在 Faces API 中,FacesContext 和 ExternalContext 是两个经常使用的类,本文将详细介绍 FacesContext 的编程接口和使用方法。 FacesContext 的实例是在 FacesServlet 对象中创建的,每个 JSF 请求都会获取一个 ...

    《JSF入门》培训教程PPT

    JSF提供了一组可重用的UI组件,可以像HTML元素一样在页面上使用。这些组件通过后台的数据模型与业务逻辑进行交互,从而实现数据的处理和展示。 二、JSF组件库 JSF的组件库包括各种UI元素,如按钮、文本框、下拉列表...

    JSF API (有索引功能)

    2. **组件树(Component Tree)** - JSF页面由组件树构成,其中每个组件都可能有子组件。树的根通常是`UIViewRoot`,其他组件依此挂载。 3. **渲染(Rendering)** - 渲染器(Renderers)负责将组件转化为HTML或...

    jsf入门

    2.2 组件模型:JSF的核心是组件库,它提供了一系列预定义的UI组件,如按钮、输入框等,可以直接在视图中使用。 2.3 视图技术:Facelets是JSF 2.x及以后版本的默认视图技术,它是一种XML-based模板语言,用于创建可...

    使用richfaces 实现tree

    3. RichFaces 3.1.*:这个版本的RichFaces提供了许多高级组件,包括我们要用到的Tree组件。 创建树形结构通常是为了展示层次化的数据,例如目录结构、组织架构或数据库的分类。在RichFaces中,`&lt;rich:tree&gt;`是实现...

    jsf 中文Demo 本人付出研究一个月的Demo 请认真学习一下

    这个"jsf 中文Demo"是作者经过一个月研究精心制作的示例项目,旨在帮助学习者深入理解JSF的使用方法。 **导航**在JSF中指的是页面之间的跳转控制。JSF使用`&lt;h:link&gt;`和`&lt;h:button&gt;`等组件来创建链接,以及`...

    JSF入门资料收集

    1. **组件树(Component Tree)**:JSF应用的核心是组件树,它由UI组件组成,这些组件可以相互嵌套,形成一个表示用户界面的结构。 2. **生命周期(Life Cycle)**:JSF组件有一个从初始化到销毁的生命周期,包括六...

    JSF实现,里边有很多JSF工程用到的Jar包

    2. **Component Tree**:JSF使用组件树来构建用户界面。每个组件都有属性、事件和行为,可以嵌套形成复杂的UI结构。 3. **View Handling**:视图处理涉及创建、更新和管理视图状态。JSF会将用户界面的状态保存在...

    IBM Redbook -WebSphere Studio 5.1.2 for JSF and SDO

    - **容器独立性**:JSF组件和页面在不同的Java EE容器中具有高度的可移植性,这意味着应用可以在不同的服务器上运行而无需修改代码。 - **JSF生命周期**:JSF页面请求遵循特定的生命周期,包括Restore Component ...

    JSF1.2的新特性

    #### 改进tree组件创建方法和内容组织 针对JSF与JSP混合使用时可能出现的问题,JSF 1.2提供了更精细的组件树创建和渲染机制。通过将组件树的构建与渲染分离,避免了JSP引擎过早渲染静态文本,从而解决了诸如文本...

    JSF概论

    2. **CDI/Managed Beans**:JSF支持Contexts and Dependency Injection(CDI),使得依赖注入更加灵活,同时还能使用Managed Beans进行轻量级的组件管理。 3. **Faces Servlet**:JSF通过Faces Servlet处理HTTP请求...

    JSF教程

    它允许开发者使用XML或者XHTML语法来定义页面结构,同时支持EL(表达式语言)和JSF组件,使得页面的可维护性和可重用性大大提高。 **3. UIComponent和Component Tree** JSF中的UIComponent是表示Web页面元素的基类。...

    JSF电子书两本打包

    3. **Component Tree**:JSF维护一个组件树,每个UI组件都在树中有一个位置,这使得组件之间的通信和状态管理变得简单。 4. **Lifecycle**:JSF有六种生命周期阶段,包括初始化、应用请求值、处理验证、更新模型值、...

Global site tag (gtag.js) - Google Analytics