admin 管理员组

文章数量: 887142


2024年1月5日发(作者:伦勃朗布光示意图人像图)

JSTL2.0 and 1.0(JSP标准标签库)介绍

2010-01-03 01:17:04| 分类: JSTL | 标签: |字号大中小 订阅

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

期待已久的日子即将到来: 最新版JavaServer Pages (JSP)2.0规范即将和其他的J2EE 1.4一同发布。新的JSP版本有一个新的飞跃,采用了新的方式:由于新的语言表达式(Expression Language,以下简称为EL)和JSP标准标签库(JSP Standard Tag Library ,以下简称为JSTL)这两种新的方式,在页面中不需要用java,对于开发一般的应用来说,重用代码变得更加容易。更具体来说,JSP 2.0带来了以下的优点:

首次被JSTL 1.0引入的EL现在被合并到JSP规范中,就像应用template text一样地使用所有的标准的和定制的组件。

新的EL已经被扩展,具备一个函数调用机制,JSTL1.1整合了一系列经常需要使用的函数。

新增加的变量和servlet 规范定义的错误处理机制被更好地组织起来。通过新增加的变量,JSP error pages

现在可以提供更多的错误信息。

容器因为更加严格的语法检查可以更容易地找出发生的错误。

所有的J2EE 1.4规范(包括JSP 2.0 和 Servlet 2.4),为了声明部署的规则描述而应用了XML schema。这样的好处之一是你现在可以通过任何顺序列出文件中的描述。JSP 2.0也增加了一些新的配置选项用于部署描述,允许通过全局的配置来代替基于每页的配置。

由于更具伸缩性的规则和新的自定义action element,现在就像编写XML文件一样,编写JSP页面变得更加容易。

定制的标签库现在可以开发成一系列的标签文件(具有JSP元素的文本文件),标签处理器可以使用新的、简化的标签处理器的API。与此同时,新规范加入了一些新的特性,比如:支持在jsp页面上显示动态属性列表和可执行片断属性。

在众多的书籍中,这是头一个讲解JSP 2.0新特性的文章。在这一部分,我们将看到和EL相关的信息,其他的新特性留到后面。在这里我假定读者已经熟悉JSP 1.2,而且至少听说过JSTL。

你可能对这本第三版的《JavaServer Pages》感兴趣。这本书中,我尽可能在细节上讲述所有的内容,而且并不认为你对JSP或者JSTL了解一切。这本书预计在2003年12月出版,但是你现在可以在、Barnes&Noble,或者其他在线书店预订。

EL(The Expression Language)

如果过去使用过JSTL,那么你可能已经熟悉了EL。EL在JSTL 1.0规范中被引入,用来在运行期间对Java表达式中action element属性赋值提供另一种选择。当JSTL EL已经非常迅速的流行起来情况下,还是存在一个问题: JSTL EL 表达式仅仅可以与JSTL和custom action一起使用,怎样才能使用非标准API对EL表达式求值?

JSP 2.0中,JSP容器自己可以理解EL表达式。这使你在所有过去只能应用Java表达式的地方应用EL表达式成为可能,比如:标准和定制action的属性值,模板文本。

在我们看具体的例子前,让我们更进一步的看看什么是EL。EL是从JavaScript中获得启发的一种语言,XPath(一种用来访问XML文档的语言),但是EL在对变量的null值和执行更多数据类型的自动类型转换的处理上更加宽松。这些新特性对于web应用非常重要,在这些应用中输入通常通过html表单的request

parameter来得到。这些参数可能仅仅在某些请求下才能体现出来,而且浏览器经常将request parameter作为文本发送,然而应用程序经常需要把他们作为数字类型、布尔类型(true 或者 false)来使用。通过EL,你根本就很少需要关心缺少某些参数的值或者类型转换。

一个EL表达式包含变量和操作符。任何存储在某个JSP作用范围(如:page、 request、session、application)的bean能被作为一个EL变量来使用。另外,EL支持以下预定义的变量:

变量名称

说明

pageScope

一个包含所有page scope范围的变量集合 (a )

requestScope

