软件开发实训(720科技)--Spring MVC 第八章

内容关键字  :
表达式语言语法
关键字
【】和.运算符
取值规则
访问java bean
el隐式对象
使用其他el运算符
引用静态属性和静态方法
创建set list 和map
访问列表元素和map条目
操作集合
格式化集合
使用html注解
格式化数字
格式化日期
如何在jsp2.0及其更高版本 中配置el
授课老师 720科技 张森鹏
一:知识笔记

JSP 2.0 最重要的特性之一就是表达式语言(EL),JSP 用户可以用它来访问应用程序数据。由于受到 ECMAScript 和 XPath 表达式语言的启发,EL 也设计成可以轻松地编写免脚本的 JSP 页面。也就是说,页面不使用任何 JSP 声明、表达式或者 scriptlet。第 11 章会进一步介绍为何无脚本的的JSP 页面是一个最佳实践。

本章介绍如何使用 EL 表达式在 JSP 页面中显示数据和对象属性。它涵盖了最新的 EL 3.0

版本技术。

本章中的所有示例都可以在本书附带的zip 文件中的 el-demo 项目中找到。

 

8.1 表达式语言简史

JSP 2.0 最初是将 EL 应用在 JSP 标准标签库(JSTL1.0 规范中。JSP 1.2 程序员将标准库导入到他们的应用程序中,就可以使用ELJSP 2.0 及其更高版本的用户即使没有 JSTL, 也能使用 EL,但在许多应用程序中,还是需要 JSTL 的,因为它里面还包含了与 EL 无关的其他标签。

JSP 2.1 JSP 2.2 中的 EL 要将JSP 2.0 中的EL 与 JSFJavaServer Faces)中定义的 EL 统一起来。JSF 是在 Java 中快速构建 Web 应用程序的框架,并且是构建在 JSP 1.2 之上。由于JSP 1.2 中缺乏整合式的表达式语言,并且JSP 2.0 EL 也无法满足JSF 的所有需求,因此为JSF 1.0 开发出了一款 EL 的变体。后来这两种语言变体合二为一。

2013 年 月发布了EL  3.0 版本(JSR  341),EL 不再是 JSP 或任何其他技术的一部分,而是一个独立的规范。EL 3.0 添加了对 lambda 表达式的支持,并允许集合操作。其 lambda 支持不需要 Java SE 8Java SE 7 即可。


 

8.2 表达式语言的语法

EL 表达式以 ${  开头,并以 }  结束。EL 表达式的结构如下:

${expression} #{expression}

例如,表达式 x+y,可以写成:

${x+y}

#{x+y}

$ {exp}和#{exp}结构都由 EL 引擎以相同的方式进行计算。然而,当 EL 未被用作独立引擎而是使用诸如 JSF JSP 的底层技术时,该技术可以不同地解释构造。例如,在 JSF 中,${exp}结构用于立即计算,#{expr}结构用于延迟计算(即表达式直到系统需要它的值时,才进行计算)。另一方面,立即计算的表达式,会在 JSP 页面编译时同时编译,并在执行 JSP 页面时被执行。在 JSP 2.1 和更高版本中,#{exp}表达式只能在接受延迟表达式的标签属性中使用。

两个表达式可以连接在一起。对于一系列的表达式,它们的取值将是从左到右进行,计算结果的类型为 String,并且连接在一起。假如 a+b 等于 8c+d 等于 10,那么这两个表达式的计算结果将是 810

${a+b}${c+d}

表达式${a+b}and${c+d}的取值结果则是 8and10

如果在定制标签的属性值中使用 EL 表达式,那么该表达式的取值结果字符串将会强制变成该属性需要的类型:

<my:tag someAttribute="${expression}"/>

