5-4 与Context 有关的隐含对象(1)

在本节中,我们要介绍session、application、pageContext 这三个对象。session对象提供一

些机制,让服务器能个别辨认用户。当程序在执行时,application对象能提供服务端(Server-Side)

的Context,说明哪些资源是可利用的,哪些信息是可获取的。pageContext对象提供存取所有在此

网页中可被利用的隐含对象,并且可以管理它们的属性。

session 对象

session 对象表示目前个别用户的会话(session)状况,用此项机制可以轻易识别每一个用户,

然后针对每一个别用户的要求,给予正确的响应。例如:购物车最常使用session 的概念,当用户

把物品放入购物车时,他不须重复做身份确认的动作(如:Login),就能把物品放入用户的购物车。

服务器利用session 对象,就能确认用户是谁,把它的物品放在属于用户的购物车,而不会将物

品放错到别人的购物车。除了购物车之外,session 对象也通常用来__________做追踪用户的功能,这在第十

章有更加详细的说明。

session 对象实现javax.servlet.http.HttpSession 接口,表5-12 列出了一些常用的方法。

表 5-12 javax.servlet.http.HttpSession 接口所提供的方法

方 法 说 明

long getCreationTime()

取得session产生的时间,单位是毫秒,由1970

年1 月1 日零时算起

String getId() 取得session 的ID

续表

方 法 说 明

long getLastAccessedTime()

取得用户最后通过这个session送出请求的时

间,单位是毫秒,由1970 年1 月1 日零时算

long getMaxInactiveInterval()

取得最大session不活动的时间,若超过这时

间,session 将会失效,时间单位为秒

void invalidate()

取消session 对象,并将对象存放的内容完全

抛弃

boolean isNew()

判断session 是否为"新"的,所谓"新"的

session,表示session 已由服务器产生,但

是client 尚未使用

void setMaxInactiveInterval(int

interval)

设定最大session不活动的时间,若超过这时

间,session 将会失效,时间单位为秒

session 对象也可以储存或取得用户相关的数据,例如:用户的名称、用户所订购的物品、用户的

权限,等等,这些要看我们的程序如何去设计。例如:我要设定某些网页必须要求用户先做登录(Login)

的动作,确定是合法的用户时,才允许读取网页内容,否则把网页重新转向到登录的网页上。

Login.jsp

<%@ page contentType="text/html;charset=GB2312" %>

<html>

<head>

<title>CH5 - Login.jsp</title>

</head>

<body>

<h2>javax.servlet.http.HttpSession - session 对象</h2>

<form action=Login.jsp method="POST" >

Login Name: <input type="text" name="Name"><br>

Login Password: <input type="text" name="Password" ><br>

<input type="submit" value="Send"><br>

<form>

<% if (request.getParameter("Name") != null &&

request.getParameter("Password") != null) {

String Name = request.getParameter("Name");

String Password = request.getParameter("Password");

if (Name.equals("mike") && Password.equals("1234")) {

session.setAttribute("Login", "OK");

response.sendRedirect("Member.jsp");

}

else {

out.println("登录错误,请输入正确名称");

}

}

%>

</body>

</html>

在Login.jsp 的程序中,我要求用户分别输入名称和密码,如果输入的名称和密码分别为mike

和1234 时,就把名称为Login、其值为OK 的属性,加入到session 对象当中,然后进入Member.jsp

网页,如图5-9;若输入错误时,就显示出“登录错误,请输入正确名称”。不允许登录至Member.jsp,

如图5-10 所示。

图 5-9 登录成功,顺利进入Member.jsp

图 5-10 登录失败画面

这时大家一定会想,如果我不通过Login.jsp网页,直接执行Member.jsp,那不就能够进去___________了。

没错,因此我们还要在Member.jsp 中加入一段程序代码,来确认用户是否有先通过Login.jsp的身

份确认,然后再到Member.jsp 中。Member.jsp 程序如下:

Member.jsp

<%@ page contentType="text/html;charset=GB2312" %>

<html>

<head>

<title>CH5 - Member.jsp</title>

</head>

<body>

<h2>javax.servlet.http.HttpSession - session 对象</h2>

<%

String Login = (String)session.getAttribute("Login");

if (Login != null && Login.equals("OK")) {

out.println("欢迎进入");

session.invalidate();

}

else {

out.println("请先登录,谢谢") ;

out.println("<br>经过五秒之后,网页会自动返回Login.jsp");

response.setHeader("Refresh","5;URL=Login.jsp");

}

%>

</body>

</html>

在Member.jsp中我利用session.getAttribute("Login"),如果用户是通过Login.jsp网页进入,

并且顺利通过身份确认取得Login=OK,到Member.jsp 再做确认时,也能顺利通过;否则,如果直接

连接到Member.jsp时,Login的值会等于NULL,则程序经过五秒后,重新加载Login.jsp,要求用户

先行登录。若直接执行Member.jsp,而没有经过登录手续时,就会发现如图5-11。

图 5-11 直接执行Member.jsp,并未经过登录手续

最后要提醒读者一点,session对象不像其他的隐含对象,可以在任何的JSP 网页中使用,如果

在JSP 网页中,page 指令的属性session 设为false 时,使用session 对象就会产生编译错误

(javax.servlet.ServletException: Compilation error occurred ),如下所示:

<%@ page session="false" %>

<%

String Login = (String)session.getAttribute("Login");

….

….

%>

在本书“第十章:Session Tracking”中对session 有更多更详细的介绍。

application 对象

application 对象实现javax.servlet.ServletContext 接口,它主要功用在于取得或更改

Servlet 的设定。下面程序用来说明JSP 网页被编译成Servlet 时,application 对象是如何初

始化的:

pageContext = JspxFactory.getPageContext ( this , request , response ,

"errorpage.jsp" , true , 8192 , true );

application = pageContext.getServletContext( );

你可以看到产生的Servlet 取得了目前的ServletContext,并且将它储存在application 对象

当中。application 对象拥有Application 的范围,意思就是说它的生命周期是由服务器产生开始

至服务器关机为止。表5-13、表5-14、表5-15 列出了其相关方法:

表 5-13 javax.servlet.ServletContext 接口容器相关信息的方法

方 法 说 明

int getMajorVersion( ) 取得 Container 主要的Servlet API 版本,如:2

int getMinorVersion( ) 取得 Container 次要的Servlet API 版本,如:4

String getServerInfo( ) 取得 Container 的名称和版本

<%= application.getMajorVersion() %><br>

<%= application.getMinorVersion() %><br>

