2025年SpEL表达式的使用

SpEL表达式的使用Spring Expression Language SpEL 是 Spring 提供的一种的表达式语言 支持在运行时查询和操作对象 SpEL 并不直接与 Spring 相关联 可以独立使用 SpEL 解析器 SpEL 提供了对应的解析器 SpelExpressi 用于解析 SpEL 表达式 EvaluationCo

大家好,我是讯享网,很高兴认识大家。

Spring Expression Language

SpEL是Spring提供的一种的表达式语言,支持在运行时查询和操作对象。

SpEL并不直接与Spring相关联,可以独立使用。

SpEL解析器

SpEL提供了对应的解析器SpelExpressionParser用于解析SpEL表达式

EvaluationContext

EvaluationContext用于计算表达式以解析属性、方法、字段,并帮助执行类型转换。

Spring提供了两个实现SimpleEvaluationContextStandardEvaluationContext

表达式类型

Literal Expressions 文字表达式

文字表达式支持字符串、数值、布尔值、空值。字符串由单引号进行引用,要将单引号本身放在字符串中,需使用两个单引号。

数字类型支持使用负号、指数表示法、小数点,默认使用Double.parseDouble()解析数值

ExpressionParser parser = new SpelExpressionParser(); String helloWorld = (String) parser.parseExpression("'Hello World'").getValue(); System.out.println(helloWorld); // Hello World String word = (String) parser.parseExpression("'''word'''").getValue(); System.out.println(word); // 'word' double avogadrosNumber = (Double) parser.parseExpression("6.0E+23").getValue(); System.out.println(avogadrosNumber); // 6.0E23 int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue(); System.out.println(maxValue); //  boolean trueValue = (Boolean) parser.parseExpression("true").getValue(); System.out.println(trueValue); // true Object nullValue = parser.parseExpression("null").getValue(); System.out.println(nullValue==null); // true 

讯享网

Properties, Arrays, Lists, Maps, and Indexers 属性,数组,列表,Map,索引

通过点进行属性获取,嵌套属性使用点对属性进行分隔

properties 属性

讯享网@AllArgsConstructor @NoArgsConstructor @Data public static class TestVo{ 
    private String name; private int age; private Date birth; private Addr addr; } @AllArgsConstructor @NoArgsConstructor @Data public static class Addr{ 
    private String province; private String city; } 
TestVo testVo = new TestVo("young", 20, new Date(), new Addr("beijing", "beijing")); ExpressionParser parser = new SpelExpressionParser(); int year = (int) parser.parseExpression("birth.year+1900").getValue(testVo); System.out.println(year); // 2021 String city = (String) parser.parseExpression("addr.city").getValue(testVo); System.out.println(city); // beijing 

数组、列表

数组,列表,可以通过[]指定下标来获取对应的值,其余与properties一样

讯享网@AllArgsConstructor @Data public static class TestList{ 
    private List<Integer> listField; } 
List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); // 0-9 int[] arr = IntStream.range(0, 10).toArray(); // 0-9 ExpressionParser parser = new SpelExpressionParser(); System.out.println(parser.parseExpression("[5]").getValue(list));// 5 System.out.println(parser.parseExpression("[9]").getValue(arr)); // 9 TestList testList = new TestList(list); System.out.println(parser.parseExpression("listField[4]").getValue(testList)); // 4 

Map

map的内容是通过[]中指定key来获取值的,对象类型也可以用同样的方式获取,字符串类型的key要用单引号引起来

讯享网TestVo testVo = new TestVo("young", 20, new Date(), new Addr("shanxi", "xi'an")); ExpressionParser parser = new SpelExpressionParser(); System.out.println(parser.parseExpression("['name']").getValue(testVo)); // young  System.out.println(parser.parseExpression("addr['city']").getValue(testVo)); // xi'an Map<String,String> map = new HashMap<>(); map.put("beijing","beijing"); map.put("shanxi","xi'an"); map.put("jiangsu","南京"); System.out.println(parser.parseExpression("['jiangsu']").getValue(map)); // 南京 

Inline Lists 内联列表

可以使用{}直接在表达式中表示列表,{}表示一个空列表,如果完全由固定文字组成,则SpEL会创建一个列表常量

