SpEL主要提供如下三个接口:
- ExperssionParser : 该接口中的实例方法parseExpression(String str)负责将字符串str解析,返回Expression 对象。
- Expression 该接口实例代表一个表达式
- EvaluationContext : 计算表达式上下文,类似于ApplicationContext功能
三个接口中的主要方法:
-
ExperssionParser中有方法:
Expression parseExpression(String str): 负责将字符串str解析,返回Expression 对象。 -
Expression中有方法:
Object getValue(): 计算表达式的值。
<T> T getValue(Class<T> desiredResultType): 计算表达式的值,并尝试吧表达式的值当成指定类型来处理。Object getValue(EvaluationContext context): 用指定的EvaluationContext 计算表达式的值。
<T> T getValue(EvaluationContext context, Class<T> desiredResultType): 用指定的EvaluationContext 计算表达式的值,并尝试吧表达式的值当成指定类型来处理。Object getValue(Object rootObject): 以rootObject作为表达式的root对象来计算表达式的值。
<T> T getValue(Object rootObject,Class<T> desiredResultType): 以rootObject作为表达式的root对象来计算表达式的值,并尝试吧表达式的值当成指定类型来处理。 -
EvaluationContext中有方法:
void setVariable(String name,Object value):向EvaluationContext中添加新的对象
void setRootObject(Object rootObject):设置EvaluationContext的rootObject,在SpEL访问root对象的属性时,可以省略root对象前缀
下面程序演示了比较全面的SpEL的详细用法,以及一些知识点说明
public class SpELTest
{
public static void main(String[] args)
{
//表达式解析器
SpelExpressionParser parser = new SpelExpressionParser();
//直接量表达式
Expression ex = parser.parseExpression("'Hello world!'");
System.out.println(ex.getValue());//Hello world!
ex = parser.parseExpression("0.2");
System.out.println(ex.getValue(Double.class));//0.2
//list集合
ex = parser.parseExpression("{56,'哈哈啊哈',{'嵌套list',666}}");
System.out.println(ex.getValue());//[56, 哈哈啊哈, [嵌套list, 666]]
//数组
ex = parser.parseExpression("new String[]{'孙悟空','沙和尚','猪八戒'}");
System.out.println(ex.getValue());//[Ljava.lang.String;@7a220c9a
//访问List、Map等集合的元素
var list = List.of("白云","大地",45);
var map = Map.of("语文",59,"数学",66,"英语",15);
//创建容器,相当于传统的ApplicationContext
StandardEvaluationContext ctx = new StandardEvaluationContext();
//向容器中添加变量,相当于传统的在ApplicationContext中添加bean元素
ctx.setVariable("li",list);
ctx.setVariable("ma",map);
//#表示该变量是在容器中的
ex = parser.parseExpression("#li[1]");
//在getValue中指定容器
System.out.println(ex.getValue(ctx));//大地
ex = parser.parseExpression("#ma['英语']");
System.out.println(ex.getValue(ctx));//15
//调用方法
ctx.setVariable("str","ABCDE");
ex = parser.parseExpression("#str.length()");
System.out.println(ex.getValue(ctx));//5
//算数运算符、比较运算符、逻辑运算符、赋值运算符、三目运算符
ex = parser.parseExpression("15+15/5 > 17");
System.out.println(ex.getValue());//true
ctx.setVariable("num",5);
ex = parser.parseExpression("#num = #num + 1");
System.out.println(ex.getValue(ctx));//6
ex = parser.parseExpression("#num==6? 'num等于6' : 'num不等于6' ");
System.out.println(ex.getValue(ctx));//num等于6
//类型运算符
//T()告诉SpEl把它当成一个类来处理,而不是其他解析
ex = parser.parseExpression("T(java.lang.System).getProperty('os.name')");
System.out.println(ex.getValue());//Windows 10
//调用构造器
ex = parser.parseExpression("new java.util.Date()");
System.out.println(ex.getValue());//Sat Aug 15 11:47:06 CST 2020
//SpEL特殊变量
//#this:引用SpEl正在计算的对象
//#root:引用SpEL的容器的root对象,容器的方法setRootObject用来设置容器唯一的root
//自定义函数,实质就是引入方法并且重命名方法名
//容器StandardEvaluationContext中的方法:
//registerFunction(String newName,Method m):将m方法在容器中注册成自定义函数
//该功能意义不大
//安全导航
//?表示如果aaa不为null就访问aaa.bbb,否则只会访问aaa不会往下访问bbb(ctx中没有aaa变量)
ex = parser.parseExpression("#aaa?.bbbb");
System.out.println(ex.getValue(ctx));//null
// ex = parser.parseExpression("#aaa.bbbb");
// System.out.println(ex.getValue(ctx));//空指针异常
//集合元素选择(集合元素筛选)
//语法:collection.?[condition_expr]
var list2 = List.of("德玛西亚","守望之海","祖安");
ctx.setVariable("li2",list2);
ex = parser.parseExpression("#li2.?[length() < 4]");
System.out.println(ex.getValue(ctx));//[祖安]
//集合投影运算(对集合元素进行处理,然后把处理后的值替换掉原来的值返回)
var list3 = List.of("皮城女警","未来守护者","诺克萨斯之手");
ctx.setVariable("li3",list3);
ex = parser.parseExpression("#li3.![length()]");
System.out.println(ex.getValue(ctx));//[4, 5, 6]
}
}