一个包含所有request scope范围的变量集合 (a )

sessionScope

一个包含所有session scope范围的变量集合 (a )

applicationScope

一个包含所有application scope范围的变量集合 (a )

param

一个包含所有请求参数的集合 (a ),通过每个参数对应一个String值的方式赋值

paramValues

一个包含所有请求参数的集合 (a ),通过每个参数对应一个String数组的方式赋值

header

一个包含所有请求的头信息的集合, (a ) ,通过每个头信息对应一个String值的方式赋值

headerValues

一个包含所有请求的头信息的集合 (a ) ,通过每个头信息的值都保存在一个String数组的方式赋值

cookie

一个包含所有请求的 cookie集合 (a ), 通过每一个cookie()对应一个cookie值的方式赋值

initParam

一个包含所有应用程序初始化参数的集合(a ) ,通过每个参数分别对应一个String值的方式赋值

pageContext

一个ntext类的实例, 用来提供访问不同的请求数据

操作符描述了你对变量所期望的操作。如果你之前曾经使用过任何编程语言的话,在EL表达式中所使用的操作符对你来说可能看起来很熟悉。因为它们和那些在大多数语言中所支持的操作符一样。

Operator

Description

.

访问一个bean属性或者 Map entry

[]

访问一个数组或者链表元素

()

对子表达式分组,用来改变赋值顺序

? :

条件语句,比如: 条件 ? ifTrue : ifFalse.如果条件为真,表达式值为前者,反之为后者

+

数学运算符,加操作

-

数学运算符,减操作或者对一个值取反

*

数学运算符,乘操作

/ or div

数学运算符,除操作

% or mod

数学运算符,模操作(取余)

== 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、空数组、 空Map、没有条目的Collection集合

func(args)

调用方法, func是方法名,args是参数,可以没有,或者有一个、多个参数.参数间用逗号隔开

一个EL表达式可以包含:数字、文本(在单引号或者双引号之间)、布尔值、null值。

因为一个EL表达式可以出现在静态文本出现的地方,因此你必须告诉JSP容器它应该被当作一个EL表达式来处理。你可以通过使用定界符来做到这一点。一个EL表达式总是以”${ }”来标记(一个“$”符号和一个左花括号,右花括号)。这里有一个EL表达式,它将一个命名为amount的变量加5:

${amount + 5}

如果你想要将5加到一个bean的property上,可以使用property访问操作符:

${ + 5}

在当前这个指定的bean或者collection集合中,Property访问操作符(一个“.“符号)告诉EL去寻找名字为amount的property。

${order['amount'] + 5}

在[]之间的值必须是一个property的名字(就像上面的例子中那样)或者是一个保存property名字的变量(或者是一个完整的EL子表达式)。

EL表达式可以被用来赋值给任何标准的或者定制的JSP行为属性(action attribute),这些行为属性被标记为可以接受动态值(或者请求期间的属性值,就象它被正式调用一样):

在JSP 2.0之前,你不得不使用Java表达式去给一个属性动态赋值。在过去的很多年中,这已经成为语法混乱的一个普遍根源。

最后,EL表达式可以在页面中和模板直接混合使用。当你生成HTML并且需要设置一个动态值给一个属性的时候,这非常方便:

JSP 1.2中,你不得不使用JSTL的来实现同样的事情,最后把各种不同类型的元素混合起来,这导致程序理解起来非常的困难:

value="" >

新JSTL 1.1 Tag Library 标识符

JSTL1.1发布的是一个初级的版本,主要目的是用来整合JSTL和JSP2.0 。最明显的变化是JSTL1.0 “孪生函数库”(一组库用来接受EL表达式,另外一组用来接受JAVA表达式),而它们已经被一组既可以用于EL表达式也可以用于JAVA表达式的函数库所代替。

在JSTL 1.1中使用以下标识符:

URI

前缀

Core

/jsp/jstl/core

c

XML processing

/jsp/jstl/xml

x

I18N formatting

/jsp/jstl/fmt

fmt

Database access

/jsp/jstl/sql

sql

Functions

/jsp/jstl/functions

fn

