第五章 EL表达式语言
EL全名为Expression Language。EL 是从JavaScript脚本语言得到启发的一种表达式语言,它借鉴了JavaScript多类型转换无关性的特点。在使用EL从scope中得到参数时可以自动转换类型,因此对于类型的限制更加宽松。Web服务器对于request 请求参数通常会以String类型来发送,在得到时使用的Java语言脚本是request.getParameter(“参数名”),但是这样的话,对于实际应用还必须进行强制类型转换。而EL就将用户从这种类型转换的繁琐工作脱离出来,允许用户直接使用EL表达式取得的值,而不用关心它是什么类型。
5.1 EL特点
EL语言是JSTL输出(输入)一个JAVA表达式的表示形式。在JSTL中,EL 语言只能在属性值中使用。EL语言只能通过建立表达式${表达式}来进行调用。在属性值中使用表达式有三种方式。
(1) value属性包含一个表达式
在这种情况下,表达式值被计算出来并根据类型转换规则赋值给value属性。比如:
或
<%=session.getAttribute(“参数名”)%>
(2) value属性包含一个或多个属性,这些属性被文本分割或围绕
在这种情况下,表达式从左到右进行计算,并将结果转换为字符串型(根据类型转换规则),并将结果赋值给value属性
(3) value属性仅仅包含文本
在这种情况下,字符串型属性value将根据类型转换规则转换为标签所希望的类型。
接下来更详细地来讨论一些情况,首先假设有一个EL表达式:
${var[“attribute”]}
●如果var为null时,表达式结果为null,不会产生NullPointerException异常。
●如果attribute为null,表达式结果为null。
●如果var是一个Map对象,表达式相当于var.get(attribute),而var对象中没
? 2 ?
https://www.doczj.com/doc/b710465989.html,简明教程
有attribute值得关键字则会返回null。
●如果var为List或Array对象,attribute必须为整数。若attribute不能计算成
整数,则会报错;否则表达式返回List或Array对应attribute值的位置的元
素。比如attribute=0,表达式返回List或Array的第一个元素。若attribute越
界,结果为null。
●如果var是JavaBean对象而attribute是一个var对象的可读属性,表达式返
回该属性的值。否则返回错误。
除了上面描述的内容外,EL还有以下一些特点:
1.EL表达式用${}表示,可用在所有的HTML和JSP标签中作用是代替JSP页
面中复杂的JA V A代码。
2.EL表达式可操作常量变量和隐式对象。最常用的隐式对象有${param}和
${paramValues}。${param}表示返回请求参数中单个字符串的值。
${paramValues}表示返回请求参数的一组值。pageScope表示页面范围的变量。
requestScope表示请求对象的变量。sessionScope表示会话范围内的变量。
applicationScope表示应用范围的变量。
3.<%@ page isELIgnored="true" %>表示是否禁用EL语言,TRUE表示禁止。
FALSE表示不禁止。JSP2.0中默认的启用EL语言。
4.EL语言可显示逻辑表达式如${true and false}结果是false ,关系表达式如
${7>1} 结果是true ,算术表达式如 ${2+2} 结果是4。
5.EL中的变量搜索范围是:page、request、session、application 。点运算符(。)
和"[ ]"都是表示获取变量的值。区别是[ ]可以显示非词类的变量
5.2 EL语法
下面我们就详细介绍一下EL的变量及作用范围、关键字、运算符以及优先级的划分。
5.2.1 EL变量及作用范围
在EL中,与隐式对象无关联的标识符被认为是存储在四个JSP作用域中的名称对象。首先对页面作用域检查是否存在这样的标识符,其次对请求作用域、然后对会话作用域、最后对应用程序作用域依次进行这样的检查,然后测试该标识符的名称是否与存储在该作用域中的某个对象的名称匹配。第一个这样的匹配作为 EL 标识符的值被返回。通过这种方法,可以将 EL 标识符看作引用限制了作用域的变量。
EL 存取变量数据的方法很简单,例如:${username}。它的意思是取出某一范围中名称为username 的变量。因为我们并没有指定哪一个范围的username,所以它的默认值会先从Page 范围找,假如找不到,再依序到Request、Session、Application范围。假如途中找到username,就直接回传,不再继续找下去,但是如果全部的范围都没有找到时,就回传null。
第1章 https://www.doczj.com/doc/b710465989.html,概述? 3 ?
EL将属性范围分为四个部分:
1.Page范围PageScope
2.Request范围RequestScope
3.Session范围SessionScope
4.Application范围ApplicationScope
EL自动搜索的顺序就按照从上到下进行查找,当然,用户也可以指定要取出哪一
个范围的变量。例如:
${https://www.doczj.com/doc/b710465989.html,ername} 取出Page 范围的username 变量
${https://www.doczj.com/doc/b710465989.html,ername} 取出Request 范围的username 变量
${https://www.doczj.com/doc/b710465989.html,ername} 取出Session 范围的username 变量
${https://www.doczj.com/doc/b710465989.html,ername} 取出Application 范围的username 变量其中,pageScope、requestScope、sessionScope和applicationScope都是EL 的隐含
对象
5.2.2 EL关键字
如其他语言一样,JSP EL同样也有一些保留的关键字,这些关键字是不能表示其
它含义的。EL保留的关键字有16个,见表5-1所示。
表5-1 EL关键字
and gt true null or lt false empty eq ge instanceof div ne not le mod 5.2.3访问运算符“.”和“[ ]”
EL 提供“.”和“[ ]”两种运算符来存取数据。下列两者所代表的意思是一样的:${https://www.doczj.com/doc/b710465989.html,er.age}
等于
${https://www.doczj.com/doc/b710465989.html,er[“age"]}
“.”和“ [ ]”也可以同时混合使用,如下:
${sessionScope.shoppingCart[0].value}
这个表达式的含义是回传结果为shoppingCart中第一项的value属性。
不过,以下两种情况,两者会有差异:
(1) 当要存取的属性名称中包含一些特殊字符,如“.”或“–”等并非字母或数字
的符号,就一定要使用 [ ],例如:
${user.My-Name }
上述是不正确的方式,应当改为:
${user["My-Name"] }
(2) 同时“[ ]”运算符比“.”更好的支持动态取值。如:${https://www.doczj.com/doc/b710465989.html,er[data]},
此时,data是一个变量,假若data的值为"sex"时,那上述的例子等于${https://www.doczj.com/doc/b710465989.html,er.sex}。
假若data 的值为"name"时,它就等于${https://www.doczj.com/doc/b710465989.html,}。因此,如果要动
? 4 ?
https://www.doczj.com/doc/b710465989.html,简明教程
态取值时,就可以用上述的方法来做,但“.”无法做到动态取值。
5.2.4算术运算
EL支持通用的算术运算,包括加(+)、减(-)、乘(*)、除(/)和模(%)运算。在EL中也可以使用div代表除法(/)运算,使用mod代表模(%)运算。
在表达式中同样可以使用括号来改变运算的优先顺序。例如:
${(x + y) * (m - n)}
也可以使用减号(-)来表示一个负数。而且在EL的除法中,如果除以0,返回值为无穷大(Infinity),而不是错误。EL中也有指数运算符(E)。
EL的算术运算符的优先顺序如下。
(1)括号:()
(2)负号:-
(3)乘、除、模:*、/(div)、%(mod)
(4)加、减:+、-
5.2.5 关系运算
EL支持关系运算,包括:等于(= =)、非等于(!=)、小于(<)、大于(>)、不大于(< =)、不小于(> =)等运算。在EL中也可以使用eq、ne、lt、ge、le和ge 分别表示上面的关系运算符。
EL关系表达式返回值为boolean值。例如表达式${x<7},当x小于7时返回true,否则返回false。
EL关系运算的优先顺序低于算术运算,其中关系运算符之间的优先顺序如下。
(1)<,>,<=,>=
(2)= =,!=
5.2.6 逻辑运算
EL支持的逻辑运算包括:与(&&)、或(| |)、非(!)等。在EL中可以使用and、or、not来代替上面的逻辑运算符。下面就是包含逻辑运算的表达式:
${x<7 && y >0 | | !z}
EL逻辑运算的优先顺序低于关系运算,其中逻辑运算符之间的优先顺序如下。
(1)!(not)
(2)&&(and)
(3)| |(or)
同样可以使用括号来改变运算的优先顺序。
5.2.7 empty运算符
EL中有一个特殊的运算符empty,如果操作数值为null返回true,或者操作数本身是一个空的容器、空的数组或长度为0的字符串等也返回true。空容器指的是不包含任何元素的容器。
第1章 https://www.doczj.com/doc/b710465989.html, 概述 ? 5 ?
5.2.8 自动类型转换
EL 支持自动类型转换。例如,如果一个JSP 页面需要处理request 对象中的属性attr ,以前的处理用代码表示如下:
String strAttr = (String)request.getAttribute(“attr”); int attrInt = Interger.parseInt(strAttr);
attrInt = attrint + 1; 其中由于getAttribute()方法返回值的类型为Object ,如果要作为整数使用,需要在代码中进行转换。如果使用EL 表达式,可以直接下面的代码来完成类型自动转换: ${param.attr + 1}
EL 表达式中自动类型转换的规则如下。
(1)Object 转换为数值
● 如果Object 为boolean 类型,出错
● 如果Object= =null ,返回0
● 如果Object= =””,返回0
● 如果Object 为字符串,且字符串可以转换为数值,则返回数值,否则会出错
(2)Object 转换为String
● Object 为数值型数据时,依据其值直接转换字符串,如100.23转换为“100.23” ● 如果Object= =null ,返回长度为0的字符串:“”
● 如果Object.toString()产生异常,会出错,否则返回Object.toString()
5.2.9算术运算符的优先级
EL 运算符优先级如表5-2所示(自顶到底,从左到右)
表5-2 EL 运算符优先级 [] , .
()
unary - 、 not 、 ! 、 empty
* 、 / 、 div 、 % 、 mod
+ 、binary -
()、 < 、 > 、 <= 、 >= 、 lt 、 gt 、 le 、 ge
== 、 != 、 eq 、 ne
&& 、 and
|| 、 or
5.3 EL 隐含对象
在EL 中有11个隐含对象,见表5-3所示。
表5-3 EL 隐含对象 变量名称 说明
? 6 ?
https://www.doczj.com/doc/b710465989.html,简明教程
pageContext 一个javax.servlet.jsp.PageContext类的实例, 用来提供访问不同的请求数据param 一个包含所有请求参数的集合 (a java.util.Map),通过每个参数对应一个String 值的方式赋值
paramValues 一个包含所有请求参数的集合 (a java.util.Map),通过每个参数对应一个String 数组的方式赋值
header 一个包含所有请求的头信息的集合,(a java.util.Map) ,通过每个头信息对应一个String值的方式赋值
headerValues 一个包含所有请求的头信息的集合 (a java.util.Map) ,通过每个头信息的值都保存在一个String数组的方式赋值
cookie 一个包含所有请求的 cookie集合 (a java.util.Map),通过每一个cookie (javax.servlet.http.Cookie)对应一个cookie值的方式赋值initParam 一个包含所有应用程序初始化参数的集合(a java.util.Map) ,通过每个参数分别对应一个String值的方式赋值
pageScope 一个包含所有page scope范围的变量集合 (a java.util.Map)
requestScope 一个包含所有request scope范围的变量集合 (a java.util.Map)
sessionScope 一个包含所有session scope范围的变量集合 (a java.util.Map)
applicationScope 一个包含所有application scope范围的变量集合 (a java.util.Map) 5.3.1 pageCentext对象
PageContext对象引用当前页面的页面上下文对象 javax.servlet.ServletContex表示此JSP 的PageContext。在PageContext类中有request、response、session、out和servletContext属性及getRequest(),getResponse(),getSession(),getOut(),getServletContext()等方法。因此pageContext可以取得有关用户要求或页面的详细信息,见表5-4所示。
表5-4 pageContext方法及属性
格式说明
${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.creationTime} 判断session 是否为新的
${pageContext.session.id} 取得session 的ID
${pageContext.servletContext.serverInfo} 取得主机端的服务信息
下面的代码详细介绍了pageContext对象的属性。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page contentType="text/html;charset=GB2312" %>
<%@ taglib prefix="c" uri="https://www.doczj.com/doc/b710465989.html,/jsp/jstl/core" %>
第1章 https://www.doczj.com/doc/b710465989.html,概述? 7 ?
参数字符串:\${pageContext.request.queryString}: value="${pageContext.request.queryString}"/> 绝对路径:\${pageContext.request.requestURL}: value="${pageContext.request.requestURL}"/> 工程名(相对路径):\${pageContext.request.contextPath}: value="${pageContext.request.contextPath}"/> \${pageContext.request.method}: HTTP版本:\${pageContext.request.protocol}: value="${pageContext.request.protocol}"/> \${pageContext.request.remoteUser}: value="${pageContext.request.remoteUser}"/> IP地址\${pageContext.request.remoteAddr }: value="${pageContext.request.remoteAddr}"/> session状态:\${pageContext.session.new}: value="${pageContext.session.new}"/> session编号:\${pageContext.session.id}: 运行结果如图5-1所示。 图5-1 pageContext对象实例 5.3.2 param和param Values对象 使用param对象可以访问请求的参数值,而如果一个参数名对应多个值时,就需要使用paramValues对象。 下面的语句会输出请求参数的值,如果这个参数不存在,输出空字符串(“”)而 ? 8 ? https://www.doczj.com/doc/b710465989.html,简明教程 不是null。 ${param.attr} 请看下面的例子。 <%@ page language="java" contentType="text/html; charset=gb2312" pageEncoding="gb2312"%> 姓名: 密码: 性别:男 女
年龄:
兴趣:学习
运动
旅游
音乐
这段代码提交一个表单到param.jsp页面,然后改页面会显示用户所选择的内容。处理请求的param.jsp页面代码如下所示:
<%@ page language="java" contentType="text/html; charset=gb2312"
pageEncoding="gb2312"%>
<%request.setCharacterEncoding("gb2312"); %>
姓名:${https://www.doczj.com/doc/b710465989.html,ername}
密码:${param.password}
性别:${param.sex}
年龄:${param.age}
兴趣:${paramValues.habit[0]} ${paramValues.habit[1]}
第1章 https://www.doczj.com/doc/b710465989.html,概述? 9 ?
运行第一个页面,输入以下内容,如图5-2所示。
图5-2 form页面
单击“发送”按钮,结果如图5-3所示。
图5-3 param.jsp页面
5.3.3 header和header Values对象
Header储存用户浏览器和服务端用来沟通的数据,使用对象header可以访问HTTP请求的一个具体的header值;而headerValues对象可以分别访问所有HTTP请求的header值。
例:要取得用户浏览器的版本,可以使用${header["User-Agent"]}。
? 10 ?
https://www.doczj.com/doc/b710465989.html,简明教程
也有可能同一标头名称拥有不同的值,此时必须改为使用headerValues 来取得这些值。
注意,如果属性名中包含非字母和数字字符,只能使用[ ]访问。
5.3.4 cookie对象
隐式对象提供了对由请求设置的 cookie 名称的访问。这个对象将所有与请求相关联的 cookie 名称映射到表示那些 cookie 特性的 Cookie 对象,可以快速引用输入的Cookie对象。
JSTL并没有提供设定cookie的动作,例:要取得cookie中有一个设定名称为userCountry的值,可以使用${https://www.doczj.com/doc/b710465989.html,erCountry}来取得它。
5.3.5 initParam对象
在EL中使用iniParam对象可以访问Servlet上下文的初始参数。例:一般的方法String userid = (String)application.getInitParameter("userid");
其实就可以使用 ${https://www.doczj.com/doc/b710465989.html,erid}来取得名称为userid的值。
5.3.6 属性范围
四个涉及有效范围的EL对象分别是:pageScope,requestScope,sessionScope和applicationScope。使用这些对象可以限制变量的有效范围。
例如:下面语句会依次在页面有效、请求有效、会话有效和应用有效范围内查找名字为attr的属性对象并输出第一次碰到的值:
${attr}
而使用下面语句则只在请求有效范围内查找名字为attr的属性对象并输出其值。
${sessionScope.attr}
5.4 EL函数
当EL从JSTL规范中移到JSP规范中,它使用了一个如何进行函数调用的技巧。EL函数语法非常简单:方法名,紧接着在圆括号中有一组参数:
<%@ taglib prefix="fn"
uri="https://www.doczj.com/doc/b710465989.html,/jsp/jstl/functions" %>
${ fn:length(myCollection)}
这是一个属于标签库中的函数,并且函数名字在页面中所包含的前缀要指定taglib 库。在这个例子中,使用了前缀fn,这是JSTL function库默认的前缀。这个函数的实现是标签库描述符(Tag Library Descriptor,TLD)将函数名称映射到一个由JA V A实现的静态方法中:
Returns the number of items in a collection or the number of characters in a string.
第1章 https://www.doczj.com/doc/b710465989.html,概述? 11 ?
org.apache.taglibs.standard.functions.Functions
int length(https://www.doczj.com/doc/b710465989.html,ng.Object)
在这里element是
这个静态方法 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 (iter.hasNext()) {
count++;
iter.next();
}
return count;
}
if (obj instanceof Enumeration) {
Enumeration enum = (Enumeration) obj;
count = 0;
while (enum.hasMoreElements()) {
count++;
enum.nextElement();
}
return count;
}
try {
count = Array.getLength(obj);
return count;
? 12 ?
https://www.doczj.com/doc/b710465989.html,简明教程
} catch (IllegalArgumentException ex) {
throw new JspTagException("not support this type"));
}
}
它就是一个常规的静态方法,这个函数中通过对运行期中的参数类别的判断,找
出参数的长度。
除了在这个方法中使用的length()方法,JSTL1.1标签库还包含了许多其它经常使
用的函数,如表5-4所示:
表5-4 JSTL标准函数
函数描述
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表达式语言的概念和使用。通过本章的学习,读者应该了解EL
的基本特点,掌握EL的基本语法,掌握EL隐含对象及其使用,并对四种属性范围相
当熟悉,在开发中不会出现混淆的错误,同时了解EL函数的使用,。