<%= application.getServerInfo() %><br>

上述的getMajorVersion( )和getMinorVersion( )是取得Servlet Engine 的版本信息,假如

想要取得JSP 容器的版本信息,则可能就要使用到下面这段程序代码:

GetJspVersion.jsp

<%@ page import="javax.servlet.jsp.JspFactory"

contentType="text/html;charset=GB2312" %>

<html>

<head>

<title>CH5 - GetJspVersion.jsp</title>

</head>

<body>

<h2>取得 JSP Container 版本 - JspFactory 对象</h2>

<%

JspFactory factory = JspFactory.getDefaultFactory();

out.println("JSP v 2.0"+

factory.getEngineInfo().getSpecificationVersion());

%>

</body>

</html>

执行结果如图5-12 所示。

表 5-14 javax.servlet.ServletContext 接口有关服务端的路径和文件的方法

方 法 说 明

String getMimeType(String file) 取得指定文件的MIME 类型

ServletContext getContext(String

uripath)

取得指定Local URL 的Application

context

String getRealPath(String path) 取得本地端path 的绝对路径

范例:

<%= application.getMimeType("MyFile") %>

<%= application.getContext("/") %>

<%= application.getRealPath("/") %>

表 5-15 javax.servlet.ServletContext 接口有关信息记录的方法

方 法 说 明

void log(String message) 将信息写入log 文件中

void log(String message, Throwable

throwable)

将stack trace 所产生的异常信息写入

log文件中

application对象最常被使用在存取环境的信息,因为环境的信息通常都储存在ServletContext中,

所以常利用application对象来存取ServletContext中的信息。

图 5-12 GetJspVesion.jsp 的执行结果

pageContext 对象

pageContext对象能够存取其他隐含对象。当隐含对象本身也支持属性时,pageContext对象也

提供存取那些属性的方法。不过在使用下列方法时,需要指定范围的参数:

Object getAttribute(String name, int scope)

Enumeration getAttributeNamesInScope(int scope)

void removeAttribute(String name, int scope)

void setAttribute(String name, Object value, int scope)

范围参数有四个常数,分别代表四种范围:PAGE_SCOPE 代表Page范围,REQUEST_SCOPE代表Request

范围,SESSION_SCOPE 代表Session 范围,最后APPLICATION_SCOPE 代表Application 范围(见表

5-16、表5-17、表5-18)。

表 5-16 javax.servlet.jsp.PageContext 类取得其他隐含对象的方法

方 法 说 明

Exception getException( )

回传目前网页的异常,不过此网页要为error page,

例如:exception 隐含对象

JspWriter getOut( ) 回传目前网页的输出流,例如:out 隐含对象

Object getPage( )

回传目前网页的Servlet 实体(instance),例如:page

隐含对象

ServletRequest

getRequest( )

回传目前网页的请求,例如:request 隐含对象

ServletResponse

getResponse( )

回传目前网页的响应,例如:response 隐含对象

ServletConfig

getServletConfig( )

回传目前此网页的ServletConfig 对象,例如:config

隐含对象

ServletContext

getServletContext( )

回传目前此网页的执行环境(context),例如:

application隐含对象

HttpSession getSession( )

回传和目前网页有联系的会话(session),例如:

session 隐含对象

表 5-17 javax.servlet.jsp.PageContext 类所提供取得属性的方法

方 法 说 明

Object getAttribute(String name, int

scope)

回传name 属性,范围为scope 的

属性对象, 回传类型为

java.lang.Object

Enumeration getAttributeNamesInScope(int

scope)

回传所有属性范围为scope 的属

性名称,回传类型为Enumeration

int getAttributesScope(String name) 回传属性名称为name 的属性范围

void removeAttribute(String name) 移除属性名称为name 的属性对______________象

void removeAttribute(String name, int

scope)

移除属性名称为name,范围为

scope 的属性对象

void setAttribute(String name, Object

value, int scope)

指定属性对象的名称为name、值

为value、范围为scope

Object findAttribute(String name)

寻找在所有范围中属性名称为

name 的属性对象

表 5-18 javax.servlet.jsp.PageContext 类所提供范围的变量

常 数 说 明

PAGE_SCOPE 存入pageContext 对象的属性范围

REQUEST_SCOPE 存入request 对象的属性范围

SESSION_SCOPE 存入session 对象的属性范围

APPLICATION_SCOPE 存入application 对象的属性范围

接下来示范一个小程序,让读者能够更加明白。

PageContext.jsp

<%@ page import="java.util.Enumeration"

contentType="text/html;charset=GB2312" %>

<html>

<head>

<title>CH5 - PageContext.jsp</title>

</head>

<body>

<h2>javax.servlet.jsp.PageContext - pageContext </h2>

<%

Enumeration enum =

pageContext.getAttributeNamesInScope(PageContext.APPLICATION_SCOPE );

while (enum.hasMoreElements())

{

out.println("application attribute:"+enum.nextElement( )

+"<br>"); }

%>

</body>

</html>

PageContext.jsp 主要目的是:在这页当中,取得所有属性范围为Application 的属性名称,

然后再依序显示出来这些属性。

首先要记得导入 java.util.Enumeration。pageContext.getAttributeNamesInScope( )会回传

所有指定范围的属性名称,因此,我们产生Enumeration 对象enum,利用enum 来收集所有属性范

围为Application 的数据,然后再一一地取出打印出来。这里最重要的是让读者了解如何设定scope

的参数,因此下面这行代码:

PageContext.APPLICATION_SCOPE

是最主要的。有了这个范例程序之后,读者应该能够快速学会使用pageContext 对象所提供的

方法。

pageContext对象除了提供上述的方法之外,另外还有两种方法:forward (Sting Path)、include

(String Path),这两种方法的功能和之前提到的<jsp:forward>与<jsp:include>相似,因此在这也

不多加讨论。

5-5 与Error 有关的隐含对象

最后一类的隐含对象只有一个成员:exception 对象。当JSP 网页有错误时会产生异常,而

exception 对象就来针对这个异常做处理。

exception 对象

exception 对象和session 对象一样,并不是在每一个JSP 网页中都能够使用。若要使用

exception 对象时,必须在page 指令中设定。

<%@ page isErrorPage="true" %>

才能使用,不然在编译时会产生错误。

Exception.jsp

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

<html>

<head>

<title>CH5 - Exception.jsp</title>

</head>

<body>

<h2> exception 对象</h2>

Exception:<%= exception %><br>

Message:<%= exception.getMessage() %><br>