ExpressionParser parser = new SpelExpressionParser(); List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(); System.out.println(numbers); // [1, 2, 3, 4] List listOfLists = (List) parser.parseExpression("{ 
   {'a','b'},{'x','y'}}").getValue(); System.out.println(listOfLists); // [[a, b], [x, y]] 

Inline Maps 内联Map

可以使用{key:value}直接在表达式中表示Map,{:}表示一个空Map

讯享网ExpressionParser parser = new SpelExpressionParser(); Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(); System.out.println(inventorInfo); // {name=Nikola, dob=10-July-1856} Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(); System.out.println(mapOfMaps); // {name={first=Nikola, last=Tesla}, dob={day=10, month=July, year=1856}} 

Array Construction 构建数组

可以使用Java的数组构建语法构建表示一个数组,构建多维数组时,不能进行初始化操作

ExpressionParser parser = new SpelExpressionParser(); int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(); int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(); int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(); 

Methods 方法

可以调用java的方法,支持可变参数

讯享网public static class TestMethod{ 
    public boolean isString(Object obj){ 
    return obj!=null && obj.getClass().equals(String.class); } } 
ExpressionParser parser = new SpelExpressionParser(); System.out.println(parser.parseExpression("'Hello World'.concat('!')").getValue()); // Hello World! System.out.println(parser.parseExpression("'Hello World'.bytes.length").getValue()); // 11 System.out.println(parser.parseExpression("new String('hello world').toUpperCase()").getValue()); // HELLO WORLD System.out.println(parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class)); // bc TestMethod testMethod = new TestMethod(); System.out.println(parser.parseExpression("isString(123)").getValue(testMethod)); // false System.out.println(parser.parseExpression("isString('123')").getValue(testMethod));// true 

Operators 运算符

关系运算符

支持等于,不等于,大于,大于等于,小于,小于等于这类标准关系运算符,还支持instanceof和基于正则表达式的matches运算

对于null值,任何非null的值都大于null,及x>null恒等于true,x<null恒等于false

讯享网ExpressionParser parser = new SpelExpressionParser(); System.out.println(parser.parseExpression("2 == 2").getValue(Boolean.class)); // true System.out.println(parser.parseExpression("2 < -5.0").getValue(Boolean.class)); // false System.out.println(parser.parseExpression("'black' < 'block'").getValue(Boolean.class)); // true System.out.println(parser.parseExpression("'black' == 'black'").getValue(Boolean.class)); // true System.out.println(parser.parseExpression("'xyz' instanceof T(Integer)").getValue(Boolean.class)); // false System.out.println(parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class)); // true System.out.println(parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class)); // false System.out.println(parser.parseExpression("1 instanceof T(int)").getValue(Boolean.class)); // false System.out.println(parser.parseExpression("1 instanceof T(Integer)").getValue(Boolean.class));// true 

SpEL中 T表示类型

基本类型会被处理成包装类,所以instanceof int为false

为了避免符号对嵌入表达式的文档类型(如xml)有特殊含义是,表达式可以使用转义符,且不区分大小写

  • lt (<)
  • ge (>)
  • le (<=)
  • ge (>=)
  • eq (==)
  • ne (!=)
  • div (/)
  • mod (%)
  • not (!)
逻辑运算符
  • and (&&)
  • or (||)
  • not (!)
ExpressionParser parser = new SpelExpressionParser(); TestMethod testMethod = new TestMethod(); System.out.println(parser.parseExpression("true and false").getValue(Boolean.class)); // false String expression = "isString('abc') and isString(123)"; System.out.println(parser.parseExpression(expression).getValue(testMethod, Boolean.class)); // false System.out.println(parser.parseExpression("true or false").getValue(Boolean.class)); // true expression = "isString('abc') or isString(123)"; System.out.println(parser.parseExpression(expression).getValue(testMethod, Boolean.class)); // true System.out.println(parser.parseExpression("!true").getValue(Boolean.class)); // false expression = "isString('abc') and !isString(123)"; System.out.println(parser.parseExpression(expression).getValue(testMethod, Boolean.class)); // true 
数学运算符

可以对数字和字符串使用加法运算符(+),对数字可以使用减法(-),乘法(*)、除法(/)、取模(%),指数幂(^)运算,按标准运算符优先级进行执行

