一、基本使用
1. 字面表达式
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();
System.out.println(message);
输出
Hello World
2、函数调用
调用 concat 进行字符串连接
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();
System.out.println(message);
输出
Hello World!
3、bean 属性调用
String property Bytes
ExpressionParser parser = new SpelExpressionParser();
// invokes 'getBytes()'
Expression exp = parser.parseExpression("'Hello World'.bytes");
byte[] bytes = (byte[]) exp.getValue();
System.out.println(bytes.length);
输出:11
4、构造函数创建对象
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
String message = exp.getValue(String.class);
System.out.println(message);
输出: HELLO WORLD
5、Inline List
ExpressionParser parser = new SpelExpressionParser();
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(List.class);
System.out.println(numbers);
输出如下: [1, 2, 3, 4]
6 Type与静态类
ExpressionParser parser = new SpelExpressionParser();
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
boolean trueValue = parser.parseExpression(
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
.getValue(Boolean.class);
System.out.println(dateClass);
System.out.println(stringClass);
System.out.println(trueValue);
输出:
class java.util.Date
class java.lang.String
true
7. 变量引用
首先得理解EvaluationContext, 在我们的 SpEL 表达式的解析中,getValue有一个参数就是这个 Context,你可以将他简单理解为包含一些对象的上下文,我们可以通过 SpEL 的语法,来访问操作 Context 中的某些成员、成员方法属性等
一般的操作过程如下:
context.setVariable("newName", Mike Tesla);向EvaluationContext中塞入成员变量parser.parseExpression(xxx).getValue(context)解析 SpEL 表达式,context 必须作为传参丢进去
个简单的实例
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Inventor {
private String name;
private String nationality;
}
ExpressionParser parser = new SpelExpressionParser();
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
context.setVariable("newName", "Mike Tesla");
parser.parseExpression("name = #newName").getValue(context, tesla);
System.out.println(tesla.getName());
输出如下:Mike Tesla
8.函数
Context 中的变量,除了是我们常见的基本类型,普通的对象之外,还可以是方法,在setVariable时,设置的成员类型为method即可
public class demo01 {
public static void main(String[] args) throws NoSuchMethodException {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 注册一个方法变量,参数为method类型
context.setVariable("hello", demo01.class.getDeclaredMethod("hello", String.class));
String ans = parser.parseExpression("#hello('一辉')").getValue(context, String.class);
System.out.println("function call: " + ans);
}
public static String hello(String test) {
return "hello" + test;
}
}
输出如下:
function call: hello一辉
9.bean 的访问
在 Spring 中,什么对象最常见?当然是 bean, 那么我们可以直接通过 SpEL 访问 bean 的属性、调用方法么?
要访问 bean 对象,所以我们的EvaluationContext中需要包含 bean 对象才行
- 借助
BeanResolver来实现,如context.setBeanResolver(new BeanFactoryResolver(applicationContext)); - 其次访问 bean 的前缀修饰为
@符号
为了演示这种场景,首先创建一个普通的 Bean 对象
@Data
@Component
public class BeanDemo {
private String blog = "https://juejin.cn/editor/drafts/7089353461644394509";
private Integer num = 8;
public String hello(String name) {
return "hello " + name + ", welcome to my blog " + blog;
}
}
接着我们需要获取ApplicationContext,所以可以稍微改一下我们的测试类,让它继承自ApplicationContextAware
@Component
@RestController
public class SpelController implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@RequestMapping("/spel/test")
public String hello(){
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
// 获取bean对象
BeanDemo beanDemo = parser.parseExpression("@beanDemo").getValue(context, BeanDemo.class);
// 访问bean方法
String ans = parser.parseExpression("@beanDemo.hello('一辉blog')").getValue(context, String.class);
return "bean method return: " + ans;
}
}
访问 http://127.0.0.1:8080/spel/test
输出如下:
二、小结
SpEL 属于非常强大的表达式语言了,就我个人的感觉而言,它和 OGNL 有些像,当它们的上下文中包含了 Spring 的上下文时,可以访问任何的 bean,而你可以借助它们的语法规范,做各种事情