Localized Message:<%= exception.getLocalizedMessage() %><br>

Stack Trace:<% exception.printStackTrace(new java.io.PrintWriter(out));

%><br>

</body>

</html>

一般error page 的程序代码和Exception.jsp 程序相似,它已经将所有该打印出来的错误信息

包括进来。在这段程序代码中使用了三个方法:getMessage( )、getLocalizedMessage( )、

printStackTrace(new java.io.PrintWriter(out)) ,其中printStackTrace( )的参数要为

PrintWriter 而不是JspWriter。

第六章 Expression Language

6-1 EL 简介

6-1 EL 简介

EL 全名为Expression Language,它原本是JSTL 1.0为方便存取数据所自定义的语言。当时EL

只能在JSTL 标签中使用,如下:

<c:out value="${ 3 + 7}">

程序执行结果为10。但是你却不能直接在JSP 网页中使用:

<p>Hi ! ${ username }</p>

到了JSP 2.0 之后,EL 已经正式纳入成为标准规范之一。因此,只要是支持Servlet 2.4 / JSP

2.0 的Container,就都可以在JSP 网页中直接使用EL 了。

除了JSP 2.0 建议使用EL 之外,JavaServer Faces( JSR-127 ) 也考虑将EL 纳入规范,由此

可知,EL 如今已经是一项成熟、标准的技术。

注意

假若您所用的Container 只支持Servlet 2.3/JSP 1.2,如:Tomcat 4.1.29,您就不能在

JSP 网页中直接使用EL,必须安装支持Servlet 2.4 / JSP 2.0 的Container。

6-2 EL 语法

EL 语法很简单,它最大的特点就是使用上很方便。接下来介绍EL 主要的语法结构:

${sessionScope.user.sex}

所有EL都是以${ 为起始、以} 为结尾的。上述EL范例的意思是:从Session的范围中,取得

用户的性别。假若依照之前JSP Scriptlet的写法如下:

User user = (User)session.getAttribute("user");

String sex = user.getSex( );

两者相比较之下,可以发现EL 的语法比传统JSP Scriptlet 更为方便、简洁。

6-2-1 .[ ] 运算符

EL 提供 . 和 [ ] 两种运算符来存取数据。下列两者所代表的意思是一样的:

${sessionScope.user.sex}

等于

${sessionScope.user["sex"]}

. 和 [ ] 也可以同时混合使用,如下:

${sessionScope.shoppingCart[0].price}

回传结果为shoppingCart中第一项物品的价格。

不过,以下两种情况,两者会有差异:

(1) 当要存取的属性名称中包含一些特殊字符,如. 或 – 等并非字母或数字的符号,就一定

要使用 [ ],例如:

${user.My-Name }

上述是不正确的方式,应当改为:

${user["My-Name"] }

(2) 我们来考虑下列情况:

${sessionScope.user[data]}

此时,data 是一个变量,假若data的值为"sex"时,那上述的例子等于${sessionScope.user.sex};

假若data 的值为"name"时,它就等于${sessionScope.user.name}。因此,如果要动态取值时,就可以

用上述的方法来做,但. 无法做到动态取值。

接下来,我们更详细地来讨论一些情况,首先假__________设有一个EL:

${expr-a[expr-b]}

(1) 当expr-a 的值为null时,它会回传null。

(2) 当expr-b的值为null时,它会回传null。

(3) 当 expr-a 的值为一Map 类型时:

● 假若 !value-a.containsKey(value-b)为真,则回传null。

● 否则回传value-a.get(value-b)。

(4) 当expr-a 的值为List 或array 类型时:

● 将 value-b 的值强制转型为int,假若不能转型为int 时,会产生error。

● 然后, 假若value-a.get(value-b) 或Array.get(value-a, value-b) 产生

ArrayIndexOutOfBoundsException 或IndexOutOfBoundsException 时,则回传null。

● 假若 value-a.get(value-b)或Array.get(value-a, value-b)产生其他的异常时,则会产生

error。

● 最后都没有任何异常产生时,回传value-a.get(value-b)或Array.get(value-a, value-b)。

(5) 当expr-a 的值为JavaBean 对象时:

● 将 value-b 的值强制转型为String。

● 假若 getter 产生异常时,则会产生error。若没有异常产生时,则回传getter 的结果。

6-2-2 EL 变量

EL 存取变量数据的方法很简单,例如:${username}。它的意思是取出某一范围中名称为username

的变量。因为我们并没有指定哪一个范围的username,所以它的默认值会先从Page 范围找,假如

找不到,再依序到Request、Session、Application范围。假如途中找到username,就直接回传,

不再继续找下去,但是假如全部的范围都没有找到时,就回传null(见表6-1):

表 6-1

属性范围在 EL 中的名称

Page PageScope

Request RequestScope

Session SessionScope

Application ApplicationScope

自动搜索顺序

我们也可以指定要取出哪一个范围的变量(见表6-2):

表 6-2

范例 说 明

${pageScope.username} 取出Page 范围的username 变量

${requestScope.username} 取出Request 范围的username 变量

${sessionScope.username} 取出Session 范围的username 变量

${applicationScope.username} 取出Application 范围的username 变量

其中,pageScope、requestScope、sessionScope和applicationScope都是EL 的隐含对象,由

它们的名称可以很容易猜出它们所代表的意思,例如:${sessionScope.username}是取出Session

范围的username 变量。这种写法是不是比之前JSP 的写法:

String username = (String) session.getAttribute("username");

容易、简洁许多。有关EL 隐含对象在6-3 节中有更详细的介绍。

6-2-3 自动转变类型

EL 除了提供方便存取变量的语法之外,它另外一个方便的功能就是:自动转变类型,我们来看

下面这个范例:

${param.count + 20}

假若窗体传来count的值为10时,那么上面的结果为30。之前没接触过JSP 的读者可能会认为

上面的例子是理所当然的,但是在JSP 1.2 之中不能这样做,原因是从窗体所传来的值,它们的类

型一律是String,所以当你接收之后,必须再将它转为其他类型,如:int、float 等等,然后才能

执行一些数学运算,下面是之前的做法:

String str_count = request.getParameter("count");

int count = Integer.parseInt(str_count);

count = count + 20;

接下来再详细说明EL类型转换的规则:

(1) 将A 转为String 类型

● 假若 A 为String 时:回传A

● 否则,当A 为null 时:回传 ""

● 否则,当A.toString( )产生异常时:错误!

● 否则,回传 A.toString( )

(2) 将A 转为Number 类型的N

● 假若 A 为null 或 "" 时:回传0