讯享网ExpressionParser parser = new SpelExpressionParser(); System.out.println(parser.parseExpression("1 + 1").getValue(Integer.class)); // 2 System.out.println(parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class)); // test string System.out.println(parser.parseExpression("1 - -3").getValue(Integer.class)); // 4  System.out.println(parser.parseExpression("1000.00 - 1e4").getValue(Double.class)); // -9000.0 System.out.println(parser.parseExpression("-2 * -3").getValue(Integer.class)); // 6 System.out.println(parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class)); // 24.0 System.out.println(parser.parseExpression("6 / -3").getValue(Integer.class)); // -2 System.out.println(parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class)); // 1.0 System.out.println(parser.parseExpression("7 % 4").getValue(Integer.class)); // 3 System.out.println(parser.parseExpression("8 / 5 % 2").getValue(Integer.class)); // 1 System.out.println(parser.parseExpression("1+2-3*8").getValue(Integer.class)); // -21 
赋值运算符

设置属性,可以使用赋值运算符=,可以使用getValue和setValue两种方法


讯享网

ExpressionParser parser = new SpelExpressionParser(); TestVo testVo = new TestVo(); parser.parseExpression("name").setValue(testVo, "young"); System.out.println(testVo); // TestMain.TestVo(name=young, age=0, birth=null, addr=null) String name = parser.parseExpression( "name = 'jordan'").getValue(testVo, String.class); System.out.println(name); // jordan System.out.println(testVo); //TestMain.TestVo(name=jordan, age=0, birth=null, addr=null) 

Types 类

可以使用T运算符来指定java.lang.Class的实例,静态方法也通过此运算符调用。除了java.lang包下的类,其余的类均需使用全限定类名

讯享网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); String value = parser.parseExpression("T(String).valueOf(100)").getValue(String.class); // 100 

Constructors 构造函数

可使用new调用构造函数,除了java.lang包中的类型,其他类型都应该写全限定类名

Variables 变量

可以使用#variableName引用变量,变量是使用实现setVariable上的方法设置的EvaluationContext

变量名规则由以下描述的一个或多个字符组成

  • 字母A到Z或a到z
  • 数字0到9
  • 下划线 _
  • 美元符号 $
ExpressionParser parser = new SpelExpressionParser(); SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build(); context.setVariable("testName","young"); TestVo testVo = new TestVo(); parser.parseExpression("name = #testName").getValue(context,testVo); System.out.println(testVo); // TestMain.TestVo(name=young, age=0, birth=null, addr=null) 
#this和#root

#root 表示跟对象,可以通过EvaluationContext设置或在调用方法时指定

#this 表示当前变量

讯享网ExpressionParser parser = new SpelExpressionParser(); StandardEvaluationContext context = new StandardEvaluationContext(); List<Integer> primes = new ArrayList<>(); primes.addAll(Arrays.asList(2,3,5,7,11,13,17)); context.setVariable("primes", primes); List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context); // [11, 13, 17] System.out.println(primesGreaterThanTen); Map<String,Object> map = new HashMap<>(); map.put("code",5); context.setVariable("primesMap", map); // context.setRootObject(map); System.out.println(parser.parseExpression("#primes.?[#this>#root['code']]").getValue(context,map)); // [7, 11, 13, 17] 

Functions 方法

可以自定义方法来扩展SpEL,通过EvaluationContext进行注册,被注册的方法必须是被static修饰

public static class TestMethod{ 
    public static boolean isString(Object obj){ 
    return obj!=null && obj.getClass().equals(String.class); } } 
讯享网EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); context.setVariable("myFunction", TestMethod.class.getDeclaredMethod("isString", Object.class)); ExpressionParser parser = new SpelExpressionParser(); System.out.println(parser.parseExpression("#myFunction(123)").getValue(context)); // false 

Bean References Bean引用

如果EvaluationContext配置了BeanResolver,则可以通过@符号加bean名称获取bean,如果要访问工厂Bean(FactoryBean),需在bean名称前加一个&符号

ExpressionParser parser = new SpelExpressionParser(); StandardEvaluationContext context = new StandardEvaluationContext(); context.setBeanResolver(new MyBeanResolver()); // This will end up calling resolve(context,"something") on MyBeanResolver during evaluation Object bean = parser.parseExpression("@something").getValue(context); 
讯享网ExpressionParser parser = new SpelExpressionParser(); StandardEvaluationContext context = new StandardEvaluationContext(); context.setBeanResolver(new MyBeanResolver()); // This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation Object bean = parser.parseExpression("&foo").getValue(context); 

