小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

推薦一篇關(guān)于JSTL的好文章

 shaobin0604@163.com 2006-09-08
JSP 2.0: The New Deal, Part 1

作者: Hans Bergsten, 《JavaServer Pages, 3rd Edition》11/05/2003

期待已久的日子即將到來: 最新版JavaServer Pages (JSP)2.0規(guī)范即將和其他的J2EE 1.4一同發(fā)布。新的JSP版本有一個新的飛躍,采用了新的方式:由于新的語言表達式(Expression Language,以下簡稱為EL)和JSP標準標簽庫(JSP Standard Tag Library ,以下簡稱為JSTL)這兩種新的方式,在頁面中不需要用java,對于開發(fā)一般的應用來說,重用代碼變得更加容易。更具體來說,JSP 2.0帶來了以下的優(yōu)點:

首次被JSTL 1.0引入的EL現(xiàn)在被合并到JSP規(guī)范中,就像應用template text一樣地使用所有的標準的和定制的組件。
新的EL已經(jīng)被擴展,具備一個函數(shù)調(diào)用機制,JSTL1.1整合了一系列經(jīng)常需要使用的函數(shù)。
新增加的變量和servlet 規(guī)范定義的錯誤處理機制被更好地組織起來。通過新增加的變量,JSP error pages 現(xiàn)在可以提供更多的錯誤信息。
容器因為更加嚴格的語法檢查可以更容易地找出發(fā)生的錯誤。
所有的J2EE 1.4規(guī)范(包括JSP 2.0 和 Servlet 2.4),為了聲明部署的規(guī)則描述而應用了XML schema。這樣的好處之一是你現(xiàn)在可以通過任何順序列出web.xml文件中的描述。JSP 2.0也增加了一些新的配置選項用于部署描述,允許通過全局的配置來代替基于每頁的配置。
由于更具伸縮性的規(guī)則和新的自定義action element,現(xiàn)在就像編寫XML文件一樣,編寫JSP頁面變得更加容易。
定制的標簽庫現(xiàn)在可以開發(fā)成一系列的標簽文件(具有JSP元素的文本文件),標簽處理器可以使用新的、簡化的標簽處理器的API。與此同時,新規(guī)范加入了一些新的特性,比如:支持在jsp頁面上顯示動態(tài)屬性列表和可執(zhí)行片斷屬性。
在眾多的書籍中,這是頭一個講解JSP 2.0新特性的文章。在這一部分,我們將看到和EL相關(guān)的信息,其他的新特性留到后面。在這里我假定讀者已經(jīng)熟悉JSP 1.2,而且至少聽說過JSTL。

你可能對這本第三版的《JavaServer Pages》感興趣。這本書中,我盡可能在細節(jié)上講述所有的內(nèi)容,而且并不認為你對JSP或者JSTL了解一切。這本書預計在2003年12月 出版,但是你現(xiàn)在可以在http://www.amazon.com、Barnes&Noble,或者其他在線書店預訂。

EL(The Expression Language)

如果過去使用過JSTL,那么你可能已經(jīng)熟悉了EL。EL在JSTL 1.0規(guī)范中被引入,用來在運行期間對Java表達式中action element屬性賦值提供另一種選擇。當JSTL EL已經(jīng)非常迅速的流行起來情況下,還是存在一個問題: JSTL EL 表達式僅僅可以與JSTL和custom action一起使用,怎樣才能使用非標準API對EL表達式求值?

JSP 2.0中,JSP容器自己可以理解EL表達式。這使你在所有過去只能應用Java表達式的地方應用EL表達式成為可能,比如:標準和定制action的屬性值,模板文本。

在我們看具體的例子前,讓我們更進一步的看看什么是EL。EL是從JavaScript中獲得啟發(fā)的一種語言,XPath(一種用來訪問XML文檔的語言),但是EL在對變量的null值和執(zhí)行更多數(shù)據(jù)類型的自動類型轉(zhuǎn)換的處理上更加寬松。這些新特性對于web應用非常重要,在這些應用中輸入通常通過html表單的request parameter來得到。這些參數(shù)可能僅僅在某些請求下才能體現(xiàn)出來,而且瀏覽器經(jīng)常將request parameter作為文本發(fā)送,然而應用程序經(jīng)常需要把他們作為數(shù)字類型、布爾類型(true 或者 false)來使用。通過EL,你根本就很少需要關(guān)心缺少某些參數(shù)的值或者類型轉(zhuǎn)換。

一個EL表達式包含變量和操作符。任何存儲在某個JSP作用范圍(如:page、 request、session、application)的bean能被作為一個EL變量來使用。另外,EL支持以下預定義的變量:

變量名稱
說明

pageScope
一個包含所有page scope范圍的變量集合 (a java.util.Map)

requestScope
一個包含所有request scope范圍的變量集合 (a java.util.Map)

sessionScope
一個包含所有session scope范圍的變量集合 (a java.util.Map)

applicationScope
一個包含所有application scope范圍的變量集合 (a java.util.Map)

param
一個包含所有請求參數(shù)的集合 (a java.util.Map),通過每個參數(shù)對應一個String值的方式賦值

paramValues
一個包含所有請求參數(shù)的集合 (a java.util.Map),通過每個參數(shù)對應一個String數(shù)組的方式賦值

header
一個包含所有請求的頭信息的集合, (a java.util.Map) ,通過每個頭信息對應一個String值的方式賦值

headerValues
一個包含所有請求的頭信息的集合 (a java.util.Map) ,通過每個頭信息的值都保存在一個String數(shù)組的方式賦值

cookie
一個包含所有請求的 cookie集合 (a java.util.Map),   通過每一個cookie(javax.servlet.http.Cookie)對應一個cookie值的方式賦值

initParam
一個包含所有應用程序初始化參數(shù)的集合(a java.util.Map) ,通過每個參數(shù)分別對應一個String值的方式賦值

pageContext
一個javax.servlet.jsp.PageContext類的實例, 用來提供訪問不同的請求數(shù)據(jù)


操作符描述了你對變量所期望的操作。如果你之前曾經(jīng)使用過任何編程語言的話,在EL表達式中所使用的操作符對你來說可能看起來很熟悉。因為它們和那些在大多數(shù)語言中所支持的操作符一樣。

Operator
Description

.
訪問一個bean屬性或者 Map entry

[]
訪問一個數(shù)組或者鏈表元素

()
對子表達式分組,用來改變賦值順序

:
條件語句,比如: 條件 ? ifTrue : ifFalse.如果條件為真,表達式值為前者,反之為后者

+
數(shù)學運算符,加操作

-
數(shù)學運算符,減操作或者對一個值取反

*
數(shù)學運算符,乘操作

/ or div
數(shù)學運算符,除操作

% or mod
數(shù)學運算符,模操作(取余)

