Web頁面技術綜述(包括fastm)

buaawhl發表於2004-07-07
Web頁面技術綜述(包括fastm)

1. 序
Java Web Application中,頁面生成部分是最繁瑣、令人頭痛的部分。
其它的層都可以很好的結構化,唯有頁面生成部分的結構很散亂。

本文首先介紹並比較各種頁面生成技術,然後具體介紹作者的一個把PHP 模板改進到Java的開源專案――fastm。
我希望fastm能夠幫助廣大Java Web程式設計師從繁瑣的頁面開發工作中解脫出來。

2.頁面生成技術綜述
本文所指的頁面是XML,HTML,WML等能在瀏覽器中顯示的Web頁面。
按照頁面處理邏輯的位置劃分,頁面生成技術可以分為兩大類:

(1)一類是,頁面本身包含邏輯(if, for, etc)。比如,JSP + TagLib, Velocity, XML + XSLT(處理邏輯在XSL檔案中),Tapestry等。
這一類技術中,由於頁面本身包含邏輯,頁面元件的結構和可重用性都不是很好,無法使用“物件” 、“類”、“包”等物件導向的特性。

(2)另一類是,頁面本身不包含邏輯。比如Echo,XMLC,DOM + XPath,Echo,PHP,JDynamicTe, fastm等。
這一類技術中,由於處理邏輯在Java Code裡面,所以,Java程式的結構和可重用效能有多好,頁面元件的結構和可重用性就能有多好。

下面分別講解和比較這些頁面生成技術:

2.1.JSP + TagLib
JSP + TagLib 是Sun公司的頁面生成技術規範。

優點:
權威,規範,使用者眾多,第三方提供了大量的TagLib支援。
而且,JSP本質上是Servlet。其中的Java Code部分非常強大而且靈活,能夠達到Java語言最大的靈活度。
TagLib能夠達到一定程度上的頁面元素重用。TagLib還能夠在一定程度上,幫助驅逐JSP頁面的Java Code“汙染”部分。

缺點:
JSP的缺點很明顯。Java Code和HTML頁面內容混雜在一起,這是讓廣大程式設計師最頭疼的Java Code Pollution問題。即使用TagLib也不能完全解決這個問題。
而且,程式設計師和頁面編輯人員無法在同一個檔案上工作。每次頁面編輯人員編好了HTML頁面,程式設計師必須重新加入Java Code和TagLib。
而HTML頁面一旦加入了Java Code和TagLib,就無法在頁面編輯器(Dream Weaver, Front Page)中正確顯示了。程式不跑起來,就無法看到JSP頁面的頁面結構、顯示風格和內容。
關於效率,靈活性,結構性,可重用性,JSP + TagLib是一個兩難的選擇。
在JSP中大量的使用TagLib,能夠使得JSP的頁面結構良好,更符合XML格式,而且能夠重用一些頁面元素。但TagLib的編譯之後的程式碼龐大而雜亂,而且執行效率很低,嚴重影響響應速度。TabLib很不靈活,能完成的事情很有限。TabLib程式碼本身的可重用性受到TagSupport定義的限制,不是很好。TagLib的編寫不是一件愉快的事情。
如果在JSP中大量使用Java Code,那麼頁面的結構性會很差,難以管理。所有的程式碼都在同一個檔案中,遇到大的HTML頁面,簡直如同噩夢一般。從一個左括號“{”找到對應的右括號“}”都變成很痛苦的一件事情。鑲嵌在Java Code中間的HTML元素的是無法重用的。所以,除了Include file或者jsp:include,JSP中的Java Code根本就沒有可重用性。

2.2.Velocity

http://jakarta.apache.org/velocity/

Velocity是一種模板處理工具。Velocity模板由HTML中夾雜一些Velocity指令碼語言或變數定義組成。

優點:
Velocity的指令碼語言(以開始)或變數定義(用$標誌)和HTML、WML、XML等的元素定義不衝突。
簡單的Velocity頁面(不包含分支和迴圈邏輯)能夠在頁面編輯器(Dream Weaver, Front Page)中正確顯示。

缺點:
同樣,Velocity模板的頁面處理邏輯和HTML元素混雜在一起。如果Velocity頁面的邏輯複雜的話(比如有迴圈和判斷分支),那麼該Velocity頁面同樣不能在頁面編輯器(Dream Weaver, Front Page)中正確顯示。
遇到大的HTML頁面,從一個 “if”找到對應的 “end”也是很痛苦的一件事情。鑲嵌在Velocity指令碼語言中間的HTML元素的是無法重用的。所以,Velocity模板中的指令碼程式碼和HTML元素也不具有可重用性(include file除外)。

2.3.XML + XSLT


http://cocoon.apache.org/


Cocoon專案採用XML + XSLT的方法。Java程式只需要輸出XML資料,Cocoon框架呼叫XSL檔案把XML資料轉換成HTML、WML等檔案。