${这样的字符顺序就表示是一个 EL 表达式的开头。如果需要的只是文本${,则需要在它前面加一个转义符,如\${
8.2.1 关键字

以下是关键字,它们不能用作标识符:

and eq gt true instanceof


8.2 表达式语言的语法

or ne le false empty not lt ge null div mod

8.2.2 [ ].运算符

EL 表达式可以返回任意类型的值。如果 EL 表达式的结果是一个带有属性的对象,则可以利用[ ]或者.运算符来访问该属性。[ ].运算符类似;[ ]是比较规范的形式,.运算符则比较快捷。

为了访问对象的属性,可以使用以下任意一种形式:

${object["propertyName"]}

${object.propertyName}

但是,如果 propertyName 不是有效的 Java 变量名,只能使用[ ]运算符。例如,下面这两个 EL 表达式就可以用来访问隐式对象标题中的HTTP 标题 host

${header["host"]}

${header.host}

但是,要想访问 accept-language 标题,只能使用[ ]运算符,因为 accept-language 不是一个合法的Java 变量名。如果用运算符访问它,将会导致异常。

如果对象的属性碰巧返回带有属性的另一个对象,既可以用[ ],也可以用运算符来访问第二个对象的属性。例如,隐式对象 pageContext 是表示当前 JSP 的 PageContext 对象。它有 request 属性,表示 HttpServletRequestHttpServletRequest 带有 servletPath 属性。那么, 下列几个表达式的结果相同, 均能得出 pageContext 中 HttpServletRequest 

servletPath 属性值:

${pageContext["request"]["servletPath"]}

${pageContext.request["servletPath"]}

${pageContext.request.servletPath}

${pageContext["request"].servletPath}

要访问 HttpSession,可以使用以下语法:

${pageContext.session}

例如,以下表达式会得出 session 标识符。

${pageContext.session.id}

 

8.2.3 取值规则

EL 表达式的取值是从左到右进行的。对于expr-a[expr-b]形式的表达式,其 EL 表达式的

 

取值方法如下:

1)先计算 expr-a 得到 value-a

2)如果 value-a 为 null,则返回 null

3)然后计算 expr-b 得到 value-b

4)如果 value-b 为 null,则返回 null

5)如果 value-a 为 java.util.Map,则会查看 value-b 是否为 Map 中的一个 key。若是,则返回 value-a.get(value-b),若不是,则返回 null

6)如果 value-a 为 java.util.List,或者假如它是一个 array,则要进行以下处理: a.强制 value-b 为 int,如果强制失败,则抛出异常。

b.如果 value-a.get(value-b)抛出 IndexOutOfBoundsException,或者假如 Array.get (value-a, value-b)抛出 ArrayIndexOutOfBoundsException,则返回 null

c.否则,若 value-a 是个 List,则返回 value-a.get(value-b);若 value-a 是个 array, 则返回 Array.get(value-a, value-b)

7)如果 value-a 不是一个 MapList 或者 array,那么,value-a 必须是一个 JavaBean。在这种情况下,必须强制value-b 为 String。如果 value-b 是 value-a 的一个可读属性,则要调用该属性的 getter 方法,从中返回值。如果 getter 方法抛出异常,该表达式就是无效的,否则, 该表达式有效。

 

8.3 访问JavaBean

利用[]运算符,都可以访问 bean 的属性,其结构如下:

${beanName["propertyName"]}

${beanName.propertyName}

例如,访问 myBean 的 secret 属性,可以使用以下表达式:

${myBean.secret}

如果该属性是一个带属性的对象,那么同样也可以利用.[]运算符来访问第二个对象的该属性。假如该属性是一个 MapList 或者 array,则可以利用 8.2 节介绍的访问 Map 值或 List 成员或 array 元素的同样规则。

 

8.4 EL 隐式对象

JSP 页面中,可以利用 JSP 脚本来访问 JSP 隐式对象。但是,在免脚本的 JSP 页面中, 则不可能访问这些隐式对象。EL 允许通过提供一组它自己的隐式对象来访问不同的对象。EL 隐式对象见表 8.1

表 8.1   EL 隐式对象

 

对象

描述

pageContext

这是当前 JSP 的 javax.servlet.jsp.PageContext

initParam

这是一个包含所有环境初始化参数并用参数名作为 key 的 Map

 

param

这是一个包含所有请求参数并用参数名作为 key 的 Map。每个 key 的值就是指定名称的第一个参数值。因此,如果两个请求参数同名,则只有第一个能够利用 param 获取值。要想访问同名参数的所有参数值,可用 params 代替

 

