您的位置:首页 > Web前端 > JavaScript

JSP中使用EL表达式

2015-09-18 18:04 661 查看
添加EL表达式
EL可以直接用在JSP的任何位置,除了少数例外情况。首先,EL表达式不能用在任何指令中,不要尝试这么做。在编译JSP时,指令(<%@page %>、<%@include %>和<%@taglib %>)将会被执行,但EL表达式是在稍后渲染JSP时执行,所以在其中添加EL表达式是无法正常工作的。另外,JSP声明(<%!
%>)、脚本(<%%>)或者表达式(<%= %>)中的EL表达式也是无效的。如果用在任何一种情况中,EL表达式都将被忽略,或者更坏的情况会导致语法错误。
除此之外,EL表达式可以添加到其他任何位置。一种常见的情况是将EL表达式添加到输出到屏幕的简单文本中:
The user will see ${expr} text and will know that ${expr} is good.
该例子中包含了两个EL表达式,当表达式执行时,结果将会内嵌在文本中显示到屏幕。如果第一个表达式的执行结果为“red”,第二个表达式的执行结果为“it”,那么结果将显示为:
The user will see red text and will know that it is good.

另外,表达式还可以用在标准的HTML标签特性中,如下面的代码所示:

<input type="text" name="something" value="${expr}"/>
HTML标签特性并不是唯一可以使用EL表达式的地方。还可以在JSP标签特性中使用,如下面的代码所示:
<c:url value="/something/${expr}/${expr}" />
<c:redirect url="${expr}" />
如你所见,EL表达式可以只是特性值的一部分。另外,特性值的任意一个或者多个部分都可以包含EL表达式。此时,你可以会想到另一个HTML特性,例如JavaScript或者层叠样式表。JSP引擎不会解析这些HTML特性中的内容,它会将其中的内容当作普通文本输出到响应中,所以可以在引用或者文本形式中包含EL表达式:
<script type="text/javascript" lang="javascript">
var employeeName='${expr}';
var booleanValue='${expr}';
var numericValue='${expr}';
</script>
<style type="text/css">
span.error
{
color: ${expr};
background-image: url('/some/place/${expr}.png');
}
</style>


EL语法

EL语法是弱类型,并且它包含了许多内建的隐式类型转换,类似于PHP或者JavaScript这样的语言。表达式主要的规则时执行后要产生某个值。例如,${obejct.method()}只有在其中的方法返回非空值时,该表达式才是有效的。表达式${x=5}将把5赋值给x,并且在页面中渲染出EL表达式中的5。
EL并不是设计用来替代Java的;相反,它的目的是为了提供一种创建JSP的工具,从而避免在JSP中使用Java。
比较运算符<、 lt、>、gt、<=、le、>=和ge类似于相等运算符。任何两个实现了java.lang.Comparable接口的对象都可以使用比较运算符进行比较,只要他们的类型相同或者其中一个对象可以被强制转换成另一个对象的类型。所以EL中的${ol>=o2} 等同于Java中的o1.compareTo(o2)>=0。
以下3个例子都是相等的,它们将产生相同的结果

The user will see ${expr} text and will ${expr}
${'The user will see ' += expr += " text and will " += expr += "." }
${"The user will see " += expr += "text and will "+= expr += "."}


如果某些对象中的expr结果不是字符串,它将被强制转型为字符串(调用对象的toString方法)

该样例将会构造出一个包含了5个不同类型的HashSet<Object>。第5个对象x可以是任何数据类型。

{1,2,'three',4.00,x} //集合
构造列表的方法与构造集合的方法基本一致,区别在于列表使用的是方括号,而集合使用的是花括号。

[1,2,'three',[x,y],{'foo','bar'}]  //列表
注意ArrayList<Object>中的第4个元素是另一个列表,第5个元素是一个集合。
{'one':1 ,2:'two', 'key':x, 'list':[1,2,3]} //map
最后创建一个HashMap<Object,Object>的集合字面量,这里的元素也都以逗号分割开。不过Map更复杂一些,因为它们要求包含键值对,而不只是值。

