常用提取:EL中的隐含对象
一、EL表达式简介
起初 EL 表达式只是为了方便存取数据所定义的一种语言。它只能使用在 JSTL 标签中,而不能在JSP 页面中运用。一直到了 JSP2.0 版本发布后, EL 才被正式纳入为 JSP 标准规范之一。这时,它才可以直接在 JSP 页面程序中使用,只要安装的 Web 服务器能够支持 Servlet2.4/JSP2.0。
1.1 EL表达式简单使用介绍
在 JSP2.0 之前,Web开发者只能使用表达式<%=Name%>访问系统的值,例如:
<someTags:aTag attribute="<%=pageContext.getAttribute("aName")%>">
或者调用JavaBean中的属性值:
<%= aCustomer.getAddress().getCountry() %>
而EL表达式语言允许网页开发者使用简单的语法访问对象。比如要访问一个简单变量,可以像下面这样写:
<someTags:aTag attribute="${aName}">
其中${aName}即为访问aName变量的EL表达式。而访问JavaBeans属性(例如获取aCustomer对象中定义的address对象变量的 country属性),可以使用:
${aCustomer.address.country}
EL表达式还可以很好在JavaScript中得到使用,因为表达式语言正是借用了访问结构化数据的JavaScript语法。EL可以很好的和JSTL或者自定义标签结合使用,因为EL创建的初衷就是在JSTL 中使用。例如,在<c:if>标签中的不等式EL:
<c:if test=”${bean1.num < 3}”>
body content
</c:if>
在EL中除了可以是变量、数值、对象的属性调用或者嵌套调用以及不等式判断(判断结果是Boolean类型),还可以直接包含一个字符串:
<c:out value=”an expression is ${‘${‘}expr}” />
这样输出的字符串值为:an expression is ${expr}。
page 指令中,有一个 isELignored 属性,它就是指定该 JSP 页面是否支持 EL表达式。如果isELignored属性值为true,即忽略EL表达,在JSP页面可以直接使用${之类的字符,Web容器式不会试图解析这些表达式。如果设置为false,当Web容器遇到“${”字符时会解析其中的表达式内容,并把结果输出。
注意:当 isELignored属性设置为false,即页面能够识别EL表达式语言,但是Web开发者又想使用“${”字符,则需要在前面加上“/”作标识。
1.2 EL表达式的特点和使用范围
总结起来, EL 表达式语言的使用范围以及特点包括如下:
- 不仅仅可以在 JSTL 或者自定义标签中使用 EL, JSP2.0 开始允许 EL 在 JSP 语句以及 JavaScript语句等更广范围内使用 EL 表达式语言。
- 在 EL 表达式语言中可以获得命名空间( PageContext 对象,它是页面中所有其他内置对象的最大集成者,通过它可以访问到其他内置对象,本书的第五章有介绍)。
- 既可以访问一般变量,还可以访问 JavaBean 类中的属性以及嵌套属性和集合对象。
- 在 EL 表达式中可以执行关系运算、逻辑运算以及算术运算。
- 扩展函数可以和 Java 类的静态方法映射
- 在 EL 表达式中可以访问 JSP 的一系列隐含对象( request、 session、 application 以及 page 等)。
二、EL语法
EL 表达式的使用是非常简单的,所有的 EL 表达式的格式都是以“ ${”开始,并以“ }”结尾。最直接和简单的方法,就是在 EL 中使用变量名获取到值,例如:
${ username }
当 EL 表达式中的变量不给定范围时,则表示容器会默认从 page 范围中找,再依次到 request.、session以及 application 范围(由小到大)。如果中途中找到 username 变量,则直接返回,否则返回 NULL。下面列出了 EL使用到的变量属性范围的名称:
- 属性范围 page:在 EL 中使用名称 pageScope,例如${pageScope.username},则表示在 page 范围中找 username 变量,找不到直接返回 NULL。
- 属性范围 request:在 EL 中使用名称 requestScope。
- 属性范围 session:在 EL 中使用名称 sessionScope。
- 属性范围 application:在 EL 中使用名称 applicationScope。
2.1 在EL中可以包含的文字
JSP 表达式语言( EL)定义了可以在表达式中使用的文字包括以下:
- Boolean: ture 和 false。
- Integer:与 Java 类似,可以包含任何正数或者负数,例如 24、 56、 -54 等。
- Floating Point:与 Java 类似,可以包含任何正的或者负的浮点数,例如-1.8E-5、 4.567。
- String:任何由引号或者双引号限定的字符串。对于单引号、双引号和反斜杠,使用反斜杠字符作为转义序列。必须注意,如果在字符串两端使用双引号,则但引号不需要转义。
- NULL:返回 null。
下面逐一举例:
${false}包含 Boolean 类型、 ${3*8}包含整数类型 Integer、 ${5.678}包含浮点型、 ${“string”}或者${‘string’}包含字符串、 ${NULL}表示返回为空值。
2.2 操作符“ []”和“ .”
在 EL 中,可以使用操作符“ []”和“ .”来取得对象的属性。例如:${user.name}或者${user[name]}表示取出对象 user 中的 name 属性值。
另外在 EL 中可以使用[]操作符来读取 Map、 List 或者对象集合中的数据,例如在 Session 域中存在一个数组 schools:获取数组中第二位数值:
${sessionScope.schools[1]}
如果 schools 是 School 对象集合类,则可是获取第二位对象中的 name 属性值:
${sessionScope.shools[1].name}
这里的 sessionScope 是在 EL 表达式中的调用 Session 内置对象的名称。
如果需要 EL 表达式来访问一个 JavaBean 中的属性值, JavaBean 的定义如下:
<jsp:useBean id=”user” class=”cn.User” />
对 JavaBean 类中属性的引用: ${user.name}或者${user[“name”]}。
注意:当属性名中包含了一些特殊符号时,例如“.”或者“-”等非字母或者数字符号时,就只能使用[]格式来访问属性值了,例如:${sessionScope.user[user_name]}是正确的,而${sessionScope.user.user_name}是不正确的。
另外一种情况也必须使用[]符号来引用属性值,当某个对象的属性名使用某一个变量(假设这里变量为 AttributeName)来给定的,例如:
${sessionScope.user[AttributeName]},这里的变量 AttributeName 可以在之前进行赋值。例如 AttributeName 变量赋值为 name,则以上 EL 表达式等价于:${sessionScope.user.name}
2.3 EL中的基本算术操作符
在 JSP 中的表达式语言( EL)提供了如下多个运算操作符,其中大部分是 Java 中常用的操作符。
算术操作符 | 说明 | 范例 | 结果 |
+ | “加法”操作 | ${23+5} | 28 |
- | “减法”操作 | ${34-6} | 28 |
* | “乘法”操作 | ${3*8} | 24 |
/或者div | “除法”操作 | ${8/2}或者${8 div 2} | 4 |
%或者mod | “求余”操作 | ${17/4}或者${17 mod 4} | 1 |
“+”、“-”和“ *”操作符: A+B、 A-B 和 A*B
- 如果 A 和 B 同为 NULL 时,直接返回 0。
- 如果 A 和 B 其中有一个为 Float、 Double 或者包含了“ .”、“ e”或者“ E”字符的字符串,则强行把 A 和 B 转换成 Double 类型,其中有三种情况:
- 运算符为“+”时,返回 A.add(B)
- 运算符为“-”,则返回 A.subtract(B)
- 运算符为“ *”,则返回 A.multiply(B)
- 否则,强行把 A 和 B 转为 Long 类型,然后再运行相应的运算
- 如果运算操作出现异常,则报错
“ /”或者 div 操作符: A/B 或者 A div B
- 如果 A 和 B 同时为 NULL,则返回 0
- 否则,强行把 A 和 B 转换成 Double 类型,再执行相应的操作运算
- 如果运算操作出现异常,则报错
“ %”或者“ mod”操作符: A%B 或者 A mod B
- 如果 A 和 B 同时为 NULL,则返回 0
- 如果 A 或者 B 其中一个为 Float、 Double 或者包含了“ .”、“ e”或者“ E”字符的字符串,则强行把 A 和 B 转换成 Double 类型,再执行相应的操作运算
- 否则,强行把 A 和 B 转换成 Long 类型,再执行相应操作运算
- 如果运算操作出现异常,则报错
一元负号操作符: -A
- 如果 A 为 NULL,则返回 0
- 如果 A 为一个字符串,又分如下几种情况:
- 如果这个字符串包含“ .”、“ e”或者“ E”字符,则把 A 强行转换成 Double 类型,再执行相应操作运算
- 否则,强行把 A 转换成 Long 类型,再执行相应操作运算
- 如果运算操作出现异常,则报错
- 如果 A 是一个 Byte、 Short、 Integer、 Long、 Float 或者 Double 类型时,同样可能出现两种情况:
- 直接按照原来的类型执行相应的操作运算
- 如果出现操作异常,则报错
- 否则,出现异常,报错
2.4 EL中的关系操作符
EL 中使用的关系操作包括如下六种,如下表:
关系操作符 | 说明 | 范例 | 结果 |
= =或者eq | “等于”判断 | ${5= =10}或者${5 eq 10} | false |
!=或者ne | “不等于”判断 | ${5 != 10}或者${5 ne 10} | true |
<或者lt | “小于”判断 | ${3 < 5}或者${3 lt 5} | true |
>或者gt | “大于”判断 | ${3 > 5}或者${3 gt 5} | false |
<=或者le | “小于等于”判断 | ${4 <= 4}或者${4 le 4} | true |
>=或者ge | “大于等于”判断 | ${4 >= 6}或者${4 ge 6} | false |
A{< or lt、 > or gt、 <= or le、 >= or ge}B 操作符
- 如果 A 值等于 B 时,操作符为“ <=”或者“ le”、“ >=”或者“ ge”,则返回 true。否则,操作符为“ <”或者“ lt”、“ >”或者“ gt”时,返回 false
- 如果 A 是 NULL,或者 B 是 NULL,则返回 false
- 如果 A 或者 B 是 Float 或者 Double 类型,则强行把 A 和 B 转换成 Double 类型,然后再执行相应的操作运算符
- 如果 A 或者 B 是 Byte、 Short、 Character、 Integer 或者 Long 类型时,则强行把 A 和 B 转换成Long,然后执行相应的操作运算符
- 如果 A 或者 B 是一个字符串,则强行把 A 和 B 全都转换成字符串,再进行相应的比较操作
- 如果拿 A 是去比较,存在两种情况:
- 若 A.compareTo(B)产生异常,则报错
- 否则,返回 A.compareTo(B)的比较结果
- 如果拿 B 是去比较,也存在两种情况:
- 若 B.compareTo(A)产生异常,则报错
- 否则,返回 B.compareTo(A)的比较结果
- 否则,产生异常,报错
A{== or eq、 != or ne}B 操作符
- 如果 A 等于 B,操作符为“==”或者“ eq”时,返回 true;否则,操作符为“!=”或者“ ne”时,返回 false
- 如果 A 为 NULL 或者 B 为 NULL 时,则对操作符“==”或者“ eq”,返回 false;如果操作符是“!=”或者“ ne”,则返回 true
- 如果 A 或者 B 是 Float 或者 Double 类型,则强行把 A 和 B 转换成 Double 类型,然后再执行相应的操作运算符
- 如果 A 或者 B 是 Byte、 Short、 Character、 Integer 或者 Long 类型时,则强行把 A 和 B 转换成Long 类型,然后再执行相应的操作运算符
- 如果 A 或者 B 是 Boolean 类型,则强行把 A 和 B 转换成 Boolean 类型之后再执行相应的操作运算府
- 如果 A 或者 B 是字符串类型,则强行把 A 和 B 转换成字符串类型,再执行两者之间的比较
- 如果在执行 A.equals(B)时产生异常,报错,否则返回比较结果。
2.5 逻辑操作符
逻辑操作符包括如下几种,如表所示:
逻辑操作符 | 说明 | 范例 |
&& 或者 and | “与”操作符 | ${num >5 && num <10} |
|| 或者 or | “或”操作符 | ${num <5 || num > 11} |
! 或者 not | “非”操作符 | ${!name.equals(“zzb”)} |
A{&& 或者 and、 ||或者or}B逻辑操作
执行该操作符时,首先强行把 A 和 B 转换成Boolean类型,然后再执行相应的操作运算符。
- 如果 A 和B同为true,当操作符为“&&”时,返回true;操作符为“||”时,返回true。
- 如果 A 和B其中一个为true,另一个为false。当操作符为“&&”时,返回false;操作符为“||”时,返回true。
- 如果 A 和B同为false。当操作符为“&&”时,返回false;操作符为“||”时,则返回false。
- 否则,执行过程产生异常,报错。
注意:在执行过程中,只要表达式结果一旦确定,运算过程就会停止,例如,A && B && C或者A and B and C,则一旦计算到A为false,就会立即停止计算,并返回false。
“||”操作符也同样,例如 A || B || C,则一旦检测到第一个(A、B或者C)为true,则停止计算,直接返回true。
对“ &&”操作符来讲,只要检测到一个false,则整体为false;对“||”操作符来说,只要检测到一个true,则整体返回true。
“非”操作符: !A
执行该操作符之前,会强行把 A 转换成Boolean类型,然后再执行“非”或者“反”操作:
- 如果 A 判断为false,执行“!”操作之后,返回结果true
- 如果 A 判断为true,执行完“!”操作之后,返回结果false
- 否则,执行过程发生异常,报错
2.6 Empty操作符
这个“ empty”操作符是一个前缀形式的操作符,它使用来判断某个变量是否为 NULL 或者为空,在 EL 中的使用格式如下:${empty user.name},判断 user 对象 name 属性值是否为 NULL 或者空。“ empty”操作符的运算规则如下:
- 如果 A 为 NULL,则返回 true。
- 否则,如果 A 是一个空的字符串,则返回 true。
- 否则,如果 A 是一个空的数组,则返回 true。
- 否则,如果 A 是一个空的 Map 集合类,则返回 true。
- 否则,如果 A 是一个空的 List 集合类,则返回 true。
- 否则,返回 false。
2.7 其他操作符
包括的其他操作符还有:条件操作符和括号操作符。
条件操作符
EL 中还可以使用以下形式的条件操作符:
${A ? B : C}
其中 A 为判断表达式,当 A 为 true 时,返回 B 表达式执行的结果;如果 A 为 false,则返回 C 表达式执行之后的结果。
括号操作符
在 EL 中也可以包含括号,例如:
${ (a * (b + c) ) }
括号主要是使用来改变执行优先权,所有操作符的优先级顺序如下(由上往下,由左往右):
- []
- ()
- -(负)、 not、!、 empty
- *、 /、 div、 %、 mod
- +、-(减)
- <、 >、 <=、 >=、 lt、 gt、 le、 ge
- ==、!=、 eq、 ne
- &&、 and
- ${A?B:C}
三、EL中的隐含对象
为了方便地获得 Web 应用程序中的相关数据, EL 表达式语言定义了一些隐含对象。隐含对象总共有 11 个,这样使得 EL 能够更加方便地获取到数据。
这 11 隐含对象能够很方便地读取到 session、 cookie、 HttpHeader 以及用户提交表单( param)等,具体请查看如下表所示:
注意:有很多读者会把 EL 中定义的隐含对象和 JSP 中定义的隐含对象相混淆,其实只有一个对象是它们两者所共有的,即 PageContext 对象。这样 EL 也可以访问到JSP 中的其他隐含对象,这是因为PageContext 对象拥有访问 JSP 中所有其他 8 个隐含对象的权限。实际上,这也是将 PageContext 对象包含在 EL 隐含对象中的主要原因。
3.1 EL中的pageContext隐含对象实例演示
<body>
<h3>EL中的pageContext隐含对象</h3>
<hr>
<table border="1">
<tr>
<td align="center">pageContext隐含对象的方法调用</td>
<td align="center">结果</td>
</tr>
<tr><!-- 取得请求的参数字符串 -->
<td>\${pageContext.request.queryString}:</td>
<td><c:out value="${pageContext.request.queryString}" /></td>
</tr>
<tr><!-- 取得请求的URL,但不包含请求的参数字符串 -->
<td>\${pageContext.request.requestURL}:</td>
<td><c:out value="${pageContext.request.requestURL}" /></td>
</tr>
<tr><!-- Web application的名称 -->
<td>\${pageContext.request.contextPath}:</td>
<td><c:out value="${pageContext.request.contextPath}" /></td>
</tr>
<tr><!-- 取得HTTP的方法(GET或者POST) -->
<td>\${pageContext.request.method}:</td>
<td><c:out value="${pageContext.request.method}" /></td>
</tr>
<tr><!-- 取得使用的协议(HTTP/1.1、HTP/1.0) -->
<td>\${pageContext.request.protocol}:</td>
<td><c:out value="${pageContext.request.protocol}" /></td>
</tr>
<tr><!-- 取得用户名称 -->
<td>\${pageContext.request.remoteUser}:</td>
<td><c:out value="${pageContext.request.remoteUser}" /></td>
</tr>
<tr><!-- 取得用户的IP地址 -->
<td>\${pageContext.request.remoteAddr}:</td>
<td><c:out value="${pageContext.request.remoteAddr}" /></td>
</tr>
<tr><!-- 判断session是否为新的。所谓新的session,就是刚由server产生而client尚未使用的 -->
<td>\${pageContext.session.new}:</td>
<!-- 注意:此处与其它不一样,其它都是session.something,这里如果也这样写就会解析错误 -->
<td><c:out value="${pageContext.session['new']}" /></td>
</tr>
<tr><!-- 取得session的ID -->
<td>\${pageContext.session.id}:</td>
<td><c:out value="${pageContext.session.id}" /></td>
</tr>
<tr><!-- 取得主机信息 -->
<td>\${pageContext.servletContext.serverInfo}:</td>
<td><c:out value="${pageContext.servletContext.serverInfo}" /></td>
</tr>
</table>
</body>
注:需要引入JSTL核心依赖
3.2 EL中header、 headerValues、 param、 paramValues隐含对象实例演示
这四个映射用来获取请求参数和请求头的值。因为 HTTP 协议允许请求参数和请求头具有多个值,所以它们各有一对映射。每对中的第一个映射返回请求参数或头的主要值,通常是恰巧在实际请求中首先指定的那个值。每对中第二个映射允许检索参数或头的所有值。这些映射中的键是参数或头的名称,但这些值是 String 对象的数组,其中的每个元素都是单一参数值或头值。
param 和 paramValues 两隐含对象是取得用户的请求参数,类似于 JSP 中的下列方法:
- request.getParameter(String name)
- request.getParameterValues(String name)
下面创建 paramsubmit.jsp 和 param.jsp 页面来演示这四个隐含变量的使用方法, paramsubmit.jsp 用于提交参数,param.jsp接收数据,示例如下:
paramsubmit.jsp
<body>
<h3>EL中的隐含对象:header,headerValues,param,paramValues</h3>
<hr>
<form action="param.jsp" method="post">
<table width="400" align="center" border="1">
<tr>
<td width="60">姓名:</td>
<td> <input type="text" name="name" width="15" /></td>
</tr>
<tr>
<td>性别:</td>
<td> <input type="radio" name="sex" value="male" checked />男
<input type="radio" name="sex" value="female" />女
</td>
</tr>
<tr>
<td>专业:</td>
<td> <select name="specialty">
<option value="计算机科学" selected>计算机科学</option>
<option value="通信">通信</option>
<option value="管理科学与工程">管理科学与工程</option>
</select></td>
</tr>
<tr>
<td>爱好:</td>
<td> <input type="checkbox" name="habit" value="电影" />电影
<input type="checkbox" name="habit" value="读书" />读书 <input
type="checkbox" name="habit" value="羽毛球" />羽毛球 <input
type="checkbox" name="habit" value="篮球" />篮球 <input
type="checkbox" name="habit" value="旅游" />旅游
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交" />
| <input type="reset" value="重置" /></td>
</tr>
</table>
</form>
</body>
param.jsp
<body>
<h3>EL中的隐含对象:header,headerValues,param,paramValues</h3>
<hr>
<fmt:requestEncoding value="GBK" />
HTTP连接头部的host值: ${header["host"]}
<br> HTTP头部的accept值: ${header.accept}
<br> HTTP头部的user-agent值: ${header["user-agent"]}
<br>
<hr width="50%" align="left">
姓名:
<c:out value="${param.name}" />
<br> 性别:
<c:out value="${param.sex}" />
<br> 专业:
<c:out value="${param['specialty']}" />
<br> 兴趣:
<c:out value="${paramValues.habit[0]}" />
<c:out value="${paramValues.habit[1]}" />
<c:out value="${paramValues.habit[2]}" />
<c:out value="${paramValues.habit[3]}" />
<c:out value="${paramValues.habit[4]}" />
</body>
注:需要引入JSTL核心标签库和国际化标签库。
3.3 EL中pageScope、 requestScope、 sessionScope、 applicationScope隐含对象实例演示
这四个隐含对象表示先前讨论的各种属性作用域。可以用它们来查找特定作用域中的标识符,而不用依赖于 EL 在默认情况下使用的顺序(首先 page,然后 request、 session,再 application)查找过程。
它们和 JSP 中的 page、 request、 session 以及 application 隐含对象非常相似,但是有一点要注意的,这里的四个隐含对象只能用来取得范围属性值,而不能取得其他相关信息。
下面创建一个 scope.jsp 文件。首先使用<c:set>标签在不同的范围内( page、 request、 session 和application)设置相同的 name 变量,然后调用相应的 pageScope、 requestScope、 sessionScope 以及applicationScope 隐含对象来取得 name 变量值。
<head><title>pageScope、requestScope、sessionScope以及applicationScope隐含对象在EL中使用</title></head>
<body>
<h4>EL中的pageScope、requestScope、sessionScope以及applicationScope隐含对象</h4>
<hr>
<c:set var="name" value="pageValue" scope="page" />
<c:set var="name" value="requestValue" scope="request" />
<c:set var="name" value="sessionValue" scope="session" />
<c:set var="name" value="applicationValue" scope="application" />
\${name}: <c:out value="${name}" /> <br>
\${pageScope.name}: <c:out value="${pageScope.name}" /> <br>
\${requestScope.name}: <c:out value="${requestScope.name}" /> <br>
\${sessionScope.name}: <c:out value="${sessionScope.name}" /> <br>
\${applicationScope.name}: <c:out value="${applicationScope.name}" /> <br>
</body>
3.4 cookie和initParam隐含对象
cookie 隐式对象提供了对由请求设置的 cookie 名称的访问。这个对象将所有与请求相关联的 cookie名称映射到表示那些 cookie 特性的 Cookie 对象。
JSTL 标准标签并没有提供设置 cookie 的动作,因此这个动作通常都是开发者必须要去做的事情,而不是交给前端。如已经在 cookie 中设置了一个 name 的值,则可以通过${cookie.name}来取得它的值。
最后一个 EL 隐式对象 initParam 也是一个映射,它储存与 Web 应用程序相关联的所有上下文的初始化参数的名称和值。初始化参数是通过 web.xml 部署描述符文件指定的,该文件位于应用程序的WEB-INF 目录中。例如在 web.xml 文件中设定如下:
<context-param>
<param-name>username</param-name>
<param-value>Johnson</param-value>
</content-param>
那么在程序当中就可以直接使用${initParam.username}来取得 username 参数的值“ Johnson”。
参考资料:
- 《JSP宝典》