paramValues

这是一个包含所有请求参数并用参数名作为 key 的 Map。每个 key 的值就是一个字符串数组,其中包含了指定参数名称的所有参数值。就算该参数只有一个值,它也仍然会返回一个带有一个元素的数组

 

header

这是一个包含请求标题并用标题名作为 key 的 Map。每个 key 的值就是指定标题名称的第一个标题。换句话说,如果一个标题的值不止一个,则只返回第一个值。要想获得多个值的标题,得用 headerValues 对象代替

 

headerValues

这是一个包含请求标题并用标题名作为key Map。每个 key 的值就是一个字符串数组, 其中包含了指定标题名称的所有参数值。就算该标题只有一个值,它也仍然会返回一个带有一个元素的数组

cookie

这是一个包含了当前请求对象中所有 Cookie 对象的 MapCookie 名称就是 key 名称, 并且每个 key 都映射到一个 Cookie 对象

applicationScope

这是一个包含了 ServletContext 对象中所有属性的 Map,并用属性名称作为 key

sessionScope

这是一个包含了 HttpSession 对象中所有属性的 Map,并用属性名称作为 key

requestScope

这是一个 Map,其中包含了当前 HttpServletRequest 对象中的所有属性,并用属性名称作为 key

pageScope

这是一个 Map,其中包含了全页面范围内的所有属性。属性名称就是 Map 的 key

下面逐个介绍这些对象。

 

8.4.1 pageContext

pageContext 对象表示当前 JSP 页面的 javax.servlet.jsp.PageContext。它包含了所有其他的

JSP 隐式对象,见表 8.2


 

表 8.2   JSP 隐式对象

 

对象

EL 中的类型

request

javax.servlet.http.HttpServletRequest

response

javax.servlet.http.HttpServletResponse

out

javax.servlet.jsp.JspWriter

session

javax.servlet.http.HttpSession

application

javax.servlet.ServletContext

config

javax.servlet.ServletConfig

PageContext

javax.servlet.jsp.PageContext

page

javax.servlet.jsp.HttpJspPage

exception

java.lang.Throwable

例如,可以利用以下任意一个表达式来获取当前的ServletRequest

${pageContext.request}

