Template和JSP技術__JSP

來源:互聯網
上載者:User

(本文發於java emag第一期)
一、起源與現狀:

關於Template和JSP的起源還要追述到Web開發的遠古年代,那個時候的人們用CGI來開發web應用,在一個CGI程式中寫HTML標籤。

在這之後世界開始朝不同的方向發展:sun公司提供了類似於CGI的servlet解決方案,但是無論是CGI還是servlet都面對同一個問題:在程式裡寫html標籤,無論如何都不是一個明智的解決方案。於是sun公司於1999年推出了JSP技術。而在另一個世界裡,以PHP和ASP為代表的scriptlet頁面指令碼技術開始廣泛應用。

不過即便如此,問題並沒有結束,新的問題出現了:業務和HTML標籤的混合,這個問題不僅導致頁面結構的混亂,同時也使代碼本身難以維護。

於是來自起源於70年代後期的MVC模式被引入開發。MVC的三個角色:Model——包含除UI的資料和行為的所有資料和行為。View是表示UI中模型的顯示。任何資訊的變化都由MVC中的第三個成員來處理——控制器。

在之後的應用中,出現了技術的第一次飛躍:前端的顯示邏輯和後端的商務邏輯分離,COM組件或EJB或CORBA用於處理商務邏輯,ASP、JSP以及PHP被用於前端的顯示。這個就是Web開發的Model 1階段(頁面控制器模式)。

不過這個開發模式有很多問題:

1.       頁面中必須寫入Scriptlet調用組件以獲得所必需的資料。

2.       處理顯示邏輯上Scriptlet代碼和HTML代碼混合交錯。

3.       調試困難。JSP被編譯成servlet,頁面上的調試資訊不足以定位錯誤。

這一切都是因為在Model 1中並沒有分離視圖和控制器。完全分離視圖和控制器就成了必須。這就是Model 2。它把Model 1中未解決的問題——分離對組件(商務邏輯)的調用工作,把這部分工作移植到了控制器。現在似乎完美了,不過等等,原來的控制器從頁面中分離後,頁面所需的資料怎麼獲得,誰來處理頁面顯示邏輯。兩個辦法:1. 繼續利用asp,php或者jsp等機制,不過由於它們是運行在web環境下的,他們所要顯示的資料(後端邏輯產生的結果)就需要通過控制器放入request流中;2. 使用新手法——模板技術,使用獨立的模板技術由於脫離的了web環境,會給開發測試帶來相當的便利。至於頁面所需資料傳入一個POJO就行而不是request對象。

模板技術最先開始於PHP的世界,出現了PHPLIB Template和FastTemplate這兩位英雄。不久模板技術就被引入到java web開發世界裡。目前比較流行的模板技術有:XSTL,Velocity,JDynamiTe,Tapestry等。另外因為JSP技術畢竟是目前標準,相當的系統還是利用JSP來完成頁面顯示邏輯部分,在Sun公司的JSTL外,各個第三方組織也紛紛推出了自己的Taglib,一個代表是struts tablib。

二、 模板技術分析:

模板技術從本質上來講,它是一個預留位置動態替換技術。一個完整的模板技術需要四個元素:0. 範本語言,1. 包含範本語言的模板檔案,2. 擁有動態資料的資料對象,3. 模板引擎。以下就具體討論這四個元素。(在討論過程中,我只列舉了幾個不同特點技術,其它技術或有雷同就不重複了)

1.       範本語言:

範本語言包括:變數標識和運算式語句。根據運算式的控制力不同,可以分為強控制力範本語言和弱控制力範本語言。而根據範本語言與HTML的相容性不同,又可以分為相容性範本語言和非相容性範本語言。

範本語言要處理三個要點:

1. 標量標記。把變數標識插入html的方法很多。其中一種是使用類似html的標籤;另一種是使用特殊標識,如Velocity或者JDynamiTe;第三種是擴充html標籤,如tapestry。採用何種方式有著很多考慮,一個比較常見的考慮是“所見即所得 (WYSIWYG)”的要求。

2. 條件控制。這是一個很棘手的問題。一個簡單的例子是某物流陪送系統中,物品數低於一定值的要高亮顯示。不過對於一個具體複雜顯示邏輯的情況,條件控制似乎不可避免。當你把類似於<IF condition=”$count <= 40”><then><span class=”highlight”>count </span></then></IF>引入,就象我們當初在ASP和PHP中所做得一樣,我們將不得不再一次面對scriptlet嵌入網頁所遇到的問題。我相信你和我一樣並不認為這是一個好得的編寫方式。實際上並非所有的模板技術都使用條件控制,很多已有的應用如PHP上中的以及我曾見過一個基於ASP.NET的應用,當然還有Java的JDynamiTe。這樣網頁上沒有任何邏輯,不過這樣做的代價是把高亮顯示的選擇控制移交給編程代碼。你必需做個選擇。也許你也象我一樣既不想在網頁中使用條件控制,也不想在代碼中寫html標記,但是這個顯示邏輯是無可逃避的(如果你不想被你的老闆抄魷魚的話),一個可行的方法是用CSS,在編程代碼中決定採用哪個css樣式。特別是CSS2技術,其selector機制,可以根據html類型甚至是element的attributes來apply不同的樣式。