● 假若 A 为Character 时:将A 转为 new Short((short)a.charValue( ))

● 假若 A 为Boolean 时:错误!

● 假若 A 为Number 类型和N 一样时:回传A

● 假若 A 为Number 时:

·假若N 是BigInteger 时:

·假若A 为BigDecimal 时:回传 A.toBigInteger( )

·否则,回传 BigInteger.valueOf(A.longValue( ))

·假若N 是BigDecimal 时:

·假若A 为BigInteger 时:回传 A.toBigDecimal( )

·否则,回传 BigDecimal.valueOf(A.doubleValue( ))

·假若N 为Byte 时:回传 new Byte(A.byteValue( ))

·假若N 为Short 时:回传 new Short(A.shortValue( ))

·假若N 为Integer 时:回传 new Integer(A.intValue( ))

·假若N 为Long 时:回传 new Long(A.longValue( ))

·假若N 为Float 时:回传 new Float(A.floatValue( ))

·假若N 为Double 时:回传 new Double(A.doubleValue( ))

·否则,错误!

● 假若 A 为String 时:

·假若N 是BigDecimal 时:

·假若 new BigDecimal(A)产生异常时:错误!

·否则,回传 new BigDecimal(A)

·假若N 是BigInteger 时:

·假若 new BigInteger(A)产生异常时:错误!

·否则,回传 new BigInteger(A)

·假若N.valueOf(A)产生异常时:错误!

·否则,回传 N.valueOf(A)

● 否则,错误!

(3) 将A 转为Character 类型

● 假若 A 为null 或 "" 时:回传 (char)0

● 假若 A 为Character 时:回传 A

● 假若 A 为Boolean 时:错误!

● 假若 A 为Number 时:转换为Short 后,然后回传Character

● 假若 A 为String 时:回传 A.charAt(0)

● 否则,错误!

(4) 将A 转为Boolean 类型

● 假若 A 为null 或 "" 时:回传 false

● 否则,假若A 为Boolean 时:回传 A

● 否则,假若A为String,且Boolean.valueOf(A)没有产生异常时:回传Boolean.valueOf(A)

● 否则,错误!

6-2-4 EL 保留字

EL 的保留字如表6-3:

表 6-3

And eq gt true

Or ne le false

No lt ge null

instanceof empty div mod

所谓保留字的意思是指变量在命名时,应该避开上述的名字,以免程序编译时发生错误。

6-3 EL 隐含对象

笔者在“第五章:隐含对象(Implicit Object)”中,曾经介绍过9 个JSP 隐含对象,而EL本

身也有自己的隐含对象。EL 隐含对象总共有11 个(见表6-4):

表 6-4

隐含对象类 型 说 明

PageContext javax.servlet.ServletContext 表示此JSP 的PageContext

PageScope java.util.Map 取得Page范围的属性名称所对应的值

RequestScope java.util.Map

取得Request 范围的属性名称所对应

的值

sessionScope java.util.Map

取得Session 范围的属性名称所对应

的值

applicationScope java.util.Map

取得Application 范围的属性名称所

对应的值

param java.util.Map

如同

ServletRequest.getParameter(String

name)。回传String 类型的值

续表

隐含对象类 型 说 明

paramValues java.util.Map 如同

隐含对象类 型 说 明

ServletRequest.getParameterValues(String

name)。回传String []类型的值

header java.util.Map

如同ServletRequest.getHeader(String

name)。回传String 类型的值

headerValues java.util.Map

如同ServletRequest.getHeaders(String

name)。回传String []类型的值

cookie java.util.Map 如同HttpServletRequest.getCookies( )

initParam java.util.Map

如同

ServletContext.getInitParameter(String

name)。回传String 类型的值

这 11 个隐含对象(Implicit Object),笔者将它分成三类:

1. 与范围有关的隐含对象

applicationScope

sessionScope

requestScope

pageScope

2. 与输入有关的隐含对象

param

paramValues

3. 其他隐含对象

cookie

header

headerValues

initParam

pageContext

接下来笔者会依照上面的分类顺序,为读者介绍这些隐含对象。

6-3-1 属性(Attribute)与范围(Scope)

与范围有关的EL 隐含对象包含以下四个:pageScope、requestScope、sessionScope 和

applicationScope,它们基本上就和JSP的pageContext、request、session和application一样,

所以笔者在这里只稍略说明。不过必须注意的是,这四个隐含对象只能用来取得范围属性值,即JSP

中的getAttribute(String name),却不能取得其他相关信息,例如:JSP中的request对象除可以存

取属性之外,还可以取得用户的请求参数或表头信息等等。但是在EL中,它就只能单纯用来取得对应

范围的属性值,例如:我们要在session 中储存一个属性,它的名称为username,在JSP 中使用

session.getAttribute("username") 来取得username 的值, 但是在EL 中, 则是使用

${sessionScope.username}来取得其值的。接下来分别对这四个隐含对象做简短的说明:

● pageScope

范围和JSP 的Page 相同,也就是单单一页JSP Page 的范围(Scope)。

● requestScope

范围和JSP 的Request 相同,requestScope 的范围是指从一个JSP 网页请求到另一个JSP 网页

请求之间,随后此属性就会失效。

● sessionScope

范围和JSP Scope 中的session 相同,它的属性范围就是用户持续在服务器连接的时间。

● applicationScope

范围和JSP Scope 中的application 相同,它的属性范围是从服务器一开始执行服务,到服务

器关闭为止。

6-3-2 与输入有关的隐含对象

与输入有关的隐含对象有两个:param和paramValues,它们是EL中比较特别的隐含对象。一般

而言,我们在取得用户的请求参数时,可以利用下列方法:

request.getParameter(String name)

request.getParameterValues(String name)

在 EL中则可以使用param和paramValues两者来取得数据。

${param.name}

${paramValues.name}

这里param 的功能和request.getParameter(String name) 相同, 而paramValues 和

request.getParameterValues(String name)相同。如果用户填了一个表格,表格名称为username,则我们

就可以使用${param.username}来取得用户填入的值。

为了让读者更加了解param 和paramValues 隐含对象的使用,再来看下面这个范例。此范例共

有两个文件,分别为给用户输入值用的Param.html 和显示出用户所传之值的Param.jsp。

Param.html

<html>

<head>

<title>CH6 - Param.html</title>

</head>

<body>

<h2>EL 隐含对象 param、paramValues</h2>

<form method = "post" action = "Param.jsp">

<p>姓名:<input type="text" name="username" size="15" /></p>