如果你曾经使用过JSTL1.0,你可能会注意到新的标识符和旧的EL库标试符一模一样,除了加入了“/jsp

path” element。你也可能注意到在JSTL1.1中有一个库,包含了EL的函数。我们稍后就会看到。

一个新的EL操作符

在JSP页面中一个非常普遍的需求就是:当某个条件为真时,要在网页中包含一些文字。在JSP1.2和JSTL1.1 中,用具有代表性的来实现,但是这样做非常繁琐。JSP2.0增加了一个新的条件操作符用于EL,以更加优雅的方式来处理这样的情况。这个条件操作符存在于很多编程语言中(比如:Java,C,JavaScript),因此你可能以前就见过它。它判断一个布尔的条件,当条件为真或者假时,分别取不同的结果。

一个能清楚说明它如何工作的例子:

在这里,我使用了EL表达式和条件操作符来选择是否包含 html 中的 “selected”属性,只有符合条件的

“option” 才被添加 “selected” 属性。如果条件(==1)为真时,前面的“selected” 才被添加到网页中;否则就添加后面的(在这里是空字符串 „‟)到页面中。

EL函数

当EL从JSTL规范中移到JSP规范中,它使用了一个如何进行函数调用的技巧。这个EL函数语法非常简单:方法名,紧接着在圆括号中有一组参数:

<%@ taglib prefix="fn"

uri="/jsp/jstl/functions" %>

${fn:length(myCollection)}

这是一个属于标签库中的函数,并且函数名字在页面中所包含的前缀要指定taglib库。在这个例子中,我使用了前缀fn,这是JSTL function库默认的前缀。

标签库描述符(Tag Library Descriptor,TLD)将函数名称映射到一个由JAVA实现的静态方法中:

Returns the number of items in a collection or the number of characters in a string.

length

ons

int length()

在这里最有趣的element是。它包含一个函数返回类型的声明,静态的方法的名字,在圆括号中声明该方法所有参数的类型(可以没有参数或者有多个,参数间用逗号间隔开)。返回值类型和参数类型必须是java的原始类型(Object)或者是其他合法类型。

这个静态方法 length()在Jakarta Taglibs标准库中用类似于下面的代码实现的:

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 (t()) {

count++;

();

}

return count;

}

if (obj instanceof Enumeration) {

Enumeration enum = (Enumeration) obj;

count = 0;

while (eElements()) {

count++;

ement();

}

return count;

}

try {

count = gth(obj);

return count;

} catch (IllegalArgumentException ex) {}

throw new JspTagException("Unsupported type"));

}

就像你所看到的,在那里没有什么出奇的地方。它是一个常规的静态方法,这个函数中通过对运行期中的参数类别的判断,找出参数的长度。

除了在这个方法中使用的length()方法,JSTL1.1标签库还包含了许多其它经常使用的函数:

函数

描述

fn:contains(string, substring)

如果参数string中包含参数substring,返回true

fn:containsIgnoreCase(string, substring)

如果参数string中包含参数substring(忽略大小写),返回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)

将一个给定的数组array用给定的间隔符separator串在一起,组成一个新的字符串并返回。

fn:length(item)

返回参数item中包含元素的数量。参数Item类型是数组、collection或者String。如果是String类型,返回值是String中的字符数。

fn:replace(string, before, after)

返回一个String对象。用参数after字符串替换参数string中所有出现参数before字符串的地方,并返回替换后的结果

fn:split(string, separator)

返回一个数组,以参数separator 为分割符分割参数string,分割后的每一部分就是数组的一个元素

fn:startsWith(string, prefix)

如果参数string以参数prefix开头,返回true

fn:substring(string, begin, end)

返回参数string部分字符串, 从参数begin开始到参数end位置,包括end位置的字符

fn:substringAfter(string, substring)

返回参数substring在参数string中后面的那一部分字符串

fn:substringBefore(string, substring)

返回参数substring在参数string中前面的那一部分字符串

fn:toLowerCase(string)

将参数string所有的字符变为小写,并将其返回

fn:toUpperCase(string)

将参数string所有的字符变为大写,并将其返回

fn:trim(string)

去除参数string 首尾的空格,并将其返回

结束语:

在这篇文章中,我从EL讲到JSTL1.1规范、EL新特色和JSTL 1.1函数库。接下来的部分我将要告诉你:关于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 规范中的特性的系列文章的第二部分。在前面的第一部分,我描述了新的EL表达式,但是还有更多的内容没有涉及。这一部分描述的是JavaServer Pages (JSP)

2.0 规范在错误处理机制和新的部署描述符特性方面的增强。我假设你熟悉JSP 1.2,而且至少听说过JSP

Standard Tag Library (JSTL)。

JSP Error Pages

如果你曾经在JSP和servlet的错误处理中使用过JSP error page,并且想要显示或者记录违例信息(违例导致JSP error page 被调用),那么你就知道在JSP1.2中这并不是件轻松的事情。原因是当在servlets和JSP 页面中声明了一个errorPage,违例(exception)被作为一个request attribute传递,它们要使用不同的属性名称。只有被传递的违例通过JSP属性名称自动地显示在 JSP error page中(通过exception脚本变量和${ion} EL 表达式)。

JSP 2.0通过将相同的属性名称转换为servlet规范中的ion来修正了这个问题。更进一步说,一个新增的 命名为errorData的EL pageContext变量揭露了发生问题的其他信息。ErrorData属性是ata的一个实例。这个实例可以被 用来作为一个bean和以下的properties一同使用:

Property

Java 类型

描述

requestURI

String

发生请求失败的 URI

servletName

String

发生错误的servlet或者JSP页面的名称

statusCode

int

发生错误的状态码

throwable

Throwable

导致当前error page被调用的违例

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

<%@ page isErrorPage="true" contentType="text/html" %>

<%@ taglib prefix="log" uri="/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.

-----

${now}

Request that failed: ${tURI}

Status code: ${Code}

Exception: ${ble}

-----

这个页面使用Apache Jakarta Taglib项目中的 Log tag library来显示一些确定的信息并记录下了具体的细节。

你可以在文件中使用来对servlet和JSP 页面声明这是一个error page:

...

ble

/

500

/

...

如果你需要在某些特殊的JSP页面中使用一个不同的error page,可以用“@page”设置errorPage属性来有选择性地覆盖中的声明。

JSP 语法错误的报告

在JSP 1.2 和 JSP 2.0之间,一个细微但是重要的区别是JSP 2.0需要JSP容器支持“jsp:id”特性,虽然在JSP 1.2中这仅仅是一个建议。作为一个JSP开发者,这对你意味着什么呢?对于JSTL和定制的标签库的语法错误,它意味着你可以更好地获得有用的错误信息。

下面讲述它是如何工作的。当JSP容器将JSP页面转换为可以执行的servlet class,容器着眼于这个页面中声明的所有标签库。如果标签库中的一个或者多个库包含了一个标签库验证器(Tag Library Validator,TLV),容器就会在接受这个JSP页面前给予TLV一个检验当前页面的机会。容器给予TLV一个当前页面的XML视图用以分析。 XML视图就像名称暗示的那样,是当前页面的另外一种版本, 所有常规的JSP元素和template text已经被转换为一种结构良好的XML文档。这个XML视图对TLV来说是很容易解析的,用于确定所有的custom actions被正确地使用(比如:custom actions被正确的嵌套,互斥的属性是不能在同一个action element中一同使用的)。

这就是“jsp:id”的由来。容器在页面中给每一个custom action元素分配了一个ID,并且维护了一张在ID和元素位置(文件、行号、列号)的映射表。添加的“jsp:id”属性,在XML视图中ID值对应于所有的custom

action 元素,这样TLV就可以读取它。如果TLV发现了一个语法错误,它就会在返回给容器的错误信息中包含“jsp:id”属性值来确定当前无效的action element。这时容器使用映射,并添加发生错误的custom

action element位置信息,提示给你。这使得开发人员找到并改正错误变得轻而易举。

所有的JSTL库都要有TLV。我强烈建议为你自己编写的类库开发TLV,而且任何第三方类库的开发人员也应该这样做。

如果你对XML视图和TLV并不熟悉,我在2001年的介绍JSP 1.2的文章中有一个简要的介绍("JSP 1.2:

Great News for the JSP Community")。

JSP 部署描述符

JSP 2.0在文件中使用了servlet规范中定义的部署描述符的文件格式,就像早期的JSP规范中的那样。然而在JSP 2.0中有两个重要的变化:1、现在文件的格式是通过XML Schema定义的;2、为了最大限度地减少servlet和JSP规范之间的耦合度,大多数的JSP配置细节已经被移到一个新的XML element中。

XML Schema是一种用来描述XML文档语法规则的XML语言(可以定义XML element之间是如何嵌套的;一个element可以获得什么样的值; 值的唯一性的需求等等)。这是一个复杂的规范,但是幸运的是你不用为了写文件而需要明白XML Schema语法规则。因为servlet和JSP规范提供了易于理解的图表( JavaServer Pages, 3rd Edition书中包含了许多简单易懂的图表)。如果你还是想要更进一步了解XML

Schema,请浏览W3C()的网站。

用XML Schema代替上一版本中的 Document Type Definition(DTD)语言来声明XML文档结构的主要优点是:XML Schema具有更加富有表达能力,因此在解析文件的过程中能发现更多的错误,有希望解决在JSP容器之间更好地移植这个问题。

另外一个优点是(我确定你会感激于此的): 在文件中使用XML Schema可以使顶层的element按照任何顺序排列变得轻而易举。举例来说,在servlet和JSP 规范的上一个版本中,如果将

element 放到 element 前面,你将得到一个错误提示。在新版本的规范中,这样做就不会有问题。在顶层元素中的element的顺序尽管还必须要按照严格的顺序放置,但是在顶层元素以外至少你现在可以自由地支配了。

除了要嵌套在中,其它的element现在都被归组到一个新的顶层element 中,这个element命名为。在中,你可以使用 element,和在JSP 1.2中具有相同的语法和含义,尽管它们并不需要实现了JSP 1.2 或者后续版本的容器,因为它们可以自动地从已经部署的JAR文件中获得标签库的定义。

新添加的子元素更加有趣。你可以用它来配置一组匹配某个指定的URL的JSP页面。比如:

...

*.jsp

true

...

元素确定这组JSP 页面应用哪一个配置。其他被嵌套的元素定义配置选项。这个例子中,

使应用JSP scripting elements (Java code) 在所有的JSP 页面中无效。

总地来说同一样,你可以在中使用以下的配置元素:

Element

描述

如果设置为true, 在匹配指定的URL模式的JSP 页面中,EL 表达式被当作常规的文本而不是EL 表达式。当移植看起来有EL表达式文本的JSP 1.2页面到JSP 2.0的时候,这非常有用。在已经转换为JSP 2.0的页面中,你可以使用一个新增的“elIgnoredpage”属性来选择EL是否有效

如果设置为true, 在某个匹配的JSP页面使用脚本

为匹配指定的URL模式的JSP页面指定编码。这是一个可选的配置(在每一个JSP页面中指定页面的编码),并且对于JSP页面来说这是使用某些文件编码(比如:EBCDIC)唯一的办法

为所有匹配指定的URL模式的JSP页面的末尾自动包含一个文件,而指定相关的context路径。你可以在一个中多次使用,或者通过多个来实现

为所有匹配指定的URL模式的JSP页面的开头自动包含一个文件,而指定相关的context路径。你可以在一个中多次使用,或者通过多个来实现

如果设置为true, 所有匹配指定的URL模式的JSP页面使用JSP XML语法(它们是JSP Document)

总结

在这部分,我讲述了JSP 2.0增强的错误处理机制和新的部署描述符的特性。在这个系列文章中,接下来的部分将涉及到JSP 2.0是如何使JSP操作XML变得轻松,还有与定制标签库相关的新特性。

JSP 2.0: The New Deal, Part 3

by Hans Bergsten, author of JavaServer Pages, 3rd Edition

04/21/2004


本文标签: 参数 使用 表达式 页面 属性