1,Spel 概念
Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL。能在运行时构建复杂表达式、存取对象图属性、对象方法调用等等,并且能与Spring功能完美整合,如能用来配置Bean定义。
表达式语言给静态Java语言增加了动态功能。
SpEL是单独模块,只依赖于core模块,不依赖于其他模块,可以单独使用。
2,语言参考
1,字面值
SpEL支持以下类型的字面量表达。
- string
- 数值: integer (int 或 long), 十六进制 (int 或 long), real (float 或 double)
- boolean 值: true 或 false
- null
| @Test |
| public void String(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| |
| System.out.println( (String) parser.parseExpression("'Hello World'").getValue() ); |
| |
| |
| System.out.println( (String) parser.parseExpression("'Tony''s Pizza'").getValue() ); |
| |
| |
| System.out.println( (Double) parser.parseExpression("6.0221415E+23").getValue() ); |
| |
| |
| System.out.println( (Integer) parser.parseExpression("0x7FFFFFFF").getValue() ); |
| |
| |
| System.out.println( (Boolean) parser.parseExpression("true").getValue() ); |
| |
| |
| System.out.println( parser.parseExpression("null").getValue() ); |
| } |
2,对象属性和方法
| @Test |
| public void property(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| Dog dog = new Dog(); |
| dog.setName("yq"); |
| dog.setFriend(new Friend("yl")); |
| |
| |
| String dogName = (String)parser.parseExpression("name + 1900").getValue(dog); |
| System.out.println( dogName ); |
| |
| |
| String getDogName = (String)parser.parseExpression("getName() + 1900").getValue(dog); |
| System.out.println(getDogName); |
| |
| |
| String friendName = (String) parser.parseExpression("friend.name").getValue(dog); |
| System.out.println( friendName ); |
| |
| |
| String getFriendName = (String) parser.parseExpression("getFriend().getName()").getValue(dog); |
| System.out.println( getFriendName ); |
| } |
3,Array 和 list
数组和 list 都是通过 [下标获取]
| @Test |
| public void array(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); |
| |
| Dog dog = new Dog(); |
| dog.setPrices(new Integer[]{1,2,3}); |
| dog.setLs(Arrays.asList("pz", "yq", "yl", "xx")); |
| |
| |
| Integer invention = parser.parseExpression("prices[1]").getValue( |
| context, dog, Integer.class); |
| System.out.println(invention); |
| |
| |
| String invention1 = parser.parseExpression("ls[1]").getValue(context, dog, String.class); |
| System.out.println( invention1 ); |
| } |
4,Map
map 的内容是通过在括号内指定字面的 key 值来获得的
| @Test |
| public void map(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| Dog dog = new Dog(); |
| Map<String, String> build = MapUtil.builder("f", "pz").put("s", "yq").put("t", "yl").build(); |
| dog.setLsMap( build ); |
| |
| |
| String value = parser.parseExpression("lsMap['s']").getValue(dog, String.class); |
| System.out.println(value); |
| } |
5,构造列表,map
| @Test |
| public void list(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| |
| List<Integer> value = (List)parser.parseExpression("{1,2,3,4}").getValue(); |
| System.out.println(value); |
| |
| |
| Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(); |
| System.out.println(inventorInfo); |
| |
| Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(); |
| System.out.println(mapOfMaps); |
| |
| |
| 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(); |
| |
| } |
6,方法调用
| @Test |
| public void method(){ |
| |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| |
| String bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class); |
| System.out.println(bc); |
| |
| |
| String isMember = parser.parseExpression("toString()").getValue( new Friend("yq"), String.class ); |
| System.out.println(isMember); |
| |
| |
| String member = parser.parseExpression("say('yq')").getValue( new Friend("yq"), String.class ); |
| System.out.println(member); |
| } |
7,关系操作符
- lt (<)
- gt (>)
- le (<=)
- ge (>=)
- eq (==)
- ne (!=)
- div (/)
- mod (%)
- not (!)
- instanceof
- 基于正则表达式的 matches 运算符
| @Test |
| public void relational(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| |
| System.out.println( parser.parseExpression("2 == 2").getValue(Boolean.class) ); |
| |
| |
| System.out.println( parser.parseExpression("2 < -5.0").getValue(Boolean.class) ); |
| |
| |
| System.out.println( parser.parseExpression("'black' < 'block'").getValue(Boolean.class) ); |
| |
| |
| System.out.println( parser.parseExpression("'xyz' instanceof T(Integer)").getValue(Boolean.class) ); |
| |
| |
| System.out.println( parser.parseExpression("1 instanceof T(Integer)").getValue(Boolean.class) ); |
| |
| |
| System.out.println( parser.parseExpression("1 instanceof T(int)").getValue(Boolean.class) ); |
| |
| |
| System.out.println( parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class) ); |
| |
| |
| System.out.println( parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class) ); |
| |
| |
| System.out.println( parser.parseExpression("new java.math.BigDecimal(3) < new java.math.BigDecimal(2)").getValue(Boolean.class) ); |
| } |
8,逻辑运算符
| @Test |
| public void logical(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| |
| System.out.println( parser.parseExpression("true && false").getValue() ); |
| |
| |
| System.out.println( parser.parseExpression("true || false").getValue() ); |
| |
| |
| System.out.println( parser.parseExpression( "!true" ).getValue() ); |
| } |
9,数学操作符
+ = * / % ^
| @Test |
| public void math(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| System.out.println( parser.parseExpression("1 + 1").getValue(Integer.class)); |
| |
| System.out.println( parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class)); |
| |
| System.out.println( parser.parseExpression("1 - -3").getValue(Integer.class)); |
| |
| System.out.println( parser.parseExpression("1000.00 - 1e4").getValue(Double.class)); |
| |
| System.out.println( parser.parseExpression("-2 * -3").getValue(Integer.class)); |
| |
| System.out.println( parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class)); |
| |
| System.out.println( parser.parseExpression("6 / -3").getValue(Integer.class)); |
| |
| System.out.println( parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class)); |
| |
| System.out.println( parser.parseExpression("7 % 4").getValue(Integer.class)); |
| |
| System.out.println( parser.parseExpression("8 / 5 % 2").getValue(Integer.class)); |
| |
| System.out.println( parser.parseExpression("1+2-3*8").getValue(Integer.class)); |
| } |
10,赋值操作符
= 这通常是在调用 setValue 时进行,但也可以在调用 getValue 时进行。下面的列表显示了使用赋值运算符的两种方式。
| @Test |
| public void assignment(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build(); |
| |
| Dog dog = new Dog(); |
| |
| |
| parser.parseExpression("name").setValue(context, dog, "yyq"); |
| System.out.println(dog.getName()); |
| |
| |
| parser.parseExpression("name = 'aiyyq'").getValue(context, dog, String.class); |
| System.out.println(dog.getName()); |
| } |
11,类型
T(全限定名),除了 lang 包下的不需要全限定名
| @Test |
| public void type(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| //class java.util.Date |
| Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class); |
| System.out.println(dateClass); |
| |
| //class java.lang.String |
| Class stringClass = parser.parseExpression("T(String)").getValue(Class.class); |
| System.out.println(stringClass); |
| |
| //true |
| boolean trueValue = parser.parseExpression( |
| "T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR") |
| .getValue(Boolean.class); |
| System.out.println(trueValue); |
| } |
12,构造方法
你可以通过使用 new 操作符来调用构造函数。除了位于 java.lang 包中的类型(Integer、Float、String 等),你应该对所有类型使用全路径的类名。
| @Test |
| public void construct(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| |
| Dog dog = parser.parseExpression("new com.demo.spel.Dog('yq')").getValue(Dog.class); |
| System.out.println(dog); |
| } |
13,变量
通过使用 #variableName 语法来引用表达式中的变量。变量是通过使用 EvaluationContext 实现上的 setVariable 方法来设置的。
| @Test |
| public void variable(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| Dog pz = new Dog("pz"); |
| |
| |
| EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build(); |
| context.setVariable("pName", "yq"); |
| |
| |
| parser.parseExpression("name = #pName").getValue(context, pz); |
| System.out.println(pz); |
| } |
14,方法
| @Test |
| public void methodVariable() throws NoSuchMethodException { |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); |
| context.setVariable("getName", Dog.class.getMethod("convert", String.class)); |
| context.setVariable("getName11", Dog.class.getMethod("convert11", String.class)); |
| |
| |
| String value = parser.parseExpression("#getName('gxa')").getValue(context, String.class); |
| System.out.println( value ); |
| |
| |
| String value1 = parser.parseExpression("#getName('gxaaa')").getValue(context, new Dog(), String.class); |
| System.out.println( value1 ); |
| } |
15,三元运算符
| @Test |
| public void ternary(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| System.out.println( parser.parseExpression( |
| "false ? 'trueExp' : 'falseExp'").getValue(String.class) ); |
| } |
16,埃尔维斯(Elvis)运算符
在三元运算符语法中,你通常要将一个变量重复两次 -> (name != null ? name : "Unknown")
改进 elvis -> (name?:'Unknown')
| @Test |
| public void elvis(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| |
| String name = parser.parseExpression("name?:'Unknown'").getValue(new Dog(), String.class); |
| System.out.println(name); |
| |
| |
| |
| } |
17,安全导航操作
安全导航操作,语法 ?
安全导航操作符是用来避免 NullPointerException 的,访问对象之前验证为 null,安全导航操作符返回null,而不是抛出一个异常
| @Test |
| public void navigation(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); |
| |
| Dog dog = new Dog(); |
| |
| |
| System.out.println( parser.parseExpression("friend?.name").getValue(context, dog, String.class) ); |
| |
| |
| System.out.println( parser.parseExpression("friend.name").getValue(context, dog, String.class) ); |
| } |
18,Collection Selection(选择)
语法 : .?[selectionExpression]
Selection 是一个强大的表达式语言功能,它让你通过从一个源集合的条目中进行选择,将其转化为另一个集合。
对于数组和任何实现 java.lang.Iterable 或 java.util.Map 的东西,都支持选择。对于一个列表或数组,选择标准是针对每个单独的元素进行评估的。对于一个Map,选择标准是针对每个Map entry(Java类型 Map.Entry 的对象)进行评估的。每个map entry都有它的 key 和 value,可以作为属性在选择中使用。
| @Test |
| public void collectionSelection(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); |
| |
| List<Integer> list = new ArrayList<>(); |
| list.addAll(Arrays.asList(4,6,1,2,4,0,3,9,8)); |
| |
| context.setVariable("list", list); |
| |
| |
| List<Integer> list1 = (List)parser.parseExpression("#list.?[#this<5]").getValue(context); |
| System.out.println(list1); |
| |
| |
| Friend friend = new Friend(); |
| friend.setMap(MapUtil.builder("pz", 5).put("yq", 2).put("yl", 2).put("xx", 1).build()); |
| System.out.println( parser.parseExpression("map.?[value>1]").getValue(friend) ); |
| |
| |
| System.out.println( parser.parseExpression("map.^[value>1]").getValue(friend) ); |
| |
| |
| System.out.println( parser.parseExpression("map.$[value>1]").getValue(friend) ); |
| } |
19,collection Projection(投影)
语法 .![]
投影让一个集合驱动一个子表达式的评估,其结果是一个新的集合,类似 stream 的 list.stream().map()
| @Test |
| public void collectionProjection(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| Friend friend = new Friend(); |
| friend.setMap(MapUtil.builder("pz", 5).put("yq", 2).put("yl", 2).put("xx", 1).build()); |
| |
| |
| List<String> value = (List) parser.parseExpression("map.![key]").getValue(friend); |
| System.out.println(value); |
| } |
20,表达式模板化
| @Test |
| public void template(){ |
| ExpressionParser parser = new SpelExpressionParser(); |
| |
| String value = parser.parseExpression( |
| "random number is #{T(java.lang.Math).random()}", |
| new TemplateParserContext() |
| ).getValue(String.class); |
| System.out.println( value ); |
| } |
3,Bean 定义中的表达式
为了指定一个默认值,你可以在字段、方法和方法或构造函数参数上放置 @Value 注解。
1,通过字段设置默认值
| public class FieldValueTestBean { |
| |
| @Value("#{ systemProperties['user.region'] }") |
| private String defaultLocale; |
| |
| public void setDefaultLocale(String defaultLocale) { |
| this.defaultLocale = defaultLocale; |
| } |
| |
| public String getDefaultLocale() { |
| return this.defaultLocale; |
| } |
| } |
2,在一个属性setter方法上
| public class PropertyValueTestBean { |
| |
| private String defaultLocale; |
| |
| @Value("#{ systemProperties['user.region'] }") |
| public void setDefaultLocale(String defaultLocale) { |
| this.defaultLocale = defaultLocale; |
| } |
| |
| public String getDefaultLocale() { |
| return this.defaultLocale; |
| } |
| } |
3,自动装配的方法和构造函数也可以使用 @Value 注解
| public class SimpleMovieLister { |
| |
| private MovieFinder movieFinder; |
| private String defaultLocale; |
| |
| @Autowired |
| public void configure(MovieFinder movieFinder, |
| @Value("#{ systemProperties['user.region'] }") String defaultLocale) { |
| this.movieFinder = movieFinder; |
| this.defaultLocale = defaultLocale; |
| } |
| |
| |
| } |
| public class MovieRecommender { |
| |
| private String defaultLocale; |
| |
| private CustomerPreferenceDao customerPreferenceDao; |
| |
| public MovieRecommender(CustomerPreferenceDao customerPreferenceDao, |
| @Value("#{systemProperties['user.country']}") String defaultLocale) { |
| this.customerPreferenceDao = customerPreferenceDao; |
| this.defaultLocale = defaultLocale; |
| } |
| |
| |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步