您的位置:首页 > 编程语言 > Java开发

Spring3表达式语言(SpEL)学习笔记

2015-05-24 23:39 363 查看


最新地址请访问:http://leeyee.github.io/blog/2011/06/19/spring-expression-language

Spring Excpression Language (SpEL)语言支持在运行时操作和查询对象,其语法类似统一的EL语言,但是SpEL提供了额外的功能。

1、文本表达式

2、布尔类和关系操作

3、正则表达式

4、类表达式

5、访问属性、数组、集合和map

6、方法调用

7、关系操作

8、赋值操作

9、调用构造函数

10、Bean 引用

11、数组构造

12、内联list

13、三元操作

14、变量

15、用户自定义函数

16、集合投影

17、集合选择

18、模板表达式

使用SpEl进行表达式操作,基本操作如下:

第一步,构建解析

[java] view
plaincopy

ExpressionParser parser = new SpelExpressionParser();

第二步,使用表达式进行解析

[java] view
plaincopy

Expression exp = parser.parseExpression( SpEl);

第三步,获取结果

[java] view
plaincopy

exp.getValue()

2.1 文本表达式

文本表达式支持字符表达式、日期、数字(正数、实数及十六进制数)、布尔类型及null.其中字符表达式需要用单引号声明。

对数字支持负数、指数及小数。默认情况下实数使用Double.parseDouble() 进行表达式类型转换

2.2 属性、数组、列表、字典(map)及索引

在表达式中访问类属性时直接使用属性名,属性名首字母大小写均可。

访问数组时可以使用[index]进行元素对象范围。

访问列表时,可直接使用类表的方法,通过点操作符

2.3 内置列表

列表可以直接表示在表达式中使用{}符号表达。{}本身代表一个空的list

2.4 数组构造(spring3.0.3中会抛出异常)

可以通过熟悉的java语法在表达是语言中定义。但目前不支持定义一个初始化的多维数组

2.5 方法

表达式中的方法调用遵循java语法。

2.6 操作符

2.6.1 关系操作符


支持 eq("=="),ne("!="),le("<="),lt("<"),gt(">"),ge(">="),div("/"),mod("%"),not("!"),正则表达式及instanceof操作

2.6.2 逻辑操作符

逻辑操作符支持and,or,not

2.6.3 数学运算操作符

加法运算符可以用于数字,字符串和日期。减法可以用在数字和日期。乘法和除法只能用于对数字。其他受支持的数学运算是模数(%)和指数幂(^)。运行顺序按标准运算符优先级执行

2.7 赋值

通过赋值操作进行属性设置。通常是调用setValue方法,但也可以在调用getValue时设置。

2.8 类型

通过特殊的'T'操作符可以用来指定一个java.lang.Class的实例。在实例话对象的静态方法将会被调用。

2.9 构造器

构造器通过new操作被调用。在new操作时需要指明类的完全类名(包括包路径)

2.10 变量

变量可以通过 #变量名 在表达式中被引用。变量通过StandardEvaluationContext类的setVariable方法进行设置

2.10.1 #this变量

变量 #this 被定义为当前操作对象的引用。

2.11 函数

你可以扩展SpEL通过注册自定义函数。注册后的函数可以在表达式中通过其名称进行调用。函数的注册是通过StandardEvaluationContext类的registerFunction方法进行声明

2.12 三元操作

2.13 Elvis操作

Elvis操作是一个短的三元操作符语法,通常在Groovy语言中使用。


Note: Elvis操作在表达式中可以用来生成默认值,当被访问属性为空时。比如@Value

@Value("#systemPro['mail.port'] ? : 25}") //当mail.port为空时将默认为25



2.14 安全导航操作

该操作是为避免空指针异常。他是来自Groovy语言的。典型的当你有一个指向对象的引用,在你访问其方法或属性时,可能需要验证该对象的方法或属性是否为空,为了避免验证,使用安全导航操作将简单的返回null而不是空指针异常。

2.15 集合选择

选择是一个强大的表达式语言属性,可以使用选择表达式过滤源集合,从而生成一个新的符合选择条件的集合

选择的语法为 ?[selectionExpression] 。他将过滤集合并且返回一个新的集合(原集合的子集)。

选择语句也可用在Map中,过滤keySet及valueSet分别使用key和value关键字

