7.12.3 SpEL语法详述
虽然SpEL
在功能上大致与JSP2
的EL
类似,但SpEL
比JSP 2
的EL
更强大,接下来详细介绍SpEL
所支持的各种语法细节。
1. 直接量表达式
直接量表达式是SpEL
中最简单的表达式,直接量表达式就是在表达式中使用Java
语言支持的直接量,包括字符串
、日期
、数值
、 boolean
值和null
:
例如如下代码片段:
1 | Expression exp = parser.parseExpression("'Hello World'"); |
2. 在表达式中创建数组
SpEL
表达式直接支持使用静态初始化
、动态初始化
两种语法来创建数组。例如如下代码片段:
1 | // 创建一个数组 |
3. 在表达式中创建List集合
SpEL
直接使用如下语法来创建List
集合:
1 | {element1,element2,element3,...,} |
例如如下代码:
1 | Expression exp=parser.parseExpression("{'java','Struts','Spring'}"); |
4. 在表达式中访问List、Map等集合元素
为了在SpEL
中访问List
集合的元素,可以使用如下语法格式
1 | List[index] |
为了在SpEL
中访问Map
集合的元素,可以使用如下语法格式:
1 | map[key] |
1 | List<String> list = new ArrayList<String>(); |
5. 调用方法
在SpEL
中调用方法与在Java
代码中调用方法没有任何区别。如以下代码所示:
1 | // 调用String对象的substring()方法 |
6. 算术、比较、逻辑、赋值、三目等运算符
与JSP2EL
类似的是SpEL
同样支持算术、比较、逻辑、赋值、三目运算符等各种运算符,值得指出的是,在SpEL
中使用赋值运算符的功能比较强大,这种赋值可以直接改变表达式所引用的实际对象。
如以下代码所示:
1 | List<String> list = new ArrayList<String>(); |
运行结果:
1 | 疯狂Java讲义 |
7. 类型运算符
SpEL
提供了一个特殊的运算符:T()
,这个运算符用于告诉SpEL
将该运算符内的字符串当成”类”处理,避兔Spring
对其进行其他解析。尤其是调用某个类的静态方法时,T()
运算符尤其有用。
1 | // 调用Math的静态方法 |
例如如下代码:
1 | 0.09320472533221835 |
正如在上面的代码中所看到的,在表达式中使用某个类时,推荐使用该类的全限定类名。但如果只写类名,不写包名,SpEL
也可以尝试处理,SpEL
使用StandardTypeLocator
去定位这些类,它默认会在java.lang
包下找这些类。T()
运算符使用java.lang
包下的类时可以省略包名,但使用其他包下的所有类时应使用全限定类名。
8. 调用构造器
SpEL
允许在表达式中直接使用new
来调用构造器,这种调用可以创建一个Java
对象。例如如下代码
1 | // 创建对象 |
9. 变量
SpEL
允许通过EvaluationContext
来使用变量,该对象包含了一个setVariable(String name, Object value)
方法,该方法用于设置一个变量。一旦在EvaluationContext
中设置了变量,就可以在SpEL
中通过#name
来访问该变量。前面已经有不少在SpEL
中使用变量的例子,故此处不再赘述。
值得指出的是,SpEL
中有如下两个特殊的变量。
#this
:引用SpEL
当前正在计算的对象。#root
:引用SpEL
的EvaluationContext
的root
对象。
10. 自定义函数
SpEL
允许开发者开发自定义函数。类似于JSP 2 EL
中的自定义函数,所谓自定义函数,也就是为Java
方法重新起个名字而已。
通过StandardEvaluationContext
的如下方法即可在SpEL
中注册自定义函数。registerFunction(String name, Method m)
:将m
方法注册成自定义函数,该函数的名称为name
,SpEL
自定义函数的作用并不大,因为SpEL
本身已经允许在表达式语言中调用方法,因此将方法重新定义为自定义函数的意义不大。
11. Elvis运算符
Elvis
运算符只是三目运算符的特殊写法,例如对于如下三目运算符写法:
1 | name != null ? name : "newValue" |
上面的语句使用三目运算符需要将name
变量写两次,因此比较烦琐。SpEL
允许将上面写法简写为如下形式:
1 | name?: "newValue" |
12. 安全导航操作
在SpEL
中使用如下语句时可能导致NullPointerException
:
1 | foo.bar |
如果root
对象的foo
属性本身已经是null
,那么上面表达式尝试访问foo
属性的bar
属性时自然就会引发异常。
为了避免上面表达式中的NullPointerException
异常,SpEL
支持如下用法:
1 | foo?.bar |
上面表达式在计算root
对象的foo
属性时,如果foo
属性为null
,计算结果将直接返回null
,而不会引发NullPointerException
异常。如以下代码所示:
1 | // 使用安全操作,将输出null |
13. 集合选择
SpEL
允许直接对集合进行选择操作,这种选择操作可以根据指定表达式对集合元素进行筛选,只有符合条件的集合元素才会被选择出来。SpEL
集合选择的语法格式如下:collection.[condition_expression]
在上面的语法格式中, condition_expression
是一个根据集合元素定义的表达式,只有当该表达式返回true
时,对应的集合元素才会被筛选出来。如以下代码所示:
1 | List<String> list = new ArrayList<String>(); |
正如上面的粗体字代码所示,这种集合选择既可对List
集合进行筛选,也可对Map
集合进行筛选,当操作List
集合时, condition_expression
中访间的每个属性、方法都是以集合元素为主调的;当操作Map
集合时,需要显式地用key
引用Map Entry
的key
,用value
引用Map Entry
的value
.
1 | [疯狂Java讲义, 疯狂Ajax讲义, 经典Java EE企业应用实战] |
14. 集合投影
SpEL
允许对集合进行投影运算,这种投影运算将依次迭代每个集合元素,迭代时将根据指定表达式对集合元素进行计算得到一个新的结果,依次将每个结果收集成新的集合,这个新的集合将作为投影运算的结果。SpEL
投影运算的语法格式为:collection.![condition_expression]
在上面的语法格式中, condition_expression
是一个根据集合元素定义的表达式。上面的SpEL
会把collection
集合中的元素依次传入condition_expression
中,每个元素得到一个新的结果,所有计算出来的结果所组成的新结果就是该表达式的返回值。
1 | List<String> list = new ArrayList<String>(); |
运行结果:
1 | [8, 8, 7, 15] |
15. 表达式模板
表达式模板有点类似于带占位符的国际化消息。例如如下带占位符的国际化消息:
1 | 今天的股票价格是:{1} |
上面的消息可能生成如下字符串:
1 | 今天的股票价格是:123 |
上面字符串中的123需要每次动态改变。
这种需求可以借助于SpEL
的表达式模板的支持。表达式模板的本质是对”直接量表达式”的扩展它允许在”直接量表达式”中插入一个或多个并#{expression}
,#{expression}
将会被动态计算出来。
例如,如下程序示范了使用表达式模板:
1 | Person p1 = new Person(1, "孙悟空", 162); |
正如在上面的程序中所看到的,使用ExpressionParser
解析字符串模板时需要传入一个TemplateParserContext
参数,该TemplateParserContext
实现了ParserContext
接口,它用于为表达式解析传入一些额外的信息,例如TemplateParserContext
指定解析时需要计算#{
和}
之间的值。
原文链接: 7.12.3 SpEL语法详述