== or eq
邏輯運算符,判斷符號左右兩端是否相等,如果相等返回true,否則返回false

!= or ne
邏輯運算符,判斷符號左右兩端是否不相等,如果不相等返回true,否則返回false

< or lt
邏輯運算符,判斷符號左邊是否小于右邊,如果小于返回true,否則返回false

> or gt
邏輯運算符,判斷符號左邊是否大于右邊,如果大于返回true,否則返回false

<= or le
邏輯運算符,判斷符號左邊是否小于或者等于右邊,如果小于或者等于返回true,否則返回false

>= or ge
邏輯運算符,判斷符號左邊是否大于或者等于右邊,如果大于或者等于返回true,否則返回false

&& or and
邏輯運算符,與操作賦。如果左右兩邊同為true返回true,否則返回false

|| or or
邏輯運算符,或操作賦。如果左右兩邊有任何一邊為true返回true,否則返回false

! or not
邏輯運算符,非操作賦。如果對true取運算返回false,否則返回true

empty
用來對一個空變量值進行判斷: null、一個空String、空數(shù)組、 空Map、沒有條目的Collection集合

func(args)
調(diào)用方法, func是方法名,args是參數(shù),可以沒有,或者有一個、多個參數(shù).參數(shù)間用逗號隔開


一個EL表達式可以包含:數(shù)字、文本(在單引號或者雙引號之間)、布爾值、null值。

因為一個EL表達式可以出現(xiàn)在靜態(tài)文本出現(xiàn)的地方,因此你必須告訴JSP容器它應該被當作一個EL表達式來處理。你可以通過使用定界符來做到這一點。一個EL表達式總是以”${ }”來標記(一個“$”符號和一個左花括號,右花括號)。這里有一個EL表達式,它將一個命名為amount的變量加5:

${amount + 5}

如果你想要將5加到一個bean的property上,可以使用property訪問操作符:

${order.amount + 5}

在當前這個指定的bean或者collection集合中,Property訪問操作符(一個“.“符號)告訴EL去尋找名字為amount的property。

${order[‘a(chǎn)mount‘] + 5}

在[]之間的值必須是一個property的名字(就像上面的例子中那樣)或者是一個保存property名字的變量(或者是一個完整的EL子表達式)。

EL表達式可以被用來賦值給任何標準的或者定制的JSP行為屬性(action attribute),這些行為屬性被標記為可以接受動態(tài)值(或者請求期間的屬性值,就象它被正式調(diào)用一樣):

<c:out value="${order.amount + 5}"/>

在JSP 2.0之前,你不得不使用Java表達式去給一個屬性動態(tài)賦值。在過去的很多年中,這已經(jīng)成為語法混亂的一個普遍根源。

最后,EL表達式可以在頁面中和模板直接混合使用。當你生成HTML并且需要設(shè)置一個動態(tài)值給一個屬性的時候,這非常方便:

<input name="firstName" value="${customer.firstName}">

JSP 1.2中,你不得不使用JSTL的<c:out>來實現(xiàn)同樣的事情,最后把各種不同類型的元素混合起來,這導致程序理解起來非常的困難:

<input name="firstName"

value="<c:out value="${customer.firstName}"/>" >



新JSTL 1.1 Tag Library 標識符
JSTL1.1發(fā)布的是一個初級的版本,主要目的是用來整合JSTL和JSP2.0 。最明顯的變化是JSTL1.0 “孿生函數(shù)庫”(一組庫用來接受EL表達式,另外一組用來接受JAVA表達式),而它們已經(jīng)被一組既可以用于EL表達式也可以用于JAVA表達式的函數(shù)庫所代替。

在JSTL 1.1中使用以下標識符:


URI
前綴

Core
http://java./jsp/jstl/core
c

XML processing
http://java./jsp/jstl/xml
x

I18N formatting
http://java./jsp/jstl/fmt
fmt

Database access
http://java./jsp/jstl/sql
sql

Functions
http://java./jsp/jstl/functions
fn


如果你曾經(jīng)使用過JSTL1.0,你可能會注意到新的標識符和舊的EL庫標試符一模一樣,除了加入了“/jsp path” element。你也可能注意到在JSTL1.1中有一個庫,包含了EL的函數(shù)。我們稍后就會看到。

一個新的EL操作符
在JSP頁面中一個非常普遍的需求就是:當某個條件為真時,要在網(wǎng)頁中包含一些文字。在JSP1.2和JSTL1.1中,用具有代表性的<c:if>來實現(xiàn),但是這樣做非常繁瑣。JSP2.0增加了一個新的條件操作符用于EL,以更加優(yōu)雅的方式來處理這樣的情況。這個條件操作符存在于很多編程語言中(比如:Java,C,JavaScript),因此你可能以前就見過它。它判斷一個布爾的條件,當條件為真或者假時,分別取不同的結(jié)果。

一個能清楚說明它如何工作的例子:

<select name="artist">
<option value="1" ${param.artist == 1 ? ‘selected‘ : ‘‘}>
Vesica Pisces
<option value="2" ${param.artist == 2 ? ‘selected‘ : ‘‘}>
Cortical Control
<option value="3" ${param.artist == 3 ? ‘selected‘ : ‘‘}>
Vida Vierra
</select>

在這里,我使用了EL表達式和條件操作符來選擇是否包含 html 中的 “selected”屬性,只有符合條件的 “option” 才被添加 “selected” 屬性。如果條件(param.artist==1)為真時,前面的“selected” 才被添加到網(wǎng)頁中;否則就添加后面的(在這里是空字符串 ‘’)到頁面中。

EL函數(shù)
當EL從JSTL規(guī)范中移到JSP規(guī)范中,它使用了一個如何進行函數(shù)調(diào)用的技巧。這個EL函數(shù)語法非常簡單:方法名,緊接著在圓括號中有一組參數(shù):

<%@ taglib prefix="fn"
uri="http://java./jsp/jstl/functions" %>
${fn:length(myCollection)}
這是一個屬于標簽庫中的函數(shù),并且函數(shù)名字在頁面中所包含的前綴要指定taglib庫。在這個例子中,我使用了前綴fn,這是JSTL function庫默認的前綴。

標簽庫描述符(Tag Library Descriptor,TLD)將函數(shù)名稱映射到一個由JAVA實現(xiàn)的靜態(tài)方法中:

<function>
<description>
Returns the number of items in a collection or the number of characters in a string.
</description>
<name>length</name>
<function-class>
org.apache.taglibs.standard.functions.Functions
</function-class>
<function-signature>
int length(java.lang.Object)
</function-signature>
</function>
在這里最有趣的element是<function-signature>。它包含一個函數(shù)返回類型的聲明,靜態(tài)的方法的名字,在圓括號中聲明該方法所有參數(shù)的類型(可以沒有參數(shù)或者有多個,參數(shù)間用逗號間隔開)。返回值類型和參數(shù)類型必須是java的原始類型(Object)或者是其他合法類型。