Ternary Operator (If-Then-Else) 三目运算符

String falseString = parser.parseExpression( "false ? 'trueExp' : 'falseExp'").getValue(String.class); // falseExp 
讯享网parser.parseExpression("name").setValue(societyContext, "IEEE"); societyContext.setVariable("queryName", "Nikola Tesla"); expression = "isMember(#queryName)? #queryName + ' is a member of the ' " + "+ Name + ' Society' : #queryName + ' is not a member of the ' + Name + ' Society'"; String queryResultString = parser.parseExpression(expression) .getValue(societyContext, String.class); // queryResultString = "Nikola Tesla is a member of the IEEE Society" 

Elvis Operator Elvis运算符

Elvis 运算符是三元运算符语法的缩写,来源于Groovy语言

语法:变量?:返回值

如果变量是null,则返回返回值,否则返回变量本身

ExpressionParser parser = new SpelExpressionParser(); String name = parser.parseExpression("name?:'Unknown'").getValue(new TestVo(), String.class); System.out.println(name); // 'Unknown' TestVo testVo = new TestVo("young",0,null,null); System.out.println(parser.parseExpression("name?:'jordan'").getValue(testVo, String.class)); // young testVo.setName(null); System.out.println(parser.parseExpression("name?:'jordan'").getValue(testVo, String.class)); // jordan 

可以使用这种方法设置默认值

Safe Navigation Operator 安全导航运算符

用于避免空指针操作,来源于Groovy语言

语法:对象?.属性

当对象为null时,返回null,否则取属性中的值,有点类似于Optional.ofNullable(对象).map(对象.属性).orElse(null)的操作

讯享网ExpressionParser parser = new SpelExpressionParser(); TestVo testVo = new TestVo("young", 0, new Date(), new Addr("shanxi", "xian")); System.out.println(parser.parseExpression("addr?.city").getValue(testVo, String.class)); // xian testVo.setAddr(null); System.out.println(parser.parseExpression("addr?.city").getValue(testVo, String.class)); // null 

Collection Selection 集合查找

使用.?[selectionExpression] 进行集合过滤,返回一个满足selectionExpression的新集合

数组,map或者实现了java.lang.Iterable的类型都支持

对于数组或列表,将针对每个元素进行过滤

对于map,将基于Map.Entry进行过滤,可以通过Entry的key或者value进行查找

可以通过.^[selectionExpression]获取第一个查找到的第一个元素,.$[selectionExpression]获取最后一个元素

ExpressionParser parser = new SpelExpressionParser(); SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build(); List<Integer> list = Arrays.asList(1, 3, 5, 7, 9, 11, 13, 15, 17, 19); context.setVariable("list",list); System.out.println(parser.parseExpression("#list.?[#this<10]").getValue(context)); // [1, 3, 5, 7, 9] TestSelector testSelector = new TestSelector(list); System.out.println(parser.parseExpression("code.?[#this<7]").getValue(testSelector)); // [1, 3, 5] Map<Integer, Integer> map = list.stream().collect(Collectors.toMap(e -> e, e -> e)); context.setVariable("map",map); System.out.println(parser.parseExpression("#map.?[value>11]").getValue(context)); // {17=17, 19=19, 13=13, 15=15} System.out.println(parser.parseExpression("#map.^[value>15]").getValue(context));// {17=17} System.out.println(parser.parseExpression("#map.$[value>15]").getValue(context));// {15=15} 

Collection Projection

使用.![projectionExpression],将结果表达式里的数据生成一个新的集合

讯享网ExpressionParser parser = new SpelExpressionParser(); List<TestVo> list = new ArrayList<>(); list.add(new TestVo("1",1,new Date(),new Addr("shanxi","xian"))); list.add(new TestVo("2",2,new Date(),new Addr("jingsu","nanjing"))); list.add(new TestVo("3",3,new Date(),new Addr("beijing","beijing"))); SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build(); context.setVariable("list",list); System.out.println(parser.parseExpression("#list.![addr.city]").getValue(context)); 

有点类似于java的Stream操作

list.stream().map(e -> e.getAddr().getCity()).collect(Collectors.toList()) 
小讯
上一篇 2025-02-10 14:42
下一篇 2025-03-19 17:50

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/25915.html