3. 迭代(迴圈)。在網頁上顯示一個資料表單是一個很基本的要求,使用集合標籤將不可避免,不過幸運的是,它通常很簡單,而且夠用。特別值得一提的是PHP的模板技術和JDynamiTe技術利用html的注釋標籤很簡單的實現了它,又保持了“所見既所得”的特性。

下面是一些技術的比較:

Velocity

變數定義:用$標誌

運算式語句:以#開始

強控制語言:變數賦值:#set $this = "Velocity"

            外部參考:#include ( $1 )

            條件控制:#if …. #end

非相容語言

JDynamiTe

變數定義:用{}封裝

運算式語句:寫在注釋格式(<!--  à)中

弱控制語言

相容語言

XSLT

變數定義:xml標籤

運算式:xsl標籤

強控制語言:外部參考:import,include

            條件控制:if,  choose…when…otherwise

非相容語言

Tapestry

採用component的形式開發。

變數定義(組件定義):在html標籤中加上jwcid

運算式語句:ognl規範

相容語言

 

2.       模板檔案:

模板檔案指包含了範本語言的文字檔。

模板檔案由於其範本語言的相容性導致不同結果。與HTML相容性的模板檔案只是一個資源檔,其具有良好的複用性和維護性。例如JDynamiTe的模板檔案不但可以在不同的項目中複用,甚至可以和PHP程式的模板檔案互用。而如velocity的非相容模板檔案,由於其事實上是一個指令碼程式,複用性和可維護性大大降低。

3.       擁有動態資料的資料對象:

模板檔案包含的是靜態內容,那麼其所需的動態資料就需要另外提供。根據提供資料方式的不同可以分為3種:

1.       Map:利用key/value來定位。這個是最常見的技術。如velocity的VelocityContext就是包含了map對象。

Example.vm:

Hello from $name in the $project project.

 

Example.java:

VelocityContext context = new VelocityContext();

context.put("name", "Velocity");

context.put("project", "Jakarta");

 

2.       DOM:直接操作DOM資料對象,如XSLT利用XPath技術。

3.       POJO:直接利用反射取得DTO對象,利用JavaBean機製取得資料。如Tapestry。

4.       模板引擎:

模板引擎的工作分為三步:

1. 取得模板檔案並確認其中的範本語言符合規範。

比如velocity,確定#if有對應得#end等。Xml+xslt的模型中,xml檔案標籤是否完整等。在完成這些工作後,模板引擎通常會把模板檔案解析成一顆節點樹(包含模板檔案的靜態內容節點和模板引擎所定義的特殊節點)。

2. 取得資料對象。

        該資料對象一般通過程式傳遞引用實現。現有的大量架構在程式底層完成,處理方式也各自不同,有兩種技術分別為推技術和拉技術。推技術:controller調用set方法把動態資料注入,模板引擎通過get方法獲得,典型代表:Struts;拉技術:模板引擎根據配置資訊,找到與view對應的model,調用model的get方法取得資料,典型代表:Tapestry。

3. 合并模板檔案(靜態內容)和資料對象(動態內容),並產生最終頁面。

        合并的機制一般如下,模板引擎遍曆這顆節點樹的每一個節點,並render該節點,遇到靜態內容節點按正常輸入,遇到特殊節點就從資料對象中去得對應值,並執行其運算式語句(如果有的話)。

以下詳細說明:

Velocity

Template template = Velocity.getTemplate("test.wm");

Context context = new VelocityContext();

context.put("foo", "bar");

context.put("customer", new Customer());

template.merge(context, writer);

當調用Velocity.getTemplate 方法時,將調用ResourceManger的對應方法。

ResourceManger先查看該模板檔案是否在cache中,如果沒有就去擷取,產生resource對象並調用process()方法,確定該模板是否有效,如果有效,則在記憶體中產生一個Node樹。

當調用template.merge()時,遍曆這顆Node樹,並調用每個Node的render方法。對於模板中的變數和對象Node,還將調用execute()方法,從context中取得value。

   註:ResourceManger在runtime/resource包下,Node在runtime/parser/node包下

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.