2.11.2 表达式语言

2.11.2 表达式语言

表达式语言(Expression Language)是一种简化的数据访问方式。使用表达式语言可以方便地访问JSP的隐含对象和JavaBeans组件,在JSP2规范中,建议尽量使用表达式语言使JSP文件的格式一致,避免使用JSP小脚本。
表达式语言可用于简化JSP页面的开发,允许美工设计人员使用表达式语言的语法获取业务逻辑组件传过来的变量值。
表达式语言是JSP2的一个重要特性,它并不是一种通用的程序语言,而仅仅是一种数据访问语言,可以方便地访问应用程序数据,建议避免使用JSP小脚本。实际上,Servlet3.1规范再次强化了表达式语言的功能.

表达式语法格式

表达式语言的语法格式是:

1
${expression}

1. 表达式语言支持的算术运算符和逻辑运算符

表达式语言支持的算术运算符和逻辑运算符非常多,所有在Java语言里支持的算术运算符,表达式语言都可以使用;甚至Java语言不支持的一些算术运算符和逻辑运算符,表达式语言也支持。

JSP 表达式 中使用算术运算符

arithmeticOperator.jsp

下面的JSP页面示范了在表达式语言中使用算术运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<!DOCTYPE html>
<html>
<head>
<title> 表达式语言 - 算术运算符 </title>
</head>
<body>
<h2>表达式语言 - 算术运算符</h2><hr/>
<table border="1" bgcolor="#aaaadd">
<tr>
<td><b>表达式语言</b></td>
<td><b>计算结果</b></td>
</tr>
<!-- 直接输出常量 -->
<tr>
<td>\${1}</td>
<td>${1}</td>
</tr>
<!-- 计算加法 -->
<tr>
<td>\${1.2 + 2.3}</td>
<td>${1.2 + 2.3}</td>
</tr>
<!-- 计算加法 -->
<tr>
<td>\${1.2E4 + 1.4}</td>
<td>${1.2E4 + 1.4}</td>
</tr>
<!-- 计算减法 -->
<tr>
<td>\${-4 - 2}</td>
<td>${-4 - 2}</td>
</tr>
<!-- 计算乘法 -->
<tr>
<td>\${21 * 2}</td>
<td>${21 * 2}</td>
</tr>
<!-- 计算除法 -->
<tr>
<td>\${3/4}</td>
<td>${3/4}</td>
</tr>
<!-- 计算除法 -->
<tr>
<td>\${3 div 4}</td>
<td>${3 div 4}</td>
</tr>
<!-- 计算除法 -->
<tr>
<td>\${3/0}</td>
<td>${3/0}</td>
</tr>
<!-- 计算求余 -->
<tr>
<td>\${10%4}</td>
<td>${10%4}</td>
</tr>
<!-- 计算求余 -->
<tr>
<td>\${10 mod 4}</td>
<td>${10 mod 4}</td>
</tr>
<!-- 计算三目运算符 -->
<tr>
<td>\${(1==2) ? 3 : 4}</td>
<td>${(1==2) ? 3 : 4}</td>
</tr>
</table>
</body>
</html>

上面的页面中示范了表达式语言所支持的加、减、乘、除、求余等算术运算符的功能,读者可能也发现了表达式语言还支持divmod等运算符。而且表达式语言把所有数值都当成浮点数处理,所以3/0的实质是3.0/0.0,得到的结果应该是Infinity.

测试

浏览arithmeticOperator.jsp页面,将看到如图2.46所示的效果。

如果需要在支持表达式语言的页面中正常输出“$”符号,则在“$”符号前加转义字符“\”,否则系统以为“$”是表达式语言的特殊标记

JSP 表达式 中使用逻辑运算符