访问Map的值的方式相当简单,与JavaBean中访问属性的方式很相像。假设现在有个名为map的Map,其中键username被影射到了值"Jonathon"上,键userId被影射到了值"27"上。如下面的样例所示,可以使用中括号操作符访问map的这两个属性

${map["username"]}
${map["userId"]}
访问列表也同样的简单。例如,现在有一个列表(命名为list),它包含了值“blue”、“red”、和 “green” ,按照0到2的顺序一次存储。下面讲通过中括号操作符将它当作一个数组来访问其中的值。
${list[0]}
${list[1]}
${list[2]}
其他两种集合的值,集合和队列不能通过EL访问。这些集合并未提供直接访问值的方式,例如列表中的索或者map中的键。在集合和队列中也没有访问方法。只能通过遍历的方式访问他们。

对象属性和方法
${shirt.size}
表达式 shirt.size将会变成调用shirt.getSize()的快捷方式。这种方式可以应用于任何类型的任何字段。
对于boolean字段,它的访问方法可以以 get 或者 is开头。
还可以使用[]操作符访问属性。下面表达式将分别使用getSize,getStyleCategory 和 getExpired或者 isExpired方法访问属性size,styleCategory和expired 。
${shirt["size"]}
${shirt["styleCategory"]}
${shirt["expired"]}


EL表达式中使用作用域变量
EL求值程序将按照下面的流程解析变量:
(1)检查该变量是否属于隐式变量
(2)如果变量不在11个隐式变量之中,EL求值程序将在页面作用域中寻找特性( PageContext.getAttribute("variable") ),检查其中是否包含了同名的变量(大小写敏感)。如果找到了一个匹配的页面作用域特性,它将使用该特性值作为变量的值。
(3)如果未找到匹配的页面特性,求值程序接着将寻找同名的请求特性(HttpServletRequest.getAttribute("variable"))。如果找到了,就使用该特性值作为变量值。
(4)接着求值程序将寻找同名的会话特性(HttpSession.getAttribute("variable"))。如果找到了,就使用该特性值作为变量值。
(5)接着求值程序将寻找同名的应用特性(ServletContext.getAttribute("variable"))。如果找到了,就使用该特性值作为变量值。
(6)在求值程序搜索完所有的位置之后,如果它未匹配变量名的隐式变量或者特性,它将会报错。

<%--@elvariable id="user" type="com.wrox.User"   --%>
这个注释将高速IDE “是的,在本页的隐式作用域中有一个user变量,它的类型是com.wrox.User”。这种方式的优点是:因为IDE知道有变量存在并且知道它的类型,那么它就可以提供自动完成和职能建议,否则它是无法做到的。它还可以验证你的EL表达式是否正确。即使使用的IDE不支持这种约定,维护该JSP的其他开发者也可以快速地了解EL变量的类型。

使用隐式的EL变量
EL表达式中有11个隐式EL变量可用。除了其中一个之外,其他都是Map对象

pageContext 是PageContext类的一个实例,并且是唯一一个不是Map的隐式EL变量。通过使用该变量,你可以访问页面错误数据和异常对象、表达式求值程序、输出writer、JSP Servlet 实例、请求和响应、ServletContext、ServletConfig和会话
pageScope是Map<String,Object>的一个实例,它包含了所有绑定到PageContext的特性
requestScope是Map<String,Object>的一个实例,它包含了所有绑定到ServletRequest的特性
sessionScope是Map<String,Object>的一个实例,它包含了所有绑定到当前会话的特性。
applicationScope是Map<String,Object>的一个实例,它包含了所有绑定到ServletContext实例的特性。
param和paramValues类似,它们都提供了对请求参数的访问。变量param是一个Map<String,Object>的实例,它包含了任何多值参数的第一个值,而paramValues是Map<String,String[]>的一个实例,它包含了所有参数的所有值。
header和headerValues提供了对请求头的访问,header是Map<String,String>的一个实例,它包含了所有多值头的第一个值,而headerValues是Map<String,String[]>的一个实例,它包含了所有头的所有值
initParam是Map<String,String>的一个实例,它包含了该应用程序中ServletContext实例的所有上下文初始化参数
cookie是Map<String,javax.servlet.http.Cookie>的一个实例,它包含了用户浏览器发送的请求中的所有cookie

