1、起源與現狀:
關於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階段(頁面控制器模式)。
不過這個開發模式有不少問題:
一、頁面中必須寫入Scriptlet調用組件以得到所必需的數據。
二、處理顯示邏輯上Scriptlet代碼和HTML代碼混合交錯。
三、調試困難。JSP被編譯成servlet,頁面上的調試信息不足以定位錯誤。php
這一切都是由於在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。css
2、 模板技術分析:
模板技術從本質上來說,它是一個佔位符動態替換技術。一個完整的模板技術須要四個元素:0. 模板語言,1. 包含模板語言的模板文件,2. 擁有動態數據的數據對象,3. 模板引擎。如下就具體討論這四個元素。(在討論過程當中,我只列舉了幾個不一樣特色技術,其它技術或有雷同就不重複了)
模板語言: 模板語言包括:變量標識和表達式語句。根據表達式的控制力不一樣,能夠分爲強控制力模板語言和弱控制力模板語言。而根據模板語言與HTML的兼容性不一樣,又能夠分爲兼容性模板語言和非兼容性模板語言。
模板語言要處理三個要點:
標量標記。把變量標識插入html的方法不少。其中一種是使用相似html的標籤;另外一種是使用特殊標識,如Velocity或者JDynamiTe;第三種是擴展html標籤,如tapestry。採用何種方式有着不少考慮,一個比較常見的考慮是「所見即所得」的要求。
條件控制。這是一個很棘手的問題。一個簡單的例子是某物流陪送系統中,物品數低於必定值的要高亮顯示。不過對於一個具體複雜顯示邏輯的狀況,條件控制彷佛不可避免。當你把相似於count 引入,就象咱們當初在ASP和PHP中所作得同樣,咱們將不得再也不一次面對scriptlet嵌入網頁所遇到的問題。我相信你和我同樣並不認爲這是一個好得的編寫方式。實際上並不是全部的模板技術都使用條件控制,不少已有的應用如PHP上中的以及我曾見過一個基於ASP.NET的應用,固然還有Java的JDynamiTe。這樣網頁上沒有任何邏輯,不過這樣作的代價是把高亮顯示的選擇控制移交給編程代碼。你必需作個選擇。也許你也象我同樣既不想在網頁中使用條件控制,也不想在代碼中寫html標記,可是這個顯示邏輯是無可逃避的(若是你不想被你的老闆抄魷魚的話),一個可行的方法是用CSS,在編程代碼中決定採用哪一個css樣式。特別是CSS2技術,其selector機制,能夠根據html類型甚至是element的attributes來apply不一樣的樣式。
迭代(循環)。在網頁上顯示一個數據表單是一個很基本的要求,使用集合標籤將不可避免,不過幸運的是,它一般很簡單,並且夠用。特別值得一提的是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規範
兼容語言
模板文件:
模板文件指包含了模板語言的文本文件。
模板文件因爲其模板語言的兼容性致使不一樣結果。與HTML兼容性的模板文件只是一個資源文件,其具備良好的複用性和維護性。例如JDynamiTe的模板文件不但能夠在不一樣的項目中複用,甚至能夠和PHP程序的模板文件互用。而如velocity的非兼容模板文件,因爲其事實上是一個腳本程序,複用性和可維護性大大下降。
擁有動態數據的數據對象:
模板文件包含的是靜態內容,那麼其所需的動態數據就須要另外提供。根據提供數據方式的不一樣能夠分爲3種:
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");
DOM:直接操做DOM數據對象,如XSLT利用XPath技術。
POJO:直接利用反射取得DTO對象,利用JavaBean機制取得數據。如Tapestry。
模板引擎:
模板引擎的工做分爲三步:html
The jsp test file |
/r/n/t "); out.write("The jsp test file"); out.write("/r/n/t "); out.write(" |
若是該標籤有body,根據doStartTag返回值肯定是否pop該標籤內容。若是要pop其body,則:setBodyContent(),在以後,doInitBody()。若是該標籤沒有body,此步跳過。
� 調用doEndTag()以肯定是否跳過頁面剩下部分。
� 最後把tag類返還給tagPool。
tag類爲:
package my.customtags;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
public class Hidden extends TagSupport{
String name;
public Hidden(){ name = ""; }
public void setName(String name){ this.name = name; }
public void release(){ value = null; }
public int doStartTag(){ return EVAL_BODY_INCLUDE;}
public int doEndTag() throws JspTagException{
try{ pageContext.getOut().write(", you are welcome"); }
catch(IOException ex){ throw new JspTagException("Error!"); }
return EVAL_PAGE;
}
}
Jsp頁面:前端
生成的jsp代碼:
my.customtags.Hidden _jspx_th_my_hidden_11 = (my.customtags.Hidden) _jspx_tagPool_my_hidden_name.get(my.customtags.Hidden.class);
_jspx_th_my_hidden_11.setPageContext(pageContext);
_jspx_th_my_hidden_11.setParent(null);
_jspx_th_my_hidden_11.setName("testname");
int _jspx_eval_my_hidden_11 = _jspx_th_my_hidden_11.doStartTag();
if (_jspx_th_my_hidden_11.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE)
return true;
_jspx_tagPool_my_hidden_name.reuse(_jspx_th_my_hidden_11);
return false;
Taglib技術提供兩個機制,Body和non-若是該標籤有body,根據doStartTag返回值肯定是否pop該標籤內容。若是要pop其body,則:setBodyContent(),在以後,doInitBody()。若是該標籤沒有body,此步跳過。
� 調用doEndTag()以肯定是否跳過頁面剩下部分。
� 最後把tag類返還給tagPool。
tag類爲:
package my.customtags;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
public class Hidden extends TagSupport{
String name;
public Hidden(){ name = ""; }
public void setName(String name){ this.name = name; }
public void release(){ value = null; }
public int doStartTag(){ return EVAL_BODY_INCLUDE;}
public int doEndTag() throws JspTagException{
try{ pageContext.getOut().write(", you are welcome"); }
catch(IOException ex){ throw new JspTagException("Error!"); }
return EVAL_PAGE;
}
}
Jsp頁面:java
生成的jsp代碼:
my.customtags.Hidden _jspx_th_my_hidden_11 = (my.customtags.Hidden) _jspx_tagPool_my_hidden_name.get(my.customtags.Hidden.class);
_jspx_th_my_hidden_11.setPageContext(pageContext);
_jspx_th_my_hidden_11.setParent(null);
_jspx_th_my_hidden_11.setName("testname");
int _jspx_eval_my_hidden_11 = _jspx_th_my_hidden_11.doStartTag();
if (_jspx_th_my_hidden_11.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE)
return true;
_jspx_tagPool_my_hidden_name.reuse(_jspx_th_my_hidden_11);
return false;
Taglib技術提供兩個機制,Body和non-Body致使了taglib的出現了兩個分支:Display Tag和Control Tag, 前者在java code中嵌入了html標籤,至關與一個web component,然後者則是另外一種模板腳本。
4、兩種技術方案的比較:node