這個靜態(tài)方法 length()在Jakarta Taglibs標準庫中用類似于下面的代碼實現(xiàn)的:

public static int length(Object obj)
throws JspTagException {
if (obj == null)
return 0;
if (obj instanceof String)
return ((String)obj).length();
if (obj instanceof Collection)
return ((Collection)obj).size();
if (obj instanceof Map)
return ((Map)obj).size();
int count = 0;
if (obj instanceof Iterator) {
Iterator iter = (Iterator) obj;
count = 0;
while (iter.hasNext()) {
count++;
iter.next();
}
return count;
}
if (obj instanceof Enumeration) {
Enumeration enum = (Enumeration) obj;
count = 0;
while (enum.hasMoreElements()) {
count++;
enum.nextElement();
}
return count;
}
try {
count = Array.getLength(obj);
return count;
} catch (IllegalArgumentException ex) {}
throw new JspTagException("Unsupported type"));
}

就像你所看到的,在那里沒有什么出奇的地方。它是一個常規(guī)的靜態(tài)方法,這個函數(shù)中通過對運行期中的參數(shù)類別的判斷,找出參數(shù)的長度。

除了在這個方法中使用的length()方法,JSTL1.1標簽庫還包含了許多其它經(jīng)常使用的函數(shù):

函數(shù)
描述

fn:contains(string, substring)
如果參數(shù)string中包含參數(shù)substring,返回true

fn:containsIgnoreCase(string, substring)
如果參數(shù)string中包含參數(shù)substring(忽略大小寫),返回true

fn:endsWith(string, suffix)
如果參數(shù) string 以參數(shù)suffix結(jié)尾,返回true

fn:escapeXml(string)
將有特殊意義的XML (和HTML)轉(zhuǎn)換為對應的XML character entity code,并返回

fn:indexOf(string, substring)
返回參數(shù)substring在參數(shù)string中第一次出現(xiàn)的位置

fn:join(array, separator)
將一個給定的數(shù)組array用給定的間隔符separator串在一起,組成一個新的字符串并返回。

fn:length(item)
返回參數(shù)item中包含元素的數(shù)量。參數(shù)Item類型是數(shù)組、collection或者String。如果是String類型,返回值是String中的字符數(shù)。

fn:replace(string, before, after)
返回一個String對象。用參數(shù)after字符串替換參數(shù)string中所有出現(xiàn)參數(shù)before字符串的地方,并返回替換后的結(jié)果

fn:split(string, separator)
返回一個數(shù)組,以參數(shù)separator 為分割符分割參數(shù)string,分割后的每一部分就是數(shù)組的一個元素

fn:startsWith(string, prefix)
如果參數(shù)string以參數(shù)prefix開頭,返回true

fn:substring(string, begin, end)
返回參數(shù)string部分字符串, 從參數(shù)begin開始到參數(shù)end位置,包括end位置的字符

fn:substringAfter(string, substring)
返回參數(shù)substring在參數(shù)string中后面的那一部分字符串

fn:substringBefore(string, substring)
返回參數(shù)substring在參數(shù)string中前面的那一部分字符串

fn:toLowerCase(string)
將參數(shù)string所有的字符變?yōu)樾?,并將其返?br>
fn:toUpperCase(string)
將參數(shù)string所有的字符變?yōu)榇髮懀⑵浞祷?br>
fn:trim(string)
去除參數(shù)string 首尾的空格,并將其返回


結(jié)束語:
在這篇文章中,我從EL講到JSTL1.1規(guī)范、EL新特色和JSTL 1.1函數(shù)庫。接下來的部分我將要告訴你:關(guān)于JSP error-page的改進和增強; jsp:id 屬性帶來的益處;新的配置屬性描述符;JSP2.0如何使JSP操作XML變得更加容易;自定義標簽庫的新特性。

JSP 2.0: The New Deal, Part 2
by Hans Bergsten, author of JavaServer Pages, 3rd Edition,12/03/2003

這篇文章是講述加入到JavaServer Pages (JSP) 2.0 規(guī)范中的特性的系列文章的第二部分。在前面的第一部分,我描述了新的EL表達式,但是還有更多的內(nèi)容沒有涉及。這一部分描述的是JavaServer Pages (JSP) 2.0 規(guī)范在錯誤處理機制和新的部署描述符特性方面的增強。我假設(shè)你熟悉JSP 1.2,而且至少聽說過JSP Standard Tag Library (JSTL)。

JSP Error Pages
如果你曾經(jīng)在JSP和servlet的錯誤處理中使用過JSP error page,并且想要顯示或者記錄違例信息(違例導致JSP error page 被調(diào)用),那么你就知道在JSP1.2中這并不是件輕松的事情。原因是當在servlets和JSP 頁面中聲明了一個errorPage,違例(exception)被作為一個request attribute傳遞,它們要使用不同的屬性名稱。只有被傳遞的違例通過JSP屬性名稱自動地顯示在 JSP error page中(通過exception腳本變量和${pageContext.exception} EL 表達式)。

JSP 2.0通過將相同的屬性名稱轉(zhuǎn)換為servlet規(guī)范中的javax.servlet.error.exception來修正了這個問題。更進一步說,一個新增的 命名為errorData的EL pageContext變量揭露了發(fā)生問題的其他信息。ErrorData屬性是javax.servlet.jsp.ErrorData的一個實例。這個實例可以被   用來作為一個bean和以下的properties一同使用:

Property
Java 類型
描述

requestURI
String
發(fā)生請求失敗的 URI

servletName
String
發(fā)生錯誤的servlet或者JSP頁面的名稱

statusCode
int
發(fā)生錯誤的狀態(tài)碼

throwable
Throwable
導致當前error page被調(diào)用的違例


這里有個JSP error page的例子。這個例子使用了上面提到的一些property:

<%@ page isErrorPage="true" contentType="text/html" %>
<%@ taglib prefix="log" uri="http://jakarta./taglibs/log-1.0" %>

Sorry, but things didn‘t work out as planned. I‘ve logged as much as
I know about the problem, so rest assured that my master will look
into what‘s wrong as soon as he‘s sober.

<jsp:useBean id="now" class="java.util.Date" />
<log:fatal>
-----
${now}
Request that failed: ${pageContext.errorData.requestURI}
Status code: ${pageContext.errorData.statusCode}
Exception: ${pageContext.errorData.throwable}
-----
</log:fatal>
這個頁面使用Apache Jakarta Taglib項目中的 Log tag library來顯示一些確定的信息并記錄下了具體的細節(jié)。

你可以在web.xml文件中使用<error-page>來對servlet和JSP 頁面聲明這是一個error page:

...
<error-page>
  <exception-type>java.lang.Throwable</exception-type>
  <location>/error.jsp</location>