也可以在表达式语言中使用逻辑运算符,如下面的JSP页面所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<!DOCTYPE html>
<html>
<head>
<title> 表达式语言 - 逻辑运算符 </title>
</head>
<body>
<h2>表达式语言 - 逻辑运算符</h2><hr/>
数字之间的比较:
<table border="1" bgcolor="#aaaadd">
<tr>
<td><b>表达式语言</b></td>
<td><b>计算结果</b></td>
</tr>
<!-- 直接比较两个数字 -->
<tr>
<td>\${1 &lt; 2}</td>
<td>${1 < 2}</td>
</tr>
<!-- 使用lt比较运算符 -->
<tr>
<td>\${1 lt 2}</td>
<td>${1 lt 2}</td>
</tr>
<!-- 使用>比较运算符 -->
<tr>
<td>\${1 &gt; (4/2)}</td>
<td>${1 > (4/2)}</td>
</tr>
<!-- 使用gt比较运算符 -->
<tr>
<td>\${1 gt (4/2)}</td>
<td>${1 gt (4/2)}</td>
</tr>
<!-- 使用>=比较运算符 -->
<tr>
<td>\${4.0 &gt= 3}</td>
<td>${4.0 >= 3}</td>
</tr>
<!-- 使用ge比较运算符 -->
<tr>
<td>\${4.0 ge 3}</td>
<td>${4.0 ge 3}</td>
</tr>
<!-- 使用<=比较运算符 -->
<tr>
<td>\${4 &lt;= 3}</td>
<td>${4 <= 3}</td>
</tr>
<!-- 使用le比较运算符 -->
<tr>
<td>\${4 le 3}</td>
<td>${4 le 3}</td>
</tr>
<!-- 使用==比较运算符 -->
<tr>
<td>\${100.0 == 100}</td>
<td>${100.0 == 100}</td>
</tr>
<!-- 使用eq比较运算符 -->
<tr>
<td>\${100.0 eq 100}</td>
<td>${100.0 eq 100}</td>
</tr>
<!-- 使用!=比较运算符 -->
<tr>
<td>\${(10*10) != 100}</td>
<td>${(10*10) != 100}</td>
</tr>
<!-- 先执行运算,再进行比较运算,使用ne比较运算符-->
<tr>
<td>\${(10*10) ne 100}</td>
<td>${(10*10) ne 100}</td>
</tr>
</table>
字符之间的比较:
<table border="1" bgcolor="#aaaadd">
<tr>
<td><b>表达式语言</b></td>
<td><b>计算结果</b></td>
</tr>
<tr>
<td>\${'a' &lt; 'b'}</td>
<td>${'a' < 'b'}</td>
</tr>
<tr>
<td>\${'hip' &gt; 'hit'}</td>
<td>${'hip' > 'hit'}</td>
</tr>
<tr>
<td>\${'4' &gt; 3}</td>
<td>${'4' > 3}</td>
</tr>
</table>
</body>
</html>

从上面程序的粗体字代码中可以看出:
表达式语言不仅可在数字与数字之间比较,还可在字符与字符之间比较,字符串的比较是根据其对应Unicode值来比较大小的。

2. 表达式语言的内置对象

使用表达式语言可以直接获取请求参数值,可以获取页面中JavaBean的指定属性值,获取请求头及获取pagerequestsessionapplication范围的属性值等,这些都得益于表达式语言的内置对象。

JSP表达式的11个内置对象

表达式语言包含如下11个内置对象

  1. pageContext:代表该页面的pageContext对象,与JSPpageContext内置对象相同。
  2. pageScope:用于获取page范围的属性值。
  3. requestScope:用于获取request范围的属性值。
  4. sessionScope:用于获取session范围的属性值。
  5. applicationScope:用于获取application范围的属性值。
  6. param:用于获取请求的参数值
  7. paramValues:用于获取请求的参数值,与param的区别在于,该对象用于获取属性值为数组的属性值。
  8. header:用于获取请求头的属性值。
  9. headerValues:用于获取请求头的属性值,与header的区别在于,该对象用于获取属性值为数组的属性值。
  10. initParam:用于获取请求Web应用的初始化参数
  11. cookie:用于获取指定的Cookie值。

implicit-objects.jsp

下面的JSP页面示范了如何使用表达式语言的内置对象的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<!DOCTYPE html>
<html>
<head>
<title> 表达式语言 - 内置对象 </title>
</head>
<body>
<h2>表达式语言 - 内置对象</h2>
请输入你的名字:
<!-- 通过表单提交请求参数 -->
<form action="implicit-objects.jsp" method="post">
<!-- 通过${param['name']} 获取请求参数 -->
你的名字 = <input type="text" name="name" value="${param['name']}"/>
<input type="submit" value='提交'/>
</form><br/>
<% session.setAttribute("user" , "abc");
// 下面三行代码添加Cookie
Cookie c = new Cookie("name" , "yeeku");
c.setMaxAge(24 * 3600);
response.addCookie(c);
%>
<table border="1" width="660" bgcolor="#aaaadd">
<tr>
<td width="170"><b>功能</b></td>
<td width="200"><b>表达式语言</b></td>
<td width="300"><b>计算结果</b></td>
<tr>
<!-- 使用两种方式获取请求参数值 -->
<td>取得请求参数值</td>
<td>\${param.name}</td>
<td>${param.name}&nbsp;</td>
</tr>
<tr>
<td>取得请求参数值</td>
<td>\${param["name"]}</td>
<td>${param["name"]}&nbsp;</td>
</tr>
<tr>
<!-- 使用两种方式获取指定请求头信息 -->
<td>取得请求头的值</td>
<td>\${header.host}</td>
<td>${header.host}</td>
</tr>
<tr>
<td>取得请求头的值</td>
<td>\${header["accept"]}</td>
<td>${header["accept"]}</td>
</tr>
<!-- 获取Web应用的初始化参数值 -->
<tr>
<td>取得初始化参数值</td>
<td>\${initParam["author"]}</td>
<td>${initParam["author"]}</td>
</tr>
<!-- 获取session返回的属性值 -->
<tr>
<td>取得session的属性值</td>
<td>\${sessionScope["user"]}</td>
<td>${sessionScope["user"]}</td>
</tr>
<!-- 获取指定Cookie的值 -->
<tr>
<td>取得指定Cookie的值</td>
<td>\${cookie["name"].value}</td>
<td>${cookie["name"].value}</td>
</tr>
</table>
</body>
</html>

