欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
推薦一篇關(guān)于JSTL的好文章
JSP 2.0: The New Deal, Part 1

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

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

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

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

EL(The Expression Language)

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

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

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

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

變量名稱(chēng)
說(shuō)明

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

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

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

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

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

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

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

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

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

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

pageContext
一個(gè)javax.servlet.jsp.PageContext類(lèi)的實(shí)例, 用來(lái)提供訪(fǎng)問(wèn)不同的請求數據


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

Operator
Description

.
訪(fǎng)問(wèn)一個(gè)bean屬性或者 Map entry

[]
訪(fǎng)問(wèn)一個(gè)數組或者鏈表元素

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

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

+
數學(xué)運算符,加操作

-
數學(xué)運算符,減操作或者對一個(gè)值取反

*
數學(xué)運算符,乘操作

/ or div
數學(xué)運算符,除操作

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

== 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
用來(lái)對一個(gè)空變量值進(jìn)行判斷: null、一個(gè)空String、空數組、 空Map、沒(méi)有條目的Collection集合

func(args)
調用方法, func是方法名,args是參數,可以沒(méi)有,或者有一個(gè)、多個(gè)參數.參數間用逗號隔開(kāi)


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

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

${amount + 5}

如果你想要將5加到一個(gè)bean的property上,可以使用property訪(fǎng)問(wèn)操作符:

${order.amount + 5}

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

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

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

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

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

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

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

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

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

<input name="firstName"

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



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

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


URI
前綴

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

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

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

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

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


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

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

一個(gè)能清楚說(shuō)明它如何工作的例子:

<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表達式和條件操作符來(lái)選擇是否包含 html 中的 “selected”屬性,只有符合條件的 “option” 才被添加 “selected” 屬性。如果條件(param.artist==1)為真時(shí),前面的“selected” 才被添加到網(wǎng)頁(yè)中;否則就添加后面的(在這里是空字符串 ‘’)到頁(yè)面中。

EL函數
當EL從JSTL規范中移到JSP規范中,它使用了一個(gè)如何進(jìn)行函數調用的技巧。這個(gè)EL函數語(yǔ)法非常簡(jiǎn)單:方法名,緊接著(zhù)在圓括號中有一組參數:

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

標簽庫描述符(Tag Library Descriptor,TLD)將函數名稱(chēng)映射到一個(gè)由JAVA實(shí)現的靜態(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>。它包含一個(gè)函數返回類(lèi)型的聲明,靜態(tài)的方法的名字,在圓括號中聲明該方法所有參數的類(lèi)型(可以沒(méi)有參數或者有多個(gè),參數間用逗號間隔開(kāi))。返回值類(lèi)型和參數類(lèi)型必須是java的原始類(lèi)型(Object)或者是其他合法類(lèi)型。

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

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"));
}

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

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

函數
描述

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

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

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

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

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

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

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

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

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

fn:startsWith(string, prefix)
如果參數string以參數prefix開(kāi)頭,返回true

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

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

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

fn:toLowerCase(string)
將參數string所有的字符變?yōu)樾?xiě),并將其返回

fn:toUpperCase(string)
將參數string所有的字符變?yōu)榇髮?xiě),并將其返回

fn:trim(string)
去除參數string 首尾的空格,并將其返回


結束語(yǔ):
在這篇文章中,我從EL講到JSTL1.1規范、EL新特色和JSTL 1.1函數庫。接下來(lái)的部分我將要告訴你:關(guān)于JSP error-page的改進(jìn)和增強; jsp:id 屬性帶來(lái)的益處;新的配置屬性描述符;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 規范中的特性的系列文章的第二部分。在前面的第一部分,我描述了新的EL表達式,但是還有更多的內容沒(méi)有涉及。這一部分描述的是JavaServer Pages (JSP) 2.0 規范在錯誤處理機制和新的部署描述符特性方面的增強。我假設你熟悉JSP 1.2,而且至少聽(tīng)說(shuō)過(guò)JSP Standard Tag Library (JSTL)。

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

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

Property
Java 類(lèi)型
描述

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

servletName
String
發(fā)生錯誤的servlet或者JSP頁(yè)面的名稱(chēng)

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

throwable
Throwable
導致當前error page被調用的違例


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

<%@ page isErrorPage="true" contentType="text/html" %>
<%@ taglib prefix="log" uri="http://jakarta.apache.org/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>
這個(gè)頁(yè)面使用Apache Jakarta Taglib項目中的 Log tag library來(lái)顯示一些確定的信息并記錄下了具體的細節。

你可以在web.xml文件中使用<error-page>來(lái)對servlet和JSP 頁(yè)面聲明這是一個(gè)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頁(yè)面中使用一個(gè)不同的error page,可以用“@page”設置errorPage屬性來(lái)有選擇性地覆蓋web.xml中的聲明。

JSP 語(yǔ)法錯誤的報告

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

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

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

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

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

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

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

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

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

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

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

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

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

Element
描述

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

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

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

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

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

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


總結
在這部分,我講述了JSP 2.0增強的錯誤處理機制和新的部署描述符的特性。在這個(gè)系列文章中,接下來(lái)的部分將涉及到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格式規則
JSP 2.0 規范支持兩種類(lèi)型的JSP頁(yè)面:一種是包含任何數據類(lèi)型的常規JSP頁(yè)面;另一種是具備良好結構的XML文檔(具有XHTML和JSP元素)。為了做到這一點(diǎn),在一個(gè)JSP Document中JSP的 “directive” 和 “腳本”必須用一種與常規的JSP頁(yè)面不同的語(yǔ)法來(lái)編寫(xiě):

常規的 JSP 頁(yè)面
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>


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

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

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

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

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

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

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

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

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

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

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

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

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