<p>密码:<input type="password" name="password" size="15" /></p>

<p>性别:<input type="radio" name="sex" value="Male" checked/> 男

<input type="radio" name="sex" value="Female" /> 女</p>

<p>年龄:

<select name="old">

<option value="10">10 - 20</option>

<option value="20" selected>20 - 30</option>

<option value="30">30 - 40</option>

<option value="40">40 - 50</option>

</select>

</p>

<p>兴趣:

<input type="checkbox" name="habit" value="Reading"/>看书

<input type="checkbox" name="habit" value="Game"/>玩游戏

<input type="checkbox" name="habit" value="Travel"/>旅游

<input type="checkbox" name="habit" value="Music"/>听音乐

<input type="checkbox" name="habit" value="Tv"/>看电视

</p>

<p>

<input type="submit" value="传送"/>

<input type="reset" value="清除"/>

</p>

</form>

</body>

</html>

Param.html 的执行结果如图6-1 所示。当我们把窗体填好后按下传送钮,它将会把信息传送到

Param.jsp 做处理。

图 6-1 Param.html 的执行结果,并填入信息

接下来,Param.jsp 接收由Param.html 传来的信息,并且将它显示出来:

Param.jsp

<%@ page contentType="text/html;charset=GB2312" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<html>

<head>

<title>CH6 - Param.jsp</title>

</head>

<body>

<h2>EL 隐含对象 param、paramValues</h2>

<fmt:requestEncoding value="GB2312" />

姓名: ${param.username}</br>

密码: ${param.password}</br>

性别: ${param.sex}</br>

年龄: ${param.old}</br>

兴趣: ${paramValues.habit[0]}

${paramValues.habit[1]}

</body>

</html>

由Param.html 窗体传过来的值,我们必须指定编码方式,才能够确保Param.jsp能够顺利接收中

文,传统的做法为:

<%

request.setCharacterEncoding("GB2312");

%>

假若是使用JSTL写法时,必须使用I18N 格式处理的标签库,如下:

<fmt:requestEncoding value="GB2312" />

Param.jsp主要使用EL的隐含对象param来接收数据。但是必须注意:假若要取得多重选择的复

选框的值时,必须使用paramValues,例如:使用paramValues 来取得“兴趣”的值,不过这里笔者

最多只显示两笔“兴趣”的值:

${param.username}

………

${paramValues.habit[0]}

${paramValues.habit[1]}

有关JSTL的使用,第七章有更加详细的说明。图6-2是Param.jsp的执行结果:

图 6-2 Param.jsp 的执行结果

6-3-3 其他隐含对象

介绍完上面六个隐含对象后,接下来将介绍最后五个隐含对象。

● cookie

所谓的cookie是一个小小的文本文件,它是以key、value的方式将Session Tracking的内容记录

在这个文本文件内,这个文本文件通常存在于浏览器的暂存区内。JSTL并没有提供设定cookie的动作,

因为这个动作通常都是后端开发者必须去做的事情,而不是交给前端的开发者。假若我们在cookie 中

设定一个名称为userCountry的值,那么可以使用${cookie.userCountry}来取得它。

● header 和headerValues

header 储存用户浏览器和服务端用来沟通的数据,当用户要求服务端的网页时,会送出一个记

载要求信息的标头文件,例如:用户浏览器的版本、用户计算机所设定的区域等其他相关数据。假

若要取得用户浏览器的版本,即${header["User-Agent"]}。另外在鲜少机会下,有可能同一标头名

称拥有不同的值,此时必须改为使用headerValues 来取得这些值。

注意

因为User-Agent 中包含“-”这个特殊字符,所以必须使用“[]”,而不能写成

$(header.User-Agent)。

● initParam

就像其他属性一样,我们可以自行设定web 站台的环境参数(Context),当我们想取得这些参数

时,可以使用initParam 隐含对象去取得它,例如:当我们在web.xml 中设定如下:

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"

version="2.4">

<context-param>

<param-name>userid</param-name>

<param-value>mike</param-value>

</context-param>

</web-app>

那么我们就可以直接使用 ${initParam.userid}来取得名称为userid,其值为mike 的参数。下

面是之前的做法:

String userid = (String)application.getInitParameter("userid");

● pageContext

我们可以使用 ${pageContext}来取得其他有关用户要求或页面的详细信息。表6-5 列出了几个

比较常用的部分。

表 6-5

Expression 说明

${pageContext.request.queryString} 取得请求的参数字符串

${pageContext.request.requestURL} 取得请求的URL,但不包括请求之参数字符串

${pageContext.request.contextPath} 服务的web application 的名称

${pageContext.request.method} 取得HTTP 的方法(GET、POST)

${pageContext.request.protocol} 取得使用的协议(HTTP/1.1、HTTP/1.0)

${pageContext.request.remoteUser} 取得用户名称

${pageContext.request.remoteAddr } 取得用户的IP 地址

${pageContext.session.new}

判断session 是否为新的,所谓新的session,

表示刚由server 产生而client 尚未使用

${pageContext.session.id} 取得session 的ID

${pageContext.servletContext.serverInfo}取得主机端的服务信息

我们来看下面这个范例:pageContext.jsp,相信对读者来说能更加了解pageContext的用法。

pageContext.jsp

<%@ page contentType="text/html;charset=GB2312" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>

<head>

<title>CH6 - pageContext.jsp</title>

</head>

<body>

<h2>EL 隐含对象 pageContext</h2>

\${pageContext.request.queryString}:${pageContext.request.queryString}</br>

\${pageContext.request.requestURL}:${pageContext.request.requestURL}</br>

\${pageContext.request.contextPath}:${pageContext.request.contextPath}</br>

\${pageContext.request.method}:${pageContext.request.method}</br>

\${pageContext.request.protocol}:${pageContext.request.protocol}</br>

\${pageContext.request.remoteUser}:${pageContext.request.remoteUser}</br>

\${pageContext.request.remoteAddr }:${pageContext.request.remoteAddr}</br>

\${pageContext.session.new}:${pageContext.session.new}</br>

\${pageContext.session.id}:${pageContext.session.id}</br>

</body>

</html>

pageContext.jsp 的执行结果如图6-3,执行时必须在pageContext.jsp 之后加上?test=1234,即

PageContext.jsp?test=1234,这样${pageContext.request.queryString}才会显示test=1234。

图 6-3 pageContext.jsp 的执行结果

注意

因为 ${} 在JSP 2.0 中是特殊字符,JSP容器会自动将它当做EL来执行,因此,假若要显

示 ${}时,必须在 $ 前加上 \ ,如:\${ XXXXX }

6-4 EL 算术运算符

EL 算术运算符主要有以下五个(见表6-6):

表 6-6

算术运算符说 明 范 例 结 果

+ 加${ 17 + 5 } 22

- 减 ${ 17 - 5 } 12

* 乘${ 17 * 5 } 85

/ 或 div 除${ 17 / 5 } 或 ${ 17 div 5 } 3

% 或 mod 余数${ 17 % 5 } 或 ${ 17 mod 5 } 2

接下来,我们依照下列几种情况,详细说明EL 算术运算符的规则:

(1) A {+ ,- , *} B

● 假若 A 和B 为null:回传 (Long)0

● 假若 A 或B 为BigDecimal 时,将另一个也转为BigDecimal,则:

·假若运算符为 + 时:回传 A.add(B)

·假若运算符为- 时:回传 A.subtract(B)

·假若运算符为 * 时:回传 A.multiply(B)

● 假若 A 或B 为Float、Double 或包含 e / E 的字符串时:

·假若A 或B 为BigInteger 时,将另一个转为BigDecimal,然后依照运算符执行

运算

·否则,将两者皆转为Double,然后依照运算符执行运算

● 假若 A 或B 为BigInteger 时,将另一个也转为BigInteger,则:

·假若运算符为 + 时:回传 A.add(B)

·假若运算符为- 时:回传 A.subtract(B)

·假若运算符为 * 时:回传 A.multiply(B)

● 否则,__________将A 和B 皆转为Long,然后依照运算符执行运算

● 假若运算结果产生异常时,则错误!

(2) A {/ , div} B

● 假若 A 和B 为null:回传 (Long)0

● 假若 A 或B 为BigDecimal 或BigInteger 时,皆转为BigDecimal,然后回传 A.divide(B,

BigDecimal.ROUND_HALF_UP)

● 否则,将A 和B 皆转为Double,然后依照运算符执行运算

● 假若运算结果产生异常时,则错误!

(3) A {% , mod} B

● 假若 A 和B 为null:回传 (Long)0

● 假若A 或B为BigDecimal、Float、Double或包含 e / E 的字符串时,皆转为Double,然

后依照运算符执行运算

● 假若 A 或B 为BigInteger 时,将另一个转为BigInteger,则回传 A.remainder(B)

● 否则,将A 和B 皆转为Long,然后依照运算符执行运算

● 假若运算结果产生异常时,则错误!

(4) -A

● 假若 A 为null:回传 (Long)0

● 假若 A 为BigDecimal 或BigInteger 时,回传 A.negate( )

● 假若 A 为String 时:

·假若A 包含 e / E 时,将转为Double,然后依照运算符执行运算

·否则,转为Long,然后依照运算符执行运算

·假若运算结果产生异常时,则错误!

● 假若 A 为Byte、Short、Integer、Long、Float 或Double

·直接依原本类型执行运算

·假若运算结果产生异常时,则错误!

● 否则,错误!

Tomcat 上的jsp-examples 中,有一个EL算术运算符的范例 basic-arithmetic.jsp。它的程序

很简单,所以不在这里多做说明,它的执行结果如图6-4 所示。

图 6-4 basic-arithmetic.jsp 的执行结果

6-5 EL 关系运算符

EL 关系运算符有以下六个运算符(见表6-7):

表 6-7

关系运算符说 明 范 例 结 果

= = 或 eq 等于${ 5 = = 5 } 或 ${ 5 eq 5 } true

!= 或 ne 不等于${ 5 != 5 } 或 ${ 5 ne 5 } false

< 或 lt 小于${ 3 < 5 }或 ${ 3 lt 5 } true

> 或 gt 大于${ 3 > 5 }或 ${ 3 gt 5 } false

<= 或 le 小于等于${ 3 <= 5 }或 ${ 3 le 5 } true

>= 或 ge 大于等于${ 3 >= 5 }或 ${ 3 ge 5 } false

注意

在使用EL 关系运算符时,不能够写成:

${param.password1} = = ${param.password2}

或者

${ ${param.password1 } = = ${ param.password2 } }

而应写成

${ param.password1 = = param.password2 }

接下来,我们依照下列几种情况,详细说明EL 关系运算符的规则:

(1) A {<, >, <=, >=, lt, gt, le, ge} B

● 假若 A= = B,运算符为<=, le, >=, ge 时,回传true,否则回传false

● 假若 A 为null 或B 为null 时,回传false

● 假若A或B为BigDecimal时,将另一个转为BigDecimal,然后回传A.compareTo(B)的值

● 假若 A 或B 为Float、__________Double 时,皆转为Double 类型,然后依其运算符运算

● 假若A或B为BigInteger时,将另一个转为BigInteger,然后回传A.compareTo(B)的值

● 假若A 或B为Byte、Short、Character、Integer或Long时,皆转为Long 类型,然后依其

运算符运算

● 假若 A 或B 为String 时,将另一个也转为String,然后做词汇上的比较

● 假若 A 为Comparable 时,则:

·假若A.compareTo(B)产生异常时,则错误!

● 否则,采用 A.compareTo(B) 的比较结果

● 假若 B 为Comparable 时,则:

· 假若 B.compareTo(A)产生异常时,则错误!

● 否则,采用 A.compareTo(B) 的比较结果

● 否则,错误!

(2) A {= =, !=, eq, ne} B

● 假若 A= = B,依其运算符运算

● 假若 A 为null 或B 为null 时:= = /eq 则回传false,!= / ne 则回传true

● 假若 A 或B 为BigDecimal 时,将另一个转为BigDecimal,则:

· 假若运算符为 = = / eq,则回传A.equals(B)

· 假若运算符为 != / ne,则回传 !A.equals(B)

● 假若 A 或B 为Float、Double 时,皆转为Double 类型,然后依其运算符运算

● 假若 A 或B 为BigInteger 时,将另一个转为BigInteger,则:

·假若运算符为 = = / eq,则回传A.equals(B)

·假若运算符为 != / ne,则回传 !A.equals(B)

● 假若A 或B为Byte、Short、Character、Integer 或Long时,皆转为Long 类型,然后依其

运算符运算

● 假若 A 或B 为Boolean 时,将另一个也转为Boolean,然后依其运算符运算

● 假若 A 或B 为String 时,将另一个也转为String,然后做词汇上的比较

● 否则,假若A.equals(B)产生异常时,则错误!

● 否则,然后依其运算符运算,回传A.equals(B)

Tomcat 上的jsp-examples 中,有一个EL 关系运算符的范例basic-comparisons.jsp。它的程

序很简单,所以不在这里多做说明,大家直接看它的执行结果(如图6-5 所示):

图 6-5 basic-comparisons.jsp 的执行结果

6-6 EL 逻辑运算符

EL 逻辑运算符只有三个(见表6-8):

表 6-8

逻辑运算符说 明 范 例 结 果

&& 或 and 交集${ A && B } 或 ${ A and B } true / false

|| 或 or 并集${ A || B } 或 ${ A or B } true / false

! 或 not 非${ !A } 或 ${ not A } true / false

下面举几个例子:

${ param.month = = 7 and param.day = = 14 }

${ param.month = = 7 || param.day = = 14 }

${ not param.choice }

EL 逻辑运算符的规则很简单:

(1) A {&&, and, || 或 or } B

·将A 和B 转为Boolean,然后依其运算符运算

(2) {!, not}A

·将A 转为Boolean,然后依其运算符运算

6-7 EL 其他运算符

EL 除了上述三大类的运算符之外___________,还有下列几个重要的运算符:

(1) Empty 运算符

(2) 条件运算符

(3) ( ) 括号运算符

6-7-1 Empty 运算符

Empty 运算符主要用来判断值是否为null 或空的,例如:

${ empty param.name }

接下来说明Empty 运算符的规则:

(1) {empty} A

● 假若 A 为null 时,回传true

● 否则,假若A 为空String 时,回传true

● 否则,假若A 为空Array 时,回传true

● 否则,假若A 为空Map 时,回传true

● 否则,假若A 为空Collection 时,回传true

● 否则,回传false

6-7-2 条件运算符

所谓条件运算符如下:

${ A ? B : C}

意思是说,当A 为true 时,执行B;而A 为false 时,则执行C。

6-7-3 括号运算符

括号运算符主要用来改变执行优先权,例如:${ A * (B+C) }

至于运算符的优先权,如下所示(由高至低,由左至右):

· []、.

· ( )

· - (负)、not、!、empty

· *、/、div、%、mod

· +、- (减)

· <、>、<=、>=、lt、gt、le、ge

· = =、!=、eq、ne

· &&、and

· ||、or

· ${ A ? B : C}

最后笔者写一个ELOperator.jsp 范例,将所有运算符实际操作一遍。

ELOperator.jsp

<%@ page contentType="text/html;charset=GB2312" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>

<head>

<title>CH6 – ELOperator.jsp</title>

</head>

<body>

<h2>EL 的运算符</h2>

<c:set value="mike" var="username" scope="request" />

<table border="1" width="50%" align="left">

<TR>

<TR>

<TH>运算式</TH>

<TH>结果</TH>

</TR>

<TR><TD>14 + 3</TD><TD>${14 + 3}</TD></TR>

<TR><TD>14 - 3</TD><TD>${14 - 3}</TD></TR>

<TR><TD>14 * 3</TD><TD>${14 * 3}</TD></TR>

<TR><TD>14 / 3</TD><TD>${14 / 3}</TD></TR>

<TR><TD>14 % 3</TD><TD>${14 % 3}</TD></TR>

<TR><TD>14 == 3</TD><TD>${14 == 3}</TD></TR>

<TR><TD>14 != 3</TD><TD>${14 != 3}</TD></TR>

<TR><TD>14 < 3</TD><TD>${14 < 3}</TD></TR>

<TR><TD>14 > 3</TD><TD>${14 > 3}</TD></TR>

<TR><TD>14 <= 3</TD><TD>${14 <= 3}</TD></TR>

<TR><TD>14 >= 3</TD><TD>${14 >= 3}</TD></TR>

<TR><TD>true && false</TD><TD>${true && false}</TD></TR>

<TR><TD>true || false</TD><TD>${true || false}</TD></TR>

<TR><TD>! false</TD><TD>${! false}</TD></TR>

<TR><TD>empty username</TD><TD>${empty username}</TD></TR>

<TR><TD>empty password</TD><TD>${empty password}</TD></TR>

</table>

</body>

</html>

EL 的数学运算符、相等运算符、关系运算符和逻辑运算符就跟其他程序语言一样,并没有特别

的地方。但是它的empty 运算符就比较特别,为了测试它,笔者写了这样一行程序代码:

<c:set value="mike" var="username" scope="request" />

这样Request 属性范围里就存在一个名称为username、值为mike 的属性。执行此程序时,读者

将会发现${empty username}为false; ${empty password}为true,其代表的意义就是:它可以在

四种属性范围中找到username这个属性,但是找不到password这个属性。ELOperator.jsp 的执行

结果如图6-6:

图 6-6 ELOperator.jsp 的执行结果

6-8 EL Functions

前面几节主要介绍EL 语法的使用和规则,本节笔者将介绍如何自定义EL 的函数(functions)。

EL 函数的语法如下:

ns:function( arg1, arg2, arg3 …. argN)

其中ns 为前置名称(prefix),它必须和taglib 指令的前置名称一样。如下范例:

<% @ taglib prefix="my"

uri="http://jakarta.apache.org/tomcat/jsp2-example-taglib" %>

…….

${my:function(param.name)}

前置名称都为my,至于function 为EL 函数的名称,而arg1、arg2 等等,都是function 的传

入值。在Tomcat 5.0.16中有一个简单的EL 函数范例,名称为functions.jsp,笔者接下来将依此

范例来说明如何自定义EL 函数。

6-8-1 Tomcat EL 函数范例

Tomcat 提供的EL 函数范例中,自定义两个EL 函数:reverse 和countVowels,其中:

reverse 函数:将传入的字符串以反向顺序输出。

countVowels 函数:计算传入的字符串中,和aeiouAEIOU 吻合的字符个数。

图 6-7 是functions.jsp 程序的执行结果:

图 6-7 functions.jsp 的执行结果

输入JavaWorld.com.tw 字符串至reverse 函数后,回传 wt.moc.dlroWavaJ 的结果;若传入

countVowels 函数后,因为有两个a 和o,总共四个字符吻合,所以回传4。

Tomcat 的EL 函数范例,主要分为四个部分(见表6-9):

表 6-9

web.xml 设定taglib 的TLD 文件位置

functions.jsp 使用EL 函数的范例程序

jsp2-example-taglib.tld EL 函数、标签库的设定文件

jsp2.examples.el.Functions.java EL 函数主要程序逻辑处理部分

这四个部分环环相扣,都互有关系,笔者依functions.jsp为中心,然后再慢慢说明其他部分。

