Spring表达式语言简称:SpEL,SpEL既可以独立于Spring容器使用,,也可以在Spring配置文件中使用,这样就大大简化了Spring的Bean配置,给配置文件起到了“减肥”的作用,下面开始总结SpEL语法
1:直接量表达式
直接量表达式也是SpEL最简单的表达式,如下:
public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); // 使用直接量表达式 Expression exp = parser.parseExpression("'VipMao"); System.out.println(exp.getValue(String.class)); exp = parser.parseExpression("6.9"); System.out.println(exp.getValue(Double.class)); } }
运行结果:
VipMao
6.9
2:在表达式中创建数组
SpEL创建数组的方式和常规创建没有什么不同,SpEL也支持静态创建和动态创建两种方式。
public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); //------------使用SpEL创建数组----------- Expression exp=parser.parseExpression("new String[]{'Struts2','Hibernate','Spring'}"); System.out.println(exp.getValue(String.class)); // 创建二维数组 exp = parser.parseExpression( "new int[2][4]"); System.out.println(exp.getValue(int.class));; } }
运行结果:
Struts2,Hibernate,Spring
0
3:在表达式中创建List集合
SpEL支持直接使用{ele1,ele2,ele3...}语法来创建List集合,但是这样没法修改集合内的元素。
public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); //------------使用SpEL创建数组----------- Expression exp=parser.parseExpression("{'java','c语言','PHP'}"); System.out.println(exp.getValue(String.class)); // 创建“二维”List集合 exp = parser.parseExpression( "{{'孙悟空' , '哪吒'}, {'刘备' , '诸葛亮'}}"); System.out.println(exp.getValue()); } }
运行结果:
java,c语言,PHP
[[孙悟空, 哪吒], [刘备, 诸葛亮]]
4:SpEL中访问List、Map等元素集合
在SpEL中通过list[index]访问List集合元素,通过map[key]访问Map集合元素,下面咱们通过常规创建集合,修改他们的集合元素并访问特定的集合元素。
public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); //------------使用SpEL创建数组----------- //------------使用SpEL访问List集合、Map集合的元素----------- List<String>list=new ArrayList<String>(); list.add("java"); list.add("PHP"); Map<String,Double>map=new HashMap<String,Double>(); map.put("math", 78.8); map.put("chinese", 98.6); map.put("english", 92.2); // 创建一个EvaluationContext对象,作为SpEL解析变量的上下文 EvaluationContext ctx = new StandardEvaluationContext(); // 设置两个变量 ctx.setVariable("list", list); ctx.setVariable("myMap", map); //修改并访问集合 parser.parseExpression("#list[0]").setValue(ctx, "JavaEE"); parser.parseExpression("#myMap['math']").setValue(ctx, 99.9); System.out.println("List集合中第一个元素为:"+parser.parseExpression("#list[0]").getValue(ctx)); System.out.println("map中修改后的value为:"+parser.parseExpression("#myMap['math']").getValue(ctx)); } }
咱们通过setVariable()将集合设置成上下文的变量,通过setValue()修改指定集合的值,通过getValue获得指定集合的值。
运行结果:
List集合中第一个元素为:JavaEE
map中修改后的value为:99.9
5:调用方法
与平常调用方法没什么太大的区别
public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); //------------使用SpEL调用方法----------- // 调用String对象的substring()方法 System.out.println(parser.parseExpression("'VipMao'.substring(0,3)").getValue()); List<String>list=new ArrayList<String>(); list.add("java"); list.add("PHP"); // 创建一个EvaluationContext对象,作为SpEL解析变量的上下文 EvaluationContext ctx = new StandardEvaluationContext(); // 设置两个变量 ctx.setVariable("list", list); System.out.println(parser.parseExpression("#list.subList(0,2)").getValue(ctx)); } }
运行结果:
Vip
[java, PHP]
6:算术、比较、赋值、三元运算符
public class SpelGrammar { public static void main(String[]args) { //------------在SpEL中使用运算符----------- // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); List<String>list=new ArrayList<String>(); list.add("java"); list.add("PHP"); // 创建一个EvaluationContext对象,作为SpEL解析变量的上下文 EvaluationContext ctx = new StandardEvaluationContext(); // 设置两个变量 ctx.setVariable("list", list); parser.parseExpression("#list[0]='JavaEE'").getValue(ctx); System.out.println(parser.parseExpression("#list").getValue(ctx)); //使用三元运算符 System.out.println(parser.parseExpression("#list.size()>3?'mylist长度大于3':'mylist长度不大于3'").getValue(ctx)); } }
可以看出上面程序我们直接通过#list[0]=‘JavaEE对集合第一个元素进行了赋值,而且还使用了三元运算符 a>b?a:b
运行结果:
[JavaEE, PHP]
mylist长度不大于3
7:类型运算符
SpEL提供了一个特殊的运算符:T(),这个运算符就告诉SpEL将运算符内的字符串当成是“类”处理,避免SpEL进行其他处理,尤其在调用某个类的静态方法时,T()运算符尤其有用。
public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); //------------在SpEL中使用类型运算符----------- //调用Math的静态方法 System.out.println(parser.parseExpression("T(java.lang.Math).random()").getValue()); //调用Math的静态方法 System.out.println(parser.parseExpression("T(System).getProperty('os.name')").getValue()); } }
我们在程序中通过T(java.lang.Math).random()获取Math类的random()的方法用于随机获取一个数字,这里需要注意的是T()括号内推荐使用全限定类名,即写上所在包名,如果不写,SpEL会默认在java.lang包下寻找这些类。
运行结果:
0.6289150409783065
Windows 7
8:调用构造器
SpEL可以直接通过new来调用构造器,通过这种方式来创建一个java对象
public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); //------------在SpEL中调用构造器----------- System.out.println(parser.parseExpression("new String('HelloWorld').substring(2, 4)").getValue()); System.out.println(parser.parseExpression("new javax.swing.JFrame('测试').setVisible('true')").getValue()); } }
通过new创建一个String字符串HelloWorld,并调用substring()进行字符串截取
运行结果:
ll
null
以及一个窗体
9:安全导航操作
安全导航,听意思就是为了防止报错,比如person.name这条语句,如果person对象已经为空,那么name这里肯定会报空指针NullPointerException异常,为了避免,在SpEL中可以这样写 person?.bar,如果person为空,直接返回空,程序不再往下走,也就不会再报NullPointerException异常
import java.util.*; import org.springframework.expression.*; import org.springframework.expression.common.TemplateParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); //------------在SpEL中使用安全导航操作----------- // 使用安全操作,将输出null System.out.println("---"+parser.parseExpression("#foo?.bar").getValue()); //不使用安全操作,将引发NullPointerException异常 System.out.println(parser.parseExpression("#foo.bar").getValue()); } }
第一条输出语句使用了安全导航操作#foo?.bar会输出空,但是第二条语句没有使用安全导航操作则会报错。
10:集合的选择
SpEL通过collection.?[condition_expr]对集合按照特定的筛选条件进行筛选。只有符合条件的集合才会被筛选出来。
public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); List<String>list=new ArrayList<String>(); list.add("java"); list.add("PHP"); list.add("JavaScript"); Map<String,Double>map=new HashMap<String,Double>(); map.put("math", 92.8); map.put("chinese", 98.6); map.put("english", 92.2); // 创建一个EvaluationContext对象,作为SpEL解析变量的上下文 EvaluationContext ctx = new StandardEvaluationContext(); // 设置两个变量 ctx.setVariable("list", list); ctx.setVariable("myMap", map); //长度大于7的list集合元素将被筛选出来 Expression expr=parser.parseExpression("#list.?[length()>7]"); System.out.println("符合条件的List元素是:"+expr.getValue(ctx)); //key的长度小于5且value>90的map元素将被筛选出来 expr=parser.parseExpression("#myMap.?[key.length()<5&&value>90]"); System.out.println("符合条件的Map值为:"+expr.getValue(ctx)); } }
程序对list集合、map集合通过collection.?[condition_expr]进行了筛选,这里需要注意的是,当操作Map集合的时候,需要显式地用key引用Map
Entry的key,用value引用Map Entry的value,比如咱们筛选条件是:Map key的长度需要小于5,那就是#myMap.?[key.length()<5]。如果咱们的筛选条件是:Map value的值大于90,那就是#myMap.?[value>90]。如果筛选条件需要同时满足以上两条条件就是:#myMap.?[key.length()<5&&value>90]
运行结果:
符合条件的List元素是:[JavaScript]
符合条件的Map值为:{math=92.8}
11:集合的投影
集合投影就是原集合按照一定的“投影条件”对原集合的每一个元素进行投影,把“投影出来的影子”组成新的集合,它和集合的筛选不一样,筛选是筛选出来符合条件的集合元素,但是并不组成新的集合,但是投影则需要被组成新的集合。
SpEL投影运算的语法格式:
collection.![condition_expr],和集合筛选很像,筛选是?,是不是符合条件?符合被筛选出来,而投影则是!。
public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); List<String>list=new ArrayList<String>(); list.add("java"); list.add("PHP"); list.add("JavaScript"); // 创建一个EvaluationContext对象,作为SpEL解析变量的上下文 EvaluationContext ctx = new StandardEvaluationContext(); // 设置变量 ctx.setVariable("list", list); //------------在SpEL中对集合进行投影----------- //将每个集合元素进行截取,组成新的集合 Expression expr=parser.parseExpression("#list.![substring(1,3)]"); System.out.println("投影后的新集合为:"+expr.getValue(ctx)); List<Person>list2=new ArrayList<Person>(); list2.add(new Person(1,"VipMao",130)); list2.add(new Person(2,"ZhuLin",105)); ctx.setVariable("mylist2", list2); expr=parser.parseExpression("#mylist2"); System.out.println("投影前的集合为:"+expr.getValue(ctx)); //投影条件是 只要name属性 expr=parser.parseExpression("#mylist2.![name]"); System.out.println("投影后的新集合为"+expr.getValue(ctx)); } }
上面通过投影条件依次对集合的每一个元素进行了投影,然后组成了新的集合,上面也说到了投影和筛选的不同,筛选是对满足条件的集合元素进行筛选,不满足的直接略过,但是投影不行,他需要对每一个集合元素都完成投影,如果有一个集合元素,没法满足投影条件导致投影失败,程序就会报错,比如我们将第一个集合投影条件改为截取2-5个长度,但是java、php的长度都不到5,那就会报错。第二个集合用到了Person类,以下
public class Person { private Integer id; private String name; private int weight; public Person(Integer id, String name, int weight) { this.id = id; this.name = name; this.weight = weight; } //省略所有set、get方法 public String toString(){ return "id:"+id+",name:"+name+",weight:"+weight; } }
运行结果:
投影后的新集合为:[av, HP, av]
投影前的集合为:[id:1,name:VipMao,weight:130, id:2,name:ZhuLin,weight:105]
投影后的新集合为[VipMao, ZhuLin]
从结果可以看出,已经按照投影条件组成了相应的集合。
12:表达式模板
有点类似于占位符的国际化消息
public class SpelGrammar { public static void main(String[]args) { // 创建一个ExpressionParser对象,用于解析表达式 ExpressionParser parser = new SpelExpressionParser(); //------------在SpEL中使用表达式模板----------- Person p1 = new Person(1, "孙悟空" , 120); Person p2 = new Person(2, "猪八戒" , 220); Expression expr3 = parser.parseExpression("我的名字是#{name}" + ",体重是#{weight}", new TemplateParserContext()); // 将使用p1对象name、height填充上面表达式模板中的#{} System.out.println(expr3.getValue(p1)); // 将使用p2对象name、height填充上面表达式模板中的#{} System.out.println(expr3.getValue(p2)); } }
使用表达式模板需要传入一个TemplateParserContext参数
运行结果:
我的名字是孙悟空,体重是120
我的名字是猪八戒,体重是220