浏览上面页面,并通过页面中表单来提交请求,将看到如图2.47所示的效果。

3. 表达式语言的自定义函数

表达式语言除了可以使用基本的运算符外,还可以使用自定义函数。通过自定义函数,能够大大加强表达式语言的功能。自定义函数的开发步骤非常类似于标签的开发步骤,定义方式也几乎一样。区别在于自定义标签直接在页面上生成输出,而自定义函数则需要在表达式语言中使用。
函数功能大大扩充了EL的功能,EL本身只是一种数据访问语言,因此它不支持调用方法。如果需要在EL中进行更复杂的处理,就可以通过函数来完成。**函数的本质是:提供一种语法允许在EL中调用某个类的静态方法**。

表达式语言中自定义函数的步骤

下面介绍表达式语言中自定义函数的开发步骤。

开发函数处理类

函数处理类就是普通类,这个普通类中包含若干个静态方法,每个静态方法都可定义成一个函数。实际上这个步骤也是可省略的,完全可以直接使用JDK或其他项目提供的类,只要这个类包含静态方法即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
package lee;

public class Functions {
// 对字符串进行反转
public static String reverse(String text) {
return new StringBuffer(text).reverse().toString();
}

// 统计字符串的个数
public static int countChar(String text) {
return text.length();
}
}

完全可以直接使用JDK或其他项目提供的类作为函数处理类,只要这个类包含静态方法即可。

使用标签库定义函数

定义函数的方法与定义标签的方法大致相似。

  • <taglib>元素下增加<tag>元素用于定义自定义标签;
  • <taglib>元素下增加<function>元素则用于定义自定义函数。每个<function>素只要三个子元素即可。
    • name:指定自定义函数的函数名
    • function-class:指定自定义函数的处理类。
    • function-signature:指定自定义函数对应的方法。

下面的标签库定义(TLD)文件将上面的Functions.java类中所包含的两个方法定义成两个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
web-jsptaglibrary_2_0.xsd" version="2.0">
<tlib-version>1.0</tlib-version>
<short-name>crazyit</short-name>
<!-- 定义该标签库的URI -->
<uri>http://www.crazyit.org/tags</uri>
<!-- 定义第一个函数 -->
<function>
<!-- 定义函数名:reverse -->
<name>reverse</name>
<!-- 定义函数的处理类 -->
<function-class>lee.Functions</function-class>
<!-- 定义函数的实现方法-->
<function-signature>
java.lang.String reverse(java.lang.String)</function-signature>
</function>
<!-- 定义第二个函数: countChar -->
<function>
<!-- 定义函数名:countChar -->
<name>countChar</name>
<!-- 定义函数的处理类 -->
<function-class>lee.Functions</function-class>
<!-- 定义函数的实现方法-->
<function-signature>int countChar(java.lang.String)
</function-signature>
</function>
</taglib>

上面的粗体字代码定义了两个函数,不难发现其实定义函数比定义自定义标签更简单,因为自定义函数只需配置三个子元素即可,变化更少

在JSP页面的EL中使用函数

一样需要先导入标签库,然后再使用函数。下面是使用函数的JSP页面代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<%@ taglib prefix="crazyit" uri="http://www.crazyit.org/tags"%>
<!DOCTYPE html>
<html>
<head>
<title> new document </title>
</head>
<body>
<h2>表达式语言 - 自定义函数</h2><hr/>
请输入一个字符串:
<form action="useFunctions.jsp" method="post">
字符串 = <input type="text" name="name" value="${param['name']}">
<input type="submit" value="提交">
</form>
<table border="1" bgcolor="aaaadd">
<tr>
<td><b>表达式语言</b></td>
<td><b>计算结果</b></td>
<tr>
<tr>
<td>\${param["name"]}</td>
<td>${param["name"]}&nbsp;</td>
</tr>
<!-- 使用reverse函数-->
<tr>
<td>\${crazyit:reverse(param["name"])}</td>
<td>${crazyit:reverse(param["name"])}&nbsp;</td>
</tr>
<tr>
<td>\${crazyit:reverse(crazyit:reverse(param["name"]))}</td>
<td>${crazyit:reverse(crazyit:reverse(param["name"]))}&nbsp;</td>
</tr>
<!-- 使用countChar函数 -->
<tr>
<td>\${crazyit:countChar(param["name"])}</td>
<td>${crazyit:countChar(param["name"])}&nbsp;</td>
</tr>
</table>
</body>
</html>

如上面程序中粗体字代码所示,导入标签库定义文件后(实质上也是函数库定义文件),就可以在表达式语言中使用函数定义库文件里定义的各函数了。
通过上面的介绍不难发现自定义函数的实质:就是将指定Java类的静态方法暴露成可以在EL中使用的函数,所以可以定义成函数的方法必须用public static修饰。