首先我们直接来看functions.jsp 程序:

6-8-2 functions.jsp

functions.jsp

<%@ taglib prefix="my"

uri="http://jakarta.apache.org/tomcat/jsp2-example-taglib"%>

<html>

<head>

<title>JSP 2.0 Expression Language - Functions</title>

</head>

<body>

<h1>JSP 2.0 Expression Language - Functions</h1>

…. 略

<blockquote>

<u><b>Change Parameter</b></u>

<form action="functions.jsp" method="GET">

foo = <input type="text" name="foo" value="${param['foo']}">

<input type="submit">

</form>

<br>

<code>

<table border="1">

<thead>

<td><b>EL Expression</b></td>

<td><b>Result</b></td>

</thead>

<tr>

<td>\${param["foo"]}</td>

<td>${param["foo"]}&nbsp;</td>

</tr>

<tr>

<td>\${my:reverse(param["foo"])}</td>

<td>${my:reverse(param["foo"])}&nbsp;</td>

</tr>

<tr>

<td>\${my:reverse(my:reverse(param["foo"]))}</td>

<td>${my:reverse(my:reverse(param["foo"]))}&nbsp;</td>

</tr>

<tr>

<td>\${my:countVowels(param["foo"])}</td>

<td>${my:countVowels(param["foo"])}&nbsp;</td>

</tr>

</table>

</code>

</blockquote>

</body>

</html>

functions.jsp程序中,一开始定义taglib,它的前置名称为my;uri为http://jakarta.apache.org/

tomcat/jsp2-example-taglib,如下所示:

<%@ taglib prefix="my"

uri="http://jakarta.apache.org/tomcat/jsp2-example-taglib"%>

当Container执行这段程序时,它会根据uri的值,到web.xml中找相对应的TLD (Tag Library

Descriptor)文件。至于web.xml 如何设定两者之间的对应关系,我们在6-8-3 小节再说明。

functions.jsp 中包含一个窗体(form),当用户在文本[玉玉1]输入框(text input)中输入字符

串,按下按钮时,底下会显示字符串经过EL 函数处理后的结果。functions.jsp 程序最重要的部分

是调用EL 函数:

${my:reverse(param["foo"])}

上述的意思是接收foo参数,然后传入reverse 函数。调用EL函数的方式很简单,只要前置名

称:其中EL 函数名称是被定义在TLD 文件中,这会在6-8-4 小节详细说明。至于reverse 函数的逻

辑运算,则是被定义在jsp2.examples.el.Functions.java程序中,这部分会在6-8-5 小节中说明。

注意

TLD 文件主要为标签的设定文件,其中包含标签的名称、参数等等。在JSP 2.0 之后,相关

EL 函数的设定,也可以在TLD 文件中定义。

6-8-3 web.xml

web.xml是每个web站台最主要的设定文件,在这个设定文件中,可以设定许多东西,如:Servlet、

Resource、Filter 等等。不过现在关心的是如何在web.xml 中设定taglib的uri 是对应到哪个TLD

文件。笔者从范例的web.xml 中节录出设定的片段程序如下:

web.xml

<jsp-config>

<taglib>

<taglib-uri>

http://jakarta.apache.org/tomcat/jsp2-example-taglib

</taglib-uri>

<taglib-location>

/WEB-INF/jsp2/jsp2-example-taglib.tld

</taglib-location>

</taglib>

</jsp-config>

在web.xml 中,<taglib>用来设定标签的TLD 文件位置。<taglib-uri>用来指定taglib 的uri

位置,用户可以自行给定一个uri,例如:

<taglib-uri>http://www.javaworld.com.tw/jute</taglib-uri>

<taglib-uri>tw.com.javaworld</taglib-uri>

<taglib-location>用来指定TLD 文件的位置。依照范例,它是指定在WEB-INF/jsp2/目录下的

jsp2-example-taglib.tld。

因 此 ,笔者所节录下来的web.xml , 它所代表的意思是: taglib 的uri 为

http://jakarta.apache.org/tomcat/jsp2-example-taglib,它的TLD 文件是在WEB-INF/jsp2/目

录下的jsp2-example-taglib.tld。

6-8-4 jsp2-example-taglib.tld

在jsp2-example-taglib.tld 中定义许多标签,其中笔者节录一段定义EL 函数:

jsp2-example-taglib.tld

<function>

<description>Reverses the characters in the given String</description>

<name>reverse</name>

<function-class>jsp2.examples.el.Functions</function-class>

<function-signature>

java.lang.String reverse( java.lang.String )

</function-signature>

</function>

<function>

<description>Counts the number of vowels (a,e,i,o,u) in the given

String</description>

<name>countVowels</name>

<function-class>jsp2.examples.el.Functions</function-class>

<function-signature>

java.lang.String numVowels( java.lang.String )

</function-signature>

</function>

上述定义两个EL 函数,用<name>来设定EL 函数名称,它们分别为reverse和countVowels;用

<function-class> 设定EL 函数的Java 类, 本范例的EL 函数都是定义在

jsp2.examples.el.Functions;最后用<function-signature>来设定EL 函数的传入值和回传值,例

如:

<function-signature>java.lang.String

reverse( java.lang.String )</function-signature>

表示reverse 函数有一String 类型的传入值,然后回传String 类型的值。最后我们再来看

reverse 和countVowels 的程序。

6-8-5 Functions.java

Functions.java 主要定义三个公开静态的方法,分别为:reverse、numVowels 和caps(见表

6-10)。下面是Functions.java 完整的程序代码:

Functions.java

package jsp2.examples.el;

import java.util.*;

/**

* Defines the functions for the jsp2 example tag library.

* <p>Each function is defined as a static method.</p>

*/

public class Functions {

public static String reverse( String text ) {

return new StringBuffer( text ).reverse().toString();

}

public static int numVowels( String text ) {

String vowels = "aeiouAEIOU";

int result = 0;

for( int i = 0; i < text.length(); i++ ) {

if( vowels.indexOf( text.charAt( i ) ) != -1 ) {

result++;

}

}

return result;

}

public static String caps( String text ) {

return text.toUpperCase();

}

}

表 6-10

String reverse(String

text)

将text 字符串的顺序反向处理,然后回传反向后的字符串

int numVowels(String text)将 text 字符串比对aeiouAEIOU 等字符,然后回传比对中的次

_______________数

String caps(String text) 将 text 字符串都转为大写,然后回传此字符串

注意

在定义EL 函数时,都必须为公开静态(public static)