</error-page>
<error-page>
  <exception-code>500</exception-code>
  <location>/error.jsp</location>
</error-page>
...
如果你需要在某些特殊的JSP頁面中使用一個不同的error page,可以用“@page”設(shè)置errorPage屬性來有選擇性地覆蓋web.xml中的聲明。

JSP 語法錯誤的報告

在JSP 1.2 和 JSP 2.0之間,一個細微但是重要的區(qū)別是JSP 2.0需要JSP容器支持“jsp:id”特性,雖然在JSP 1.2中這僅僅是一個建議。作為一個JSP開發(fā)者,這對你意味著什么呢?對于JSTL和定制的標簽庫的語法錯誤,它意味著你可以更好地獲得有用的錯誤信息。

下面講述它是如何工作的。當JSP容器將JSP頁面轉(zhuǎn)換為可以執(zhí)行的servlet class,容器著眼于這個頁面中聲明的所有標簽庫。如果標簽庫中的一個或者多個庫包含了一個標簽庫驗證器(Tag Library Validator,TLV),容器就會在接受這個JSP頁面前給予TLV一個檢驗當前頁面的機會。容器給予TLV一個當前頁面的XML視圖用以分析。XML視圖就像名稱暗示的那樣,是當前頁面的另外一種版本, 所有常規(guī)的JSP元素和template text已經(jīng)被轉(zhuǎn)換為一種結(jié)構(gòu)良好的XML文檔。這個XML視圖對TLV來說是很容易解析的,用于確定所有的custom actions被正確地使用(比如:custom actions被正確的嵌套,互斥的屬性是不能在同一個action element中一同使用的)。

這就是“jsp:id”的由來。容器在頁面中給每一個custom action元素分配了一個ID,并且維護了一張在ID和元素位置(文件、行號、列號)的映射表。添加的“jsp:id”屬性,在XML視圖中ID值對應于所有的custom action 元素,這樣TLV就可以讀取它。如果TLV發(fā)現(xiàn)了一個語法錯誤,它就會在返回給容器的錯誤信息中包含“jsp:id”屬性值來確定當前無效的action element。這時容器使用映射,并添加發(fā)生錯誤的custom action element位置信息,提示給你。這使得開發(fā)人員找到并改正錯誤變得輕而易舉。

所有的JSTL庫都要有TLV。我強烈建議為你自己編寫的類庫開發(fā)TLV,而且任何第三方類庫的開發(fā)人員也應該這樣做。

如果你對XML視圖和TLV并不熟悉,我在2001年的介紹JSP 1.2的文章中有一個簡要的介紹("JSP 1.2: Great News for the JSP Community")。

JSP 部署描述符
JSP 2.0在web.xml文件中使用了servlet規(guī)范中定義的部署描述符的文件格式,就像早期的JSP規(guī)范中的那樣。然而在JSP 2.0中有兩個重要的變化:1、現(xiàn)在web.xml文件的格式是通過XML Schema定義的;2、為了最大限度地減少servlet和JSP規(guī)范之間的耦合度,大多數(shù)的JSP配置細節(jié)已經(jīng)被移到一個新的XML element中。