另外:选择语法中,选择符合条件的结果集的第一个元素的语法为 ^[selectionExpression],选择最后一个元素的语法为$[selectionExpression]

2.16 集合投影

语法 ![projectionExpression] 判断集合中每个元素是否符合语法要求

2.17 表达式模板

表达式模板允许混合文字表达式,一个或多个值计算块。每一个值计算块被声明通过可被自定义的前缀和后缀,一般选择使用 #{}作为一个定界符。

------------ 以上就是SpEL的简单介绍。下面直接给出测试用例,这样比较直观,也易于理解。 ------------

pom.xml

[xhtml] view
plaincopy

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>study.spring3</groupId>

<artifactId>study-spring3</artifactId>

<version>0.0.1-SNAPSHOT</version>

<dependencies>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>3.0.5.RELEASE</version>

<scope>runtime</scope>

<exclusions>

<exclusion>

<groupId>commons-logging</groupId>

<artifactId>commons-logging</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-api</artifactId>

<version>1.5.8</version>

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-log4j12</artifactId>

<version>1.5.8</version>

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.14</version>

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.8.1</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>commons-logging</groupId>

<artifactId>commons-logging</artifactId>

<version>1.1.1</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>javax.inject</groupId>

<artifactId>javax.inject</artifactId>

<version>1</version>

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>cglib</groupId>

<artifactId>cglib</artifactId>

<version>2.1_3</version>

<scope>runtime</scope>

</dependency>

</dependencies>

</project>

spring-beans.xml

[xhtml] view
plaincopy

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"

xmlns:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- 容器注解扫描 -->

<context:component-scan base-package="study.spring.beans" />

<bean id="sputil" name="sputil" class="study.spring.beans.SpElUtil">

<property name="time" value="#{ new java.util.Date()}" />

<property name="name" value="#{'override'}" />

<property name="maps">

<map>

<entry key="1" value="string1" />

<entry key="2" value="string2" />

<entry key="3" value="string3" />

<entry key="4" value="String4" />

</map>

</property>

</bean>

</beans>

ApplicationContextFactory.java

[java] view
plaincopy

package study.spring.context.factory;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextFactory {

private static ApplicationContext ctx;

private ApplicationContextFactory() {

}

public static ApplicationContext createInstance() {

if (ctx == null) {

ctx = new ClassPathXmlApplicationContext(

new String[] { "spring-beans.xml" });

}

return ctx;

}

}

SpElUtil.java

[java] view
plaincopy

package study.spring.beans;

import java.util.Date;

import java.util.List;

import java.util.Map;

import org.springframework.expression.Expression;

import org.springframework.expression.ExpressionParser;

import org.springframework.expression.spel.standard.SpelExpressionParser;

