# Evaluation / 评估

本节介绍了 SpEL 接口的简单使用和它的表达语言。完整的语言参考可以在 语言参考中找到。

下面的代码引入了 SpEL API 来评估字面字符串表达式 Hello World。

这些类是在 org.springframework:spring-expression jar 依赖包中

package cn.mrcode.study.springdocsread.data;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

/**
 * @author mrcode
 */
public class DemoTest {
    public static void main(String[] args) {
        ExpressionParser parser = new SpelExpressionParser();
        // 字面量表达式是 Hello World
        Expression exp = parser.parseExpression("'Hello World'");
        String message = (String) exp.getValue();
        System.out.println(message);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

你最可能使用的 SpEL 类和接口位于 org.springframework.expression包及其子包中,如spel.support。

ExpressionParser 接口负责解析一个表达式字符串。在前面的例子中,表达式字符串是一个由周围的单引号表示的字符串。Expression 接口负责评估先前定义的表达式字符串。在调用 parser.parseExpression和 exp.getValue时,可以分别抛出两个异常,即 ParsException 和 EvaluationException。

SpEL 支持广泛的功能,如调用方法、访问属性和调用构造函数。

在下面这个方法调用的例子中,我们对字符串调用 concat 方法:

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
// 获取到的值就变成了 Hello World!
String message = (String) exp.getValue();
1
2
3
4

下面是调用 JavaBean 属性的例子,调用字符串属性 Bytes:

ExpressionParser parser = new SpelExpressionParser();

// 调用 'getBytes()' 方法
Expression exp = parser.parseExpression("'Hello World'.bytes");
byte[] bytes = (byte[]) exp.getValue();
1
2
3
4
5

这一行表达式将字符串转换为字节数组

SpEL 还支持通过使用标准的点符号(如 prop1.prop2.prop3 )来嵌套属性,也支持相应的属性值的设置。公共字段也可以被访问。

下面的例子显示了如何使用点符号来获得一个字面量的长度:

ExpressionParser parser = new SpelExpressionParser();
// 调用 getBytes().length
Expression exp = parser.parseExpression("'Hello World'.bytes.length");
// 值是 11
int length = (Integer) exp.getValue();
1
2
3
4
5

可以调用 String 的构造函数,而不是使用字符串字面量,如下例所示:

ExpressionParser parser = new SpelExpressionParser();
// 需要注意的是这里的方法调用,可以写 toUpperCase() 也可以不写后面的括号
Expression exp = parser.parseExpression("new String('hello world').toUpperCase");
String message = (String) exp.getValue();
1
2
3
4

注意通用方法的使用: public T getValue(Class desiredResultType)。使用这个方法就不需要将表达式的值转换为期望的结果类型。如果值不能被 强转为 T 类型 或 不能通过 使用注册的类型转换器进行转换,就会抛出一个评估异常 EvaluationException。

SpEL 更常见的用法是提供一个表达式字符串,该字符串将针对特定的对象实例(称为根对象)进行评估。下面的例子显示了如何从 Inventor 类的一个实例中检索名称属性或创建一个布尔条件:

package cn.mrcode.study.springdocsread.data;

import java.util.Date;

/**
 * @author mrcode
 */
public class Inventor {
    private String name;
    private String country;
    private Date time;
    public Inventor(String name, Date time, String country) {
        this.name = name;
        this.time = time;
        this.country = country;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public Date getTime() {
        return time;
    }

    public void setTime(Date time) {
        this.time = time;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package cn.mrcode.study.springdocsread.data;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.util.GregorianCalendar;

/**
 * @author mrcode
 */
public class DemoTest {
    public static void main(String[] args) {
        // 创建和设置一个日历
        GregorianCalendar c = new GregorianCalendar();
        c.set(1856, 7, 9);

        // 构造函数的参数是姓名、生日和国籍。
        Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

        ExpressionParser parser = new SpelExpressionParser();

        Expression exp = parser.parseExpression("name"); // 将名字解析为一个表达式
        // 这里的 getValue 传入的是一个 根 对象
        // 表示会将这个表达式,在根对象中来评估
        String name = (String) exp.getValue(tesla);
        // name == "Nikola Tesla"

        exp = parser.parseExpression("name == 'Nikola Tesla'");
        // 这里也是一样,从根对象中评估表达式,并根据传入的类型获得表达式的结果
        boolean result = exp.getValue(tesla, Boolean.class);
        // result == true
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35