XML Schema是一種用來描述XML文檔語法規(guī)則的XML語言(可以定義XML element之間是如何嵌套的;一個element可以獲得什么樣的值; 值的唯一性的需求等等)。這是一個復雜的規(guī)范,但是幸運的是你不用為了寫web.xml文件而需要明白XML Schema語法規(guī)則。因為servlet和JSP規(guī)范提供了易于理解的圖表( JavaServer Pages, 3rd Edition書中包含了許多簡單易懂的圖表)。如果你還是想要更進一步了解XML Schema,請瀏覽W3C(http://www.)的網(wǎng)站。

用XML Schema代替上一版本中的 Document Type Definition(DTD) 語言來聲明XML文檔結(jié)構(gòu)的主要優(yōu)點是:XML Schema具有更加富有表達能力,因此在解析web.xml文件的過程中能發(fā)現(xiàn)更多的錯誤,有希望解決在JSP容器之間更好地移植這個問題。

另外一個優(yōu)點是(我確定你會感激于此的): 在web.xml文件中使用XML Schema可以使頂層的element按照任何順序排列變得輕而易舉。舉例來說,在servlet和JSP 規(guī)范的上一個版本中,如果將<error-page> element 放到<welcome-file-list> element 前面,你將得到一個錯誤提示。在新版本的規(guī)范中,這樣做就不會有問題。在頂層元素中的element的順序盡管還必須要按照嚴格的順序放置,但是在頂層元素以外至少你現(xiàn)在可以自由地支配了。

除了<jsp-file>要嵌套在<servlet>中,其它的element現(xiàn)在都被歸組到一個新的頂層element中,這個element命名為<jsp-config>。在<jsp-config>中,你可以使用<taglib> element,和在JSP 1.2中具有相同的語法和含義,盡管它們并不需要實現(xiàn)了JSP 1.2 或者后續(xù)版本的容器,因為它們可以自動地從已經(jīng)部署的JAR文件中獲得標簽庫的定義。

新添加的<jsp-property-group>子元素更加有趣。你可以用它來配置一組匹配某個指定的URL的JSP頁面。比如:

...
<jsp-config>
  <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <scripting-invalid>true</scripting-invalid>
  </jsp-property-group>
</jsp-config>
...
<url-pattern>元素確定這組JSP 頁面應用哪一個配置。其他被嵌套的元素定義配置選項。這個例子中, <scripting-invalid>使應用JSP scripting elements (Java code) 在所有的JSP 頁面中無效。

總地來說同<scripting-invalid>一樣,你可以在<jsp-property-group>中使用以下的配置元素:

Element
描述

<el-ignored>
如果設(shè)置為true, 在匹配指定的URL模式的JSP 頁面中,EL 表達式被當作常規(guī)的文本而不是EL 表達式。當移植看起來有EL表達式文本的JSP 1.2頁面到JSP 2.0的時候,這非常有用。在已經(jīng)轉(zhuǎn)換為JSP 2.0的頁面中,你可以使用一個新增的“elIgnoredpage”屬性來選擇EL是否有效

<scripting-invalid>
如果設(shè)置為true, 在某個匹配的JSP頁面使用腳本

<page-encoding>
為匹配指定的URL模式的JSP頁面指定編碼。這是一個可選的配置(在每一個JSP頁面中指定頁面的編碼),并且對于JSP頁面來說這是使用某些文件編碼(比如:EBCDIC)唯一的辦法

<include-coda>
為所有匹配指定的URL模式的JSP頁面的末尾自動包含一個文件,而指定相關(guān)的context路徑。你可以在一個<jsp-property-group>中多次使用,或者通過多個<jsp-property-group>來實現(xiàn)

<include-prelude>
為所有匹配指定的URL模式的JSP頁面的開頭自動包含一個文件,而指定相關(guān)的context路徑。你可以在一個<jsp-property-group>中多次使用,或者通過多個<jsp-property-group>來實現(xiàn)

<is-xml>
如果設(shè)置為true, 所有匹配指定的URL模式的JSP頁面使用JSP XML語法(它們是JSP Document)


總結(jié)
在這部分,我講述了JSP 2.0增強的錯誤處理機制和新的部署描述符的特性。在這個系列文章中,接下來的部分將涉及到JSP 2.0是如何使JSP操作XML變得輕松,還有與定制標簽庫相關(guān)的新特性。

JSP 2.0: The New Deal, Part 3
by Hans Bergsten, author of JavaServer Pages, 3rd Edition
04/21/2004


更具伸縮性的JSP Document格式規(guī)則
JSP 2.0 規(guī)范支持兩種類型的JSP頁面:一種是包含任何數(shù)據(jù)類型的常規(guī)JSP頁面;另一種是具備良好結(jié)構(gòu)的XML文檔(具有XHTML和JSP元素)。為了做到這一點,在一個JSP Document中JSP的 “directive” 和 “腳本”必須用一種與常規(guī)的JSP頁面不同的語法來編寫:

常規(guī)的 JSP 頁面
JSP 文檔

<%@ page attribute list %>
<jsp:directive.pageattribute list />

<%@ include file="path" %>
<jsp:directive.include file="path" />

<%! declaration %>
<jsp:declaration>declaration</jsp:declaration>

<%= expression %>
<jsp:expression>expression</jsp:expression>

<% scriptlet %>
<jsp:scriptlet>scriptlet</jsp:scriptlet>


在一個JSP Document中,標簽庫作為XML名稱空間被聲明。比如:一個JSP Document 包含來自標準JSTL核心庫中的XHTML模板文字和JSP action, 它應該有一個<html>根元素,有以下的名稱空間的聲明:

<html
  xmlns="http://www./1999/xhtml"
  xmlns:jsp="http://java./JSP/Page"
  xmlns:c="http://java./jsp/jstl/core"
  xml:lang="en" lang="en">
xmlns屬性為XHTML名稱空間設(shè)置默認的名稱空間,xmlns:jsp屬性把jsp前綴和定義為JSP標準action的元素關(guān)聯(lián)起來,并且xmlns:c屬性將前綴“c”和JSTL核心庫定義的元素關(guān)聯(lián)起來。

JSP Document已經(jīng)是JSP規(guī)范中的一部分了,但是起初是作為一個可選擇的特性,并且后來還有許多的局限性。JSP 2.0解決了大多數(shù)局限性的問題,使XML和JSP協(xié)同工作變得更加簡單。

首先對于JSP 2.0來說,一個JSP Document 必須要有一個<jsp:root>根元素用以告訴容器它是哪一種類型的JSP頁面。JSP 2.0通過這種新的方式來標識一個JSP Document文件解決了這個限制。如果以下條件中有一個為true,這個文件就將被JSP 2.0容器作為一個JSP Document來處理:

請求的路徑與在web.xml中聲明的URL匹配, JSP property group 聲明有一個 <is-xml>元素設(shè)置為 true。關(guān)于 JSP property group 聲明在上一篇中有詳細的說明。
請求路徑的擴展名是.jspx,除非這個擴展名匹配一個JSP property group聲明的URL pattern,而JSP property group聲明<is-xml>元素為false。 換句話說,.jspx是默認的JSP Document的擴展名,但是它可以被一個property group的聲明置為無效。
請求路徑擴展名是.jsp或者匹配一個JSP property group聲明的URL pattern,而且這個文件中的root element是<jsp:root>。
這些新的規(guī)則使采用一個常規(guī)的XHTML文件(用JSP element處理動態(tài)內(nèi)容)的形式來編寫JSP Document成為可能,比如:不需要將所有的內(nèi)容都放到<jsp:root> element中。如果類似下面的例子那樣創(chuàng)建一個JSP property group,你甚至可以用擴展名為.html的文件:

...
<jsp-config>
  <jsp-property-group>
    <url-pattern>*.html</url-pattern>
    <is-xml>true</is-xml>
  </jsp-property-group>
</jsp-config>
...
用新的方法來生成XML Element
如果你曾經(jīng)嘗試用JSP1.2來編寫JSP Document,那么你很可能在給XML element的attribute動態(tài)賦值時陷入了麻煩之中。比如,你想要給一個XML element的 class attribute賦值為一個用來保存用戶風格樣式參數(shù)的bean property。你首先可能試圖像下面這樣做:

<table class="%= user.getTableClass() %">
這樣類型的Java 表達式,在一個JSP Document中能被用來作為一個 JSP action element的屬性值。但是在template text中,JSP不會識別這樣的語法,因此在這里是不會工作的。

用一個JSP action element來設(shè)置attribute的值,同樣不可以:

<table class="<c:out value="${user.tableClass}" />">

這是因為在一個element attribute中一個格式完整的XML 文檔不可以有一個“<”符號。

在JSP 1.2中,唯一動態(tài)設(shè)置一個element attribute 值的方法是使用令人生厭的CDATA 片斷,將開始和結(jié)束的element當作原始文本(被動態(tài)生成的值包裝)來處理:

<jsp:text><!CDATA[<table class="]]></jsp:text>
<c:out value="${user.tableClass}" />
<jsp:text><!CDATA[">]]></jsp:text>
JSP 2.0對于這種情況提供了兩種簡單的可選方案:1、在template text中使用一個EL表達式;2、使用一組新的標準的action element生成element。用EL表達式的例子如下:

<table class="${user.tableClass}">
一個JSP 2.0的容器對在template text中遇到的EL表達式求值,與在action 屬性中一樣。因此在大多數(shù)的情況下,這個解決方案是合適的。

如果你不能表示出你想要分配的值,你可以用三個新的標準action動態(tài)構(gòu)造整個XML element,用JSP代碼生成attribute的值。

<jsp:element name="table">
  <jsp:attribute name="class">
    <c:out value="${user.tableClass}" />
  </jsp:attribute>
  <jsp:body>
    ...
  </jsp:body>
</jsp:element>
這個 <jsp:element> action 創(chuàng)建一個XML element,它的屬性是由嵌套的<jsp:attribute> action 所創(chuàng)建的。這個屬性的值被設(shè)置為<jsp:attribute>的運算結(jié)果,因此你可以使用自定義的action來產(chǎn)生它,比如:在這個例子中的<c:out> action。同樣的element被設(shè)置為一個嵌套的<jsp:body>的運算結(jié)果。

一個用來聲明XML的新的標準Action
一個XML document應該在文檔的起始位置有一個XML的聲明,可能跟隨著一個DOCTYPE的聲明。在JSP 2.0中,你可以用新增的<jsp:output>標準 action來生成這兩個聲明。

除非這個JSP Document有一個<jsp:root> element,就像它的root element(或者一個標簽文件,標簽文件我將在下一篇文章中講述),JSP容器默認創(chuàng)建一個XML聲明,就像這樣:

<? xml version="1.0" encoding="encodingValue" ?>
encoding屬性的值是字符編碼,是由JSP頁面的contentType屬性決定的。如果你沒有指定一個字符集,默認的就是UTF-8編碼。如果你不希望生成一個XML的聲明(因為這個JSP Document可能被包含在另外一個JSP頁面中),你需要通過包含一個<jsp:output> action element來告訴JSP容器,就像這個JSP Document中那樣:

<jsp:output omit-xml-declaration="true" />
用屬性值true或者 yes來禁止生成這個聲明。用false或者 no來允許生成這個聲明。

一個DOCTYPE聲明告訴一個XML parser(例如一個瀏覽器使用的parser)這個XML文檔遵循了哪一個DTD(Document Type Declaration)。Parser可以用此信息來確認這個XML文檔包含的僅是這個DTD聲明的XML element。你不能在這個生成的JSP Documen中放置DOCTYPE聲明(因為此時你正在表明這個 JSP Document和DTD一起編譯),而是使用<jsp:output> action來告訴JSP容器為生成的結(jié)果添加一個聲明:

<jsp:output doctype-root-element="html"
  doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
  doctype-system="http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd"/>

<jsp:directive.page contentType="text/html" />
就像這個例子一樣,<jsp:output> action為XHTML給輸出的結(jié)果添加了一個DOCTYPE聲明:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"   "http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd">
在這個例子中,我也包含了一個有contentType屬性的<jsp:directive.page>聲明,用來給輸出的內(nèi)容設(shè)置MIME類型為text/html,用來告訴瀏覽器如何對輸出的內(nèi)容進行處理。記住,因為XHTML特有的MIME類型實際是application/xhtml+xml,但是一些比較新的瀏覽器(特別是Internet Explorer 6)并不認識它,對于知道如何處理XHTML 1.0的大多數(shù)瀏覽器來說text/html才是一種允許接受的MIME類型。

結(jié)論
JSP2.0用XML document方式編寫JSP頁面更加容易,就像你已經(jīng)在這部分看到的那樣。最后一篇文章將要講述和自定義標簽庫相關(guān)的新特性:新的標簽文件格式和新的簡單的標簽API。
JSP 2.0: The New Deal, Part 4

byHans Bergsten, author of JavaServer Pages, 3rd Edition05/12/2004

在“JSP 2.0: 新特性”的最后一部分中,我們將要看兩個新特性,它們使開發(fā)自定義標簽庫變得更加容易,它們是:標簽文件和簡化的tag-handler Java API。

以JSP Tag文件形式開發(fā)自定義Action

JSP試圖讓對Java沒有經(jīng)驗的人寫動態(tài)頁面成為可能。在頁面間,重用一部分動態(tài)的、復雜的內(nèi)容到目前為止仍然是令人痛苦的事情。舉例來說,你想要在一些頁面中放置一個投票程序,包括問題和答案。在   JSP 2.0之前,你有三個選擇:1、你可以拷貝并粘貼投票的程序到你希望添加的每一個頁面中;2、一個稍好的選擇是編寫一個獨立的JSP頁面來生成投票的表單,并且在其他頁面中用<jsp:include>或者 <c:import> action來包含這個獨立的頁面。但是你僅僅可以通過它來輸入String類型的參數(shù),不能是一個保存答案的bean或者一個Map。3、用一個Java tag handler類實現(xiàn)一個自定義action, 但是這需要建立在你對Java的了解基礎(chǔ)上。

JSP 2.0增加了第四種選擇:也就是用標簽文件的形式開發(fā)自定義action。一個標簽文件是一個純文本文件,你對所有的動態(tài)生成的部分使用JSP element,就像在常規(guī)的JSP頁面中那樣。和一個Java 標簽handler有同樣目的,即:為自定義的action 提供邏輯運算。標簽文件和JSP 頁面之間主要的區(qū)別是一個標簽文件有一個以.tag為擴展名的標簽文件,用這個擴展名來區(qū)別jsp頁面,并且你可以使用僅在標簽文件中有效的一些新的標簽來定義輸入和輸出。

更進一步來看,這里有一個標簽文件“poll.tag”,它生成一個投票的表單:

<%@ tag body-content="empty" %>
<%@ attribute name="question" required="true" %>
<%@ attribute name="answers" required="true"
  type="java.lang.Object" %>
<%@ attribute name="votesMapName" required="true" %>
<%@ attribute name="answersMapName" required="true" %>
<%@ taglib prefix="c" uri="http://java./jsp/jstl/core" %>

Question: ${question}<br>
<form action="result.jsp" target="result">
  <input type="hidden" name="question" value="${question}">
  <input type="hidden" name="votesMapName" value="${votesMapName}">
  <input type="hidden" name="answersMapName" value="${answersMapName}">
  <c:forEach items="${answers}" var="a">
    <input type="radio" name="vote" value="${a.key}">${a.value}<br>
  </c:forEach>
  <input type="submit" value="Vote">
</form>
在文件的頂部,有一個標簽指示符“tag”。這個標簽指示符和你在JSP頁面中使用的頁面指示符“page”相似,它聲明該文件的性質(zhì)。這里,我使用了body-content屬性來聲明:在一個JSP頁面中,一個表現(xiàn)這個標簽文件的action element必須是empty,也就是這個action element不能有body。其他的值你可以使用“scriptless”(body可以包含除了腳本元素以外的任何期望的內(nèi)容),或者“tagdependent”(容器傳遞主體內(nèi)容給標簽處理器(tag handler)而不做任何運算)。如果你曾經(jīng)以Java class這種形式開發(fā)過自定義action,你可能就會從用來聲明Java 標簽處理器的TLD (Tag Library Descriptor)中認出“body-content”和“valid”。因為一個標簽文件并不需要在一個TLD文件中被聲明,標簽指示符和其他特殊的標簽文件指示符被用來提供相同類型的信息,TLD將這個信息提供給JSP容器。

在這個例子中跟隨著這個標簽指示符的是attribute指示符,用于同樣的函數(shù),和TLD 的element一樣有著相同的名字:它聲明有效的自定義action element 屬性。這個自定義的用于投票的標簽文件接受四個屬性:

question: 投票的問題
answers:一個具有application-scope作用范圍的Map,用于保存投票的答案,用數(shù)字做主鍵(key)
votesMapName:一個具有application-scope作用范圍的變量名字,用于一個Map 保存每個答案的得票數(shù),用答案數(shù)量做主鍵
answersMapName:一個具有application-scope作用范圍的變量名字,用于保存答案的Map
每一個action element屬性都有一個attribute指示符對應,它的名字用“name”屬性來聲明。在這個例子中,所有的action element屬性都是需要的,就像對每一個attribute指示符都要用required屬性來聲明一樣。“answers”屬性值必須是一個“Map”,它被” type”屬性來聲明。所有其它的屬性必須是String類型的,這是默認的類型,因此我沒有特別為它們的屬性指出類型。

一個taglib聲明:在這個文件中使用了JSTL核心庫,在一個用來輸出question和每一個answer都有一個radio單選按鈕的表單的EL表達式中,文件的主體使用了屬性值(以page-scope變量形式,對標簽文件有效)。answer 和 vote Map變量名字和question在表單中以隱藏域的形式在表單中出現(xiàn),因此它們通過頁面?zhèn)鬟f被處理,它們可以像下面這樣應用:

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java./jsp/jstl/core" %>
<html>
  <head>
    <title>Poll Results</title>
  </head>
  <body bgcolor="white">
    <c:set target="${applicationScope[param.votesMapName]}"
    property="${param.vote}"
    value="${applicationScope[param.votesMapName][param.vote] + 1}" />
 
    <p>
    Question: ${param.question}<br>
    <c:forEach items="${applicationScope[param.answersMapName]}"
      var="a">
      ${a.key}) ${a.value}:
      ${applicationScope[param.votesMapName][a.key]}<br>
    </c:forEach>
    </p>
  </body>
</html>
這是一個常規(guī)的JSP頁面,使用了JSTL action。在保存投票結(jié)果的Map中,它對符合鍵值條件的被選中的投票答案加一。通過votesMapName參數(shù)提供名字,在application作用范圍內(nèi)有效。接下來,在頁面上輸出question并且通過Map迭代輸出answer,通過answersMapName參數(shù)提供名字在application作用范圍內(nèi)有效, 向頁面輸出每一個answer和當前answer的得票數(shù)。

比如何處理poll vote更令人感興趣的是如何在JSP頁面中使用由poll tag標簽文件實現(xiàn)的自定義action,這里有一個例子:

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java./jsp/jstl/core" %>
<%@ taglib prefix="my" tagdir="/WEB-INF/tags/mytags" %>

<html>
  <head>
    <title>My Page</title>
  </head>
  <body bgcolor="white">
    <jsp:useBean id="myAnswers" scope="application"
    class="java.util.TreeMap">
    <c:set target="${myAnswers}" property="1" value="Yes" />
    <c:set target="${myAnswers}" property="2" value="No" />
    <c:set target="${myAnswers}" property="3" value="Maybe" />
    </jsp:useBean>
    <jsp:useBean id="myVotes" scope="application"
    class="java.util.HashMap" />  
    ...
    <p>
    <my:poll question="Will you start using tag files?"
      answers="${myAnswers}"
      answersMapName="myAnswers" votesMapName="myVotes" />
    </p>
    ...
  </body>
</html>
首先要注意的是“taglib”標簽指示符,它聲明使用的這個標簽文件所在的標簽庫。要使用一個沒有創(chuàng)建TLD的標簽文件,你必須將這個標簽文件保存在WEB-INF/tags目錄下。例子中的poll.tag文件保存在WEB-INF/tags/mytags目錄下,并且我讓這個目錄名字和“taglib”的“tagdir”屬性的值相同。這樣就告訴容器在這個目錄下所找到的所有標簽文件都屬于同一個標簽庫,上面的例子中,在這個庫中的action element被“taglib” 標簽指示符的“prefix” 屬性所指定的前綴所標識。另一種可選擇的方式是:你可以將這些屬于某個TLD的標簽文件打包到一個jar文件中,用同樣的“taglib” 標簽指示符聲明你使用了一個自定義標簽庫,并且用一個“uri”屬性來替換“tagdir”屬性。

在這個例子中,用于answer的“Map”對象和vote的計數(shù)由<jsp:useBean> action創(chuàng)建的,并且由JSTL的<c:set> action來操作,你當然可以用任何喜歡的方式來創(chuàng)建它們(比如:在一個context listener中,或者在Apache Struts application中用一個“plugin” class來創(chuàng)建)。無論它是如何被創(chuàng)建的,這個標簽文件都是通過一個常規(guī)的JSP自定義action element被調(diào)用的。我使用一個EL表達式來對這個answers “Map”求值(“answers”的屬性值)。標簽文件默認是接受EL表達式的,你可以聲明:一個靜態(tài)值必須用“attribute”指示符的“rtexprvalue”屬性來指定。

當你請求這個頁面的時候,JSP容器就像通常一樣對這個頁面進行處理,通過element的“prefix” 和 “taglib“指示符的幫助來查找并定位 “<my:poll>”自定義標簽的實現(xiàn)。容器可以按照它想要的任何方式來處理這個標簽文件;Tomcat 5 容器把標簽文件轉(zhuǎn)換為一個Java標簽處理器的類(tag handler class),編譯并執(zhí)行它。

處理自定義Action
就像用java語言編寫的tag handler類一樣,一個標簽文件能要求容器處理自定義action element,更進一步地處理運算結(jié)果。

下面,在action element body中我們添加一個上一篇文章中poll question的小例子,就像下面這樣:

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java./jsp/jstl/core" %>
<%@ taglib prefix="my" tagdir="/WEB-INF/tags/mytags" %>
...
<html>
  ...
  <body bgcolor="white">
    ...
    <p>
    <my:poll question="Will you start using tag files?"
      answers="${myAnswers}"
      answersMapName="myAnswers" votesMapName="myVotes" >
      JSP 2.0 introduces a new way to develop custom action
      tag handlers, called <i>tag files</i>
    </my:poll>
    </p>
    ...
  </body>
</html>
這個例子僅僅包含文本,但是它也可以包含action element和EL 表達式。為了處理action element body并且講結(jié)果添加到response中,我們需要象下面這樣修改poll tag 文件:

<%@ tag body-content="scriptless" %>
<%@ attribute name="question" required="true" %>
<%@ attribute name="answers" required="true"
  type="java.lang.Object" %>
<%@ attribute name="votesMapName" required="true" %>
<%@ attribute name="answersMapName" required="true" %>
<%@ taglib prefix="c" uri="http://java./jsp/jstl/core" %>

<p>
  <jsp:doBody/>
</p>
Question: ${question}<br>
<form action="result.jsp" target="result">
  <input type="hidden" name="question" value="${question}">
  <input type="hidden" name="votesMapName" value="${votesMapName}">
  <input type="hidden" name="answersMapName" value="${answersMapName}">
  <c:forEach items="${answers}" var="a">
    <input type="radio" name="vote" value="${a.key}">${a.value}<br>
  </c:forEach>
  <input type="submit" value="Vote">
</form>
首先,我們改變“tag”指示符的“body-content”屬性值為“scriptless”。就像我前面說過的那樣,這意味著在這個文件的主體內(nèi)容中可以包含除了scripting element以外的任何內(nèi)容。接下來,我們添加一個“<jsp:doBody>” action,它告訴容器去處理body,并且將處理結(jié)果添加到response中。你可以有選擇性的使用“var” 屬性,捕獲處理的結(jié)果,并在下一步進行處理。

另外對于我已經(jīng)講述的新特性來說,一個標簽文件可以通過變量,未聲明的屬性將信息返回給調(diào)用文件,并且可以有 “fragment” 屬性(也就是說這些屬性可以擁有action element和EL表達式,標簽文件處理EL表達式采用的方式與處理action element類似)。在我這本書第11章中,你可以看到關(guān)于這些特性的全部內(nèi)容,你可以在http://www./catalog/jserverpages3/chapter/下載程序范例。

簡單的Java Tag-Handler API
采用標簽文件的方式編寫自定義action tag handler,這是一個重大的新特性。尤其對自定義action來說,它往往要生成很多的HTML。但是在處理某些事情時,僅僅用JSP action 和 EL 表達式是非常難以做到的,因此仍然還是需要Java tag-handler API 。首先,對于JSP 2.0來說,用Java編寫一個tag handler是非常復雜的。這是由于在容器和tag handler之間的交互需要處理action element body,而為了在action element body中支持Java scripting element就變得復雜起來!畢竟,如果在body中僅僅是包含template text、EL表達式、action element的話,一種相對簡單的API就可以被設(shè)計出來。而這就恰恰是JSP 2.0所做的,并且它被恰當?shù)孛麨閟imple tag handler API。

