MyFaces開源網站: http://www.irian.at/myfacesexamples/home.jsf
================================================
<a href="http://www.blogjava.net/steady/archive/2005/12/01/22068.html">JSF Tree2 實踐</a>
通過一次小小的實踐,終于了解如何使用tomahawk中的tree2這個元件了,并且寫了小段程式,從xml中讀取樹的結構,生成一個tree,不過tree2不能直接和xml綁定是一個遺憾,那樣就會省不少事情了。記下一點心得,以供後來參考了。
對tree2的操作分為兩部分,一部分是在頁面中通過tag定義樣式相關的東西,一部分就是通過程式設計添加樹的節點,起初看了sample以後總是以為這東西有多麼的複雜,其實邏輯是很簡單的,隻是sample中定義了多種不同的樣式的節點,看上去很複雜而已。
下面附上我對sample簡化過的這段tag來說明一下。
<t:tree2 value="#{catalog.node}" var="node" >"clientside" varNodeToggler="t" >
<f:facet >"folder">
<h:panelGroup>
<f:facet >"expand">
<t:graphicImage value="images/yellow-folder-open.png" rendered="#{t.nodeExpanded}" border="0"/>
</f:facet>
<f:facet >"collapse">
<t:graphicImage value="images/yellow-folder-closed.png" rendered="#{!t.nodeExpanded}" border="0"/>
<h:outputText value="#{node.description}"/>
</h:panelGroup>
</f:facet>
</t:tree2>
tree2的主tag定義了tree的根節點和一些相關的參數。嵌套的那個facet定義了一種節點的樣式,包括展開與關閉時的圖檔,以及顯示的文字内容。
在程式裡面,我們root TreeNodeBase = new TreeNodeBase(…)來建立一個root節點,然後通過root.getChildren().add(new TreeNodeBase(…))為其添加子節點,任何一個節點都可以添加任意多的子節點,通過這樣的操作,我們可以很容易的生成一個tree的結構了,實際上,這個tree的結構是通過遞歸從xml中讀取出來,生成一個和xml tree完全相同的結構。
除了明白如何去用這個tree2之外的收獲就是,終于明白了如何去通過遞歸方法周遊一個樹形結構,雖然在學校裡學過周遊的算法,也抄過例程,但從來沒有了解過是怎麼一回事,終于在實踐中了解了,實踐才是軟體的根本之道。
程式的其它部分放在附件裡面了,如果有興趣了可以和我讨論tree2,讨論其它JSF的東西。
先拿回來收藏了再說,等驗證後再把結果貼出來。
===========================================================================================
析Tree2(一) 原址:http://www.blogjava.net/steady/archive/2006/01/13/27904.html
在我的 blog 中,JSF 的Tree2 元件一直都是一個熱門的讨論話題,為了向大家介紹更多關于Tree2的内容,我翻譯了這篇原産于 Apache Myfaces 社群的介紹 Tree2 的文章,希望大家能夠對 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="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 中的順序呈現出來。
==================================================
JSF TREE2 例子-- JAVA類檔案 [折疊]
package cn.bizprocess.sysmanage.user.web.webtree;
import java.io.Serializable;
import java.util.Iterator;
import java.util.*;
import org.apache.myfaces.custom.tree2.TreeNodeBase;
import cn.common.exception.BizException;
import cn.common.model.bo.PubCodeBO;
import cn.common.web.BaseBackingBean;
import cn.bizprocess.sysmanage.user.ucc.ISysParameterUCC;
/**
* <p>Title:DictTree</p>
*
* <p>Description: 系統參數(資料字典)管理類</p>
*/
public class DictTree extends BaseBackingBean implements Serializable {
private static final long serialVersionUID = 1L;
private String _nodePath;
private TreeNodeBase TreeNode;
private ISysParameterUCC sysParameterUCC;
private PubCodeBO sysParameterBO;
TreeNodeBase temp2;
/**
* 獲得系統代碼樹
* @return
* @throws Exception
*/
public TreeNodeBase getBranchTree() throws BizException {
try {
sysParameterBO=sysParameterUCC.querySysParameterByParentCodeNo("-1");
String parent_code_no=sysParameterBO.getCodeNo();
if ((sysParameterUCC.getChildPubCodeBOs(parent_code_no)).size()>0) {
TreeNode=new TreeNodeBase("parent",sysParameterBO.getPubCodeId().toString(),sysParameterBO.getCodeName(), false);
TreeNode=findBranchChild_Branch(TreeNode,sysParameterBO);
}
else {
TreeNode=new TreeNodeBase("parent",sysParameterBO.getPubCodeId().toString(),sysParameterBO.getCodeName(), true);
}
}
catch(BizException biz) {
this.exceptionMsg.setMainMsg(biz);
return TreeNode;
}
/**
* 查詢子代碼
* @param superNode
* @param superBO
*/
public TreeNodeBase findBranchChild_Branch(TreeNodeBase superNode,PubCodeBO superBO) throws BizException {
try{
PubCodeBO childBO=new PubCodeBO();
List childlist=sysParameterUCC.getChildPubCodeBOs(superBO.getCodeNo());
Iterator it =childlist.iterator();
while(it.hasNext()) {
childBO=(PubCodeBO)it.next();
//System.out.println("2222222222222222222----------------FFF--------------"+childBO);
List ss_list=(sysParameterUCC.getChildPubCodeBOs(childBO.getCodeNo()));
if (ss_list!=null) {
temp2=new TreeNodeBase("parent",childBO.getPubCodeId().toString(),childBO.getCodeName(), false);
}
else {
temp2=new TreeNodeBase("parent",childBO.getPubCodeId().toString(),childBO.getCodeName(), true);
}
superNode.getChildren().add(temp2);
if ((sysParameterUCC.getChildPubCodeBOs(childBO.getCodeNo()))!=null) {
temp2=findBranchChild_Branch(temp2,childBO);
}
}
}
catch(BizException biz) {
throw biz;
return superNode;
}
/**
* @return 傳回 sysParameterBO。
public PubCodeBO getSysParameterBO() {
return sysParameterBO;
}
* @param sysParameterBO 要設定的 sysParameterBO。
public void setSysParameterBO(PubCodeBO sysParameterBO) {
this.sysParameterBO = sysParameterBO;
* @return 傳回 sysParameterUCC。
public ISysParameterUCC getSysParameterUCC() {
return sysParameterUCC;
* @param sysParameterUCC 要設定的 sysParameterUCC。
public void setSysParameterUCC(ISysParameterUCC sysParameterUCC) {
this.sysParameterUCC = sysParameterUCC;
public void setNodePath(String nodePath) {
_nodePath = nodePath;
public String getNodePath() {
return _nodePath;
public TreeNodeBase getTreeNode() {
return TreeNode;
public void setTreeNode(TreeNodeBase treeNode) {
TreeNode = treeNode;
=======================================================================
<a href="http://www.blogjava.net/steady/archive/2006/01/13/27960.html">解析Tree2(二)</a>
原址:http://www.blogjava.net/steady/archive/2006/01/13/27960.html
改變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:outputText value=" (#{node.childCount})" styleClass="childCount"

rendered="#{!empty node.children}" />

</h:panelGroup>


<f:facet name="person-folder">


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 中進行配置。
很多朋友和我交流了一些有關 Tree2 的問題,我把一些大家經常碰到的問題拿出來,希望剛開始學習的朋友能夠避免再犯一些這樣的錯誤。
希望這兩篇介紹 Tree2 的文章能給大家一些新的認識,今後也會努力拿出更多更好的東西來和大家分享
本文轉自kenty部落格園部落格,原文連結http://www.cnblogs.com/kentyshang/archive/2008/06/05/1214087.html如需轉載請自行聯系原作者
kenty