如果你不能表示出你想要分配的值,你可以用三個(gè)新的標準action動(dòng)態(tài)構造整個(gè)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>
這個(gè) <jsp:element> action 創(chuàng )建一個(gè)XML element,它的屬性是由嵌套的<jsp:attribute> action 所創(chuàng )建的。這個(gè)屬性的值被設置為<jsp:attribute>的運算結果,因此你可以使用自定義的action來(lái)產(chǎn)生它,比如:在這個(gè)例子中的<c:out> action。同樣的element被設置為一個(gè)嵌套的<jsp:body>的運算結果。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

更進(jìn)一步來(lái)看,這里有一個(gè)標簽文件“poll.tag”,它生成一個(gè)投票的表單:

<%@ 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.sun.com/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>
在文件的頂部,有一個(gè)標簽指示符“tag”。這個(gè)標簽指示符和你在JSP頁(yè)面中使用的頁(yè)面指示符“page”相似,它聲明該文件的性質(zhì)。這里,我使用了body-content屬性來(lái)聲明:在一個(gè)JSP頁(yè)面中,一個(gè)表現這個(gè)標簽文件的action element必須是empty,也就是這個(gè)action element不能有body。其他的值你可以使用“scriptless”(body可以包含除了腳本元素以外的任何期望的內容),或者“tagdependent”(容器傳遞主體內容給標簽處理器(tag handler)而不做任何運算)。如果你曾經(jīng)以Java class這種形式開(kāi)發(fā)過(guò)自定義action,你可能就會(huì )從用來(lái)聲明Java 標簽處理器的TLD (Tag Library Descriptor)中認出“body-content”和“valid”。因為一個(gè)標簽文件并不需要在一個(gè)TLD文件中被聲明,標簽指示符和其他特殊的標簽文件指示符被用來(lái)提供相同類(lèi)型的信息,TLD將這個(gè)信息提供給JSP容器。

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

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

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

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/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>
這是一個(gè)常規的JSP頁(yè)面,使用了JSTL action。在保存投票結果的Map中,它對符合鍵值條件的被選中的投票答案加一。通過(guò)votesMapName參數提供名字,在application作用范圍內有效。接下來(lái),在頁(yè)面上輸出question并且通過(guò)Map迭代輸出answer,通過(guò)answersMapName參數提供名字在application作用范圍內有效, 向頁(yè)面輸出每一個(gè)answer和當前answer的得票數。

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

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/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”標簽指示符,它聲明使用的這個(gè)標簽文件所在的標簽庫。要使用一個(gè)沒(méi)有創(chuàng )建TLD的標簽文件,你必須將這個(gè)標簽文件保存在WEB-INF/tags目錄下。例子中的poll.tag文件保存在WEB-INF/tags/mytags目錄下,并且我讓這個(gè)目錄名字和“taglib”的“tagdir”屬性的值相同。這樣就告訴容器在這個(gè)目錄下所找到的所有標簽文件都屬于同一個(gè)標簽庫,上面的例子中,在這個(gè)庫中的action element被“taglib” 標簽指示符的“prefix” 屬性所指定的前綴所標識。另一種可選擇的方式是:你可以將這些屬于某個(gè)TLD的標簽文件打包到一個(gè)jar文件中,用同樣的“taglib” 標簽指示符聲明你使用了一個(gè)自定義標簽庫,并且用一個(gè)“uri”屬性來(lái)替換“tagdir”屬性。

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

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

處理自定義Action
就像用java語(yǔ)言編寫(xiě)的tag handler類(lèi)一樣,一個(gè)標簽文件能要求容器處理自定義action element,更進(jìn)一步地處理運算結果。

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

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/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>
這個(gè)例子僅僅包含文本,但是它也可以包含action element和EL 表達式。為了處理action element body并且講結果添加到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.sun.com/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”。就像我前面說(shuō)過(guò)的那樣,這意味著(zhù)在這個(gè)文件的主體內容中可以包含除了scripting element以外的任何內容。接下來(lái),我們添加一個(gè)“<jsp:doBody>” action,它告訴容器去處理body,并且將處理結果添加到response中。你可以有選擇性的使用“var” 屬性,捕獲處理的結果,并在下一步進(jìn)行處理。

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

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

這里有一個(gè)前面的范例poll的自定義action的例子,在前面我們是用一個(gè)標簽文件來(lái)實(shí)現的:

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>");
  }
}
一個(gè)singple tag必須實(shí)現新增的javax.servlet.jsp.tagext.SimpleTag接口。這個(gè)例子中的tag handler繼承javax.servlet.jsp.tagext.SimpleTagSupport類(lèi),父類(lèi)提供了所有方法默認的實(shí)現。就像經(jīng)典的tag handler類(lèi)一樣,你需要給每一個(gè)自定義的action屬性創(chuàng )建setter方法,但是這里僅僅有一個(gè)處理方法,那就是要實(shí)現doTag()方法。

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

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

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

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

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

如果你想要嘗試JSP2.0的新特性,我建議你使用Apache Tomcat 5。它是最早實(shí)現了JSP新規范的容器之一。在公布最終版本的JSP 2.0規范之前,一個(gè)被標記為“stable”版本的Tomcat是不能被發(fā)布的。但是最新的beta版已經(jīng)被證實(shí)是非常穩定的,不要理會(huì )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ù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
JSTL標簽EL表達式學(xué)習 -- 含學(xué)習結構圖
使用JDOM設計簡(jiǎn)單的JSP+XML的系統留言板
入門(mén)教程:JSP標準模板庫
JSP標準模板庫(下)
自定義標簽之EL函數
Java學(xué)習——JSTL標簽與EL表達式之間的微妙關(guān)系
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久