這里有一個前面的范例poll的自定義action的例子,在前面我們是用一個標簽文件來實現(xiàn)的:

package com.mycompany.mylib;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class PollTag extends SimpleTagSupport {
  private String question;
  private Map answers;
  private String votesMapName;
  private String answersMapName;

  public void setQuestion(String question) {
    this.question = question;
  }

  public void setAnswers(Map answers) {
    this.answers = answers;
  }

  public void setVotesMapName(String votesMapName) {
    this.votesMapName = votesMapName;
  }

  public void setAnswersMapName(String answersMapName) {
    this.answersMapName = answersMapName;
  }

  public void doTag() throws JspException, IOException {
    JspWriter out = getJspContext().getOut();
    JspFragment body = getJspBody();
    if (body != null) {
      out.println("<p>");
      body.invoke(null);
      out.println("</p>");
    }
    out.print("Question:");
    out.print(question);
    out.println("<br>");
    out.println("<form action=\"result.jsp\" target=\"result\">");
    out.print("<input type=\"hidden\" name=\"question\" value=\"");
    out.print(question);
    out.println("\">");
    out.print("<input type=\"hidden\" name=\"votesMapName\" value=\"");
    out.print(votesMapName);
    out.println("\">");
    out.print("<input type=\"hidden\" name=\"answersMapName\" value=\"");
    out.print(answersMapName);
    out.println("\">");
    Iterator i = answers.keySet().iterator();
    while (i.hasNext()) {
      String key = (String) i.next();
      String value = (String) answers.get(key);
      out.print("<input type=\"radio\" name=\"vote\" value=\"");
      out.print(key);
      out.print("\">");
      out.print(value);
      out.println("<br>");
    }
    out.println("<input type=\"submit\" value=\"Vote\">");
    out.println("</form>");
  }
}
一個singple tag必須實現(xiàn)新增的javax.servlet.jsp.tagext.SimpleTag接口。這個例子中的tag handler繼承javax.servlet.jsp.tagext.SimpleTagSupport類,父類提供了所有方法默認的實現(xiàn)。就像經(jīng)典的tag handler類一樣,你需要給每一個自定義的action屬性創(chuàng)建setter方法,但是這里僅僅有一個處理方法,那就是要實現(xiàn)doTag()方法。

