作者: ecsun 鏈接:http://papa.javaeye.com/blog/231734 發表時間: 2008年08月22日
聲明:本文系JavaEye網站發布的原創博客文章,未經作者書面許可,嚴禁任何網站轉載本文,否則必將追究法律責任!
三年前,我剛剛畢業,取得了第一份工作,在經過三個月的試用期以后,開始參考一個小項目的需求調研及前期的準備工作,由于公司人手有限,最終的編碼實現,也落到了我身上.
在做demo的時候,我遇到的第一個項工作,就是去實現一個無限的方便的樹形結構,因為當時的項目,是建筑節能領域的一個新項目,公司在這方面,沒有太多的沉淀,而公司已有的資源,是自己的一個開發平臺,叫做MISD,不知道現在市場上還有沒有個工具.MISD無法實現這樣的結構,就只有能過編碼來實現了.初出茅廬,經驗不足,沒有那么的考慮,于是拿tree maker一個多小時,把項目要用的幾個樹結構,做出來了,Ctrl+c,Ctrl+v,搞定~~拿去給經理一看:小伙子,手腳挺麻利的嘛~不錯不錯~~我先看看.
心里挺樂~~真的挺樂,沒幾分鐘,又被leader叫了過去,這樹我在哪里加節點編輯啊?"要改代碼啊."leader聽了傻了,"那不行啊,客戶不懂代碼~",去寫一個動態的吧,存數據....
連靜態的都是拿tree maker做的,動態的,我這怎么做啊?當時是真的不會做.于是到網上去找,還真不少.經過對比,在struts-menu里面,有一個數據庫支持的樹結構的例子,于是,按照文檔,做了幾天,還好,結構出來了.基本實現了項目所需要的功能,而這個項目,后來里面很多的樹結構,都是通過我對struts-menu的修改實現的,效果還不錯.
這是我第一次寫樹結構的經歷,整個過程中也是被leader叫去談了好幾次,好在最終沒有給項目造成影響,保證了項目的按時完成,這套結構,后來也成為公司各個項目中使用的標準樹結構,即使在離職到現在,這套結構,包括后來我搭建的項目開發基礎框架,依然在原公司各個項目中發揮著重要的作用.
我相信很多朋友和我一樣,在剛開始做項目的時候,都或多或少的,被這種無限的樹形結構所困擾.希望我的經歷,可以給后來的朋友帶來一些有用的參考價值.
所謂無限的權形結構,最主要的方面,主要是可以無限的添加子結節,到底有沒有人會無限的去添加子節點的,在我做過的項目中,不存在這樣的問題,當節點添加的第四級的時候,已經很少有用戶希望再點下去了,所以說,無限,只是客戶或者leader希望服務于項目的樹形結構更靈活而提出的一種需求,因為不管是客戶也好,leader也好,在項目開始的時候,并不知道,未來需要多少級樹形結構.
設計這個的樹形結構,最基礎的,是數據庫表的設計,要實現無限,數據庫需要像這樣的結構:
id varchar(32) primary key,
name varchar(100) not null,
parent_id varchar(32)
);
其中最主要的是id和parent_id兩上字段,它們定義了所有父節點與子節點之間的父子關系,這也是一種我們很常用的遞歸表結構設計,或者在ORM叫做自身雙向一對多關系映射.現在oracle,SQLServer 2005都支持了遞歸SQL的查詢.不過我們不常用.
有了這樣的數據表結構,那么不管我們用什么技術去實現無限級樹形結構,都是很容易的.
1.struts-menu.
struts-menu從本質上來說,是一種taglib,作者把眾多的腳本以及對樹的操作,封裝成簡單的taglib,用戶在生成樹的時候,只需要簡單的幾句標簽,就可以完成整個樹形結構的生成,比如經典的struts-menu生成樹形結構的頁面代碼,基本如下:
<c:forEach var="parent" items="${parentMenus}">
<menu:displayMenu name="${parent.title}"> </menu:displayMenu>
</c:forEach>
</menu:useMenuDisplayer>
其它的,基本上是一個js的import,沒有更多其它的代碼,當然,我們需要提前將樹結構數據放入request或session中.
關于struts-menu的詳細實現,可以參考我寫的另一篇博客:
http://papa.javaeye.com/admin/blogs/145554
2.DTree
struts-menu 有一個很大的問題,就是速度,在界面上的反應速度,明顯比較慢,當然,很多人從很多方面對struts-menu做了優化,但優化以后,個人覺得,還不是很理想,這個時候,我們就需要一種速度相對比較快的樹形結構了,Dtree在方面,可以說做的相對比較好.同時,使用也很簡單,Dtree可以使用和struts-menu一樣的數據結構,只需要在里面加入一個很簡單的隨機數就可以了,在http://papa.javaeye.com/admin/blogs/145554有完整的描述 ,可以看到,如何將struts-menu的數據結構轉化為Dtree的數據結構.
Dtree在頁面中的展現,主要需要使用少量的javascript,這些代碼,可以參考官方網站上的,也可以參考下面不太友好的實現.
<!--
d = new dTree('d');
<%
try{
List nodesCollection =(List)request.getAttribute("dTree");
Iterator it=nodesCollection.iterator();
while(it.hasNext()){
Map item=(Map) it.next();
%>
d.add(<%=item.get("dTree_id").toString()%>,<%=item.get("dTree_parentid").toString()%>,'<%=item.get("name").toString()%>','<%=item.get("location").toString()%>','','<%=item.get("target")%>');
<%
}
}catch(Exception e){
System.out.println(e.toString());
}
%>
document.write(d);
//-->
</script>
可以看到,dtree的實現,也是很簡單的.
3.Ext Tree.
從一年多以前,Ext 開始火爆,很多人開始使用ext tree ,也有很多人,因為ext tree 而開始使用ext,在這一塊,在我的另一篇博客(三篇連載,請在博客中查詢):
http://papa.javaeye.com/admin/blogs/157922
同時,在開源項目FaceYe中,使用了大量的Ext tree,包括帶多選框的Ext tree 結構,可以到http://faceye.googlecode.com 下載FaceYe代碼包并安裝查看效果,在我的博客http://papa.javaeye.com中,對FaceYe有完整的描述 .
有完整的描述,Ext tree使用的數據結構,與struts-menu類似.
但需要注意的是,ext tree的加載速度并不太好.大的項目使用需要注意.
4.YUI tree.
說了Ext tree,再說YUI tree,似乎有點多此一舉,使用Ext的朋友,都知道Ext tree和 YUI tree可以說是師出同門,但Ext tree對YUI tree做了比較多的擴展.也就是因為這些擴展,使得使用Ext tree 相對簡單,而使用YUI tree或許多多少少有些不便.廢話少說,先看一下如何展現YUI TREE:
(function(){
var tree;
function loadNodeData(node,fnLoadComplete){
var callback={
success:function(o){
if(o.responseText){
var result=YAHOO.lang.JSON.parse(o.responseText);
if(result){
for(var i=0;i<result.length;i++){
var tempNode=new YAHOO.widget.TextNode(result[i],node,false);
if(result[i].isLeaf){
tempNode.isLeaf=true;
}
}
}
tree.draw();
}
o.argument.fnLoadComplete();
},
failure:function(o){
o.argument.fnLoadComplete();
},
argument:{
'node':node,
'fnLoadComplete':fnLoadComplete
},
timeout:7000
};
var req=YAHOO.util.Connect.asyncRequest('POST', base.path+'security/treeAction!tree.do', callback,'nodeId='+node.data.id);
}
function init(){
tree=new YAHOO.widget.TreeView("tree-viewer");
tree.setDynamicLoad(loadNodeData,0);
initRoot();
tree.draw();
}
function initRoot(){
var root=tree.getRoot();
var callback={
success:function(o){
var result=YAHOO.lang.JSON.parse(o.responseText);
for(var i=0;i<result.length;i++){
var node=new YAHOO.widget.TextNode(result[i],root,false);
if(result[i].isLeaf){
node.isLeaf=true;
}
}
tree.draw();
},
failure:function(o){
}
};
var req=YAHOO.util.Connect.asyncRequest('POST', base.path+'security/treeAction!tree.do', callback);
}
YAHOO.util.Event.on(window,'load',function(e){
init();
});
})();
</script>
后臺方面的代碼,大多都大同小異,有興趣的朋友參考FaceYe的實現了.
已有 0 人發表留言,猛擊->>這里<<-參與討論
JavaEye推薦