優點:
程式設計師省事了,不用考慮頁面結構和顯示方式,只需要輸出XML資料即可。
同一份XML資料,只要定義不同的XSL檔案,就能夠很方便地產生不同顯示風格的頁面。
在內容和顯示風格分離的方面,XML + XSLT這種方法做得最好。

缺點:
慢。XSLT的速度比較慢。
由於沒有HTML檔案,根本看不到頁面結構、顯示風格和內容。只有程式跑起來,XSLT轉換之後,才能
XSL語法比較難以掌握,由於沒有“所見即所得”編輯工具,學習成本較高,遠遠高於HTML的學習成本。

2.4. Tapestry


http://jakarta.apache.org/tapestry/


Tapestry擴充套件了HTML元素的定義。Tapestry用這些擴充套件的HTML元素屬性來表示處理邏輯(迴圈,分支等)、元件定義和變數定義。

優點:
整個Tapestry頁面檔案都是HTML元素,能夠在頁面編輯器(Dream Weaver, Front Page)中顯示。但顯示的樣子是否正確,是另一回事,和包含的處理邏輯(迴圈,分支等)的複雜度相關。大致和Velocity的情況相似。
Tapestry的頁面元件重用性比較高。

缺點:
複雜。Tapestry的定義和用法都很複雜。由於複雜,所以慢。

我沒有實際使用Tapestry的具體經驗,這裡就不繼續妄加評論了。

2.5. XMLC


http://xmlc.enhydra.org/


XMLC把HTML、WML等檔案編譯成一個DOM結構的Java類。程式設計師不用管頁面,只需要操作這個DOM結構,就可以動態生成頁面。
XMLC根據HTML元素的id定義,生成相應結點的操作方法。

優點:
頁面是純粹的HTML,沒有任何邏輯。能夠在頁面編輯器(Dream Weaver, Front Page)中正確顯示。
Java Code處理DOM結構,程式碼結構和可重用性良好。DOM節點即HTML元素,即頁面元件,也具有很好的可重用性,你隨時可以把一個DOM節點放到任何文件中的任何位置。
由於是靜態編譯,沒有動態解析過程,文件生成的速度很快。

缺點:
每次修改HTML頁面,必須重新把HTML檔案編譯成Java檔案。而且,很多HTML都不是良好的XML結構,不能夠正確地編譯成DOM結構。
該DOM結構不能在多執行緒環境中重複使用,這就意味著,每一個頁面請求,都需要生成一個單獨的DOM結構,佔用記憶體空間比較大。而且,每個DOM結構使用過之後,也很難清空重置,很難提供給下一個請求使用。在HTML檔案比較大的時候,記憶體的開銷顯著增大。
XMLC有些方面不夠靈活。比如,我們知道,很多Java Script方法定義在XML註釋當中。比如:
<SCRIPT LANGUAGE="Javascript" type="text/javascript">
<!--
function aa{

}
//-->
</SCRIPT>

如果Java Script中有需要動態生成的部分,而註釋部分的Java Script不是XML結構,XMLC很難處理這種情況。