在tag handler這個例子中,方法doTag()試圖通過調(diào)用getJspBody()方法(從SimpleTagSupport類繼承而來)而獲得一個可以執(zhí)行的action element body(一個JspFragment實例)的請求。如果找到這個body, tag handler就用一個null 值來調(diào)用它,就像對invoke()方法的爭論一樣,這意味著處理的結(jié)果被添加到response輸出中。至于<jsp:doBody> action,通過一個Writer實例來代替invoke()方法,你能捕獲到處理的結(jié)果。此時doTag()方法輸出帶有radio單選按鈕的HTML表單,就像標簽文件的實現(xiàn)一樣。

因為容器只能調(diào)用一個方法來讓tag handler處理自己該做的事情,這代替了經(jīng)典的tag handler的三個方法(doStartTag(), doAfterBody(), and doEndTag(),每一個方法的返回值告訴容器下一步該做什么),實現(xiàn)一個SimpleTag的tag handler比經(jīng)典的tag-handler API更容易。另外,simple tag-handler的實例永遠不能被再次使用,因此你不需要擔心重置后的狀態(tài),而它的狀態(tài)將會導致很多的問題。在我前面的文章中描述過這個問題,具體見"JSP 1.2: Great News for the JSP Community, Part 2"。

在一個TLD中聲明一個simple tag handler,所用的方式與你聲明一個經(jīng)典的tag handler一樣。但是除了JSP,<body-content> TLD element必須有一個值。這是因為simple tag handler不允許scripting element出現(xiàn)在自定義action的element body中。除此之外,使用一個實現(xiàn)了simple tag handler的自定義action與使用一個實現(xiàn)了經(jīng)典tag handler的action沒有任何區(qū)別。

