最新地址请访问: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进行表达式操作,基本操作如下:
第一步,构建解析ExpressionParser parser = new SpelExpressionParser();
第二步,使用表达式进行解析Expression exp = parser.parseExpression( SpEl);
第三步,获取结果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
spring-beans.xml
ApplicationContextFactory.javapackage 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.javapackage 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
SpElUtilTest.javapackage 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> 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