Spring表达式语言(简称SpEL)是一个支持查询并在运行时操纵一个对象图的功能强大的表达式语言。SpEL语言的语法类似于统一EL,但提供了更多的功能,最主要的是显式方法调用和基本字符串模板函数。
同很多可用的Java 表达式语言相比,例如OGNL,MVEL和JBoss EL,SpEL的诞生是为了给Spring社区提供一个可以给Spring目录中所有产品提供单一良好支持的表达式语言。其语言特性由Spring目录中的项目需求驱动,包括基于eclipse的SpringSource套件中的代码补全工具需求。也就是说,SpEL是一个基于技术中立的API允许需要时与其他表达式语言集成。
SpEL作为Spring目录中表达式求值的基础,它并不是直接依赖于Spring而是可以被独立使用。为了能够自包含,本章中的许多示例把SpEL作为一个独立的表达式语言来使用。这就需要创建一些如解析器的引导基础组件类。大多数Spring用户只需要为求值编写表达式字符串而不需要关心这些基础组件
SpEL表达式 Hello World
Spring表达式语言(SpEL)从3.X开始支持,它是一种能够支持运行时查询和操作对象的强大的表达式,其表达式语法类似于统一表达式语言。
SpEL支持如下表达式:
- 基本表达式:字面量表达式、关系,逻辑与算数运算表达式、字符串连接及截取表达式、三目运算、正则表达式、括号优先级表达式;
- 类相关表达式:类类型表达式、类实例化、instanceof表达式、变量定义及引用、赋值表达式、自定义函数、对象属性存取及安全导航表达式、对象方法调用、Bean引用;
- 集合相关表达式:内联List、内联数组、集合,字典访问、列表,字典,数组修改、集合投影、集合选择;不支持多维内联数组初始化;不支持内联字典定义;
- 其他表达式:模板表达式。
从一个Hello World!的示例开始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static void main(String[] args) { ExpressionParser parser=new SpelExpressionParser(); Expression exp=parser.parseExpression("'Hello '+' World!'"); String result=exp.getValue().toString(); System.out.println(result); }
|
从示例中可以看出java成功的将一个字符解析出了结果,如果我们把要解析的内容设置成1+1则会解析出2来,这里的1+1就是一个SpEL表达式,该表达式在java中只是一个String,通过解析可以得到字符串本身的意见,有点类型编译程序的感觉。
SpEL表达式
1、文字表达式
支持的文字表达的类型是字符串,日期,数值(整型,实型,和十六进制),布尔和空。字符串是由单引号分隔。使用反斜杠字符转移把一个单引号字符本身放在字符串中。
1 2 3 4 5
| ExpressionParser ep= new SpelExpressionParser(); System.out.println(ep.parseExpression("'HelloWorld'").getValue()); System.out.println(ep.parseExpression("0xffffff").getValue()); System.out.println(ep.parseExpression("1.234345e+3").getValue()); System.out.println(ep.parseExpression("new java.util.Date()").getValue());
|
运行结果:
HelloWorld
16777215
1234.345
Fri Jul 01 14:50:59 CST 2016
2、属性
1 2 3 4 5 6 7 8 9 10 11 12 13
| ExpressionParser parser=new SpelExpressionParser(); User user=new User(9527,"周星驰"); EvaluationContext ctx = new StandardEvaluationContext(); ctx.setVariable("user", user); int id = (Integer) parser.parseExpression("#user.getId() + 1900").getValue(ctx); System.out.println(id);
|
User类在前面已定义,这里增加了一个有参构造方法。上面的示例是调用方法,其实可以这样:引用对象属性,只需使用一个句点来表示一个嵌套的属性值,如下代码所示:
1
| int id = (Integer) parser.parseExpression("#user.id + 1900").getValue(ctx);
|
要注意的是此时#user后不再是一个方法而是.id,直接访问属性,在java中这样做是不行的,便SpEL中允许
3、数组
1 2 3 4 5 6 7
| String[] students=new String[]{"tom","jack","rose","mark","lucy"}; ctx.setVariable("students", students); String student = parser.parseExpression("#students[3]").getValue(ctx, String.class); System.out.println(student);
|
4、列表
1 2 3 4 5 6
| List numbers = (List) parser.parseExpression("{1,2,3,4,5}").getValue(); System.out.println(numbers.get(2)+""); List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(); System.out.println(((List)listOfLists.get(1)).get(1));
|
5、索引器、与字典
1 2 3 4 5 6 7 8 9 10
| User user1=new User(9001,"邹任飞"); User user2=new User(9002,"练汶峰"); List<User> users=new ArrayList<User>(); users.add(user1); users.add(user2); ctx.setVariable("users", users); String name = parser.parseExpression("#users[1].name").getValue(ctx,String.class); System.out.println(name);
|
在java中访问集合中的对象通过get(索引)而在SpEL中我们可以直接像数组那样访问对象。如果是一个字典可以这样:#users[“tom”].id
6、方法
方法调用使用典型的Java编程语法。 你可能 还在文字调用方法。 也支持可变参数。
1 2 3 4
| String c = parser.parseExpression("'abcdef'.substring(2, 3)").getValue(String.class); System.out.println(c);
|
7、操作符
关系操作符:使用标准的操作符号支持关系操作符:等于,不等于,小于,小于等于,大于,大于等于。
逻辑操作符:支持的逻辑操作符包括and,or和not(!),不支持&&和||。
算术操作符:加法运算符可以用于数字,字符串和日期。减法可用于数字和日期。乘法和除法仅可以用于。其他支持的数学运算包括取模(%)和指数幂(^)。使用标准的运算符优先级。
关系运算符:
1 2 3 4 5 6 7 8 9 10 11 12
| boolean trueValue1 = parser.parseExpression("2 == 2").getValue(Boolean.class);
boolean falseValue1 = parser.parseExpression("2 < -5.0").getValue(Boolean.class);
boolean trueValue2 = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);
boolean falseValue2 = parser.parseExpression("'xyz' instanceof T(int)").getValue(Boolean.class);
boolean trueValue3 =parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
boolean falseValue3=parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
|
逻辑运算:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
boolean falseValue4 = parser.parseExpression("true and false").getValue(Boolean.class);
String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')"; boolean trueValue4 = parser.parseExpression(expression).getValue(Boolean.class);
boolean trueValue5 = parser.parseExpression("true or false").getValue(Boolean.class);
String expression1 = "isMember('Nikola Tesla') or isMember('Albert Einstein')"; boolean trueValue6 = parser.parseExpression(expression).getValue( Boolean.class);
boolean falseValue5 = parser.parseExpression("!true").getValue(Boolean.class);
String expression2 = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')"; boolean falseValue6 = parser.parseExpression(expression).getValue(Boolean.class);
|
算术运算:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| int two = parser.parseExpression("1 + 1").getValue(Integer.class); String testString = parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class);
int four = parser.parseExpression("1 - -3").getValue(Integer.class); double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class);
int six = parser.parseExpression("-2 * -3").getValue(Integer.class); double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class);
int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class);
int three = parser.parseExpression("7 % 4").getValue(Integer.class); int one = parser.parseExpression("8 / 5 % 2").getValue(Integer.class);
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class);
|
8、表达式支持定义bean、****基于注解的配置
用户类User.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 31 32 33 34 35 36 37
| package com.zhangguo.Spring053.spel03;
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;
@Component("user1") public class User {
@Value("#{9527+100}") private int id;
@Value("#{'Hello'.toUpperCase()}") private String name;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
|
订单类:Order.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 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
| package com.zhangguo.Spring053.spel03;
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Repository;
@Repository("Order03") public class Order {
@Value("#{'Apple订单'}") private String orderName;
@Value("#{user1.name}") private String userName;
@Value("#{user1}") private User customer;
public String getOrderName() { return orderName; }
public void setOrderName(String orderName) { this.orderName = orderName; }
public User getCustomer() { return customer; }
public void setCustomer(User customer) { this.customer = customer; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; } @Override public String toString() { return "订单名:"+this.getOrderName()+",姓名:"+this.getUserName()+",编号:"+this.getCustomer().getId(); } }
|
测试代码Test.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.zhangguo.Spring053.spel03;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zhangguo.Spring053.spel03.User;
public class Test {
public static void main(String[] args) { ApplicationContext ctx=new ClassPathXmlApplicationContext("spel03.xml"); User user1=ctx.getBean("user1",User.class); System.out.println(user1.getId()+","+user1.getName()); Order Order03=ctx.getBean("Order03",Order.class); System.out.println(Order03); } }
|
9、操作符
1 2 3 4 5 6 7 8
| ExpressionParser ep = new SpelExpressionParser();
System.out.println(ep.parseExpression("5>2").getValue()); System.out.println(ep.parseExpression("2 between {1,9}").getValue());
System.out.println(ep.parseExpression("(5>2) and (2==1)").getValue());
System.out.println(ep.parseExpression("100-2^2").getValue());
|
结果:
true
true
false
96
10、变量与赋值
变量:变量可以在表达式中使用语法#’变量名’引用
1 2 3 4 5 6 7
| ExpressionParser ep= new SpelExpressionParser();
EvaluationContext ctx = new StandardEvaluationContext(); ctx.setVariable("name", "Hello"); System.out.println(ep.parseExpression("#name").getValue(ctx));
|
11、模板
1 2 3 4 5 6 7 8 9 10 11
| String template = "Hello, #{#name}! Today's date is #{#date}.";
EvaluationContext context = new StandardEvaluationContext(); context.setVariable("name", "Alice"); context.setVariable("date", LocalDate.now().toString()); ExpressionParser parser = new SpelExpressionParser(); String result = parser.parseExpression(template, new TemplateParserContext()).getValue(context, String.class); System.out.println(result);
|
注意,如果context不存在此变量,则不赋值,并且 #