simple tag handler 和 classic tag handler都可以通過實現(xiàn)一個新的接口(javax.faces.jsp.tagext.DynamicAttributes)來支持未聲明的attribute。兩種類型的attribute 都可以是JspFragment,包含其他的action或者EL表達式,tag handler可以用它進行任意多次的處理。在我的《JavaServer Pages, 3rd Edition》這本書中,你可以看到更多關(guān)于這些特性的內(nèi)容。

小節(jié)
在以上系列文章中,我已經(jīng)向你展示了JSP 2.0中所有的新特性:EL表達式,更好的錯誤處理機制,新的配置選項,改進的XML頁面格式,用來開發(fā)tag handler的兩個新途徑??傊?,這些改進之處使開發(fā)JSP頁面變得易于理解和維護。

如果你想要嘗試JSP2.0的新特性,我建議你使用Apache Tomcat 5。它是最早實現(xiàn)了JSP新規(guī)范的容器之一。在公布最終版本的JSP 2.0規(guī)范之前,一個被標記為“stable”版本的Tomcat是不能被發(fā)布的。但是最新的beta版已經(jīng)被證實是非常穩(wěn)定的,不要理會beta版的標記。Tomcat 5在the Jakarta Project site可以下載。

Hans Bergsten is the founder of Gefion Software and author of O‘Reilly‘s JavaServer Pages, 3rd Edition.

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多