public class SpElUtil {

private Date time;

private String name;

private SpelTestInnerClass innerClass = new SpelTestInnerClass(

"innerClass", 29);

private List<Integer> numbers;

private Map<Integer, String> maps;

public static Object sayHelloForSpEl(String express) {

ExpressionParser exp = new SpelExpressionParser();

Expression ex = exp.parseExpression(express);

return ex.getValue();

}

/**

* 自定义方法

*

* @param string

* @return

*/

public static int len(String string) {

return string.length();

}

public Map<Integer, String> getMaps() {

return maps;

}

public void setMaps(Map<Integer, String> maps) {

this.maps = maps;

}

public List<Integer> getNumbers() {

return numbers;

}

public void setNumbers(List<Integer> numbers) {

this.numbers = numbers;

}

public Date getTime() {

return time;

}

public void setTime(Date time) {

this.time = time;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public SpelTestInnerClass getInnerClass() {

return innerClass;

}

public void setInnerClass(SpelTestInnerClass innerClass) {

this.innerClass = innerClass;

}

}

class SpelTestInnerClass {

private String name;

private int age;

public SpelTestInnerClass(String name, int age) {

this.name = name;

this.age = age;

}

public boolean isGt30ForAge() {

return this.age > 30 ? true : false;

}

public String getName() {

return name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

SpElUtilTest.java

[java] view
plaincopy

package study.spring.beans;

import static org.junit.Assert.*;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Date;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.expression.Expression;

import org.springframework.expression.ExpressionParser;

import org.springframework.expression.common.TemplateParserContext;

import org.springframework.expression.spel.standard.SpelExpressionParser;

import org.springframework.expression.spel.support.StandardEvaluationContext;

import study.spring.context.factory.ApplicationContextFactory;

public class SpElUtilTest {

// spring配置文件上下文

ApplicationContext context = null;

// spring el测试辅助类

SpElUtil spel = null;

// 表达式解析对象

ExpressionParser exp = null;

// 标准赋值上下文

StandardEvaluationContext secontext;

@Before

public void setUp() throws Exception {

context = ApplicationContextFactory.createInstance();

spel = context.getBean(SpElUtil.class);

secontext = new StandardEvaluationContext(spel);

exp = new SpelExpressionParser();

}

@After

public void tearDown() throws Exception {

context = null;

spel = null;

secontext = null;

exp = null;

}

/**

* 文字表达式测试用例

*

* @throws Exception

*/

@Test

public void testSpELLiteralExpression() throws Exception {

// 定义各种文字表达式

String[] lELs = { "'hello SpEL'", "1.028E+7", "0x12EF", "true", "null" };

assertEquals("hello SpEL",

exp.parseExpression(lELs[0]).getValue(String.class));

assertEquals(new Double(10280000), exp.parseExpression(lELs[1])

.getValue(Double.class));

assertEquals(new Integer(4847),

exp.parseExpression(lELs[2]).getValue(Integer.class));

assertTrue(exp.parseExpression(lELs[3]).getValue(Boolean.class));

assertNull(exp.parseExpression(lELs[4]).getValue());

}

/**

* 访问属性、数组、集合和 map 测试

*

* @throws Exception

*/

@Test

public void testSpELProOrArrayOrIndexEtcExpression() throws Exception {

// 属性测试。time为SpElUtil类Date型数据,这里调用Date的属性Year

assertEquals(new Integer(2011), exp.parseExpression("time.Year + 1900")

.getValue(secontext, Integer.class));

// 属性测试。innerClass为SpElUtil类中引入的其他类。

assertEquals(29,

exp.parseExpression("innerClass.age").getValue(secontext));

// 设置SpElUtil类的numbers属性

spel.setNumbers(Arrays.asList(2, 3, 4, 5, 6, 7, 9));

// 访问对象属性数组通过索引

assertEquals(2, exp.parseExpression("numbers[0]").getValue(secontext));

// 访问map

assertEquals("string1",

exp.parseExpression("maps[1]")

.getValue(secontext, String.class));

}

/**

* 内联list测试

*

* @throws Exception

*/

@SuppressWarnings({ "unchecked", "rawtypes" })

@Test

public void testSpELInnerListExpression() throws Exception {

// 构造list

List<String> nums = (List<String>) exp.parseExpression(

"{'a','b','c','d'}").getValue();

assertEquals(Arrays.asList("a", "b", "c", "d"), nums);

// 构造List<List<>>

List listOfLists = (List) exp.parseExpression("{{1,2},{3,4}}")

.getValue(secontext);

assertEquals(Arrays.asList(1, 2), listOfLists.get(0));

}

/**

* Array 构造测试

*

* @throws Exception

*/

@Test

public void testSpELArrayConstructionExcpression() throws Exception {

// 创建没有初始值的数组

int[] a = (int[]) exp.parseExpression("new int[4]").getValue();

assertEquals(4, a.length);

// 创建带有初始值的数组

int[] b = (int[]) exp.parseExpression("new int[4]{1,2,3,4}").getValue();

assertEquals(3, b[2]);

// 创建二维数组

int[][] c = (int[][]) exp.parseExpression("new int[4][5]").getValue();

assertEquals(4, c.length);

assertEquals(5, c[0].length);

}

/**

* 方法表达式测试

*

* @throws Exception

*/

@Test

public void testSpELMethodExcpression() throws Exception {

// String.replace方法测试

assertEquals(

"abC2def",

exp.parseExpression("'abcdef'.replace('c','C2')").getValue(

String.class));

// 自定义类方法测试

assertFalse(exp.parseExpression("innerClass.isGt30ForAge()").getValue(

secontext, Boolean.class));

spel.getInnerClass().setAge(34);

assertTrue(exp.parseExpression("innerClass.isGt30ForAge()").getValue(

secontext, Boolean.class));

}

/**

* 操作符、正则表达式测试

*

* @throws Exception

*/

@Test

public void testSpElOperatorAndRegExpression() throws Exception {

// 关系操作

assertTrue(exp.parseExpression("1 == 1").getValue(Boolean.class));

assertTrue(exp.parseExpression("1 eq 1").getValue(Boolean.class));

assertTrue(exp.parseExpression("1 > -1").getValue(Boolean.class));

assertTrue(exp.parseExpression("1 gt -1").getValue(Boolean.class));

assertTrue(exp.parseExpression("'a' < 'b'").getValue(Boolean.class));

assertTrue(exp.parseExpression("'a' lt 'b'").getValue(Boolean.class));

assertTrue(exp.parseExpression(

" new Integer(123) instanceof T(Integer) ").getValue(

Boolean.class));

assertTrue(exp.parseExpression("'5.00' matches '^-?//d+(//.//d{2})?$'")

.getValue(Boolean.class));

// 逻辑操作

assertTrue(exp.parseExpression("true and true").getValue(Boolean.class));

assertTrue(exp.parseExpression("true or false").getValue(Boolean.class));

assertFalse(exp.parseExpression("innerClass.isGt30ForAge() and false ")

.getValue(secontext, Boolean.class));

assertFalse(exp.parseExpression("!innerClass.isGt30ForAge() and true ")

.getValue(secontext, Boolean.class));

assertTrue(exp.parseExpression("!false").getValue(Boolean.class));

// 运算操作

assertEquals(2, exp.parseExpression("1 + 1").getValue());

assertEquals("ABab",

exp.parseExpression("'AB' + 'ab'").getValue(String.class));

assertEquals(25.0,

exp.parseExpression("1 + 2 * 8 div 4 mod 2 + 2 ^ 3 * 3e0")

.getValue());

assertEquals(exp.parseExpression("1 + 2 * 8 / 4 % 2 + 2 ^ 3 ")

.getValue(),

exp.parseExpression("1 + 2 * 8 div 4 mod 2 + 2 ^ 3 ")

.getValue());

}

/**

* 赋值表达式测试

*

* @throws Exception

*/

@SuppressWarnings("deprecation")

@Test

public void testSpelAssignmentExpression() throws Exception {

Date oldDate = spel.getTime();// 获取当前time属性值

exp.parseExpression("time").setValue(secontext, new Date(113, 2, 25)); // 为time属性重新赋值

Date newDate = spel.getTime();// 获取赋值后的time属性值

assertEquals(2013,

exp.parseExpression("time.Year + 1900").getValue(secontext));

assertNotSame(oldDate, newDate);

// 或者使用下属方法赋值

assertEquals("abc",

exp.parseExpression("Name = 'abc'").getValue(secontext));

// 还原time默认,避免后续测试错误

spel.setTime(oldDate);

spel.setName("override");

}

/**

* 类型操作表达式测试

*

* @throws Exception

*/

@SuppressWarnings("rawtypes")

@Test

public void testSpelTypesExpression() throws Exception {

Class dateClass = exp.parseExpression("T(java.util.Date)").getValue(

Class.class);

assertEquals("java.util.Date", dateClass.getName());

assertTrue(exp

.parseExpression(

"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")

.getValue(Boolean.class));

}

/**

* 构造函数调用测试

*

* @throws Exception

*/

@Test

public void testSpelConstructorsExpression() throws Exception {

SpelTestInnerClass spt = exp

.parseExpression(

"new study.spring.beans.SpelTestInnerClass('constructTest',23)")

.getValue(SpelTestInnerClass.class);

assertEquals(23, spt.getAge());

assertEquals("constructTest", spt.getName());

}

/**

* 设置变量测试

*

* @throws Exception

*/

@SuppressWarnings("unchecked")

@Test

public void testSpelVariablesExpression() throws Exception {

List<Integer> list = new ArrayList<Integer>();

list.addAll(Arrays.asList(2, 3, 4, 5, 6, 7, 9));

secontext.setVariable("list", list);

List<Integer> vList = (List<Integer>) exp.parseExpression("#list")

.getValue(secontext);

assertEquals(vList, list);

List<Integer> nums = (List<Integer>) exp.parseExpression(

"#list.?[#this >5]").getValue(secontext); // 获取值大于5的元素集合

assertEquals(nums, Arrays.asList(6, 7, 9));

}

/**

* 自定义函数表达式测试

*

* @throws Exception

*/

@Test

public void testSpelFunctionExpression() throws Exception {

StandardEvaluationContext context = new StandardEvaluationContext();

context.registerFunction("len", SpElUtil.class.getDeclaredMethod("len",

new Class[] { String.class }));

assertEquals(3, exp.parseExpression("#len('abc')").getValue(context));

}

@Test

public void testSpelBeanExpression() throws Exception {

}

/**

* 三元操作测试

*

* @throws Exception

*/

@Test

public void testSpelTernaryOperatorExpression() throws Exception {

assertTrue(exp.parseExpression(" true ? true :false").getValue(

Boolean.class));

assertEquals("is true",

exp.parseExpression(" 1 == 1 ? 'is true' :'is false'")

.getValue(String.class));

}

/**

* Elvis 操作测试

*

* @throws Exception

*/

@Test

public void testSpeleElvisOperatorExpression() throws Exception {

Expression ex = exp.parseExpression("name?:'name is null'");

assertEquals("override", ex.getValue(secontext, String.class));

spel.setName(null);

assertEquals("name is null", ex.getValue(secontext, String.class));

spel.setName("override");

}

/**

* 安全导航操作测试

*

* @throws Exception

*/

@Test

public void testSpelSafeNavOperatorExpression() throws Exception {

assertEquals("innerClass", exp.parseExpression("innerClass?.name")

.getValue(secontext, String.class));

spel.setInnerClass(null);

// 使用这种表达式可以避免抛出空指针异常

assertNull(exp.parseExpression("innerClass?.name").getValue(secontext,

String.class));

}

/**

* 集合选择表达式测试

*

* @throws Exception

*/

@SuppressWarnings("unchecked")

@Test

public void testSpelCollectionSelectExpression() throws Exception {

spel.setNumbers(Arrays.asList(2, 3, 4, 5, 6, 7, 9));

List<Integer> nums = (List<Integer>) exp.parseExpression(

"numbers.?[#this >5]").getValue(secontext);

assertEquals(nums, Arrays.asList(6, 7, 9));

// 获取第一个元素

assertEquals(6,

exp.parseExpression("numbers.^[#this > 5]").getValue(secontext));

// 获取最后一个元素

assertEquals(9,

exp.parseExpression("numbers.$[#this > 5]").getValue(secontext));

Map<Integer, String> maps = (Map<Integer, String>) exp.parseExpression(

"maps.?[value == 'string3' ]").getValue(secontext);

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

tmap.put(3, "string3");

assertEquals(maps, tmap);

Map<Integer, String> mapk = (Map<Integer, String>) exp.parseExpression(

"maps.?[key > 2 and key < 4 ]").getValue(secontext);

assertEquals(mapk, tmap);

}

/**

* 投影表达式测试

*

* @throws Exception

*/

@SuppressWarnings("unchecked")

@Test

public void testSpelProjectionExpression() throws Exception {

spel.setNumbers(Arrays.asList(2, 3, 4, 5, 6));

assertEquals(Arrays.asList(5, 6, 7, 8, 9),

exp.parseExpression("numbers.![#this+3]").getValue(secontext));

List<Integer> keys = (List<Integer>) exp.parseExpression("maps.![key]")

.getValue(secontext);

assertEquals(keys, Arrays.asList(1, 2, 3, 4));

List<String> mapv = (List<String>) exp.parseExpression("maps.![value]")

.getValue(secontext);

assertEquals(mapv,

Arrays.asList("string1", "string2", "string3", "String4"));

List<Boolean> mapK = (List<Boolean>) exp.parseExpression(

"maps.![key > 2 and value !='String4']").getValue(secontext);

assertEquals(mapK, Arrays.asList(false, false, true, false));

}

/**

* 模板语言测试

*

* @throws Exception

*/

@Test

public void testSpelTemplate() throws Exception {

assertEquals(

" this is a test 4",

exp.parseExpression(" this is a test #{ maps.![key].get(3)}",

new TemplateParserContext()).getValue(secontext,

String.class));

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: