JSTL 学习笔记
JSP Standard Tag Library (JSTL) 的规范完成于2002年7月,随后Apache Taglibs Projects在不久的几天中提交了一个参考实现。
JSTL 的出现是为了解决程序员一直渴望有一个标准的标签库的需求,同时也为开发JSP带来了很大的便利。
JSTL 1.0提供了一系列基于JSP 1.2 API的标签库,下表列举了一些标签库的信息:
Description |
Prefix |
Default URI |
Core |
c |
http://java.sun.com/jstl/core |
XML Processing |
x |
http://java.sun.com/jstl/xml |
I18N & Formatting |
fmt |
http://java.sun.com/jstl/fmt |
Database Access |
sql |
http://java.sun.com/jstl/sql |
如果要使用JSTL,那么需要加入如下声明段:
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
除了标签库之外,JSTL 1.0还定义了一个所谓的Expression Language (EL)表达式语言。
EL用于访问运行时数据而出现,如果学过JavaScript,你会发现EL在表达上与其很类似。
${myObj.myProperty}$
${myObj["myProperty"]}$
${myObj[varWithTheName]}$
以上的语句用来检索一个对象的内部值,都是等价的。如果是访问一个数组或者列表:
${myList[2]}$
${myList[aVar + 1]}$
EL的支持的操作符:
Operator |
Description |
. |
Access a property |
[] |
Access an array/list element |
() |
Group a subexpression |
+ |
Addition |
- |
Subtraction or negation of a number |
/ or div |
Division |
% or mod |
Modulo (remainder) |
== or eq |
Test for equality |
!= or ne |
Test for inequality |
< or lt |
Test for less than |
> or gt |
Test for greater than |
<= or le |
Test for less than or equal |
>= or gt |
Test for greater than or equal |
&& or and |
Test for logical AND |
|| or or |
Test for logical OR |
! or not |
Unary Boolean complement |
empty |
Test for empty value (null, empty string, or an empty collection) |
支持的字面量:
Literal Type |
Description |
String |
Enclosed with single or double quotes. A quote of the same type within the string must be escaped with backslash: (/' in a string enclosed with single quotes; /" in a string enclosed with double quotes). The backslash character must be escaped as // in both cases. |
Integer |
An optional sign (+ or -) followed by digits between 0 and 9. |
Floating Point |
The same as an integer literal, except that a dot is used as the separator for the fractional part and an exponent can be specified as e or E, followed by an integer literal. |
Boolean |
true or false. |
Null |
null. |
支持的内建对象:
Variable |
Description |
param |
A collection of all request parameters as a single string value for each parameter. |
paramValues |
A collection of all request parameters as a string array value for each parameter. |
header |
A collection of all request headers as a single string value for each header. |
headerValues |
A collection of all request headers as a string array value for each header. |
cookie |
A collection of all request cookies as a single javax.servlet.http.Cookie instance value for each cookie. |
initParams |
A collection of all application init parameters as a single string value for each parameter. |
pageContext |
An instance of the javax.servlet.jspPageContext class. |
pageScope |
A collection of all page scope objects. |
requestScope |
A collection of all request scope objects. |
sessionScope |
A collection of all session scope objects. |
applicationScope |
A collection of all application scope objects. |
如果你要访问GET参数:${param.listType}
如果你要访问HTTP头信息:${header['User-Agent']}
访问Session或者Request内部包含对象:
${sessionScope.customer}
${requestScope.customer}
一些例子:
First name:
First name:
都是等价的。
控制流程和迭代操作也是JSTL的一个特性,个人认为迭代标签是当Java 1.5没出来之前对于Java语言的最好补充。
迭代操作使用的forEach标签:
City:
Tomorrow's high:
Tomorrow's low:
Choose标签:
">
Previous Page
Previous Page
">
Next Page
Next Page
URL操作:
这里的"/images/logo.gif"不是从网站的根目录起始,而是自动调整到所对应的context根目录,非常实用。
发表于 @ 2006年01月07日 3:40 PM | 评论 (0)
编写 "纯HTML" jsp应用--学会使用 JSTL
刚开始用JSP做web应用的时候,象使用PHP,ASP一样用JSP,在HTML代码中夹杂着一大堆的 scriptlet---即java 代码段。由于本人的“排版”技术还算可以,开始的时候觉得挺好,编写“效率”高,调试又方便!
到了后来才知道---这是一种极其愚蠢的做法儿----JSP诞生的时候就已经明确与ASP,PHP划清了界限,使用javaBean、Servlet可以有效的将HTML中夹杂的java 代码段剥离,然后包装成一个可在多个页面复用的“逻辑处理组件”---这是JSP相对于PHP,ASP的优越之处之一。
但有时即使使用javabean + servlet,我们也不得不将“极少量”的 java代码 嵌入到HTML中----的确,有时你必须这样:因为在 javabean中,你无法使用JSP中的隐含对象,比如 request,session,response等.
使用Servlet虽然可以使用JSP的对象,但却不能象javaBean灵活地插入到 html 中--
所以,Tag(标签) 就出现了(可以使用所有的JSP隐含对象),它的出现彻底解决了这个问题,可以让你编写出“纯HTML”的JSP页码---由此带来的好处自然不言而喻:更高的可维护性、更高的组件复用效率、更易维护的HTML页面````
小弟不才,刚刚开始学JSTL,觉得这个东东真的很不错!很想让更多的 初学者 知道这个,并能应用到实际的web开发中。
下面,就开始编写我们的第一个 Tag!
**下面是使用了简单Tag的JSP文件,运行结果是显示当前时间:
<%@ page contentType="text/html;charset=gb2312" %>
<%@taglib uri="/tags" prefix="visa"%>
现在时间是:
很明显,使用了tag的JSP页清爽了许多---如果将数据库操作等一些复杂功能也封装进去的话,tag的优势就更明显了!
**环境:win2000 server + Tomcat5.019 + j2sdk1.42 + SQLServer 2k
**开发一个Tag,需要编写2个主要文件:
1-标签处理器(一个类servlet的java类)
2-标签描述符(一个XML风格的tld文件)
完成这两个文件,就可以在WEB应用中部署、应用了。
好了,下面我们就开始做吧!
1-编写tag处理器:datetag.java
它的作用就象一个Servlet,接受来自客户端的请求,但它却可以象javaBean一样在JSP中方便调用。
package tag;
import java.util.Date;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class datetag extends TagSupport{
public int doStartTag() throws JspException{
Date dte=new Date();
try{
JspWriter out=pageContext.getOut();
out.print(dte);
}
catch(java.io.IOException e)
{throw new JspTagException(e.getMessage());}
return SKIP_BODY;
}
}
用 javac编译之后,就得到了 datetag.class文件了,将其放在 xxx/WEB-INF/classes/tag 目录下。
2-编写tag库描述符:tags.tld
比较容易看出,
将tags.tld保存在xxx/WEB-INF/ 目录下。
3-配置你的web.xml:
配置web.xml,注册你的标签库:在web.xml的
在这里注册你的自定义标签符,在JSP中的引用名为:/tags
4-开始在JSP中使用!
因为已经在web.xml中注册过,通过 /tags 引用你的标签库;
prefix的作用就象
<%@ page contentType="text/html;charset=gb2312" %>
<%@taglib uri="/tags" prefix="visa"%>
现在时间是:
**相信到了这里,有人就有了疑问了:为了使用一个Tag,我就做了这么多的“多余”工作(编写tld,修改web.xml,还要重启tomcat),值得吗?!
---答案是:这是很值得的!
1、如果将比较复杂的逻辑功能封装进Tag,它就具有比Servlet,javaBean更高的灵活性,更多的优点,更易扩展,更易维护---彻底分离表示层与逻辑层!
2、因为Tag的功能并非只是这一些,还有更多高级功能---值得去学习!
****
这只是一个很简单的应用,当然,你会有很多的“迷惑点”,这是正常的---在TAG中有一些独有的特性,想完全学会TAG并不是件简单的事情。
--所以,在这里,我向大家推荐一本好书:电子工业出版社的《jsp标志库编程指南》(英文名:《Professional JSP Tag Libraries》)
PS:使用JSTL配合javabean,servlet还可以有效保护你的源码哦 ---- 因为,你可以向你的客户交付不含有java源代码的web应用,因为,所有的 java代码 都已经被编译成 *.class了 *^_^*
[注意]:针对 Tomcat 5.0x以下的版本----如:Tomcat 4.0x:要编译标签处理器,必须将你的 servlet.jar(在% TOMCAT_HOME%/common/lib下面) 放进环境变量 CLASSPATH 中---(如果是 tomcat5.0x 以上的版本,好象没这个要求)---否则,会提示编译错误。
发表于 @ 2006年01月07日 3:38 PM | 评论 (0)
JSTL(JSP标准标签库)介绍
前言
从JSP 1.1规范开始,JSP就支持在JSP中使用自定义标签了,自定义标签的广泛使用造成了程序员重复定义,这样就促成了JSTL(JavaServer Pages Standard Tag Library)的诞生。
因为工作中需要用到JSTL,但网上却苦于找不到有关JSTL的中文资料,所以就有了这篇文章。
JSTL简介
JSTL是一个不断完善的开放源代码的JSP标签库,是由apache的jakarta小组来维护的。JSTL只能运行在支持JSP1.2和Servlet2.3规范的容器上,如tomcat 4.x。但是在即将推出的JSP 2.0中是作为标准支持的。
JSTL目前的最新版本为1.02,最终发布版为1.0。JSTL包含两个部分:标签库和EL(Expression Language表达式语言)语言。标签库目前支持四种标签:
标签 |
URI |
前缀 |
示例 |
Core |
http://java.sun.com/jstl/core |
c |
|
XML processing |
http://java.sun.com/jstl/xml |
x |
|
I18N capable formatting |
http://java.sun.com/jstl/fmt |
fmt |
|
Database access (SQL) |
http://java.sun.com/jstl/sql |
sql |
|
Core支持JSP中的一些基本的操作;
XML processing支持XML文档的处理;
I18N capable formatting支持对JSP页面的国际化;
Database access (SQL)支持JSP对数据库的操作。
由于本人水平有限,本文仅介绍Core标签,如有兴趣,可一起探讨其它三种标签的使用与扩充。
EL语言介绍
EL语言是JSTL输出(输入)一个JAVA表达式的表示形式。
在JSTL中,EL语言只能在属性值中使用。EL语言只能通过建立表达式${exp1}来进行调用。在属性值中使用表达式有三种方式。
1、 value属性包含一个表达式
在这种情况下,表达式值被计算出来并根据类型转换规则赋值给value属性。比如:
2、 value属性包含一个或多个属性,这些属性被文本分割或围绕
在这种情况下,表达式从左到右进行计算,并将结果转换为字符串型(根据类型转换规则),并将结果赋值给value属性
3、 value属性仅仅包含文本
在这种情况下,字符串型属性value将根据类型转换规则转换为标签所希望的类型。
EL语言的操作符
取得某个对象或集合中的属性值
为了获得集合中的属性,EL支持以下两种操作
1. 使用.操作符来获得有名字的属性。例如表达式${user.username}表明对象user的username属性
2. 使用[]操作符来获得有名字或按数字排列的属性。
表达式${user["username"]}和表达式${user. username }含义相同
表达式${row[0]} 表明row集合的第一个条目。
在这里user是一个类的对象,它的属性username必须符合标准JavaBean的规范,即必须为username属性定义相应的getter、setter方法。
Empty操作符(空值检查)
使用empty操作符来决定对象、集合或字符串变量是否为空或null。例如:
${empty param.username}
如果request的参数列表中的username值为null,则表达式的值为true。 EL也可以直接使用比较操作符与null进行比较。如${param.firstname == null}。
比较操作符
操作符 |
描述 |
==或eq |
相等检查 |
!=或ne |
不等检查 |
<或lt |
小于检查 |
>或gt |
大于检查 |
<=或le |
小于等于检查 |
>=或ge |
大于等于检查 |
数字运算符与逻辑运算符均与JAVA语言相同,不再列表。
Core标签库
1、 通用标签
属 性 |
描 述 |
是否必须 |
缺省值 |
value |
输出的信息,可以是EL表达式或常量 |
是 |
无 |
default |
value为空时显示信息 |
否 |
无 |
escapeXml |
为true则避开特殊的xml字符集 |
否 |
true |
例子:
您的用户名是: |
显示用户的用户名,如为空则显示guest
|
指定从session中获取username的值显示;
|
显示username的值,默认是从request(page)中取,如果request中没有名为username的对象则从session中取,session中没有则从application(servletContext)中取,如果没有取到任何值则不显示。
属 性 |
描 述 |
是否必须 |
缺省值 |
value |
要保存的信息,可以是EL表达式或常量 |
否 |
|
target |
需要修改属性的变量名,一般为javabean的实例 |
否 |
无 |
property |
需要修改的javabean属性 |
否 |
无 |
var |
需要保存信息的变量 |
否 |
无 |
scope |
保存信息的变量的范围 |
否 |
page |
如果指定了target属性, 那么property属性也必须指定。
例子:
|
将test.testinfo的值保存到session的test2中,其中test是一个javabean的实例,testinfo是test对象的属性。
|
将对象cust.address的city属性值保存到变量city中
属 性 |
描 述 |
是否必须 |
缺省值 |
var |
要删除的变量 |
是 |
无 |
scope |
被删除变量的范围 |
否 |
所有范围,包括page、request、session、application等 |
例子:
|
从session中删除test2变量。
2、 流控制标签
属 性 |
描 述 |
是否必须 |
缺省值 |
test |
需要评价的条件,相当于if (...){}语句中的条件 |
是 |
无 |
var |
要求保存条件结果的变量名 |
否 |
无 |
scope |
保存条件结果的变量范围 |
否 |
page |
这个标签不接受任何属性
属 性 |
描 述 |
是否必须 |
缺省值 |
test |
需要评价的条件 |
是 |
无 |
这个标签同样不接受任何属性
例子:
|
如果user.wealthy值true,则显示user.wealthy is true.
|
只有当条件user.generous返回值是true时,才显示user.generous is true.
只有当条件user.stingy返回值是true时,才显示user.stingy is true.
其它所有的情况(即user.generous和user.stingy的值都不为true)全部显示user.generous and user.stingy are false.
由于JSTL没有形如if (){…} else {…}的条件语句,所以这种形式的语句只能用
3、 循环控制标签
属 性 |
描 述 |
是否必须 |
缺省值 |
items |
进行循环的项目 |
否 |
无 |
begin |
开始条件 |
否 |
0 |
end |
结束条件 |
否 |
集合中的最后一个项目 |
step |
步长 |
否 |
1 |
var |
代表当前项目的变量名 |
否 |
无 |
varStatus |
显示循环状态的变量 |
否 |
无 |
例子:
|
相当于java语句
for (int i=0;i |
在这里vectors是一个java.util.Vector对象,里面存放的是String数据,vector是当前循环条件下String对象。实际上这里的vectors可以是任何实现了java.util. Collection接口的对象。
|
输出:
count=0
...
count=100
属 性 |
描 述 |
是否必须 |
缺省值 |
items |
进行循环的项目 |
是 |
无 |
delims |
分割符 |
是 |
无 |
begin |
开始条件 |
否 |
0 |
end |
结束条件 |
否 |
集合中的最后一个项目 |
step |
步长 |
否 |
1 |
var |
代表当前项目的变量名 |
否 |
无 |
varStatus |
显示循环状态的变量 |
否 |
无 |
例子
|
这个标签的使用相当于java.util.StringTokenizer类。在这里将字符串a:b:c:d以:分开循环四次,token是循环到当前分割到的字符串。
4.导入文件和URL
JSTL核心标签库支持使用
属 性 |
描 述 |
是否必须 |
缺省值 |
url |
需要导入页面的url |
是 |
无 |
context |
/后跟本地web应用程序的名字 |
否 |
当前应用程序 |
charEncoding |
用于导入数据的字符集 |
否 |
ISO-8859-1 |
var |
接受导入文本的变量名 |
否 |
page |
scope |
接受导入文本的变量的变量范围 |
否 |
1 |
varReader |
用于接受导入文本的java.io.Reader变量名 |
否 |
无 |
varStatus |
显示循环状态的变量 |
否 |
无 |
属 性 |
描 述 |
是否必须 |
缺省值 |
url |
url地址 |
是 |
无 |
context |
/后跟本地web应用程序的名字 |
否 |
当前应用程序 |
charEncoding |
用于导入数据的字符集 |
否 |
ISO-8859-1 |
var |
接受处理过的url变量名,该变量存储url |
否 |
输出到页 |
scope |
存储url的变量名的变量范围 |
否 |
page |
例子:
|
将url http://www.url.com/edit.js包含到当前页的当前位置,并将url保存到newsfeed变量中
在当前页的当前位置输出,http://www.yourname.com是当前页的所在的位置。
属 性 |
描 述 |
是否必须 |
缺省值 |
url |
url地址 |
是 |
无 |
context |
/后跟本地web应用程序的名字 |
否 |
当前应用程序 |
例子:
|
将请求重新定向到http://www.yourname.com/login.jsp页,相当于response.setRedirect("http://www.yourname.com/login.jsp");
属 性 |
描 述 |
是否必须 |
缺省值 |
name |
在request参数中设置的变量名 |
是 |
无 |
value |
在request参数中设置的变量值 |
否 |
无 |
例子:
|
将参数888以id为名字传递到login.jsp页面,相当于login.jsp?id=888
JSTL的优点
1、 在应用程序服务器之间提供了一致的接口,最大程序地提高了WEB应用在各应用服务器之间的移植。
2、 简化了JSP和WEB应用程序的开发。
3、 以一种统一的方式减少了JSP中的scriptlet代码数量,可以达到没有任何scriptlet代码的程序。在我们公司的项目中是不允许有任何的scriptlet代码出现在JSP中。
4、 允许JSP设计工具与WEB应用程序开发的进一步集成。相信不久就会有支持JSTL的IDE开发工具出现。
总结
上面介绍的仅仅是JSTL的一部分,如果有时间我会继续把其它部分写出来分享给大家。如果要使用JSTL,则必须将jstl.jar和standard.jar文件放到classpath中,如果你还需要使用XML processing及Database access (SQL)标签,还要将相关JAR文件放到classpath中,这些JAR文件全部存在于下载回来的zip文件中。这个zip文件可以从http://jakarta.apache.org/builds/jakarta-taglibs/releases/standard/jakarta-taglibs-standard-1.0.zip下载。
参考资料
1、 http://java.sun.com/products/jsp/jstl/
sun公司的JSTL站点
2、 http://jakarta.apache.org/taglibs/doc/standard-doc/intro.html
jakarta小组的JSTL站点
3、 http://www.manning.com/bayern/appendixA.pdf
JSTL的参考文档,本文很多内容都是从这个PDF文件里翻译的。
4、 <<J2EE编程指南(1.3版)>>
介绍了JSTL的雏形,wrox的书都是精品。
发表于 @ 2006年01月07日 3:36 PM | 评论 (1)
使用JSTL标签来访问list并判断list中的选中项
本文将向大家讲述如何通过sun公司的jstl标签来访问list对象,并在jsp页面进行显示
一般而言,list对象会存储在request对象,session对象中,一般采用框架(比如说Struts框架中的Action)完成把list对象置入request对象中,
XXAction{
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
/*从session中获得用户信息*/
HttpSession session=request.getSession();
User user =(User)session.getAttribute("user");
request.setAttribute("user",user);
/*建立rolelist*/
List rolelist =new ArrayList();
for(int i=0;i<5;i++){
Role role= new Role(i,"role"+i);
rolelist.add(role);
}
request.setAttribute("role_list",rolelist);
}
本文的讲解重点是jstl标签部分:
<%@ taglib uri="/jstl/core" prefix="c"%>
发表于 @ 2006年01月07日 3:32 PM | 评论 (0)
jstl,fmt标签总结
首先,jstl既然可以国际化,那么必然可以自动根据local设置来选择资源文件。
2,fmt:setLocal 可以设置Local,从而改变输出格式。
3,fmt:message 可以输出资源文件里的key对应的value。
4,
Nitrox插件提示找不到resources.properties的警告.
使用
原因:工程没有指定input ,output的对应关系.这样classes并不是classpath路径.
解决办法:
设置input为/WEB-INF/src ,output /WEB-INF/classes
然后把resources.properties放在 /WEB-INF/src/下面。
这样在/WEB-INF/classes/下面自动生成了一个resources.properties.这就是我想要的。
好了,在试一次,资源文件找到了。
5,难道
没办法,jstl就是这样用的。
6,jstl使用资源文件有个大的问题,因为fmt:bundle basename="xxx" 指定死了资源文件了,那么如果local不同了
岂不是还从这个资源文件里取数据吗?这样美国的网页浏览仍旧显示日文,就不合理了.
我理解错了,
如果是英国的local那么自动查找xxx_en.properties,如果是中国的local那么自动去查找xxx_zh.properties.
和struts是一样的.
发表于 @ 2006年01月07日 3:32 PM | 评论 (0)
JSTL 标签库介绍
随着J2EE瘦客户机技术JavaServer Pages(JSP)在过去几年中的流行,独立开发人员已经创建了许多自定义的JSP标记库。虽然很多标记库是编写用来实现不同目标的,但它们往往也对迭代、条件及其他通用操作都提供了类似的解决方案。
为了减少对解决类似通用问题的独立标记库的需求,在Java Community Process(JSR 52)的赞助下创建了JSTL(JavaServer Pages Standard Tag Library,JSP)标准标记库,为解决这些通用功能提供一个单一的标准解决方案。
JSTL库
JSTL特别为条件处理、迭代、国际化、数据库访问和可扩展标记语言(XML)处理提供支持。JSTL还引入了expression language(EL,表达式语言),极大地简化了对JSP中应用数据的访问和操作。JSTL包括4个JSP 1.2自定义标记库,每一个都涵盖了一个特定的功能领域。
核心(Core)标记库为日常任务提供通用支持,如显示和设置变量、重复使用一组项目、测试条件以及其他操作(如导入和重定向Web内容)。
XML标记库提供了对XML处理和操作的支持,包括XML节点的解析、迭代、基于XML数据的条件评估以及可扩展样式表语言转换(Extensible Style Language Transformations,XSLT)的执行。
国际化(Internationalization)标记库支持多语种的应用程序。
数据库(Database)标记库对访问和修改数据库数据提供标准化支持。
表1:JSTL的四个标记库 |
|||
功能领域 |
URI |
前缀 |
例子 |
核心(Core) |
http://java.sun.com/jstl/core |
c |
|
XML |
http://java.sun.com/jstl/xml |
x |
|
国际化(Internationalization) |
http://java.sun.com/jstl/fmt |
fmt |
|
数据库(Database) |
http://java.sun.com/jstl/sql |
sql |
|
JSTL入门
初步了解JSTL的最好方法是访问Apache网站--jakarta.apache.org,并下载JSTL的参考实现。在Apache站点还可找到详细的安装指南。可下载的参考实现是一个JAR文件、文档和简单代码示例的组合包。要在你的J2EE Web应用程序中使用JSTL,只需简单地将"lib"目录下的JSTL JAR文件复制到你应用程序的WEB-INF/lib目录下。要在一个特定的JSP中使用JSTL标记,你还必须提供一个taglib指令。例如,要将"核心"JSTL库导入到你的页面中,你应该在你的JSP顶端包含下面的指令,如下所示:
<%@ taglib uri="http://java.sun.com /jstl/core" prefix="c" %>
JSTL的EL支持
JSTL的一个重要优势是它采用了简单的expression language(EL),该语言提供一个访问和操作应用程序数据(如存储在servlet上下文中的数据)的简单方式。
EL的语法很简单,而且比Java中具有相同功能的表示要对用户更为友好。例如, pageContext.getAttribute("aName")表达式在EL中就成了${aName}。所有的JSTL标记在其属性值中都使用EL表达式。EL表达式在访问嵌套属性时使用${Java.expression}或${ data.reference}格式。数据参考可以是对象及其属性或者对象及其属性数组: ${myobject.property}
数组存取操作符也用于以索引元素集合显示的数据,如Java数组或java.util.List:${myList[2]}$
在EL表达式中除了可以使用属性和数组元素操作符以及算术、关系和逻辑操作符以外,你还可以使用特别操作符来测试对象是否为空。 除了对象和数组存取,EL还提供了一个完整的常用操作符集合,包括=、!、<、>、<=、>=、+、-、*、/等。
在任何JSP范围(页面、请求、会话或应用程序)中的对象都可以在EL表达式中引用。例如,如果你有一个带有一个属性"Ename"的Java bean--Employee,那么可以用EL表达式${Employee.Ename}访问这个变量。
除了显式变量,EL还提供了对隐式变量的请求和应答对象中的隐式变量的直接访问。例如,以下语句将访问一个名为"empname"的请求参数:
${param.empname}
即将推出的JSP 2.0和JSTL 1.0都使用EL。然而,JSP 2.0中使用的EL稍有一点不同。JSTL专家组(JSR-052)已经同意在即将推出的JSTL维护版中使用EL的JSP 2.0版本。
使用JSTL核心标记库
JSTL核心标记库为诸如显示、迭代和设置变量等操作提供了最常用的标记。下面,我们更详细地介绍一些最常用的JSTL核心标记库。首先,在使用任何JSTL核心标记之前,你需要将以下指令添加到你的JSP中:
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
你最常使用的JSTL操作之一是显示动态值。为了显示动态数据,核心库提供了c:out标记。c:out标记在一个页面中显示一个EL表达式的值。例如:
First name:
c:out的值属性还可以包含文本和表达式的组合:
(注意:当JSP 2.0提供对EL的支持时,你无需再使用c:out操作,你可以直接在页面中嵌入JSP表达式。)
另一个操作是设置变量。为了在一个页面中设置变量,核心标记库提供了c:set标记。这个例子显示了将变量Ename设置为参数"enameparm"的值:
JSTL核心标记库还提供了用于处理条件的标记。c:if处理简单的条件测试。计算test属性中布尔表达式的值;如果是真,计算主体中的内容。在下面的操作中,你还可以看到存储测试结果以备以后在页面(或者在别的地方,如果指定了其他的可选范围属性)中使用的可选的var属性:
下面,你可以看到JSTL通过c:choose、c:when和c:otherwise对跳转逻辑的支持。你可以在一个选择(choose)标记中包含一组c:when操作;如果对c:when块中的表达式求值为真,则不对下面的c:choose操作中的测试进行计算。如果对c:when块中测试求值没有一个为真,则计算c:otherwise操作(如果存在的话)的内容:
c:forEach标记提供了一个对元素集合进行迭代的简单方法。如果你只想迭代集合中的部分元素,你可以分别指定开始和结束索引以及带有可选的开始、结束与步进属性的增量值。在下例中,我们对变量empNames中的一个集合的内容进行迭代;在每个循环中,下一个元素被放置在变量名中,并在c:forEach操作的主体中进行求值。
JSTL核心标记库还可以简化异常处理。以前,你必须将Java try/catch语句放置在Java scriptlet中,或者在错误页面中提供它们。JSTL通过c:catch标记提供了一个处理异常的高明方法,而无需使用scriptlet。
可以在jakarta.apache.org的参考实现中提供的JSTL文档中找到其他JSTL标记库如XML、国际化和数据库标记库的例子。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=526943
发表于 @ 2006年01月07日 3:31 PM | 评论 (0)
JSTL 访问SQL和XML内容
Web应用程序的标志是多个子系统的集成。SQL和XML是在这类子系统之间交换数据的两种最通用的机制。在本文中,Mark Kolb介绍访问JSP页面数据库和XML内容的sql和xml库并对JSTL进行了总结。
Web应用程序的模板式(stereotypical)架构分为三层:处理请求的Web服务器、实施业务逻辑的应用程序服务器以及管理永久性数据的数据库。应用程序和数据库层之间的联接通常采用关系数据库中的SQL调用格式。当业务逻辑被写入到Java语言中时,JDBC用于实现这些调用。
如果应用程序调用与其它服务器(本地或远程)的集成,我们将需要用于在不同子系统之间交换数据的更深层次的机制。在Web应用程序内部和应用程序之间传送数据采用的越来越普遍的一种方法是XML文件的交换。
迄今为止,在我们的JSTL之旅中,我们讨论了JSTL 表达式语言(expression language,EL)和core和fmt标记库。在最后一部分,我们将考虑sql和xml库--正如它们的名字表示的一样 -- 提供定制标记来接入和管理从SQL数据库和XML文件检索到的数据。
xml库
根据设计,XML提供灵活的方式来表示结构化数据,这些数据同时准备进行验证,因此它尤其适应于在松散联合的系统之间交换数据。这反过来使其成为Web应用程序极具吸引力的集成技术。
与使用XML表示的数据进行交互的第一步是把数据作为一个XML文件,对其进行检索并进行分解,以创建数据结构来接入该文件中的内容。在分解文件后,您可以有选择的对其进行转换以创建新的XML文件,您可以对新的XML文件进行相同的操作。最终,文件中的数据可以被提取,然后显示或使用作为输入数据来运行其它操作。
这些步骤都在用于控制XML的JSTL标记中反映出。根据我们在第2部分探讨核心中所讨论的,我们使用core库中的
分解XML
在这五种属性中,只有xml属性是需要的,其值应该是包含要分解的XML文件的字符串,或者是java.io.Reader实例,通过它可以读取要被分解的文件。此外,您可以使用以下语法,根据
body content
var和scope属性规定存储分解后的文件的scoped变量。然后xml库中的其它标记可以使用这一变量来运行其它操作。注意,当var和 scope 属性存在时,JSTL用于表示分解后的文件的数据结构类型以实施为导向,从而厂商可以对其进行优化。
如果应用程序需要对JSTL提供的分解后的文件进行处理,它可以使用另一种格式的
当您使用
body content
其它两个属性filter 和 systemId 可以实现对分解流程的精确控制。filter 属性规定org.xml.sax.XMLFilter类的一个实例,以在分解之前对文件进行过滤。如果要被分解的文件非常大,但目前的工作只需要处理一小部分内容时这一属性尤其有用。systemId属性表示要被分解的文件的URI并解析文件中出现的任何相关的路径。当被分解的XML文件使用相关的URL来引用分解流程中需要接入的其它文件或资源时需要这种属性
清单1展示了
清单1:
转换XML
XML通过XSL样式表来转换。JSTL使用
xmlSystemId="expression" xsltSystemId="expression">
...
此处,xml 属性规定要被转换的文件,xslt 属性规定定义这次转换的样式表。这两种属性是必要的,其它属性为可选。
与
而且,您可以根据
xmlSystemId="expression" xsltSystemId="expression">
body content
...
在这两种情况下,规定XSL 样式表的xslt 属性应是字符串、Reader或javax.xml.transform.Source实例。
如果var 属性存在,转换后的XML文件将分配给相应的scoped变量,作为org.w 3c .dom.Document 类的一个实例。通常,scope属性规定这类变量分配的范围。
清单2:使用result属性来提供javax.xml.transform.Result实例时,
xmlSystemId="expression" xsltSystemId="expression">
...
xmlSystemId="expression" xsltSystemId="expression">
body content
...
无论您采用这两种
如果既不存在var 属性,也不存在result属性,转换的结果将简单地插入到JSP页面,作为处理
清单3:在JSP页面直接显示转换的XML数据
在本例中,使用
图1:清单3的输出结果
发表于 @ 2006年01月07日 3:30 PM | 评论 (0)
调试JSTL碰到的问题,真的是,无语.....
随着各种框架的产生,各种标签语言也越来越多,不过其中官方支持的只有一个那就是JSTL.
看了一下各个框架的例程,几乎所有的框架都对JSTL有支持.
所以下定决心,不怕牺牲了解一下JSTL,并尝试在项目中慢慢过渡..
写了一个Very Simple的例子:
********************************************************************************************
<%@ page contentType="text/html; charset=gbk" import="
java.io.*,
java.sql.*,
java.util.*,
javax.servlet.jsp.jstl.sql.*"
%>
<%@ taglib uri="/core" prefix="c" %>
<%@ taglib uri="/format" prefix="fmt" %>
<%@ include file="../include/common.jsp" %>
<%
String testid="测试";
//读取数据到JSTL的Result
Result data=openResult("select * from test");
if (data.getRowCount()>0){
System.err.println(data.getColumnNames()[1]);
System.err.println(data.getRows()[1].get("id"));
}
//一般分页操作,需要知道总行数
request.setAttribute("data",data);
request.setAttribute("testid",testid);
%>
字典数据:
<%
out.println("ok");
//最终关闭连接
try {
if ( stat != null ) { stat.close(); }
if ( conn != null ) { conn.close(); }
}
catch ( Exception e ) {
}
data=null;
jrs=null;
System.gc();
%>
********************************************************************************************
结果,我想移值这个代码到Appfuse的框架中时问题出现了...怎么样处理,变量都不能显示...
结果花了四五个小时,才发现是 Jstl版本 和 描述的 fmt.tld c.tld的版本不匹配,而且,这些例子均依赖于Appache 的Taglib
修改了一下,采用默认得的uri(注意,低版本的URI和高版本的URI语法上还有差异T^@#^@^#@^)
<%@ page contentType="text/html; charset=gbk" import="
java.io.*,
java.sql.*,
java.util.*,
javax.servlet.jsp.jstl.sql.*"
%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
<%@ include file="../include/common.jsp" %>
<%
String testid="测试";
//读取数据到JSTL的Result
Result data=openResult("select * from test");
if (data.getRowCount()>0){
System.err.println(data.getColumnNames()[1]);
System.err.println(data.getRows()[1].get("id"));
}
//一般分页操作,需要知道总行数
request.setAttribute("data",data);
request.setAttribute("testid",testid);
%>
字典数据:
<%
out.println("ok");
//最终关闭连接
try {
if ( stat != null ) { stat.close(); }
if ( conn != null ) { conn.close(); }
}
catch ( Exception e ) {
}
data=null;
jrs=null;
System.gc();
%>
*********************************************************************************************
在这个过程,我仔细看了一下配置文件,JSTL其实只实现很少的几个标签,而我们常用的大部分功能,很多都是依赖于Apache TagLib的实现
而随着版本的变化,这些细微的配置会造成一些差异,可恨的是,竟然没有明确的错误提示....
结果浪费了我数个小时,最后是到Apache下载了一个最新的Jstl.jar和stander.jar 及描述文件.
发表于 @ 2006年01月07日 3:28 PM | 评论 (0)
JSTL教程
JSTL教程
JSTL教程
JSP 标准标记库(JSP Standard Tag Library,JSTL)是一个实现 Web 应用程序中常见的通用功能的定制标记库集,这些功能包括迭代和条件判断、数据管理格式化、XML 操作以及数据库访问。在 developerWorks 上其新系列的第一篇文章中,软件工程师 Mark Kolb 向您展示了如何使用 JSTL 标记来避免在 JSP 页面中使用脚本编制元素。您还将了解如何通过从表示层删除源代码来简化软件维护。最后,您将了解 JSTL 经过简化的表达式语言,它允许在不必使用功能齐全的编程语言的情况下对 JSTL 操作指定动态属性值。
JavaServer Pages(JSP)是用于 J2EE 平台的标准表示层技术。JSP 技术提供了用于执行计算(这些计算用来动态地生成页面内容)的脚本编制元素和操作。脚本编制元素允许在 JSP 页面中包括程序源代码,在为响应用户请求而呈现页面时可以执行这些源代码。操作将计算操作封装到很象 HTML 或 XML 标记的标记中,JSP 页面的模板文本通常包含这些标记。JSP 规范只将几种操作定义成了标准,但从 JSP 1.1 开始,开发人员已经能够以定制标记库的方式创建其自己的操作了。
JSP 标准标记库(JSTL)是 JSP 1.2 定制标记库集,这些标记库实现大量服务器端 Java 应用程序常用的基本功能。通过为典型表示层任务(如数据格式化和迭代或条件内容)提供标准实现,JSTL 使 JSP 作者可以专注于特定于应用程序的开发需求,而不是为这些通用操作“另起炉灶”。
当然,您可以使用 JSP 脚本编制元素(scriptlet、表达式和声明)来实现此类任务。例如,可以使用三个 scriptlet 实现条件内容,清单 1 中着重显示了这三个 scriptlet。但是,因为脚本编制元素依赖于在页面中嵌入程序源代码(通常是 Java 代码),所以对于使用这些脚本编制元素的 JSP 页面,其软件维护任务的复杂度大大增加了。例如,清单 1 中的 scriptlet 示例严格地依赖于花括号的正确匹配。如果不经意间引入了一个语法错误,则条件内容中的嵌套其它 scriptlet 可能会造成严重破坏,并且在 JSP 容器编译该页面时,要使所产生的错误信息有意义可能会很困难。
清单 1. 通过 scriptlet 实现条件内容 <% if (user.getRole() == "member")) { %>
Welcome, member! Welcome, guest! |
修正此类问题通常需要相当丰富的编程经验。尽管通常会由十分精通页面布局和图形设计的设计人员来开发和维护 JSP,但是同一页面中的脚本编制元素出现问题时,需要程序员的介入。这种状况将单个文件中代码的责任分担给多人,因而使得开发、调试和增强此类 JSP 页面成为很麻烦的任务。通过将常用功能包装到定制标记库的标准集合中,JSTL 使 JSP 作者可以减少对编制脚本元素的需求,甚至可以不需要它们,并避免了相关的维护成本。
JSTL 1.0
JSTL 1.0 发布于 2002 年 6 月,由四个定制标记库(core、format、xml 和 sql)和一对通用标记库验证器(ScriptFreeTLV 和 PermittedTaglibsTLV)组成。core 标记库提供了定制操作,通过限制了作用域的变量管理数据,以及执行页面内容的迭代和条件操作。它还提供了用来生成和操作 URL 的标记。顾名思义,format 标记库定义了用来格式化数据(尤其是数字和日期)的操作。它还支持使用本地化资源束进行 JSP 页面的国际化。xml 库包含一些标记,这些标记用来操作通过 XML 表示的数据,而 sql 库定义了用来查询关系数据库的操作。
两个 JSTL 标记库验证器允许开发人员在其 JSP 应用程序中强制使用编码标准。可以配置 ScriptFreeTLV 验证器以在 JSP 页面中禁用各种类型的 JSP 脚本元素 — scriptlet、表达式和声明。类似地,PermittedTaglibsTLV 验证器可以用来限制可能由应用程序的 JSP 页面访问的定制标记库集(包括 JSTL 标记库)。
尽管 JSTL 最终将会成为 J2EE 平台的必需组件,但目前只有少数应用程序服务器包括它。JSTL 1.0 的参考实现可作为 Apache 软件基金会(Apache Software Foundation)的 Jakarta Taglibs 项目(请参阅参考资料)的一部分而获得。可以将该参考实现中的定制标记库合并到任何支持 JSP 1.2 和 Servlet 2.3 规范的服务器,以添加对 JSTL 的支持。
表达式语言
在 JSP 1.2 中,可以使用静态字符串或表达式(如果允许的话)指定 JSP 操作的属性。例如,在清单 2 中,对
清单 2. 合并请求时属性值的 JSP 操作
|
因为请求时属性值是用表达式指定的,所以它们往往有和其它脚本元素一样的软件维护问题。因此,JSTL 定制标记支持另一种用于指定动态属性值的机制。可以用简化的表达式语言(EL)而不使用完整的 JSP 表达式来指定 JSTL 操作的属性值。EL 提供了一些标识符、存取器和运算符,用来检索和操作驻留在 JSP 容器中的数据。EL 在某种程度上以 EcmaScript(请参阅参考资料)和 XML 路径语言(XML Path Language,XPath)为基础,因此页面设计人员和程序员都应该熟悉它的语法。EL 擅长寻找对象及其特性,然后对它们执行简单操作;它不是编程语言,甚至不是脚本编制语言。但是,与 JSTL 标记一起使用时,它就能使用简单而又方便的符号来表示复杂的行为。EL 表达式的格式是这样的:用美元符号($)定界,内容包括在花括号({})中,如清单 3 所示。
清单 3. 说明 EL 表达式定界符的 JSTL 操作
此外,您可以将多个表达式与静态文本组合在一起以通过字符串并置来构造动态属性值,如清单 4 所示。单独的表达式由标识符、存取器、文字和运算符组成。标识符用来引用存储在数据中心中的数据对象。EL 有 11 个保留标识符,对应于 11 个 EL 隐式对象。假定所有其它标识符都引用限制了作用域的变量。存取器用来检索对象的特性或集合的元素。文字表示固定的值 — 数字、字符、字符串、布尔型或空值。运算符允许对数据和文字进行组合以及比较。
清单 4. 组合静态文本和多个 EL 表达式以指定动态属性值
限制了作用域的变量
JSP API 通过
·页面作用域
·请求作用域
·会话作用域
·应用程序作用域
您可能还记得,只有在为特定请求处理页面期间才能检索存储在该页面作用域中的对象。如果对象是存储在请求作用域中的,可以在处 理所有参与处理某请求的页面期间检索这些对象(譬如在对某个请求的处理中遇到了一个或多个
通过将字符串映射为期望作用域中的对象来将对象存储到该作用域。然后,就可以通过提供相同字符串来从该作用域检索该对象。在作用域的映射中查找字符串,并 返回被映射的对象。在 Servlet API 中,将此类对象称为相应作用域的属性。但是,在 EL 的上下文中,也将与属性相关联的字符串看作变量的名称,该变量通过属性映射的方式获得特定的值。
在 EL 中,与隐式对象无关联的标识符被认为是存储在四个 JSP 作用域中的名称对象。首先对页面作用域检查是否存在这样的标识符,其次对请求作用域、然后对会话作用域、最后对应用程序作用域依次进行这样的检查,然后测 试该标识符的名称是否与存储在该作用域中的某个对象的名称匹配。第一个这样的匹配作为 EL 标识符的值被返回。通过这种方法,可以将 EL 标识符看作引用限制了作用域的变量。
从更技术的方面来说,没有映射到隐式对象的标识符是用 PageContext 实例的 findAttribute() 方法求值的,该实例表示对页面的处理,在该页面上,当前正在处理用于请求的表达式。标识符的名称作为参数传递给这个方法,然后该方法依次在四个作用域中搜 索具有相同名称的属性。并将所找到的第一个匹配项作为 findAttribute() 方法的值返回。如果未在这四个作用域中找到这样的属性,则返回 null。
最终,限制了作用域的变量是四个 JSP 作用域的属性,这些属性具有可以用作 EL 标识符的名称。只要对限制了作用域的变量赋予由字母数字组成的名称,就可以通过 JSP 中提供的用于设置属性的任何机制来创建它们。这包括内置的
隐式对象
表 1 中列出了 11 个 EL 隐式对象的标识符。不要将这些对象与 JSP 隐式对象(一共只有九个)混淆,其中只有一个对象是它们所共有的。
表 1. EL 隐式对象
类别 标识符 描述
JSP pageContext PageContext 实例对应于当前页面的处理
作用域 pageScope 与页面作用域属性的名称和值相关联的 Map 类
requestScope 与请求作用域属性的名称和值相关联的 Map 类
sessionScope 与会话作用域属性的名称和值相关联的 Map 类
applicationScope 与应用程序作用域属性的名称和值相关联的 Map 类
请求参数 param 按名称存储请求参数的主要值的 Map 类
paramValues 将请求参数的所有值作为 String 数组存储的 Map 类
请求头 header 按名称存储请求头主要值的 Map 类
headerValues 将请求头的所有值作为 String 数组存储的 Map 类
Cookie cookie 按名称存储请求附带的 cookie 的 Map 类
初始化参数 initParam 按名称存储 Web 应用程序上下文初始化参数的 Map 类
尽管 JSP 和 EL 隐式对象中只有一个公共对象(pageContext),但通过 EL 也可以访问其它 JSP 隐式对象。原因是 pageContext 拥有访问所有其它八个 JSP 隐式对象的特性。实际上,这是将它包括在 EL 隐式对象中的主要理由。
其余所有 EL 隐式对象都是映射,可以用来查找对应于名称的对象。前四个映射表示先前讨论的各种属性作用域。可以用它们来查找特定作用域中的标识符,而不用依赖于 EL 在缺省情况下使用的顺序查找过程。
接下来的四个映射用来获取请求参数和请求头的值。因为 HTTP 协议允许请求参数和请求头具有多个值,所以它们各有一对映射。每对中的第一个映射返回请求参数或头的主要值,通常是恰巧在实际请求中首先指定的那个值。每 对中第二个映射允许检索参数或头的所有值。这些映射中的键是参数或头的名称,但这些值是 String 对象的数组,其中的每个元素都是单一参数值或头值。
cookie 隐式对象提供了对由请求设置的 cookie 名称的访问。这个对象将所有与请求相关联的 cookie 名称映射到表示那些 cookie 特性的 Cookie 对象。
最后一个 EL 隐式对象 initParam 是一个映射,它储存与 Web 应用程序相关联的所有上下文的初始化参数的名称和值。初始化参数是通过 web.xml 部署描述符文件指定的,该文件位于应用程序的 WEB-INF 目录中。
存取器
因为 EL 标识符是作为隐式对象或限制了作用域的变量(通过属性来实现)解析的,因此有必要将它们转换成 Java 对象。EL 可以自动包装和解包其相应的 Java 类中的基本类型(例如,可以在后台将 int 强制转换成 Integer 类,反之亦可),但大多数的标识符将成为指向完整的 Java 对象的指针。
结果是,对这些对象的特性或(在对象是数组和集合的情况下)对其元素的访问通常是令人满意的。就为了实现这种用途,EL 提供了两种不同的存取器(点运算符(.)和方括号运算符([])),也支持通过 EL 操作特性和元素。
点运算符通常用于访问对象的特性。例如,在表达式 ${user.firstName} 中,使用点运算符来访问 user 标识符所引用对象的名为 firstName 的特性。EL 使用 Java bean 约定访问对象特性,因此必须定义这个特性的 getter 方法(通常是名为 getFirstName() 的方法),以便表达式正确求值。当被访问的特性本身是对象时,可以递归地应用点运算符。例如,如果我们虚构的 user 对象有一个实现为 Java 对象的 address 特性,那么也可以用点运算符来访问这个对象的特性。例如,表达式 ${user.address.city} 将会返回这个地址对象嵌套的 city 特性。
方括号运算符用来检索数组和集合的元素。在数组和有序集合(也即,实现了 java.util.List 接口的集合)的情况下,把要检索的元素的下标放在方括号中。例如,表达式 ${urls[3]} 返回 urls 标识符所引用的数组或集合的第四个元素(和 Java 语言以及 JavaScript 中一样,EL 中的下标是从零开始的)。
对于实现 java.util.Map 接口的集合,方括号运算符使用关联的键查找存储在映射中的值。在方括号中指定键,并将相应的值作为表达式的值返回。例如,表达式 ${commands["dir"]} 返回与 commands 标识符所引用的 Map 中的 "dir" 键相关联的值。
对于上述两种情况,都可允许表达式出现在方括号中。对嵌套表达式求值的结果将被作为下标或键,用来检索集合或数组的适当元素。和点运算符一样,方括号运算 符也可以递归应用。这使得 EL 能够从**数组、嵌套集合或两者的任意组合中检索元素。此外,点运算符和方括号运算符还可以互操作。例如,如果数组的元素本身是对象,则可以使用方括号运 算符来检索该数组的元素,并结合点运算符来检索该元素的一个特性(例如 ${urls[3].protocol})。
假定 EL 充当指定动态属性值的简化语言,EL 存取器有一个有趣的功能(与 Java 语言的存取器不同),那就是它们在应用于 null 时不抛出异常。如果应用 EL 存取器的对象(例如,${foo.bar} 和 ${foo["bar"]} 中的 foo 标识符)是 null,那么应用存取器的结果也是 null。事实证明,在大多数情况下,这是一个相当有用的行为,不久您就会了解这一点。
最后,点运算符和方括号运算符可能实现某种程度的互换。例如,也可以使用 ${user["firstName"]} 来检索 user 对象的 firstName 特性,正如可以用 ${commands.dir} 获取与 commands 映射中的 "dir" 键相关联的值一样。
运算符
EL 还可以通过使用标识符和存取器,遍历包含应用程序数据(通过限制了作用域的变量公开)或关于环境的信息(通过 EL 隐式对象)的对象层次结构。但是,只是访问这些数据,通常不足以实现许多 JSP 应用程序所需的表示逻辑。
最终,EL 还包括了几个用来操作和比较 EL 表达式所访问数据的运算符。表 2 中汇总了这些运算符。
表 2. EL 运算符
类别 运算符
算术运算符 +、-、*、/(或 div)和 %(或 mod)
关系运算符 ==(或 eq)、!=(或 ne)、<(或 lt)、>(或 gt)、<=(或 le)和 >=(或 ge)
逻辑运算符 &&(或 and)、||(或 or)和 !(或 not)
验证运算符 empty
算术运算符支持数值的加法、减法、乘法和除法。还提供了一个求余运算符。注:除法和求余运算符都有替代的、非符号的名称(为的是与 XPath 保持一致)。清单 5 中显示了一个演示算术运算符用法的示例表达式。对几个 EL 表达式应用算术运算符的结果是将该算术运算符应用于这些表达式返回的数值所得的结果。
清单 5. 利用算术运算符的 EL 表达式
${item.price * (1 + taxRate[user.address.zipcode])} |
关系运算符允许比较数字或文本数据。比较的结果作为布尔值返回。逻辑运算符允许合并布尔值,返回新的布尔值。因此,可以将 EL 逻辑运算符应用于嵌套的关系或逻辑运算符的结果,如清单 6 所示。
清单 6. 利用关系和逻辑运算符的 EL 表达式
${(x >= min) && (x <= max)} |
最后一种 EL 运算符是 empty,它对于验证数据特别有用。empty 运算符采用单个表达式作为其变量(也即,${empty input}),并返回一个布尔值,该布尔值表示对表达式求值的结果是不是“空”值。求值结果为 null 的表达式被认为是空,即无元素的集合或数组。如果参数是对长度为零的 String 求值所得的结果,则 empty 运算符也将返回 true。
表 3 显示了 EL 运算符的优先级。正如清单 5 和 6 所示,可以用圆括号对表达式分组,高于普通的优先级规则。
表 3. EL 运算符优先级(自顶到底,从左到右)
[], . |
文字
在 EL 表达式中,数字、字符串、布尔值和 null 都可以被指定为文字值。字符串可以用单引号或双引号定界。布尔值被指定为 true 和 false。
Taglib 伪指令
正如我们先前讨论的,JSTL 1.0 包括四个定制标记库。为了演示 JSTL 标记和表达式语言的交互,我们将研究几个来自 JSTL core 库的标记。和使用任何 JSP 定制标记库一样,必须在您想要使用这个库标记的任何页面中包括 taglib 伪指令。清单 7 显示了用于这个特定库的伪指令。
清单 7. 用于 JSTL core 库 EL 版本的 taglib 伪指令
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> |
实际上,对应于 JSTL core 库的 taglib 伪指令有两种,因为在 JSTL 1.0 中,EL 是可选的。所有四个 JSTL 1.0 定制标记库都有使用 JSP 表达式(而不是 EL)指定动态属性值的备用版本。因为这些备用库依赖于 JSP 的更传统的请求时属性值,所以它们被称为 RT 库,而那些使用表达式语言的则被称为 EL 库。开发人员用不同的 taglib 伪指令来区分每个库的这两个版本。清单 8 显示了使用 core 库的 RT 版本的伪指令。但是,由于现在我们讨论的重点是 EL,所以首先需要这些伪指令。
清单 8. 用于 JSTL core 库 RT 版本的 taglib 伪指令
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt" %> |
变量标记
我们首先要考虑的 JSTL 定制标记是
清单 9.
|
scope 属性是可选的,其缺省值是 page。
清单 10 中显示了
清单 10.
|
您还可以将限制了作用域的变量的值指定为
清单 11. 通过主体内容指定
|
JSTL core 库包含第二个用于管理限制了作用域的变量的标记 —
清单 12.
|
输出
尽管
清单 13.
|
escapeXml 属性也是可选的。它控制当用
例如,假定有一个名为 user 的会话作用域变量,它是一个类的实例,该类为用户定义了两个特性:username 和 company。每当用户访问站点时,这个对象被自动分配给会话,但直到用户实际登录后,才会设置这两个特性。假定是这种方案,请考虑清单 14 中的 JSP 片段。在用户登录之后,这个片段将显示单词“Hello”,其后是他/她的用户名和一个惊叹号。但是,在用户登录之前,由这个片段生成的内容则是短语 “Hello Guest!”。在这种情况下,因为 username 特性还有待初始化,所以
清单 14. 带缺省内容的
|
接下来,考虑清单 15,它使用了
清单 15. 禁用转义的
|
用缺省值设置变量
除了简化动态数据的显示之外,当通过
清单 16 中说明了这种方法。外部
清单 16. 合并
|
Your preferred time zone is ${timezone}
但是,请考虑以下情况,用户是第一次尝试使用这段代码的 Web 应用程序。结果是,请求中没有提供名为 tzPref 的 cookie。这意味着使用隐式对象的查找将返回 null,在这种情况下整个表达式将返回 null。因为对
EL 和 JSP 2.0
目前,表达式语言仅可用于指定 JSTL 定制标记中的动态属性值。但 JSTL 1.0 表达式语言的一个扩展已经被提出,会把它包括到 JSP 2.0 中去,眼下正在进行最后评审。这个扩展将允许开发人员通过自己的定制标记来使用 EL。页面作者将可以在目前允许使用 JSP 表达式的任何地方使用 EL 表达式,譬如将动态值插入模板文本中:
这个 JSP 2.0 功能(就象 JSTL 本身一样)将支持页面作者进一步减少对 JSP 编制脚本元素的依赖,从而改进 JSP 应用程序的可维护性。
结束语
EL(与四个 JSTL 定制标记库提供的操作结合起来)允许页面作者不使用脚本元素即可实现表示层逻辑。例如,对比本文开头清单 1 中的 JSP 代码和清单 17 中显示的通过 JSTL 实现的同样功能。(JSTL core 库中其余的标记,包括
清单 17. 合并
Welcome, member! Welcome, guest! |
通过提供大多数 Web 应用程序常用功能的标准实现,JSTL 有助于加速开发周期。与 EL 结合起来,JSTL 可以不需要对表示层程序编写代码,这极大地简化了 JSP 应用程序的维护。
参考资料
Sun 的