${pageContext["request"]

并且,还可以利用以下任意一个表达式来获取请求方法:

${pageContext["request"]["method"]}

${pageContext["request"].method}

${pageContext.request["method"]}

${pageContext.request.method}

表 8.3 列出了 pageContext.request 中一些有用的属性。

表 8.3 pageContext.request 中一些有用的属性

 

属性

说明

characterEncoding

请求的字符编码

contentType

请求的 MIME 类型

locale

浏览器首先 locale

locales

所有 locale

protocol

HTTP 协议,例如:HTTP/1.1

remoteAddr

客户端 IP 地址

remoteHost

客户端 IP 地址或主机名

scheme

请求发送方案,HTTP 或 HTTPS

serverName

服务器主机名

serverPort

服务器端口

secure

请求是否通过安全链接传输


 

对请求参数的访问比对其他隐式对象更加频繁;因此,这里提供了 param 和 paramValues

两个隐式对象。

 

8.4.2 initParam

隐式对象 initParam 用于获取上下文参数的值。例如,为了获取名为 password 的上下文参数值,可以使用以下表达式:

${initParam.password}

或者

${initParam["password"]

 

 

8.4.3 param
隐式对象 param 用于获取请求参数值。这个对象表示一个包含所有请求参数的 Map。例如,要获取 userName 参数,可以使用以下任意一种表达式:

${param.userName}

${param["userName"]}

 

 

8.4.4 paramValues
利用隐式对象 paramValues 可以获取一个请求参数的多个值。这个对象表示一个包含所有请求参数,并以参数名称作为 key 的 Map。每个 key 的值是一个字符串数组,其中包含了指定参数名称的所有值。即使该参数只有一个值,它也仍然返回一个带有一个元素的数组。例如, 为了获得 selectedOptions 参数的第一个值和第二个值,可以使用以下表达式:

${paramValues.selectedOptions[0]}

${paramValues.selectedOptions[1]}

 

 

8.4.5 header
隐式对象 header 表示一个包含所有请求标题的 Map。为了获取 header 值,要利用 header

名称作为 key。例如,为了获取 accept-language 这个 header 值,可以使用以下表达式:

${header["accept-language"]}

如果 header 名称是一个有效的Java 变量名,如 connection,那么也可以使用.运算符:

${header.connection}


 

8.4.6 headerValues
隐式对象 headerValues 表示一个包含所有请求 head 并以 header 名称作为 key 的 Map。但是,与head 不同的是,隐式对象 headerValues 返回的 Map 返回的是一个字符串数组。例如, 为了获取标题 accept-language 的第一个值,要使用以下表达式:

${headerValues["accept-language"][0]}

 

8.4.7 cookie
隐式对象 cookie 可以用来获取一个 cookie。这个对象表示当前 HttpServletRequest 中所有

cookie 的值。例如,为了获取名为 jsessionid 的 cookie 值,要使用以下表达式:

${cookie.jsessionid.value}

为了获取 jsessionid cookie 的路径值,要使用以下表达式:

${cookie.jsessionid.path}

 

8.4.8 applicationScopesessionScoperequestScope pageScope
隐式对象 applicationScope 用于获取应用程序范围级变量的值。假如有一个应用程序范围级变量 myVar,就可以利用以下表达式来获取这个属性:

${applicationScope.myVar}

注意,在 servlet/JSP 编程中,有界对象是指在以下对象中作为属性的对象:PageContext

ServletRequest HttpSession 或者 ServletContext 。隐式对象 sessionScope requestScope 

pageScope 与 applicationScope 相似。但是,其范围分别为 sessionrequest 和 page

有界对象也可以通过没有范围的 EL 表达式获取。在这种情况下,JSP 容器将返回

PageContextServletRequestHttpSession 或者 ServletContext 中第一个同名的对象。执行顺序是从最小范围(PageContext)到最大范围(ServletContext)。例如,以下表达式将返回 today引用的任意范围的对象。

${today}

 

8.5 使用其他EL 运算符

除了.和 [] 运算符外,EL 还提供了其他运算符:算术运算符、关系运算符、逻辑运算

8.5 使用其他EL 运算符

符、条件运算符,以及 empty 运算符。使用这些运算符时,可以进行不同的运算。但是,由于 EL 的目的是方便免脚本 JSP 页面的编程,因此,除了关系运算符外,这些 EL 运算符的用处都很有限。

8.5.1 算术运算符

算术运算符有 种。

— 加法(+)。

— 减法()。

— 乘法(*)。

— 除法(/和 div)。

— 取余/取模(%和 mod)。

除法和取余运算符都有两种形式,与 XPath 和 ECMAScript 是一致的。

注意,EL 表达式的计算按优先级从高到低、从左到右进行。下列运算符是按优先级递减顺序排列的:

— */div%mod

 

— +-

这表示*/div%以及 mod 运算符的优先级相同,+的优先级相同,但第二组运算符的优先级小于第一组运算符。因此,表达式

${1+2*3}

的运算结果是 7,而不是 9

8.5.2 关系运算符

下面是关系运算符列表:

— 等于(==和 eq)。

— 不等于(!=和 ne)。

— 大于(>和 gt)。

— 大于或等于(>=和 ge)。


 

— 小于(<和 lt)。

— 小于或等于(<=和 le)。

例如,表达式${3==4}返回 False${“b”<“d”}则返回 True

8.5.3 逻辑运算符

下面是逻辑运算符列表:

— 和(&&和 and)。

— 或(||  和 or)。

— 非(!和 not)。

8.5.4 条件运算符

EL 条件运算符的语法如下:

${statement? A:B}

如果 statement 的计算结果为 True,那么该表达式的输出结果就是 A,否则为 B

例如,利用下列 EL 表达式可以测试 HttpSession 中是否包含名为 loggedIn 的属性。如果找到这个属性,就显示“You have logged in(您已经登录)”。否则显示“You have not logged in

(您尚未登录)”。

${(sessionScope.loggedIn==null)? "You have not logged in" : "You have logged in"}

8.5.5 empty 运算符

empty 运算符用来检查某一个值是否为 null 或者 empty。下面是一个 empty 运算符的使用范例:

${empty X}

如果为 null,或者说 是一个长度为 的字符串,那么该表达式将返回 True。如果 X

是一个空 Map、空数组或者空集合,它也将返回 True。否则,将返回 False

8.5.6 字符串连接运算符

+ =运算符用于连接字符串。 例如,以下表达式打印 a + b 的值。


8.6 引用静态属性和静态方法

$ {a + = b}

 

8.7 创建Set、List 和Map

可以动态的创建 SetList 和 Map。创建一个 Set 的语法如下:

{ comma-delimited-elements }

例如,如下表达式创建一个 个数字 Set

${{1, 2, 3, 4, 5}}

创建一个 List 的语法如下

[ comma-delimited-elements ]

例如,如下表达式创建了一组花名的 List

${["Aster", "Carnation", "Rose"]}

最后,创建一个 Map 的语法为:

{ comma-delimited-key-value-entries}


 

 

如下为一组国家及其首都的 Maps

${{"Canada": "Ottawa", "China": "Beijing", "France": "Paris"}}

 

8.8 访问列表元素和 Map 条目

可以通过索引来访问 List,如下表达返回 Cities 的第一个元素

${cities[0]}

可以通过如下方式访问 Map

${map[key]}

例如,下面的表达式返回“Ottawa”:

${{"Canada": "Ottawa", "China": "Beijing"} ["Canada"]}

 

8.9 操作集合

EL 3.0 带来了很多新特性。 其中一个主要的贡献是操纵集合的能力。你可以通过调用流方法将集合转换为流来使用此功能。

下面展示如何将列表转换为流,假设 myList 是一个 java.util.List

${myList.stream()}

大部分流的操作会返回另一个流,因而可以形成链式操作。

$ {MyList.stream().operation-1().operation-2().toList()}

在链式操作的末尾,通常调用 toList 方法,以便打印或格式化结果。以下小节介绍了你可以对流执行的一些操作

 

8.9.1 toList

toList 方法返回一个 List,它包含与当前流相同的成员。调用此方法的主要目的是轻松地打印或操作流元素。下面是一个将列表转换为流并返回列表的示例:

$ {[100, 200, 300].stream().toList()}

当然这个例子没有什么用。稍后在接下来的小节中,你将看到更多的例子。

 

8.9.2 toArray

与 toList 类似,但返回一个 Java 数组。同样,在数组中呈现元素通常是有用的,因为许多Java 方法将数组作为参数。这里是一个 toArray 的例子:

$ {["One""Two""Three"].stream().toArray()}

与 toList 不同,toArray 不打印元素。因此,toList 更经常使用。

 

8.9.3 limit

limit 方法限制流中元素的数量。名为 cities 的 List 包含 个城市:

[Paris, Strasbourg, London, New York, Beijing, Amsterdam, San Francisco]

下面的代码将元素的数量限制为 3

$ {cities.stream().limit(3).toList()}

执行时,表达式将返回此列表:

[Paris, Strasbourg, London]

如果传递给 limit 方法的参数大于元素的数量,则返回所有元素。

 

8.9.4 sort

此方法对流中的元素进行排序。例如,这个表达式

$ {cities.stream().sorted().toList()}

返回如下排序后的列表。

[Amsterdam, Beijing, London, New York, Paris, San Francisco, Strasbourg]

 

8.9.5 average

此方法返回流中所有元素的平均值。其返回值是一个 Optional 对象,它可能为 null。需要调用 get()获取实际值。

此表达式返回 4.0

$ {[1,3,5,7].stream().average().get()}


8.9.8 min
此方法返回流的元素中的最小值。同 average 方法一样,其返回值是一个 Optional 对象, 因此你需要调用 get 方法来获取实际值。例如,此表达式返回 1

$ {[1,3,100,1000].stream().min().get()}

 

8.9.9 max
此方法返回流的元素中的最大值。同 average 方法一样,其返回值是一个 Optional 对象, 因此你需要调用 get 方法来获取实际值。例如,此表达式返回 1000

$ {[1,3,100,1000].stream().max().get()}

 

8.9.10 map
此方法将流中的每个元素映射到另一个流中的另一个元素,并返回该流。此方法接受一个 lambda 表达式。

例如,此映射方法使用 lambda 表达式 x - > 2 * x,这实际上将每个元素乘 2,并将它们返回到新的流中。

$ {[1,3,5].stream().map(x - > 2 * x).toList()}

返回列表如下:

[2,6,10]

下面是另一个示例,它将字符映射为大写。

$ {cities.stream().map(x - > x.toUpperCase()).toList()}

它返回以下列表。

[PARISSTRASBOURGLONDONNEW YORKBEIJINGAMSTERDAMSAN FRANCISCO]


 

8.9.11 filter
此方法根据 lambda 表达式过滤流中的所有元素,并返回包含结果的新流。例如,以下表达式测试城市是否以“S”开头,并返回所有的结果。

$ {cities.stream().filter(x - > x.startsWith("S")).toList()}

它产生的列表如下所示:

[Strasbourg, San Francisco]

 

8.9.12 forEach
此方法对流中的所有元素执行操作。它返回 void。 例如,此表达式将城市中的所有元素打印到控制台。

$ {cities.stream().forEach(x - > System.out.println(x))}

8.10 格式化集合

由于 EL 定义了如何写表达式而不是函数,因此无法直接打印或格式化集合,毕竟,打印和格式化不是 EL 负责的领域。然而,打印和格式化是两个不能忽视的重要任务。

如果你是 EL 3.0 的新手,但熟悉 JSP,那么格式化集合最简单的方法就是使用第 章中讨论的 JSTL。然而,具有强大的功能的 EL  3.0 应足以解决这些问题,并允许我们完全抛弃

JSTL

例如,你可以尝试使用 forEach,类似于 JSTL 的 forEach。以下代码可以在 Tomcat 8 上运行。

$ {cities.stream().forEach(x - > pageContext.out.println(x))}

遗憾的是,这在 GlassFish 4 中不起作用,所以 forEach 不能通用。

我最终想出的两个解决方案不像 forEach 那样优雅,但在所有主要的 servlet 容器上都可用。第一个解决方案适用于 Java SE 7。第二个解决方案可能比第一个更优雅,但只适用于 Java SE 8

 

8.10.1 使用 HTML 注释

List 的字符串表示形式如下所示:


8.10 格式化集合

[element-1element-2...]

现在,如果我想在HTML 中呈现列表元素,需要这样写。

<ul>

<li> element-1 </ li>

<li> element-2 </ li>

...

</ul>

现在,你可能已经注意到每个元素必须转向<li> element-n </ li>。我怎么做?如果你一直密切关注,你可能仍然记得 map 方法可以用来转换每个元素。所以,我会有这样的内容:

$ {myList.stream().map(x - >"<li>"+ = x + ="</ li>").toList()}

它给了我这样的 List

[<li> element-1 </ li><li> element-2 </ li>...]

足够接近,但仍然需要删除括号和逗号。遗憾的是,你不能控制列表的字符串表示。好在你可以使用HTML 注释。

所以,这里是一个例子:

<ul>

<!-${cities.stream().map(x - >"--> <li>"+ = x + ="</ li> <!--").toList()}-->

</ul>

结果如下所示:

<ul>

<!--[--><li>Paris</li><!--, --><li>Strasbourg</li><!--, -->

<li>London</li><!--, --><li>New York</li><!--, -->

<li>Beijing</li><!--, --><li>Amsterdam</li><!--, -->

<li>San Francisco</li><!--]-->

</ul>

 


这有效地注释掉了括号和逗号。虽然结果看起来有点凌乱,但它是有效的 HTML,更重要的是,它能工作!

图 8.2 显示了页面显示结果。

这里有另一个例子,这个例子用表格格式化显示地址信息。

<table>

<tr><th>Street</th><th>City</th></tr>

<!--${addresses.stream().map(a->"-->

 

 

 

 

图 8.2 使 用 HTML 注 释 来格式化集合


<tr><td>"+=a.streetName+="</td><td>"+=a.city+="</td></tr><!--").toList()}


-->

</table>

 

8.10.2 使用 String.join()

这第二个解决方案之所以有效,因为EL 3.0 允许你引用静态方法。在 Java 8 中,String 类新增了一些静态方法,其中一个方法是 join,这正是我寻找的解决方案。有两个重载 join 方法,但这里要用到的一个方法如下所示。

public static String joinCharSequence delimiter, Iterable <extends CharSequence> elements

此方法返回用指定分隔符连接在一起的 CharSequence 元素组成的字符串。而 java.util.

Collection 接口正好扩展了 Iterable。因此,你可以将 Collection 传递给 join 方法。

例如,下面是如何将列表格式化为HTML 有序列表:

$ {"<ol> <li>"+ = String.join"</ li> <li>",城市)+ ="< li> </ ol>"}

此表达式适用于至少有一个元素的集合。如果你可能要处理一个空集合,这里是一个更好的表达式:

${empty cities? "" : "<ol><li>"

+= String.join("</li><li>", cities. stream().sorted().toList())

+= "</li></ol>"}

 

8.11 格式化数字

要格式化数字,你可以再次利用EL 3.0 允许引用静态方法的能力。String 类的 format 静态方法可以用来格式化数字。

例如,以下表达式返回带有两个小数点位的数字。

${String.format("%-10.2f%n", 125.178)}

更多格式化规则可以查阅 java.text.DecimalFormat 的 javadoc 文档。

 

8.12 格式化日期

可以通过 String.format()来格式化一个 date 或 time。例如:

${d = LocalDate.now().plusDays(2); String.format("%tB %te, %tY%n", d, d, d)}


8.13 如何在 JSP 2.0 及其更高版本中配置 EL

首先计算 LocalDate.now().plusDays(2),并将结果复制给变量 d,然后用 String.format()方法来格式化 LocalDate,引用了 次变量 d

更多的格式化规则见:

https://docs.oracle.com/javase/tutorial/java/data/numberformat.html

 

8.13 如何在JSP 2.0 及其更高版本中配置EL

有了ELJavaBeans 和定制标签,就可以编写免脚本的JSP 页面了。JSP 2.0 及其更高的版本中还提供了一个开关,可以使所有的 JSP 页面都禁用脚本。现在,软件架构师可以强制编写免脚本的JSP 页面了。

另一方面,在有些情况下,可能还会需要在应用程序中取消 EL。例如,正在使用与 JSP 2.0 兼容的容器,却尚未准备升级到 JSP 2.0,那么就需要这么做。在这种情况下,可以关闭 EL 表达式的计算。

 

8.13.1 实现免脚本的JSP 页面

为了关闭 JSP 页面中的脚本元素,要使用 jsp-property-group 元素以及 url-pattern scripting- invalid 两个子元素。url-pattern 元素定义禁用脚本要应用的 URL 样式。下面展示如何将一个应用程序中所有 JSP 页面的脚本都关闭:

<jsp-config>

<jsp-property-group>

<url-pattern>*.jsp</url-pattern>

<scripting-invalid>true</scripting-invalid>

</jsp-property-group>

</jsp-config>

注意:

在部署描述符中只能有一个  jsp-config  元素。如果已经为禁用  EL  而定义了一个

jsp-property-group,就必须在同一个 jsp-config 元素下,为禁用脚本而编写 jsp- property-group

8.13.2 禁用EL 计算

在某些情况下,比如,当需要在 JSP 2.0 及其更高版本的容器中部署 JSP 1.2 应用程序时, 可能就需要禁用 JSP 页面中的 EL 计算了。此时,出现的 EL 结构,就不会作为 EL 表达式进


 

行计算。目前有两种方式可以禁用JSP 中的 EL 计算。

第一种,可以将 page 指令的 isELIgnored 属性设为 True,像这样:

<%@ page isELIgnored="true" %>

isELIgnored 属性的默认值为 False。如果想在一个或者几个 JSP 页面中关闭 EL 表达式计算,建议使用isELIgnored 属性。

第二种,可以在部署描述符中使用 jsp-property-group 元素。jsp-property-group 元素是 jsp-

config 元素的子元素。利用 jsp-property-group 可以将某些设置应用到应用程序中的一组 JSP

页面中。

为了利用 jsp-property-group 元素禁用 EL 计算,还必须有 url-pattern 和 el-ignored 两个子元素。url-pattern 元素用于定义EL 禁用要应用的URL 样式。el-ignored 元素必须设为 True

下面举一个例子,展示如何在名为noEI.jsp JSP 页面中禁用 EL 计算。

<jsp-config>

<jsp-property-group>

<url-pattern>/noEl.jsp</url-pattern>

<el-ignored>true</el-ignored>

</jsp-property-group>

</jsp-config>

也可以像下面这样,通过给 url-pattern 元素赋值*.jsp,来禁用一个应用程序中的所有 JSP

页面的 EL 计算:

<jsp-config>

<jsp-property-group>

<url-pattern>*.jsp</url-pattern>

<el-ignored>true</el-ignored>

</jsp-property-group>

</jsp-config>

无论是将其 page 指令的 isELIgnored 属性设为 True,还是 其 URL 与 el-ignored 为 True jsp-property-group 的 URL 模式相匹配,都将禁用 JSP 页面中的 EL 计算。假如将一个 JSP 页面中 page 指令的 isELIgnored 属性设为 False,但其 URL 与在部署描述符中禁用了 EL 计算的

JSP 页面的模式匹配,那么该页面的 EL 计算也将被禁用。

此外,如果使用的是与 Servlet 2.3 及其更低版本兼容的部署描述符,那么 EL 计算已经默认关闭,即便使用的是JSP 2.0 及其更高版本的容器,也一样。


8.14 小结

 

8.14 小结

EL 是 JSP 2.0 及其更高版本中最重要的特性之一。它有助于编写更简短、更高效的 JSP 页面,还能帮助编写免脚本的页面。本章介绍了如何利用EL 来访问JavaBeans 和隐式对象, 还介绍了如何使用EL 运算符。本章的最后一个小节介绍了如何在与JSP 2.0 及其更高版本相关的容器中使用与EL 相关的应用程序设置。

二:重要记录

算术运算符有 种。

— 加法(+)。

— 减法()。

— 乘法(*)。

— 除法(/和 div)。

— 取余/取模(%和 mod)。

除法和取余运算符都有两种形式,与 XPath 和 ECMAScript 是一致的。

注意,EL 表达式的计算按优先级从高到低、从左到右进行。下列运算符是按优先级递减顺序排列的:

— */div%mod

 

— +-

这表示*/div%以及 mod 运算符的优先级相同,+的优先级相同,但第二组运算符的优先级小于第一组运算符。因此,表达式

${1+2*3}

的运算结果是 7,而不是 9

8.5.2 关系运算符

下面是关系运算符列表:

— 等于(==和 eq)。

— 不等于(!=和 ne)。

— 大于(>和 gt)。

— 大于或等于(>=和 ge)。


 

— 小于(<和 lt)。

— 小于或等于(<=和 le)。

例如,表达式${3==4}返回 False${“b”<“d”}则返回 True

8.5.3 逻辑运算符

下面是逻辑运算符列表:

— 和(&&和 and)。

— 或(||  和 or)。

— 非(!和 not)。

8.5.4 条件运算符

EL 条件运算符的语法如下:

${statement? A:B}

表达式 x+y,可以写成:

${x+y}

#{x+y}


以下是关键字,它们不能用作标识符:

and eq gt true instanceof

or ne le false empty not lt ge null div mod

想访问 accept-language 标题,只能使用[ ]运算符,因为 accept-language 不是一个合法的Java 变量名。如果用运算符访问它,将会导致异常。
要访问 HttpSession,可以使用以下语法:

${pageContext.session}

例如,以下表达式会得出 session 标识符。

${pageContext.session.id}


三 :学习参考
spring mvc 学习指南  第二版 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值