EL表达式的使用

时间:2022-09-29 19:09:12
在JSP 2.0的页面中,我们使用下面形式的元素调用表达式语言:
${expression}
EL可以出现在JSP页面的模板文本中,也可以出现在JSP标签的属性中。
下面是在JSP模板文本中使用表达式:
<ul>
  <li>客户名:${customer.custName}
  <li>Email地址:${customer.email}
</ul> 
下面是在JSP标准动作的属性中使用EL表达式:
<jsp:include page = "${expression1}" />
<c:out value = "${expression2} " />

表达式语言的功能

(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>hacker@163.com</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