js
標籤庫Taglib
標籤被定義和分布在一個稱為標籤庫的結構中,一個標籤庫是由元資訊和類組成的集合:
1.標籤處理器:實現定製標籤功能的Java類。
2.標籤附加資訊(TEI):向JSP容器提供邊輯以確認標籤屬性和建立變數的類。
3.標籤庫描述器(TLD):描述單個標籤和整個標籤庫屬性的XML文檔。
標籤處理器和標籤附加資訊需要定位在JSP容器類載入器可以找到的地方。標籤庫描述器可在URL指定的符意位置。JSP1.1規範要求JSP容器接受一個打包成因定結構的JAR檔案的標籤庫。TLD必須是/META-INF目錄中名為taglib.tld的檔案,JAR檔案則複製到/WEB-INF/lib目錄下。
一、標籤實現
1.開發步驟
a.定義標籤的名字、屬性、聲明的變數和標籤體的內容。
b.編寫標籤庫描述器TLD。
c.編寫標籤處理器。
d.在JSP頁面中使用標籤。
2.JSP頁面在JSP容器中的轉換步驟:
JSP頁面存在三種形式:jsp檔案、java檔案和class檔案。
a.指令元素<%@page%>、<%@include%>和<%@taglib%>向JSP容器提供轉換時資訊。
b.HTML行在_jspService()方法中依順序轉換到out.print()語名中。
c.指令碼元素的聲明被原封不動地複製到_jspService()方法外的源碼中。
d.指令碼元素的運算式在_jspService()方法中依順序轉換到out.print()語名中。
e.指令碼元素的Scriptlet被原封不動地複製到_jspService()方法中。
f.行為元素被轉換為執行其功能的運行時邏輯代碼。
g.定製標籤被擴充到調用其相應標籤處理器中方法的Java語句中。
3.標籤在JSP容器中的轉換步驟:
a.JSP容器使用taglib指令元素定位標籤庫描述器,將頁面中用到的定製標籤和TLD相匹配。
b.讀取標籤庫描述器的標籤列表和每一標籤相關的類名字。
c.在頁面中遇到一個標籤時,尋找與具有指定名字的標籤首碼相關的一個標籤庫。
d.容器使用在TLD中找到的標籤結構資訊產生一系列完成標籤功能的Java語句。
二、標籤庫描述器(TLD)
標籤庫描述器是一個描述整個標籤庫標記資訊和庫中每個標籤處理器及其屬性的XML文檔。
標籤庫描述器的DTD由一個簡單的元素組成,此元素包含下列一些子項目。
整個標籤庫標記資訊
tlibversion 標籤庫版本號碼。是一個點式十進位數,最多為4組小數點分隔的數字組成。
jspversion 標籤庫所需的JSP規範最低版本。例如JSP1.1
shortname 標籤庫的縮寫名。JSP可以使用該名字作為庫中標籤的預設首碼。
uri 標籤庫唯一URI的元素。典型URL位置來自可下載taglib的位置。
info 標籤庫描述資訊。
每個標籤處理器及其屬性
tag 在TLD中加入標籤,描述組成庫的每個標籤。
name 與標籤庫的名字首碼一起使用的標籤的名字, 是JSP容器唯一的標籤標識。
tagclass 實現標籤的標籤處理器類的全名。
teiclass 標籤附加資訊(TEI)類的全名。TEI類給出關於標籤處理器建立變數及對標籤司性執行的任意有效性驗證的資訊。
bodycontent 描述標籤處理器如何使用標籤體的內容。有三種取值:
empty:表示標籤體必須為空白;
JSP:表示指令碼元素和模板及其它標籤一樣被評估。
tagdependent:體內容被原封不動寫入BodyContent,其它指令碼元素以源碼形式出現,而不被JSP容器解釋。
info 標籤的人工可讀描述性資訊。
attribute 使用標籤時被編碼的屬性資訊。用於定義標籤的屬性。
屬性名稱:屬性的名字。
true|false:屬性在標籤用到的位置是否要被編碼。
true|false:屬性值能否用運算式指定。
三、標籤處理器
標籤處理器是通過實現JSP容器調用的一系列預定義方法執行定製標籤行為的一個Java類。
標籤處理器實現了標籤的行為,標籤處理器是Java類。
1.標籤處理器的工作方式
a.匯入javax.servlet.jsp和javax.servlet.jsp.tagext包。
b.實現javax.servlet.jsp.tagext包中的Tag介面或BodyTag介面。BodyTag是Tag的子介面。
c.繼承TagSupport類或BodyTagSuppoert類。它們是上述介面的預設實現。
d.重載public int doStartTag()throws JspException方法。
2.標籤處理器的介面與實現
javax.servlet.jsp.tagext.Tag是實現標籤的最基本的介面。
javax.servlet.jsp.tagext.TagSupport是實現Tag介面的具體類。
通常情況下繼承tagSupport類而不直接實現Tag介面通常是有益的。除了對所有必需方法提供了預設實現外、還儲存了pageContext對象及對嵌套標籤的支援。
Tag介面包含4個常量,表示doStartTag()和doEndTag()方法可能的返回碼。
EVAL_BODY_INCLUDE 當doStartTag()返回時,指明servlet應對標籤體進行評估。
SKIP_BODY 當doStartTag()返回時,指明servlet應忽視標籤體。
EVAL_PAGE 當doEndTag()返回時,指明頁面其餘部分應被評估。
SKIP_PAGE 當doEndTag()返回時,指明頁面其餘部分就被跳過。
Tag介面的方法
public void setPageContext (PageContext ctx) 產生的servlet在要求處理常式執行其它任務前首先調用此方法,實作類別應儲存內容物件以便它可以在標籤生命期中使用。從頁面上下文中標籤處理器可以訪問所有JSP隱含對象。
public void setParent(Tag p) 使用一個標答可以找到操作棧中它上面的標籤。在setPageContext後立即調用。
public Tag getParent() 返回父標籤。
public int doStartTag() throws Jsp 在設定了頁面上下文、父標籤和開始標記中編碼的屬性後調用。返回碼錶明JSP實現servlet是否就評估標籤體。
public int doEndTag()throws JspException 當遇到結否標記時調用。返回碼錶明JSP是否就繼紐頁面的其餘部份。
public void release() 確保在頁面退出前被調用。釋放資源並重設標籤處理器狀態。
TagSupport類的方法
public static Tag finAncestorWithClass(Tag thisTag, Class cls) 為所需的父標籤處理器尋找運行時標籤棧。一個標籤處理器可以提供其範圍內子標籤調用的方法。
public void setId(String id) 儲存和檢索在id屬性中指定的名字。
public void setValue(String name, Object o) 在本地雜湊表中設定指定名字的值。
public Object getValue (String name) 從本地雜湊表中擷取指定名稱的值。
public void removeValue (String name) 從本地雜湊表中刪除指定名稱的值。
public Enumeration getValues() 返回雜湊表中關鍵字的一個枚舉。
3.標籤處理器的生命期
a.產生servlet需要建立標籤處理器類的一個執行個體。實現方式通常是調用JSP容器的工廠類的一個方法,工廠類包含一個標籤處理器執行個體池以使其可重用不再處於啟用狀態的對象。
b.初始化標籤處理器,使servlet獲知其存在性。servlet通過調用標籤處理器的兩個方法實現此過程:setPageContext(PageContext ctx)和setParent(Tag parent)。
c.如果標籤具有屬性,屬性的取值通過處理器提供setter方法傳入到對象。屬性setter方法是一個標籤支援屬性所需的唯一方法。
d.頁面的上下文和父標籤已被調置,並已具備屬性。此時調用標籤處理器的doStartTag()方法,該方法可以讀取這些變數並執行實現標答功能所需的計算和操作。doStartTag()方法必須返回一個整型數。返回EVAL_BODY_INCLUDE則正常處理標籤體,返回SKIP_BODY則從初始JSP頁面中直到此標籤結束標記處的內容均被忽略。
e.標籤體被評估或忽視後調用標籤處理器的doEndTag()方法,返回EVAL_PAGE則頁面的其餘部分被評估,返回SKIP_PAGE則servlet代碼立即從_jspService()中返回。
4.體標籤處理器的介面與實現
javax.servlet.jsp.tagext.BodyTag是Tag的子介面。
javax.servlet.jsp.tagext.BodyTagSupport是實現BodyTag類。
BodyContent是javax.servlet.jsp.JspWriter的子類,但與其父類有所區別。
BodyContent對象的內容不自動寫了入servlet的輸出資料流,而是積累在一字串緩衝中。當標籤體完成後其對象仍可在doEndTag()方法中可以應用,由getString()或getReader()方法操作。並在必要時修改及寫入恢複的JspWriter輸出資料流。
BodyContent類的方法
public void flush()throws IOException 複寫JspWrite.flush()方法以便它總是產生溢出。重新整理寫入已失效,因為它沒有串連到將被寫入的實際輸出資料流中。
public void clearBody() 重設BodyContent緩衝為空白。
public Reader getReader() 返回Reader讀取體內容。
public String getString() 返回包含體內容的一個字串。
public void writeOut(Write w) 將體內容寫入指定輸出。
public JspWrite getEnclosing Write() 返回棧中下一個更高的寫入者對象(可能是另一個BodyContent對象)。
BodyTag介面定義了一個新的整型常量
EVAL_BODY_TAG 當doStartTag()返回時,使得新的BodyContent對象被建立並與此標籤處理器相關聯。當doAfterBody()返回時,使得JSP servlet在修改完此標籤控制的任意變數後再次評估體。
BodyTag介面的方法
public void setBodyContern (BodyContent out) 在當前JspWriter已被寫入,一個新的BodyContent在被建立後由Jsp servlet調用,它發生在doStartTag()之後。
public void doInitBody() throws JspException setBodyContent()之後,體被評估前調用的生命期方法。如果多次評估體,此方法只調用一次。
public init doAfterBody() throws JspException 體被評估後,BodyContent寫入者仍處於啟用狀態時調用的生命期方法。此方法必須返回EVAL_BODY_TAG或SKIP_BODY,若返回EVAL_BODY_TAG時體再次被評估。
BodyTagSupport類的方法
public int doStartTag() throws JspException 複寫TagSupport中的doStartTag()方法。
public int doEndTag() throws JspException 調用TagSupport中的doEndTag()方法,返回結果。
public void setBodyContent (BodyContent out) 在一保護成員變數bodyContent中儲存新的體內容對象,子類可直接存取此對象。
public void doInitBody() throws JspException 預設什麼都不做。被需要執行初始化的子類所複寫。
public int doAfterBody() throws JspException 每次體被評估後由JSP servlet調用,體同容對象仍處於啟用狀態。返回SKEP_BODY或EVAL_BODY_TAG則體再次被評估
public void release() 設定bodyContent對象為null,然後調用super.release()。
public BodyContent getBodyContent() 返回bodyContent變數。子類已經可以訪問保護變數,但此方法允許無關的標籤處理類對此體內容發送輸出。
public JspWriter getPreviousOut() 在bodyContent變數上調用getEnclosingWriter()並返回結果的簡便方法。
5.體標籤處理器的生命期
a.產生servlet需要建立標籤處理器類的一個執行個體。實現方式通常是調用JSP容器的工廠類的一個方法,工廠類包含一個標籤處理器執行個體池以使其可重用不再處於啟用狀態的對象。
b.初始化標籤處理器,使servlet獲知其存在性。servlet通過調用標籤處理器的兩個方法實現此過程:setPageContext(PageContext ctx)和setParent(Tag parent)。
c.如果標籤具有屬性,屬性的取值通過處理器提供setter方法傳入到對象。屬性setter方法是一個標籤支援屬性所需的唯一方法。
d.頁面的上下文和父標籤已被調置,並已具備屬性。調用標籤處理器的doStartTag()方法,該方法可以讀取這些變數並執行實現標答功能所需的計算和操作。
doStartTag()方法必須返回一個整型數。
返回EVAL_BODY_TAG則正常處理標籤體(跳到e);
返回SKIP_BODY則從初始JSP頁面中直到此標籤結束標記處的內容均被忽略。(跳到f)
e.如果返回EVAL_BODY_TAG時,則正常處理標籤體。
e1.在棧中儲存當前的JspWriter對象,建立新的BodyContent對象,並將其置為JSP頁面的out對象儲存在上下文範圍內名為name的屬性中。並調用它的setBodyContent()方法。
e2.調用doInitBody()方法進行初始化。
e3.處理標籤體。將輸出寫入BodyContent對象中,此過程依賴於TLD的標籤元素,有三種可能取值。
e4.調用doAfterBody()方法,將體內體內容寫入JspWriter,可如下實現:
JspWriter out=bodyContent.getEnclosingWriter();
out.println(bodyContent.getString());//bodyContent.writeOut(out);
bodyContent.clear();
e5.doAfterBody()方法返回兩種可能:
返回EVAL_BODY_TAG時,再對標籤體進行評估,這是數組和枚舉被迴圈處理的典型情況。
返回SKIP_PAGE時,繼續頁面的其餘部份。
e6.體內容完成,因此建立它的過程被反向:
調用pageContent.popBody()方法檢索前面的JspWriter對象。
將寫入者設定回out隱含對象。
f.標籤體被評估或忽視後調用doEndTag()方法,允許標籤處理器像輸出資料流發回內容。
返回EVAL_PAGE則頁面的其餘部分被評估;
返回SKIP_PAGE則servlet代碼立即從_jspService()中返回。
g. 此時體的內容在受保護的bodyContent對象中仍然可用。
可以將它寫入servlet輸出資料流中:
JspWriter out=pageContext.getOut();
out.println(bodyContent.getString());
或者
bodyContent.WriteOut(pageContext.getOut());
6.標籤附加資訊類
四、標籤指令
taglib指令元素的目的是指定TLD的位置,設定在頁面上與標籤區分開來的一個短別名。
文法:<%@ taglib prefix=”tag prefix” uri=”taglibURI” %>
屬性:prefix:用於標識標籤庫的唯一標識。uri:標籤庫本身的URI。
uri不必指向一個實際檔案,它是JSP容器可以在web.xml中尋找實際檔案位置的唯一識別碼。