`
tuxq5721
  • 浏览: 34486 次
社区版块
存档分类
最新评论

Spring3.0 —— 表达式语言(SpEL)

 
阅读更多

Spring3.0中新增加了Spring 表达式语言,可以在Spring 的任意需要配置的地方使用该功能。

Spring的表达式语言与Java注解结合,以便开发人员可以撰写和指向他们的配置,而不需要单独的XML文件写入,使得Spring开发者在不需要XML的情况下对应用进行配置。

SpelExpressionParser


@Test

publicvoid testClassTypeExpression() {

ExpressionParser parser = new SpelExpressionParser();

// java.lang包类访问

Class<String> result1 = parser.parseExpression("T(String)").getValue(Class.class);

Assert.assertEquals(String.class, result1);

//其他包类访问

String expression2 = "T(cn.javass.spring.chapter5.SpELTest)";

Class<String> result2 = parser.parseExpression(expression2).getValue(Class.class);

Assert.assertEquals(SpELTest.class, result2);

//类静态字段访问

int result3 = parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class);

Assert.assertEquals(Integer.MAX_VALUE, result3);

//类静态方法调用

int result4 = parser.parseExpression("T(Integer).parseInt('1')").getValue(int.class);

}

基本表达式

<table valign="top" style="cellpadding="0" cellspacing="0">
    • 字面量表达式
    • 算术运算表达式
    • 比较运算表达式
    • 逻辑运算表达式
    • 字符串连接与截取表达式
    • 三目运算及Elivis运算表达式
    • 正则表达式


字面量表达式

字符串、数字类型(int、long、float、double)、布尔类型、null。

字符串

'Hello World!'"Hello World!"

数值类型

1-1L1.11.1E+20xa0xaL

布尔类型

truefalse

null

null


算术运算表达式

加(+)、减(-)、乘(*)、除(/或DIV)、求余(%MOD)、幂(^)。

加减乘除

1+2-3*4/21+2-3*4DIV2

求余

4%34MOD 3

幂运算

2^3


比较运算表达式

不等于

!= ne

1!= 1 1ne 1

等于

== eq

1== 1 1eq 1

大于等于

>= ge

1>= 1 1ge 1

小于等于

<= le

1<= 1 1le 1

大于

> gt

1> 1 1gt 1

小于

< lt

1< 1 1lt 1

区间

between

1 between {1, 2}


逻辑运算表达式

AND

true AND true

OR

true OR true

NOT

NOT true


字符串连接及截取表达式

连接

+

'Hello' + 'World !'

截取一个字符

string[index]

'Hello World'[0]


三目运算及Elivis运算表达式

三目运算符

表达式1?表达式2:表达式3

2>1?true:false

Elivis运算

表达式1?:表达式2

null? :falsetrue?:false


正则表达式

正则表达式

matches

'123' matches '\\d{3}'

类相关表达式

    • 类类型表达式
    • 类实例化表达式
    • instanceof表达式
    • 变量定义及引用
    • 自定义函数
    • 赋值表达式
    • 对象属性存取及安全导航表达式
      • 访问root对象属性
      • 安全访问
      • root对象属性赋值
    • 对象方法调用
    • Bean引用


类类型表达式

使用"T(Type)"来表示java.lang.Class实例,"Type"必须是类全限定名(java.lang包除外)。使用类类型表达式还可以进行访问类静态方法及类静态字段。

实例

示例

java.lang包类访问

T(String)

其他包的类访问

T(foo.bar.spel.SpELTest)

类静态字段访问

T(Integer).MAX_VALUE

类静态方法调用

T(Integer).parseInt('1')


类实例化表达式

实例

示例

java.lang包类的实例化

new String('hello')

其他包的类实例化

new java.util.Date()


instanceof

实例

示例

Java内使用同义

'hello' instanceof T(String)


变量定义与引用

变量定义通过EvaluationContext接口的setVariable(variableName, value)方法定义;在表达式中使用“#variableName”引用;除了引用自定义变量,SpEL还允许引用根对象及当前上下文对象,使用 “#root”引用根对象,使用“#this”引用当前上下文对象。“#this”引用当前上下文对象,此处“#this”即根对象。

@Test

publicvoid testVariableExpression() {

ExpressionParser parser =new SpelExpressionParser();

EvaluationContext context =new StandardEvaluationContext();

context.setVariable("variable","hello");

context.setVariable("variable","world");

String result1 = parser.parseExpression("#variable").getValue(context, String.class);

Assert.assertEquals("world", result1);

context =new StandardEvaluationContext("hello");

String result2 = parser.parseExpression("#root").getValue(context, String.class);

Assert.assertEquals("hello", result2);

String result3 = parser.parseExpression("#this").getValue(context, String.class);

Assert.assertEquals("hello", result3);

}


自定义函数

目前只支持类静态方法注册为自定义函数;SpEL使用StandardEvaluationContext的registerFunction方法进行注册自定义函数,其实完全可以使用setVariable代替,两者其实本质是一样的。

@Test

publicvoid testFunctionExpression()throws SecurityException, NoSuchMethodException {

ExpressionParser parser = new SpelExpressionParser();

StandardEvaluationContext context = new StandardEvaluationContext();

Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class);

context.registerFunction("parseInt", parseInt);

context.setVariable("parseInt2", parseInt);

String expression1 = "#parseInt('3') == #parseInt2('3')";

boolean result1 = parser.parseExpression(expression1).getValue(context,boolean.class);

Assert.assertEquals(true, result1);

}


赋值表达式

SpEL即允许给自定义变量赋值,也允许给跟对象赋值,直接使用“#variableName=value”即可赋值:

@Test

publicvoid testAssignExpression() {

ExpressionParser parser = new SpelExpressionParser();

// 1.root对象赋值

EvaluationContext context = new StandardEvaluationContext("aaaa");

String result1 = parser.parseExpression("#root='aaaaa'").getValue(context, String.class);

Assert.assertEquals("aaaaa", result1);

String result2 = parser.parseExpression("#this='aaaa'").getValue(context, String.class);

Assert.assertEquals("aaaa", result2);

// 2.给自定义变量赋值

context.setVariable("#variable","variable");

String result3 = parser.parseExpression("#variable=#root").getValue(context, String.class);

Assert.assertEquals("aaaa", result3);

}


对象属性存取及安全导航表达式

对象属性获取非常简单,即使用如“a.property.property”这种点缀式获取,SpEL对于属性名首字母是不区分大小写的。

给对象属性赋值可以采用赋值表达式或Expression接口的setValue方法赋值,而且也可以采用点缀方式赋值。

SpEL还引入了Groovy语言中的安全导航运算符“(对象|属性)?.属性”,用来避免当“?.”前边的表达式为null时抛出空指针异常,而是返回null。

ExpressionParser parser =new SpelExpressionParser();

// ===============访问root对象属性 ===============

Date date =new Date();

StandardEvaluationContext context =new StandardEvaluationContext(date);

int result1 = parser.parseExpression("Year").getValue(context,int.class);

Assert.assertEquals(date.getYear(), result1);

int result2 = parser.parseExpression("year").getValue(context,int.class);

Assert.assertEquals(date.getYear(), result2);

// ===============安全访问 ===============

context.setRootObject(null);

Object result3 = parser.parseExpression("#root?.year").getValue(context, Object.class);

Assert.assertEquals(null, result3);

// ===============root对象属性赋值 ===============

context.setRootObject(date);

int result4 = parser.parseExpression("Year = 4").getValue(context,int.class);

Assert.assertEquals(4, result4);

parser.parseExpression("Year").setValue(context, 5);

int result5 = parser.parseExpression("Year").getValue(context,int.class);

Assert.assertEquals(5, result5);


对象方法调用

对象方法调用更简单,跟Java语法一样;如“'helo'.substring(2,4)”将返回“lo”。对于根对象可以直接调用方法。

ExpressionParser parser =new SpelExpressionParser();

// ===============直接调用对象方法 ===============

String result1 = parser.parseExpression("'hello'.substring(3)").getValue(String.class);

Assert.assertEquals("lo", result1);

// ===============调用上下文root对象方法 ===============

Date date =new Date();

StandardEvaluationContext context =new StandardEvaluationContext(date);

int result2 = parser.parseExpression("getYear()").getValue(context,int.class);

Assert.assertEquals(date.getYear(), result2);


Bean引用

SpEL支持使用“@”符号来引用Bean,在引用Bean时需要使用BeanResolver接口实现来查找Bean,Spring提供BeanFactoryResolver实现。

在示例中首先初始化了一个IoC容器,ClassPathXmlApplicationContext 实现默认会把“System.getProperties()”注册为“systemProperties”Bean,因此使用 “@systemProperties”来引用该Bean。

@Test

publicvoid testBeanExpression() {

ClassPathXmlApplicationContext ctx =new ClassPathXmlApplicationContext();

ctx.refresh();

ExpressionParser parser =new SpelExpressionParser();

StandardEvaluationContext context =new StandardEvaluationContext();

context.setBeanResolver(new BeanFactoryResolver(ctx));

Properties result1 = parser.parseExpression("@systemProperties").getValue(context, Properties.class);

Assert.assertEquals(System.getProperties(), result1);

}

集合相关表达式

    • 内联List
    • 内联Array
    • CollectionMap元素访问
    • CollectionMapArray元素修改
    • 集合投影
    • 集合选择


内联List

Spring3.0.4开始支持内联List,使用{表达式,……}定义内联List。如“{1,2,3}”将返回一个整型的ArrayList,而“{}”将返回空的List,对于字面量表达式列表,SpEL会使用java.util.Collections.unmodifiableList方法将列表设置为不可修改。

//将返回不可修改的空List

List<Integer> result2 = parser.parseExpression("{}").getValue(List.class);

//对于列表中只要有一个不是字面量表达式,将只返回原始List,不会进行不可修改处理

String expression3 ="{{1+2,2+4},{3,4+4}}";

List<List<Integer>> result3 = parser.parseExpression(expression3).getValue(List.class);

result3.get(0).set(0, 1);

Assert.assertEquals(2, result3.size());


内联Array

//声明一维数组并初始化值

int[] result2 = parser.parseExpression("new int[]{1,2}").getValue(int[].class);

Assert.assertEquals(result2[0], 1);

//定义多维数组但不初始化(定义多维数组不能初始化

int[][][] result3 = parser.parseExpression("new int[2][2][2]").getValue(int[][][].class);


集合,字典元素访问

SpEL目前支持所有集合类型和字典类型的元素访问,使用“集合[索引]”访问集合元素,使用“map[key]”访问字典元素。

集合元素访问是通过Iterator遍历来定位元素位置的。

// SpEL内联List访问

int result1 = parser.parseExpression("{1,2,3}[0]").getValue(int.class);

//list.get(0)

Assert.assertEquals(1, result1);

// SpEL目前支持所有集合类型的访问

Collection<Integer> collection =new HashSet<Integer>();

collection.add(1);

collection.add(2);

EvaluationContext context2 =new StandardEvaluationContext();

context2.setVariable("collection", collection);

int result2 = parser.parseExpression("#collection[1]").getValue(context2,int.class);

//对于任何集合类型通过Iterator来定位元素

Assert.assertEquals(2, result2);

// SpELMap字典元素访问的支持

Map<String, Integer> map =new HashMap<String, Integer>();

map.put("a", 1);

EvaluationContext context3 =new StandardEvaluationContext();

context3.setVariable("map", map);

int result3 = parser.parseExpression("#map['a']").getValue(context3,int.class);

Assert.assertEquals(1, result3);


列表,字典,数组元素修改

可以使用赋值表达式或Expression接口的setValue方法修改。对数组修改直接对“#array[index]”赋值即可修改元素值,同理适用于集合和字典类型。

// ===============修改数组元素值 ===============

int[] array =newint[] { 1, 2 };

EvaluationContext context1 =new StandardEvaluationContext();

context1.setVariable("array", array);

int result1 = parser.parseExpression("#array[1] = 3").getValue(context1,int.class);

Assert.assertEquals(3, result1);

// ===============修改集合值 ===============

Collection<Integer> collection =new ArrayList<Integer>();

collection.add(1);

collection.add(2);

EvaluationContext context2 =new StandardEvaluationContext();

context2.setVariable("collection", collection);

int result2 = parser.parseExpression("#collection[1] = 3").getValue(context2,int.class);

Assert.assertEquals(3, result2);

parser.parseExpression("#collection[1]").setValue(context2, 4);

result2 = parser.parseExpression("#collection[1]").getValue(context2,int.class);

Assert.assertEquals(4, result2);

// ===============修改map元素值 ===============

Map<String, Integer> map =new HashMap<String, Integer>();

map.put("a", 1);

EvaluationContext context3 =new StandardEvaluationContext();

context3.setVariable("map", map);

int result3 = parser.parseExpression("#map['a'] = 2").getValue(context3,int.class);

Assert.assertEquals(2, result3);


集合投影

SQL中投影指从表中选择出列,而在SpEL指根据集合中的元素中通过选择来构造另一个集合,该集合和原集合具有相同数量的元素;SpEL使用“list|map.![投影表达式]”来进行投影运算:

Collection<Integer> collection =new ArrayList<Integer>();

collection.add(4);

collection.add(5);

//===============测试集合或数组===============

EvaluationContext context1 =new StandardEvaluationContext();

context1.setVariable("collection", collection);

Collection<Integer> result1 = parser.parseExpression("#collection.![#this+1]").getValue(context1, Collection.class);

Assert.assertEquals(2, result1.size());

Assert.assertEquals(new Integer(5), result1.iterator().next());

对于集合或数组使用如上表达式进行投影运算,其中投影表达式中“#this”代表每个集合或数组元素,可以使用比如“#this.property”来获取集合元素的属性,其中“#this”可以省略。

Map<String, Integer> map =new HashMap<String, Integer>();

map.put("a", 1);

map.put("b", 2);

// ===============测试Map ===============

EvaluationContext context2 =new StandardEvaluationContext();

context2.setVariable("map", map);

List<Integer> result2 =

parser.parseExpression("#map.![value+1]").getValue(context2, List.class);

Assert.assertEquals(2, result2.size());

SpEL投影运算还支持Map投影,但Map投影最终只能得到List结果,如上所示,对于投影表达式中的“#this”将是Map.Entry,所以可以使用“value”来获取值,使用“key”来获取键。


集合选择

SQL中指使用select进行选择行数据,而在SpEL指根据原集合通过条件表达式选择出满足条件的元素并构造为新的集合,SpEL使用“(list|map).?[选择表达式]”,其中选择表达式结果必须是boolean类型,如果true则选择的元素将添加到新集合中,false将不添加到新集合中。

Collection<Integer> collection =new ArrayList<Integer>();

collection.add(4);

collection.add(5);

// ===============集合或数组测试 ==============

EvaluationContext context1 =new StandardEvaluationContext();

context1.setVariable("collection", collection);

Collection<Integer> result1 = parser.parseExpression("#collection.?[#this>4]").getValue(context1, Collection.class);

Assert.assertEquals(1, result1.size());

Assert.assertEquals(new Integer(5), result1.iterator().next());

Map<String, Integer> map =new HashMap<String, Integer>();

map.put("a", 1);

map.put("b", 2);

// =============== Map测试 ==============

EvaluationContext context2 =new StandardEvaluationContext();

context2.setVariable("map", map);

Map<String, Integer> result2 = parser.parseExpression("#map.?[#this.key != 'a']").getValue(context2, Map.class);

Assert.assertEquals(1, result2.size());

List<Integer> result3 = parser.parseExpression("#map.?[key != 'a'].![value+1]").getValue(context2, List.class);

Assert.assertEquals(new Integer(3), result3.iterator().next());

对于Map选择,如“#map.?[#this.key != 'a']”将选择键值不等于”a”的,其中选择表达式中“#this”是Map.Entry类型,而最终结果还是Map,这点和投影不同;集合选择和投影可以一起使用,如“#map.?[key != 'a'].![value+1]”将首先选择键值不等于”a”的,然后在选出的Map中再进行“value+1”的投影。

表达式模板

模板表达式就是由字面量与一个或多个表达式块组成。每个表达式块由“前缀+表达式+后缀”形式组成,如“${1+2}”即表达式块。在前边我们已经介绍了使用ParserContext接口实现来定义表达式是否是模板及前缀和后缀定义。在此就不多介绍了,如“Error ${#v0} ${#v1}”表达式表示由字面量“Error ”、模板表达式“#v0”、模板表达式“#v1”组成,其中v0和v1表示自定义变量,需要在上下文定义。

分享到:
评论

相关推荐

    spring3.0_doc_api

    4. **基于表达式的SpEL(Spring Expression Language)**:提供了强大的表达式语言,用于在运行时查询和操作对象图。 5. **RESTful Web服务支持**:Spring MVC模块增加了对RESTful服务的支持,通过`@RequestMapping...

    spring 3.0 jar包

    Spring 3.0的Web MVC模块引入了ModelAndView类的替代品——Model,使得模型数据的处理更加简洁。另外,新增了@ModelAttribute注解,用于将请求参数绑定到模型对象上。同时,对RESTful风格的URL支持也有所加强。 6....

    spring3.0MVC中文教材

    2. **Spring Expression Language (SpEL)**: 引入了一个新的表达式语言——Spring Expression Language,可以用于定义基于XML和注解的Bean定义。 3. **REST Web服务支持**: Spring 3.0支持RESTful Web服务的开发,...

    Spring3.0源码3

    7. **表达式语言(SpEL)**:Spring Expression Language提供了一种强大的方式来在运行时查询和操作对象图。在Spring 3.0中,SpEL被广泛应用在注解驱动的配置和AOP中。 8. **基于注解的配置**:Spring 3.0大力推广了...

    Spring3.0官方英文文档

    SpEL是Spring 3.0引入的一个强大表达式语言,用于在运行时查询和操作对象图。它支持在XML配置、注解和代码中使用,极大增强了Spring的应用表达能力。 ### 4. **注解驱动开发** Spring 3.0大大增强了对注解的支持,...

    Spring3.0_MVC_中文教程

    同时,Spring3.0引入了一种新的表达式语言——Spring 表达式语言(SpEL),它允许在XML和注解中定义基于bean的定义。此外,Spring3.0还支持REST Web服务和注解的格式化,例如,可以使用@DateTimeFormat和@...

    spring-framework-reference 3.0

    Spring 3.0 中引入了一个新的表达式语言——**Spring Expression Language (SpEL)**。这是一种强大的脚本语言,用于在Spring组件之间描述任务和配置。SpEL可以更好地与XML配置文件交互,并且对于安全性和集成方面...

    Spring 3.x 企业应用开发实战

    同时,Spring AOP的表达式语言(SpEL)也得到了增强,可以用于更复杂的切点匹配和通知配置。 在Web层,Spring MVC在Spring 3.0中引入了更多的RESTful支持,包括@RequestMapping注解的改进,可以更方便地处理HTTP...

    spring-context-3.0.0.RELEASE.jar.zip

    4. **表达式语言(SpEL)**:提供了强大的表达式语言,用于在运行时查询和操作对象模型。 5. **AOP增强**:增加了对环绕通知的支持,使AOP的使用更加灵活。 **四、Spring-Context-3.0.0.RELEASE.jar的结构与内容** ...

    Spring3_权威开发指南

    - **Spring表达式语言(SpEL)支持**: - **核心接口及类**:介绍SpEL的核心组件。 - **基于API方式使用**:说明如何通过API使用SpEL。 - **基于XML方式使用**:演示如何在XML配置文件中使用SpEL。 - **基于...

    集成Hibernate3.6.8+Spring3.0.6+struts2.2.3.0

    标题中的"集成Hibernate3.6.8+Spring3.0.6+struts2.2.3.0"指的是一个经典的Java Web开发框架整合,它将三个强大的开源框架——Hibernate、Spring和Struts2结合在一起,以实现高效、模块化且可维护的Web应用程序。...

    使用Maven配置Spring的方法步骤

    通过支持一些核心Spring技术来扩充容器:Core Spring实用程序,Spring表达式语言(SpEL)、面向对象编程支持和JavaBeans机制。 在 pom.xml 文件中,我们定义了依赖关系的版本号 `${org.springframework.version}`,...

Global site tag (gtag.js) - Google Analytics