Attribute元素
對于tag標簽的每個屬性,你必須定義它是否必須的,它的值是否可以用諸如<%= …%>的表達式來獲得,
以及它的類型(可選),如果不指定它的類型,那就默認為是java.lang.String類型。如果rtexprvalue
元素被定義為true或yes,那么在type元素中就定義了attribute的返回類型。
<attribute>
<name>attr1</name>
<required>true|false|yes|no</required>
<rtexprvalue>true|false|yes|no</rtexprvalue>
<type>attribute的返回類型(只用當rtexprvalue為真是才有效)</type>
</attribute>
如果tag的某個屬性不是必須的,那tag處理類會自動提供一個缺省值。
例如,在logic:present這個tag標簽中定義了一個屬性叫parameter,但它不是必須的,而且它可以
被諸如<%= …%>的表達式來賦值。
<tag>
<name>present</name>
<tag-class>org.apache.struts.taglib.logic.PresentTag</tag-class>
<body-content>JSP</body-content>
…
<attribute>
<name>parameter</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
…
</tag>
屬性元素的校驗
有關于tag標簽的有效值可以從tag庫的說明文檔中獲得,當JSP頁面被編譯時,jsp引擎會強制性地
參照TLD中定義的規則進行檢查。
還有一個方法也可以進行屬性元素的校驗,就是先繼承類TagExtraInfo,然后調用它的isValid方法。
這個類同時也起到提供tag中定義的腳本變量信息的作用。
IsValid方法通過TagData對象來傳遞屬性信息,它包括著tag的所有的屬性名-值的信息。
由于校驗發生在運行時刻,因此這個屬性的值將被賦值為TagData.REQUEST_TIME_VALUE。
例如tag標簽<tt:twa attr1=”value1” />在TLD中定義如下:
<attribute>
<name>attr1</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
這個定義說明了attr1能在運行期間被賦值。
以下的isValid方法檢查attr1屬性的值是否屬于Boolean類型。注意由于attr1能在運行刻被賦值,
那么isValid方法必須檢查tag用戶是否對此tag進行了運行時刻賦值。
Public class TwaTEI extends TagExtraInfo
{
public boolean isValid(Tagdata data)
{
Object o = data.getAttribute(“attr1”);
If(o != null && o != TagData.REQUEST_TIME_VALUE)
{
if( ( (String)o).toLowerCase().equals(“true”) ||??
((String)o).toLowerCase().equals(“false”) )
return true;
else
return false;
}
else
return true;
}
}
帶body的tag
tag處理類
如果tag標簽含有內容,那處理方式會略微有些不同,而且還要視tag處理類是否要與body交互的情況而定。
如果要與body交互,那我們認為tag處理類要可能要對body進行操作。
Tag處理類不與body交互
如果tag處理類不與body交互,tag處理類應該實現Tag接口或從TagSupport中派生,如果body要被計算,
那么doStartTag方法應返回 EVAL_BODY_INCLUDE,否則應返回SKIP_BODY。
如果tag處理類要對body反復運算,則它應該實現IterationTag或從TagSupport中派生。如果tag處理類
認為body還未計算完的話,那它的doStartTag方法和doAfterBody方法必須返回EVAL_BODY_AGAIN。
Tag處理類與body交互
如果tag處理類與body交互,那tag處理類應實現BodyTag接口或從BodyTagSupport中派生。這種tag處理類
一般要實現doInitBody和doAfterBody方法。
Body允許一些方法來讀寫它的內容。Tag處理類可以調用body內容的getString或getReader方法來從body中
提取信息,也可用 writeOut(out) 方法來將body的內容寫入到out對象中。其中out對象通過tag處理類的
getPreviousOut方法來獲得。
如果body的內容需要被計算,那么doStartTag方法必須返回EVAL_BODY_BUFFERED,否則,它將返回SKIP_BODY。
doInitBody 方法
此方法在body內容已經設好,但未被計算之前被調用。你可以根據不同的body內容來制定初始化策略。
doAfterBody方法
此方法在body內容已被計算后進行調用。
和doStartTag方法一樣,doAfterBody方法返回一個指示符指示是否要繼續計算body,如果要繼續計算,
則doAfterBody應返回EVAL_BODY_BUFFERED,否則,它應返回SKIP_BODY。
release 方法
tag處理類調用此方法將它的狀態重置為初始狀態,并釋放所有的私有資源。
以下的例子讀取body的內容(其中含有一條sql語句),然后將它傳遞給一個對象,讓它進行查詢。
由于此處body不須重新計算,所以doAfterBody會返回SKIP_BODY。
Public class QueryTag extends BodyTagSupport
{
public int doAfterBody() throws JspTagException
{
BodyContent bc = getBodyContent();
//將body的內容以字符串的格式提取出來
String query = bc.getString();
//清除body
bc.clearBody();
try{
Statement stmt = connection.createStatement();
Result result = stmt.executeQuery(query);
}catch(SQLException e){
throw new JspTagException(“queryTag: “ + e.getMessage() );
return SKIP_BODY;
}
}
body-content元素
由于tag可能會有body,你必須用body-content元素來指定body內容的類型:
<body-content>JSP|tagdependent</body-content>
如果body的內容是定制的或內部的tag、腳本元素、或HTML廣本,則歸類為JSP類型。其他的類型,
比如上面代碼所述的?D?D將sql statement類傳給 query tag的這種類型應該標為tagdependent。
注意:實際上body-content的值并不影響tag處理類對body內容的處理,它僅僅是被tag編輯工具
用來描述此body的內容。
用tags定義腳本變量
tag處理類
tag處理類負責創建或設置頁面中定義的腳本變量,用pageContext.setAttribute(name,value,scope)
或pageContext.setAttribute(name,value)方法來實現。一般來說,tag處理類通過腳本變量的名稱來
獲取它,腳本變量的名稱一般可用get方法來獲得。
如果腳本變量的值依賴于tag處理類中的上下文中某一對象,那它可用pageContext.getAttribute(name,scope)
方法來找到那個對象。一般的處理過程是tag處理類先找到腳本變量,再對其進行處理,
然后用pageContext.setAttribute(name,object)的方法來設置它的新值。
對象的生存周期(scope)如下表:
對象的生存周期表
名字
可訪問范圍
生存周期
page
當前頁面
一直有效,除非頁面向客戶提交響應或重定向到一個新頁面
request
當前頁面或當前頁面重定向到的頁面
一直有效,除非頁面向客戶提交響應
session
當前頁面或在同一瀏覽器窗口中的頁面
一直有效,除非關閉當前瀏覽器、超時、網絡故障
application
整個web應用程序的所有請求
一直有效,除非發生網絡故障、服務器故障
提供關于腳本變量的信息
以下示例定義了一個名為“book”的腳本變量,用來訪問程序中關于書的信息:
<bean:define id=”book” name=”bookDB” property=”bookDetails” type=”database.BookDetails” />
<font color=”red” size=”+2” >
<%= messages.getString(“CartRemoved”) %>
<strong><jsp:getProperty name=”book” property=”title” /></strong>
</font>
當包含此tag的JSP頁面被編譯時,jsp引擎會自動生成關于此book的同步的代碼
(同步可以避免幾個客戶同時訪問此book時造成的沖突),要生成同步代碼,
jsp引擎需要知道此腳本變量的如下信息:
· 腳本變量名稱
· 腳本變量所屬的類
· 此腳本變量是否引用了一個新的或已存在的對象
· 此腳本變量的有效性
有兩種辦法可以向jsp引擎提供關于腳本變量的信息:在TLD中定義variable子元素,
或用tei-class子元素定義一個額外tag信息類。用variable最簡單,但可能降低了一些靈活性。
Variable元素
Variable元素有如下子元素:
· name-given ?D?D 給出的名字,是一個常量
· name-from-attribute?D?D 屬性名,在編譯時給出的屬性名
name-given或name-from-attribute兩者必須選一,但以下子元素是可選的:
· variable-class?D?D變量的類型,缺省為java.lang.String。
· declare?D?D此腳本變量是否引用了一個新對象,缺省為True。
· scope?D?D腳本變量的范圍,缺省為NESTED。下表描述了scope的幾種類型:
腳本變量的有效范圍
值
有效性
方法
NESTED
在tag標簽的開始和結束之間
如果tag處理類實現BodyTag接口,則在doInitBody和doAfterBody中調用,否則在doStartTag中調用
AT_BEGIN
從tag標簽的開始一直到頁面結束
如果tag處理類實現BodyTag接口,則在doInitBody、doAfterBody和doEndTag中調用,
否則在doStartTag和doEndTag中調用
AT_END
從tag標簽的結束一直到頁面結束
在doEndTag中調用
以struts為例,它的bean:define標簽的實現遵循JSP1.1規范,此規范要求使用額外tag信息類來定義腳本變量。
Variable元素是JSP1.2規范中加入的。以bean:define標簽為例,你可以定義如下variable元素:
<tag>
<variable>
<name-from-attribute>id</name-from-attribute>
<variable-class>database.BookDetails</variable-class>
<declare>true</declare>
<scope>AT_BEGIN</scope>
</variable>
</tag>
額外tag信息類
如果要定義一個額外tag信息類,你要繼承javax.servlet.jsp.TagExtraInfo類。
一個TagExtraInfo類必須實現getVariableInfo方法,此方法返回一個叫VariableInfo的數組類,
它包括如下信息:
· 變量名
· 變量所屬類名
· 此變量是否引用了一個新對象
· 此變量的有效范圍
jsp引擎將一個名為data的參數傳給getVariableInfo方法,data中包括tag標簽中的所有“屬性名?D?D屬性值”對。
它可以用來向VariableInfo對象提供腳本變量的名字和類名。
以struts為例,它在bean:define標簽中定義了一個名為DefineTei的額外tag信息類,用來向腳本變量提供信息。
由于腳本變量的名稱(book)和類名(database.BookDetails)是通過tag標簽的屬性來傳遞的,
它們一般定義在VariableInfo的構建代碼中,并且可用data.getAttributeString方法來得到這些信息。
如果要允許book腳本變量能在從tag開始直到整個JSP頁面結束的范圍內都可用的話,那它的范圍應設為AT_BEGIN。
如下所示:
public class DefineTei extends TagExtraInfo
{
public VariableInfo[] getVariableInfo(TagData data)
{
String type = data.getAttributeString(“type”);
If( type == null)
type = “java.lang.Object”;
return new VariableInfo[] {
new VariableInfo(data.getAttributeString(“id”),??
type,
true,
VariableInfo.AT_BEGIN)
};
}
}
注意:關于額外tag信息類的類名必須要在TLD中的tag標簽下的tei-class子元素中定義。
因此,DefineTei的tei-class中的定義看起來如下:
<tei-class>
org.apache.struts.taglib.bean.DefineTagTei
</tei-class>
具有協作關系的tag
tag通過共享對象來進行協作,JSP技術支持2種方式的對象共享。
第一種方法是使用pageContext對象進行對象的共享(可支持JSP頁面和tag處理類之間的共享),
如果在一個tag處理類中要調用由另一個tag處理類創建的對象,可調用pageContext.getAttribute(name, scope)方法。
第二各方式的共享是對于tag之間有嵌套關系而言的,外層的tag所創建的對象對于內層的tag來說是
可以共用的。這種形式的共享的好處是減少了可能存在的重名沖突。
要訪問一個嵌套tag創建的對象,tag處理類必須先找到此嵌套tag對象,可用TagSupport的靜態方法
TagSupport.findAncestorWithClass(from, class)或TagSupport.getParent方法。前者在當不確定
此tag是否為嵌套tag對象時使用。一旦它的父類被找到,它就能訪問其所有動態或靜態創建的對象。
靜態創建的對象是父類的成員,而動態創建的對象可能是父類的私有對象。諸如此類的對象可以用tag處理類的setValue方法來保存,用getValue方法來獲得。
下例闡述了以上兩種共享對象的方法。在這個例子當中,一個查詢tag檢查一個名為connection的屬性名
是否在doStartTag中被設置。如果connection屬性被設置,tag處理類從pageContext中得到這個connection對象。
否則,此tag處理類先找到它的父tag處理類,然后從它的父tag處理類中找到connection對象。
public class QueryTag extends BodyTagSupport
{
???? private String connectionId;
???? public int doStartTag() throws JspException
??? {
?????? String cid = getConnection();
?????? if(cid != null)
?????? {
?????????? //存在一個connection id,使用它。
?????????? connection = (Connection) pageContext.getAttribute(cid);
?????? }
?????? else
?????? {
?????????? ConnectionTag ancestorTag = (ConnectionTag)findAncestorWithClass(this,??
?????????? ConnectionTag.class);
?????????? if(ancestorTag == null)
?????????? {
????????????? throw new JspTagException(“一個沒有connection屬性的查詢標簽必須被一個connection標記嵌套。”);
?????????? }
?????????? connection = ancestorTag.getConnection();
?????? }
??? }
}??
此查詢標簽在JSP頁面中的調用形式可以從以下2種定義中任選一種:
<tt:connection id=”con01” ...> ... </tt:connection>
<tt:query id=”balances” connection=”con01” >
SELECT account, balance FROM acct_table
where customer_num = <%= request.getCustno() %>
</tt:query>
或
<tt:connection ...>
<x:query id=”balances”>
SELECT account, balance FROM acct_table
where customer_num = <%= request.getCustno() %>
</x:query>
</tt:connection>
與此同時,在TLD中必須指定connection屬性為可選的,定義如下:
<tag>
...
<attribute>
<name>connection</name>
<required>false</required>
</attribute>
</tag>
posted on 2007-08-14 23:51
jadmin 閱讀(84)
評論(0) 編輯 收藏