表达式语言的功能
(1)提供了一组简单的运算符。表达式语言提供了一组简单有效的运算符,通过这些运算符可以完成算术、关系、逻辑、条件或空值检查运算。
(2)对作用域变量的方便访问。作用域变量是使用setAttribute()方法存储在PageContext、HttpServletRequest、HttpSession或ServletContext作用域中的对象,可以简单地使用下面的形式访问:
${userName}
(3)对JavaBeans对象访问的简单表示。在JSP页面中要访问一个JavaBean对象customer的custName属性,需要下面的语法:
<jsp:getProperty name="customer" property="custName">
而使用EL表达式,可以表示为:
${customer.custName}
(4)对集合元素的简单访问。集合包括数组、List对象、Map对象等,对这些对象的元素的访问可以使用下面的简单形式:
${variable[indexOrKey]}
(5)对请求参数、Cookie和其他请求数据的简单访问。如要访问Accept请求头,可以使用header隐含变量,如下所示:
${header.Accept}或${header["Accept"]}
(6)提供了在EL中使用Java函数的功能。EL中不能定义和使用变量,也不能调用对象的方法,但可以通过标签的形式使用Java语言定义的函数。
EL表达式和JSP的区别:
JSP表达式的使用格式为:
<%=expression %>
这里的expression为合法的Java表达式,它属于脚本语言的代码。在expression中可以使用由脚本声明的变量。
EL表达式的格式为:
${expression}
这里的expression是符合EL规范的表达式,并且不需要包含在标签内的。在EL表达式不能使用脚本中声明的变量。
使用传统的脚本语言,很容易在JSP中声明变量,使用的标签为<%!和%>,例如:
<%! int count = 100; %>
这里声明了一个整型变量,接下来使用下面的JSP表达式语句,这将输出变量count的值为100:
The count value is :<%= count %>
而如果使用下面的语句,将返回一个空值,即用EL的empty运算符测试结果为true。
The count value is: ${count}
在EL中不能定义变量,也不能使用脚本中声明的变量,但它可以访问请求参数、作用域变量、JavaBeans以及EL隐含变量等。
E算数运算符:
算术运算符 说明 示 例 结果
+ 加 ${6.80 + -12} -5.2
- 减 ${15-5} 10
* 乘 ${2 * 3.14159} 6.28318
/或div 除 ${25 div 5} 与 ${25/5} 5.0
%或mod 取余 ${24 mod 5} 与 ${24 % 5} 4
在EL表达式中还可以使用“e”在浮点数中表示幂运算,例如:
${1.5e6/1000000} 的结果为 1.5;
${1e6 * 1} 的结果为 1000000.0。
这些操作在执行时调用类中的方法,但是要注意操作结果的数据类型。例如,定点数和浮点数的运算结果总是浮点数值。类似地,低精度的值与高精度的值进行运算,如一个Integer的值与一个BigInteger的值相加,总是得到一个高精度的值。
与数值一样,String对象上也可以使用算术运算符,只要String对象能够转换为数值即可,例如:
${"16" * 4} 的结果为 64,字符串被转换成整数16;
${a div 4} 的结果为 0.0,a没有定义,它的默认值为0;
${"a" div 4} 将产生编译错误,字符串“a”不能和数值运算。
关系运算符 说明 示 例 结果
== 或 eq 相等 ${3==5}或${3 eq 5} false
!= 或ne 不相等 ${3!=5}或${3 ne 5} true
< 或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中不允许使用Java的流程控制语句,如if、for及while,因此,逻辑表达式的使用是直接显示表达式的boolean值。
EL的条件运算符的语法是:
expression ? expression1 : expression2
表达式的值是基于expression的值,它是一个boolean表达式。如果expression的值为true,则返回expression1结果;如果expression的值为false,则返回expression2的结果。例如:
${(5 * 5) == 25 ? 1 : 0} 的结果为 1;
${(3 gt 2) && !(12 gt 6) ? "Right" : "Wrong"} 的结果为Wrong;
${("14" eq 14.0) && (14 le 16) ? "Yes" : "No"} 的结果为Yes;
${(4.0 ne 4) || (100 <= 10) ? 1 : 0} 的结果为 0。
empty运算符的使用格式为:
${empty expression}
它判断expression的值是否为null、空字符串、空数组、空Map或空集合,若是则返回true,否则返回false。
属性和几何元素的访问运算符
属性访问运算符用来访问对象的成员,集合访问运算符用来检索Map、List或数组对象的元素。这些运算符在处理隐含变量时特别有用。在EL中,这类运算符有下面两个:
• 点号(.)运算符。
• 方括号([])运算符。
1. 点号(.)运算符
点号运算符用来访问Map对象一个键的值或bean对象的属性值,例如:param是EL的一个隐含对象,它是一个Map对象,下面代码返回param对象username请求参数的值:
${param.username}
再比如,假设customer是CustomerBean类的一个实例,下面代码访问该实例的custName属性值:
${customer.custName}
2. 方括号([])运算符
方括号运算符除了可以访问Map对象键值和bean的属性值外,还可以访问List对象和数组对象的元素。例如:
${ param ["username"]}或${ param ['username']}
${customer["custName"]}
访问作用域变量:
在JSP页面中,可以使用JSP表达式访问作用域变量。
一般做法是:在Servlet中使用setAttribute()方法将一个变量存储到某个作用域对象上,如HttpServletRequest、HttpSession及ServletContext等。然后使用RequestDispatcher对象的forward()方法将请求转发到JSP页面,在JSP页面中调用隐含变量的getAttribute()方法返回作用域变量的值。
使用EL就可以更方便地访问这些作用域变量。要输出作用域变量的值,只需在EL中使用变量名即可,例如:
${variable_name}
对该表达式,容器将依次在页面作用域、请求作用域、会话作用域和应用作用域中查找名为variable_name的属性。如果找到该属性,则调用它的toString()方法并返回属性值。如果没有找到,则返回空字符串(不是null)。
访问JavaaBean属性:
设有一个名为com.model.CustomerBean的JavaBeans,它有一个名为custName的属性。在JSP页面中如果需要访问custName属性,应使用下面代码实现:
<%@ page import="com.model.CustomerBean"%>
<%
CustomerBean customer= (CustomerBean)pageContext.findAttribute("customer");
customer.setCustName("Hacker");
%>
<%= customer.getCustName()%>
这里使用了pageContext的findAttribute()方法查找名为customer的属性,使用JSP表达式输出custName的值,但是如果找不到指定的属性,上面的代码会抛出NullPointerException异常。
如果知道JavaBeans的完整名称和它的作用域,也可以使用下面JSP标准动作访问JavaBeans的属性:
<jsp:useBean id="customer" class="com.model.CustomerBean"
scope="session" />
<jsp:setProperty name="customer" property="custName" value="Hacker" />
<jsp:getProperty name="customer" property="custName" />
如果使用表达式语言,就可以通过点号表示法很方便地访问JavaBeans的属性,如下所示:
${customer.custName}
使用表达式语言,如果没有找到指定的属性不会抛出异常,而是返回空字符串。
使用表达式语言还允许访问嵌套属性。例如,如果CustomerBean有一个address属性,它的类型为AddressBean,而AddressBean又有zipCode属性,则可以使用下面简单形式访问zipCode属性:
${customer.address.zipCode}
上面的方法不能使用<jsp:useBean>和<jsp:getProperty>实现。
下面通过一个示例来说明对JavaBeans属性的访问。该例中有两个JavaBeans,分别为AddressBean,它有三个字符串类型的属性,city、street和zipCode;CustomerBean是在前面的类的基础上增加了一个AddressBean类型的属性address表示地址。
在CustomerServlet.java程序中创建了一个CustomerBean对象并将其设置为请求作用域的一个属性,然后将请求转发到JSP页面,在JSP页面中使用下面的EL访问客户地址的三个属性:
<li>city:${customer.address.city}
<li>street: ${customer.address.street}
<li>zipCode:${customer.address.zipCode}
访问集合元素:
在EL中可以访问各种集合对象的元素,集合可以是数组、List对象或Map对象。这需要使用数组记法的运算符([])。例如,假设有一个上述类型的对象attributeName,可以使用下面形式访问其元素:
${attributeName[entryName]}
如果attributeName对象是数组,则entryName为下标。上述表达式返回指定下标的元素值。
(1)下面代码演示了访问数组元素:
<%
String[] favoriteFruit = {"apple","orange","banana"};
request.setAttribute("favoriteList", favoriteFruit);
%>
My favorite fruit is:${favoriteList [2]}
上面一行还可以写成:
My favorite fruit is:${favoriteList ["2"]}
(2)如果attributeName对象是实现了List接口的对象,则entryName为索引。
下面代码演示了访问List元素:
<%@ page import="java.util.ArrayList" %>
<%
ArrayList<String> favoriteFruit = new ArrayList<String>();
favoriteFruit.add("apple");
favoriteFruit.add("orange");
favoriteFruit.add("banana");
request.setAttribute("favoriteList", favoriteFruit);
%>
My favorite fruit is:${favoriteList [2]}
(3)如果attributeName对象是实现了Map接口的对象,则entryName为键,相应的值通过Map对象的get(key)方法获得的,例如:
<%@ page import="java.util.*"
contentType="text/html;charset=gb2312" %>
<%
Map<String,String> capital = new HashMap<String,String>();
capital.put("England","伦敦");
capital.put ("China","北京");
capital.put ("Russia","莫斯科");
request.setAttribute("capital", capital);
%>
The capital of China is:${capital["China"]}
The capital of Russia is:${capital.Russia}
在EL中访问隐含的变量:
在JSP页面中可以访问JSP隐含变量,如request、session、application等。在EL表达式中也定义了一套自己的隐含变量。使用EL可以直接访问这些隐含变量。
1. pageContext变量
pageContext是PageContext类型的变量。PageContext类依次拥有request、response、session、out和servletContext属性,使用pageContext变量可以访问这些属性的属性。
下面是一些例子:
${pageContext.request.method} //获得HTTP请求的方法,如GET或POST。
${pageContext.request.queryString} //获得请求的查询串
${pageContext.request.requestURL} //获得请求的URL
${pageContext.request.remoteAddr} //获得请求的IP地址
${pageContext.session.id} //获得会话的ID
${pageContext.session.new} //判断会话对象是否是新建的
${pageContext.servletContext.serverInfo} //获得服务器的信息
上述EL是通过成员访问运算符访问对象的属性。在EL中不允许调用对象的方法,所以下面的使用是错误的:
${pageContext.request.getMethod()}
然而,仍然可以使用下面的脚本表达式:
<%= request.getMethod() %>
2. param和paramValues变量
param和paramValues变量用来从ServletRequest中检索请求参数值。param变量是调用给定参数名的getParameter(String name)方法的结果,使用EL表示如下:
${param.name}
类似地,paramValues是使用getParameterValues(String name)方法返回给定名称的参数值的数组。要访问参数值数组的第一个元素,可使用下面代码:
${paramValues.name[0]}
上述代码也可以用下面两种形式表示:
${paramValues.name["0"]}
${paramValues.name['0']}
因为数组元素是按整数下标访问的,因此必须使用“[]”运算符访问数组元素。下面两个表达式都会产生编译错误:
${paramValues.name.0}
${paramValues.name."0"}
所以,EL在处理属性和集合的访问时与传统的Java语法并不完全一样。
3. header和headerValues变量
header和headerValues变量是从HTTP请求头中检索值,它们的运行机制与param和paramValues类似。下面代码使用EL显示了请求头host的值。
${header.host}或${header["host"]}
类似地,headerValues.host是一个数组,它的第一个元素可使用下列表达式之一显示:
${headerValues.host[0]}
${headerValues.host["0"]}
${headerValues.host['0']}
4. cookie变量
在Servlet中向客户发送一个Cookie可以使用下面代码:
Cookie cookie = new Cookie("userName","Hacker");
response.addCookie(cookie);
要检索客户发给服务器的Cookie,应该使用下面代码:
Cookie[] cookies = request.getCookies();
for(int i =0; i<cookies.length;i++){
if((cookies[i].getName()).equals("userName")){
out.println(cookies[i].getValue());
}
}
在JSP页面中可以使用EL的cookie隐含变量得到客户向服务器发回的Cookie数组,即调用request对象的getCookies()方法的返回结果。如果要访问cookie的值,则需要使用Cookie类的属性value(即getValue方法)。因此,下面一行可以输出名为userName的Cookie的值。如果没有找到这个cookie对象,则输出空字符串:
${cookie.userName.value}
使用cookie变量还可以访问会话Cookie的ID值,例如:
${cookie.JSESSIONID.value}
5. initParam变量
initParam变量存储了Servlet上下文的参数名和参数值。例如,假设在DD中定义了如下初始化参数:
<context-param>
<param-name>email</param-name>
<param-value>[email protected]</param-value>
</context-param>
则可以使用下面的EL表达式得到参数email的值:
${initParam.email}
如果通过JSP脚本元素访问该Servlet上下文参数,应该使用下面表达式:
<%= application.getInitParameter("email") %>
6. pageScope、requestScope、sessionScope和applicationScope变量
这几个隐含变量很容易理解,它们用来限定访问不同作用域的属性。例如,下面代码在会话作用域中添加一个表示商品价格的totalPrice属性,然后使用EL访问该属性值:
<%
session.setAttribute("totalPrice",1000);
%>
${sessionScope.totalPrice}
注意,访问应用作用域的属性应使用applicationScope变量而不是使用pageContext变量。
在EL中使用函数:
创建静态的方法:
在JSP页面中使用EL函数需要创建下面三个文件:
(1)方法的类文件(*.java),它定义了在JSP中要使用的Java方法。
(2)标签库描述文件(*.tld),它实现将每个Java方法与函数名的映射。
(3)JSP文件(*.jsp),使用标签库URI以及函数名调用Java方法。
开发EL函数首先要创建在JSP中要调用的Java方法。在下面的例子中,创建了一个名为add(String x,String y)的方法来计算传递的两个字符串参数的和。
程序9.11 Compute.java
在创建EL函数时请记住下面这些要点:
(1)类需要声明为public,方法需要声明为public static。这样容器可以不用创建新对象就可以访问类的方法。
(2)类文件要保存在 /WEB-INF/classes目录中。
(3)在EL中方法的参数和返回值必须合法。否则,Web容器将不能识别方法的签名。
要在JSP页面中调用这些方法还要创建一个标签库描述文件。标签库描述文件(Tag Library Descriptor,TLD)的主要作用是定义静态方法与函数名之间的映射。
下面的TLD文件就实现了add()方法与名为add的函数之间的映射。
程序9.12 sampleLib.tld
9.4.1 创建静态(static)方法
9.4.3 在JSP中访问EL函数
创建了TLD文件后,在JSP中调用Java函数就非常简单了,这主要包括两步:
(1)通过taglib指令指定函数使用的前缀(prefix)和函数的URI,该URI必须与TLD文件中定义的<uri>元素的值匹配。
(2)使用前缀名和函数名创建EL表达式。
程序9.13 sum.jsp