Spring-spel表达式

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();

    //Hello World
    System.out.println( (String) parser.parseExpression("'Hello World'").getValue() );

    //Tony's Pizza
    System.out.println( (String) parser.parseExpression("'Tony''s Pizza'").getValue() );

    //6.0221415E23
    System.out.println( (Double) parser.parseExpression("6.0221415E+23").getValue() );

    //2147483647
    System.out.println( (Integer) parser.parseExpression("0x7FFFFFFF").getValue() );

    //true
    System.out.println( (Boolean) parser.parseExpression("true").getValue() );

    //null
    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"));

    //通过属性:yq1900
    String dogName = (String)parser.parseExpression("name + 1900").getValue(dog);
    System.out.println( dogName );

    //通过方法:yq1900
    String getDogName = (String)parser.parseExpression("getName() + 1900").getValue(dog);
    System.out.println(getDogName);

    //通过属性:yl
    String friendName = (String) parser.parseExpression("friend.name").getValue(dog);
    System.out.println( friendName );

    //通过属性:yl
    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"));

    //2
    Integer invention = parser.parseExpression("prices[1]").getValue(
            context, dog, Integer.class);
    System.out.println(invention);

    //yq
    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 );

    //yq
    String value = parser.parseExpression("lsMap['s']").getValue(dog, String.class);
    System.out.println(value);
}

5,构造列表,map

@Test
public void list(){
    ExpressionParser parser = new SpelExpressionParser();

    //内联列表:[1, 2, 3, 4]
    List<Integer> value = (List)parser.parseExpression("{1,2,3,4}").getValue();
    System.out.println(value);

    //内联Map:
    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);

    //Array 构造:
    int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue();

    // Array with initializer
    int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue();

    // Multi dimensional array,二维数组不能初始化
    int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue();

}

6,方法调用

@Test
public void method(){

    ExpressionParser parser = new SpelExpressionParser();

    //bc
    String bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);
    System.out.println(bc);

    //Friend{name='yq'}
    String isMember = parser.parseExpression("toString()").getValue( new Friend("yq"), String.class );
    System.out.println(isMember);

    //我和yq是好朋友!
    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();

    //true
    System.out.println( parser.parseExpression("2 == 2").getValue(Boolean.class) );

    //false
    System.out.println( parser.parseExpression("2 < -5.0").getValue(Boolean.class) );

    //true
    System.out.println( parser.parseExpression("'black' < 'block'").getValue(Boolean.class) );

    //false
    System.out.println( parser.parseExpression("'xyz' instanceof T(Integer)").getValue(Boolean.class) );

    //true:对于基本类型,只能到包装类上
    System.out.println( parser.parseExpression("1 instanceof T(Integer)").getValue(Boolean.class) );

    //false
    System.out.println( parser.parseExpression("1 instanceof T(int)").getValue(Boolean.class) );

    //true
    System.out.println( parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class) );

    //false
    System.out.println( parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class) );

    //false
    System.out.println( parser.parseExpression("new java.math.BigDecimal(3) < new java.math.BigDecimal(2)").getValue(Boolean.class) );
}

8,逻辑运算符

  • and (&&)
  • or (||)
  • not (!)
@Test
public void logical(){
    ExpressionParser parser = new SpelExpressionParser();

    //false
    System.out.println( parser.parseExpression("true && false").getValue() );

    //true
    System.out.println( parser.parseExpression("true || false").getValue() );

    //false
    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));  // 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

    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
}

10,赋值操作符

= 这通常是在调用 setValue 时进行,但也可以在调用 getValue 时进行。下面的列表显示了使用赋值运算符的两种方式。

@Test
public void assignment(){
    ExpressionParser parser = new SpelExpressionParser();
    EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();

    Dog dog = new Dog();

    //yyq
    parser.parseExpression("name").setValue(context, dog, "yyq");
    System.out.println(dog.getName());

    //aiyyq
    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{name='yq'}
    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));

    //静态方法:gxayq
    String value = parser.parseExpression("#getName('gxa')").getValue(context, String.class);
    System.out.println( value );

    //非静态方法:gxaaayq
    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();

    //相当于   name != null ? name : "Unknown"
    String name = parser.parseExpression("name?:'Unknown'").getValue(new Dog(), String.class);
    System.out.println(name);

    //@Value("#{systemProperties['pop3.port'] ?: 25}")
    //这将注入一个系统属性 pop3.port(如果它被定义了),如果没有则注入25。
}

17,安全导航操作

安全导航操作,语法 ?
安全导航操作符是用来避免 NullPointerException 的,访问对象之前验证为 null,安全导航操作符返回null,而不是抛出一个异常

@Test
public void navigation(){
    ExpressionParser parser = new SpelExpressionParser();
    EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

    Dog dog = new Dog();

    //null
    System.out.println( parser.parseExpression("friend?.name").getValue(context, dog, String.class) );

    // EL1007E: Property or field 'name' cannot be found on null
    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);

    //[4, 1, 2, 4, 0, 3]
    List<Integer> list1 = (List)parser.parseExpression("#list.?[#this<5]").getValue(context);
    System.out.println(list1);

    //{yl=2, yq=2, pz=5}
    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) );

    //获取匹配的第一个:{yl=2}
    System.out.println( parser.parseExpression("map.^[value>1]").getValue(friend) );

    //获取匹配的最后一个:{pz=5}
    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());

    //[xx, yl, yq, pz]
    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;
    }

    // ...
}
posted @ 2024-08-01 15:23  primaryC  阅读(4)  评论(0编辑  收藏  举报