2.6.DOM + XPath
前面講了XMLC把HTML靜態編譯成DOM結構。
我們也可以採用動態生成DOM結構的方法,然後用XPath定位DOM結點並操作它們。
NekoHTML(http://www.apache.org/~andyc/neko/doc/html/)是一個HTML文件解析工具。
NekoHTML使用Apache Xerces(http://xml.apache.org/xerces2-j/index.html)的Xerces Native Interface對HTML文件進行解析,能夠自動補足並修正不符合XML文法的HTML元素,並生成HTML DOM文件樹。
Apache Xcerse的XPathAPI,可以用XPath方便地定位DOM結構的結點。DOM + XPath的詳細用法請參見NekoHTML的使用文件。

優點:
大致具有上述XMLC方法的優點。
沒有靜態編譯過程,動態生成DOM結構,及時反映頁面檔案的變化。

缺點:
大致具有上述XMLC方法的缺點。
DOM結構的動態生成比較花時間。我們可以採用這樣的方法解決這個問題,把第一個生成的DOM結構作為標準模板。我們不對標準模板操作,每次請求需要一個DOM結構的時候,我們就從這個標準模板深度複製(deep copy)一個新的DOM結構,然後使用這個新的DOM結構。這樣每個HTML檔案只需要解析一次,成為標準模板。每次HTML檔案更改的時候(這種情況很少),標準模板也跟著更新。
XPath的解析和定位速度不是很快,幾乎每次都要遍歷整個文件樹。

2.7.Echo


http://sourceforge.net/projects/echo


Echo專案中不用定義模板檔案。程式設計師按照Swing的方式寫程式碼,Echo幫助你生成HTML結果。

優點:不用處理HTML部分。Swing是可重用性極好的真正元件。

缺點:Echo把HTML遮蔽起來,自動生成了很多JavaScript和HTML程式碼。對於Web程式來說,不夠靈活,難以維護。

2.8. PHP

PHP模板的設計思路很好,PHP模板用XML的Comment註釋部分來定義動態結構,用{}來標誌需要替換的變數部分。

優點:
頁面編輯器(Dream Weaver, Front Page)不顯示XML的Comment註釋部分,而且{}符號和XML元素定義不衝突。所以,PHP模板本身符合HTML語法,能在頁面編輯器(Dream Weaver, Front Page)中正確顯示。程式設計師和頁面編輯人員可以在同一份頁面檔案上工作,所見即所得。
簡單,易用,靈活(幾乎和最靈活的JSP Java Code一樣靈活)。具體用法見後面。本文的主要目的就是介紹PHP模板及其Java Port的用法。

缺點:
比起其它的頁面技術來說,這種技術的缺點很少。
一個需要提到的地方,也是Java Script方法定義在XML註釋當中的情況。比如:
<SCRIPT LANGUAGE="Javascript" type="text/javascript">
<!--
function aa{

}
//-->
</SCRIPT>
因為PHP Template採用XML Comment來定義動態結構,所以我們不能在Java Script中定義結構。但我們不需要在XML Comment中定義動態結構,我們可以用{}標誌需要動態改變的地方,完全能夠達到同樣的目的。

2.9 JDynamiTe


http://sourceforge.net/projects/jdynamite


從各方面來說,我認為PHP是最好的頁面生成技術。
我的一個同事向我介紹了PHP Template的定義和用法,我產生了濃厚的興趣,併產生了把PHP Template移植到Java的想法。我首先到網上搜尋了一下,發現了JDynamiTe (Java Dynamic Template) (https://sourceforge.net/projects/jdynamite)開源專案。JDynamiTe能夠把PHP模板移植到Java語言。

JDynamiTe的模板定義和PHP Template有些微小的差別,但一樣簡單。我閱讀了JDynamiTe的例子程式碼,馬上喜歡上了這種方法。

但我發現,JDynamiTe有一點不足。和DOM結構的處理過程一樣,JDynamiTe的模板部分和引數設定部分是合在一起的。JDynamiTe的模板部分不能在多執行緒中同時使用。
每次JDynamiTe都需要讀取並解析HTML檔案,生成一個模板,設值之後,產生結果。處理過後的這個模板就不能再直接使用了(也許可以清空再使用)。
如果HTML檔案很大,那麼,讀取並解析HTML檔案要花費不少時間。

所以,我決定自己實現一個高效率的可重用的PHP Template Java Port。
專案名為fastm(Fast Template的意思。)

2.10. fastm


http://sourceforge.net/projects/fastm



http://sourceforge.net/projects/lightweb


fastm的模板定義採用JDynamiTe的模板定義,而且我直接採用JDynamiTe的例子模板檔案,作為fastm測試例子的模板檔案。fastm可以說是JDynamiTe的一個Multiple Thread Port。
在fastm裡,我把HTML的解析結果文件 (Template DOM)和變數設值部分(ValueSet DOM)分開。
每個HTML檔案只需要解析一次,生成一個只讀的模板。既然只讀,當然執行緒安全,任何數量的執行緒都可以同時使用這個模板。
以後這個模板只需要和不同的變數設值結合,就可以生成不同的結果。
模板的解析過程,採用按行讀取處理的方式,解析的速度很快。

fastm的速度會比JSP + TagLib快。fastm的速度可能會比純粹的JSP慢,也可能更快一些。JSP(即Servlet)把整個頁面一行一行地寫到Response裡面,網路傳輸的效率不高(當然,也有可能用到HTTPResponse的buffer)。而fastm把整個頁面或者整塊頁面,一次寫到Response裡面,網路底層協議儘可以最佳化分塊,達到最好的網路傳輸效率。

fastm支援動態生成JavaScript。這是PHP和JDynamiTe無能為力的地方。
fastm支援JavaScript的註釋定義。比如,
// BEGIN DYNAMIC: special_code
…..
// END DYNAMIC: special_code

這一塊將被標誌為動態塊。

fastm的頁面定義完全仿照JDynamiTe的PHP頁面定義。我的思路來源是PHP Template和JDynamiTe。我自己原創的東西是fasm的實現,和使用方法。fastm的程式碼量很小,採用的技術也很簡單,沒有用任何第三方的軟體,只用了JDK1.4本身的類。

fastm是DOM & PHP思路上的又一次飛躍――Template DOM 和ValueSet DOM的分離。

在我目前所知的Java頁面生成技術中,我相信,fastm從各方面來說,是最好的方法――快,易用,靈活,強大。我期望fastm這種頁面生成方式,能夠較好地解決頁面生成技術這個令人頭痛的問題,能夠在全世界的程式設計師中流行起來。

相關文章