保留关键字
true 、false、null、instanceof、empty、div、mod、and、or、not、eq、ne、lt、gt、le、ge
关键字 empty用于验证某些集合、Map或者数组是否含有值,或者某些字符串是否含有一个或多个字符。如果它们为null或者“空”,那么表达式的结果将为真;否则,结果为假
${empty x}
关键字div和mod分别对应着Java数学运算符除(/)和求余(%),它们只是数学运算符的替代关键字。如果愿意的话,你仍然可以使用/和%。关键字and、or和not分别对应着Java逻辑运算符&&、 ||和!。如同数学运算符一样,如果你愿意,也扔可以使用传统的逻辑运算符。最后,eq、ne、lt、gt、le和ge运算符分别是Java关系运算符==、!=、<、>、<=、>=的替代关键字。

使用流API访问集合
1. 过滤流
${books.stream().filter(b->b.author =="John F. Smith")}
该例中使用的谓词是一个接受图书作为参数的lambda表达式,它将检测图书的作者是否是John F. Smith。
还可以使用特殊的distinct操作过滤出重复值。下面的表达式将从列表中移除重复的3和5.
${ [1,2,3,3,4,5,5,5,6].stream().distinct() }
2. 操作值
可以使用forEach操作流中的值。
${books.stream().forEach(b->b.setLastViewed(Instant.now()) ) }
3.对流进行排序
使用排序操作可以对流进行排序。对于Stream<E>,排序操作将接受一个java.util.Comparator<E>。
${books.stream().sorted( (b1,b2)->b1.title.compareTo(b2.title) )}
排序操作还存在一个变种,该操作不接受任何参数,相反,它认为流中的元素都已经实现了java.lang.Comparable接口,这意味着你可以对它们进行自然排序。下面的样例将对数字列表进行从小到大地排序。结果列表为-2、0、3、5、7、8、19。

${ [8,3,19,5,7,-2,0].stream().sorted() }
4. 限制流的大小
通过limit和substream操作可以限制流的元素数目。使用limit只是简单地从流中截去特定数目元素之后的所有元素。对于分页操作来说,substream更有用,因为你可以指定开始索引(包含)和结束索引(不包含)。
${books.stream().limit(10)}

${books.stream().substream(10,20)}
5.转换流
使用映射操作,你可以将流汇总的元素转换为某些其他类型的元素。映射操作将接受一个映射器,该映射器将接受一个元素的类型并返回一个数字。对于Stream<S>,映射将希望接受一个参数为类型S的lambda表达式。如果该lambda表达式返回了一个不同类型的R,那么结果流将变为Stream<R>。下面的样例接受了一个List<Book>,获得了它的Stream<Book>,并将它转换为只包含图书标题的Stream<String>:
${books.stream().map(b->b.title)}
当然,你可以返回更复杂的类型。例如,使用一个不同的类型DisplayableBook,包含一个有限的属性集。或者你可以创建一个隐式的List或者Map,返回一个Stream<List<Object>>或者Stream<Map<Object,Object>>:
${books.stream().map(b->[b.title,b.author]) }
${books.stream().map(b->{"title":b.title,"author":b.author})}


6. 使用终结操作

只是使用Stream的话并不是很有用;必须要对最终结果进行处理。

返回结果

下面的表达式将分别返回包含了图书标题的String[]或者List<String>

${books.stream().map(b->b.title).toArray()}
${books.stream().map(b->b.title).toList()}


使用聚集函数

可以在流中使用min、max、average、sum和count操作进行聚集计算
${books.stream().map(b->b.price()).min() }
${books.stream().map(b->b.price()).max() }


返回第一个值

通过findFirst操作可以返回结果流中的第一个元素

${books.stream().filter(b->b.author=="John F. Smith").findFirst()}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: