Live2D

spring官网在线学习文档翻译4

4. Spring Expression Language (SpEL)(Spring表达式语言(SpEL))

4.1. Introduction(入门)

The Spring Expression Language (SpEL for short) is a powerful expression language that supports querying and manipulating an object graph at runtime. The language syntax is similar to Unified EL but offers additional features, most notably method invocation and basic string templating functionality.

  • Spring表达式语言(SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象图。该语言的语法类似于Unified EL,但是提供了额外的特性,最显著的是方法调用和基本的字符串模板功能。

While there are several other Java expression languages available — OGNL, MVEL, and JBoss EL, to name a few — the Spring Expression Language was created to provide the Spring community with a single well supported expression language that can be used across all the products in the Spring portfolio. Its language features are driven by the requirements of the projects in the Spring portfolio, including tooling requirements for code completion support within the Eclipse based Spring Tool Suite. That said, SpEL is based on a technology agnostic API allowing other expression language implementations to be integrated should the need arise.

  • 虽然还有其他几种Java表达式语言可用——OGNL、MVEL和JBoss EL,举几个例子——但Spring表达式语言的创建是为了向Spring社区提供一种受良好支持的表达式语言,这种语言可以在Spring组合中的所有产品中使用。它的语言特性是由Spring组合中项目的需求驱动的,包括在基于Eclipse的Spring工具套件中支持代码完成的工具需求。也就是说,SpEL基于一种技术不可知的API,它允许其他表达式语言实现

While SpEL serves as the foundation for expression evaluation within the Spring portfolio, it is not directly tied to Spring and can be used independently. In order to be self contained, many of the examples in this chapter use SpEL as if it were an independent expression language. This requires creating a few bootstrapping infrastructure classes such as the parser. Most Spring users will not need to deal with this infrastructure and will instead only author expression strings for evaluation. An example of this typical use is the integration of SpEL into creating XML or annotated based bean definitions as shown in the section Expression support for defining bean definitions.

  • 虽然SpEL是Spring投资组合中表达式评估的基础,但它并不直接与Spring绑定,可以独立使用。为了自我包含,本章中的许多例子使用SpEL,好像它是一种独立的表达语言。这需要创建一些引导基础设施类,比如解析器。大多数Spring用户不需要处理这个基础设施,而只需要编写表达式字符串来进行计算。这种典型用法的一个示例是将SpEL集成到创建XML或基于注释的bean定义中,如定义bean定义的表达式支持部分所示。

This chapter covers the features of the expression language, its API, and its language syntax. In several places an Inventor and Inventor’s Society classes are used as the target objects for expression evaluation. These class declarations and the data used to populate them are listed at the end of the chapter.

  • 本章涵盖了表达式语言的特性,它的API和它的语言语法。在一些地方,发明人和发明人的社会阶层被用作表达式求值的目标对象。本章末尾列出了这些类声明和用于填充它们的数据。

The expression language supports the following functionality:

  • 表达式语言支持以下功能:

  • Literal expressions

  • Boolean and relational operators

  • Regular expressions

  • Class expressions

  • Accessing properties, arrays, lists, maps

  • Method invocation

  • Relational operators

  • Assignment

  • Calling constructors

  • Bean references

  • Array construction

  • Inline lists

  • Inline maps

  • Ternary operator

  • Variables

  • User defined functions

  • Collection projection

  • Collection selection

  • Templated expressions

    • 文字表达方式

    布尔和关系运算符

    正则表达式

    类表达式

    访问属性、数组、列表和映射

    方法调用

    关系运算符

    赋值

    调用构造函数

    Bean的引用

    阵列结构

    内联列表

    内联映射

    三元运算符

    变量

    用户定义函数

    收集投影

    选择集合

    模板化表达式

4.2. Evaluation(评价

This section introduces the simple use of SpEL interfaces and its expression language. The complete language reference can be found in the section Language Reference.

  • 本节介绍SpEL接口及其表达式语言的简单使用。完整的语言参考可以在语言参考部分中找到。

The following code introduces the SpEL API to evaluate the literal string expression 'Hello World'.

  • 下面的代码引入了SpEL API来计算字符串字面表达式“Hello World”。
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();

The value of the message variable is simply 'Hello World'.

  • 消息变量的值就是“Hello World”。

The SpEL classes and interfaces you are most likely to use are located in the packages org.springframework.expression and its sub packages such as spel.support.

  • 您最可能使用的SpEL类和接口位于org.springframework包中。表达式及其子包,如spell .support。

The interface ExpressionParser is responsible for parsing an expression string. In this example the expression string is a string literal denoted by the surrounding single quotes. The interface Expression is responsible for evaluating the previously defined expression string. There are two exceptions that can be thrown, ParseException and EvaluationException when calling parser.parseExpression and exp.getValue respectively.

  • ExpressionParser接口负责解析表达式字符串。在本例中,表达式字符串是由周围的单引号表示的字符串文字。接口表达式负责计算前面定义的表达式字符串。调用parser时,可以抛出两个异常:ParseException和EvaluationException。分别是parseExpression和exp.getValue。

SpEL supports a wide range of features, such as calling methods, accessing properties, and calling constructors.

  • EL支持广泛的特性,比如调用方法、访问属性和调用构造函数。

As an example of method invocation, we call the concat method on the string literal.

  • 作为方法调用的一个示例,我们对字符串文字调用concat方法。
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();

The value of message is now 'Hello World!'.

As an example of calling a JavaBean property, the String property Bytes can be called as shown below.

  • 消息的价值现在是“Hello World!”

作为调用JavaBean属性的一个示例,可以如下所示调用字符串属性字节。

ExpressionParser parser = new SpelExpressionParser();

// invokes 'getBytes()'
Expression exp = parser.parseExpression("'Hello World'.bytes");
byte[] bytes = (byte[]) exp.getValue();

SpEL also supports nested properties using standard dot notation, i.e. prop1.prop2.prop3 and the setting of property values

Public fields may also be accessed.

  • SpEL还支持使用标准点表示法的嵌套属性,即prop1.prop2。prop3和属性值的设置

公共字段也可以被访

ExpressionParser parser = new SpelExpressionParser();

// invokes 'getBytes().length'
Expression exp = parser.parseExpression("'Hello World'.bytes.length");
int length = (Integer) exp.getValue();

The String’s constructor can be called instead of using a string literal.

  • 可以调用字符串的构造函数,而不是使用字符串文字。
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
String message = exp.getValue(String.class);

Note the use of the generic method public <T> T getValue(Class<T> desiredResultType). Using this method removes the need to cast the value of the expression to the desired result type. An EvaluationException will be thrown if the value cannot be cast to the type T or converted using the registered type converter.

  • 注意泛型方法public T getValue(Class desiredResultType)的使用。使用此方法无需将表达式的值强制转换为所需的结果类型。如果无法将值转换为T类型或使用注册的类型转换器进行转换,则会抛出EvaluationException。

The more common usage of SpEL is to provide an expression string that is evaluated against a specific object instance (called the root object). The example shows how to retrieve the name property from an instance of the Inventor class or create a boolean condition:

  • SpEL更常见的用法是提供针对特定对象实例(称为根对象)求值的表达式字符串。这个例子展示了如何从一个Inventor类的实例中检索name属性,或者创建一个布尔条件:
// Create and set a calendar
GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);

// The constructor arguments are name, birthday, and nationality.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

ExpressionParser parser = new SpelExpressionParser();

Expression exp = parser.parseExpression("name");
String name = (String) exp.getValue(tesla);
// name == "Nikola Tesla"

exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean result = exp.getValue(tesla, Boolean.class);
// result == true

4.2.1. EvaluationContext

The interface EvaluationContext is used when evaluating an expression to resolve properties, methods, or fields and to help perform type conversion. There are two out-of-the-box implementations.

  • 对表达式求值以解析属性、方法或字段并帮助执行类型转换时,将使用EvaluationContext接口。有两种开箱即用的实现。

  • SimpleEvaluationContext — exposes a subset of essential SpEL language features and configuration options, for categories of expressions that do not require the full extent of the SpEL language syntax and should be meaningfully restricted. Examples include but are not limited to data binding expressions, property-based filters, and others.

    • SimpleEvaluationContext——针对不需要完全SpEL语言语法并且应该有意义地加以限制的表达式类别,公开基本SpEL语言特性和配置选项的子集。示例包括但不限于数据绑定表达式、基于属性的过滤器等。
  • StandardEvaluationContext — exposes the full set of SpEL language features and configuration options. You may use it to specify a default root object and to configure every available evaluation-related strategy.

    • 提供SpEL语言的全部特性和配置选项。您可以使用它来指定一个默认根对象,并配置每个可用的与计算相关的策略。

SimpleEvaluationContext is designed to support only a subset of the SpEL language syntax. It excludes Java type references, constructors, and bean references. It also requires that one explicitly choose the level of support for properties and methods in expressions. By default, the create() static factory method enables only read access to properties. You can also obtain a builder to configure the exact level of support needed, targeting one or some combination of the following:

  1. Custom PropertyAccessor only (no reflection)

  2. Data binding properties for read-only access

  3. Data binding properties for read and write

    • 仅自定义PropertyAccessor(无反射)

    只读访问的数据绑定属性

    用于读写的数据绑定属性

Type conversion(类型转换)

By default SpEL uses the conversion service available in Spring core (org.springframework.core.convert.ConversionService). This conversion service comes with many converters built in for common conversions but is also fully extensible so custom conversions between types can be added. Additionally it has the key capability that it is generics aware. This means that when working with generic types in expressions, SpEL will attempt conversions to maintain type correctness for any objects it encounters.

  • 默认情况下,SpEL使用Spring core中可用的转换服务。此转换服务内置了许多用于常见转换的转换器,但它也是完全可扩展的,因此可以添加类型之间的自定义转换。此外,它还具有能够识别泛型的关键能力。这意味着当在表达式中使用泛型类型时,SpEL将尝试进行转换,以维护它遇到的任何对象的类型正确性。

What does this mean in practice? Suppose assignment, using setValue(), is being used to set a List property. The type of the property is actually List<Boolean>. SpEL will recognize that the elements of the list need to be converted to Boolean before being placed in it. A simple example:

  • 这在实践中意味着什么呢?假设使用setValue()来设置列表属性的赋值。属性的类型实际上是List。SpEL将认识到,在将列表元素放入其中之前,需要将其转换为布尔值。一个简单的例子:
class Simple {
    public List<Boolean> booleanList = new ArrayList<Boolean>();
}

Simple simple = new Simple();
simple.booleanList.add(true);

EvaluationContext context = SimpleEvaluationContext().forReadOnlyDataBinding().build();

// false is passed in here as a string. SpEL and the conversion service will
// correctly recognize that it needs to be a Boolean and convert it
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");

// b will be false
Boolean b = simple.booleanList.get(0);

4.2.2. Parser configuration(解析器配置

It is possible to configure the SpEL expression parser using a parser configuration object 【可以使用解析器配置对象来配置SpEL表达式解析器】

(org.springframework.expression.spel.SpelParserConfiguration). The configuration object controls the behavior of some of the expression components. For example, if indexing into an array or collection and the element at the specified index is null it is possible to automatically create the element. This is useful when using expressions made up of a chain of property references. If indexing into an array or list and specifying an index that is beyond the end of the current size of the array or list it is possible to automatically grow the array or list to accommodate that index.

  • (org.springframework.expression.spel.SpelParserConfiguration)。configuration对象控制一些表达式组件的行为。例如,如果数组或集合的索引和指定索引处的元素为null,则可以自动创建该元素。这在使用由属性引用链组成的表达式时非常有用。如果对数组或列表进行索引并指定超出当前数组或列表大小的索引,则可以自动增加数组或列表以适应该索引。
class Demo {
    public List<String> list;
}

// Turn on:
// - auto null reference initialization
// - auto collection growing
SpelParserConfiguration config = new SpelParserConfiguration(true,true);

ExpressionParser parser = new SpelExpressionParser(config);

Expression expression = parser.parseExpression("list[3]");

Demo demo = new Demo();

Object o = expression.getValue(demo);

// demo.list will now be a real collection of 4 entries
// Each entry is a new empty String

It is also possible to configure the behaviour of the SpEL expression compiler.

  • 也可以配置SpEL表达式编译器的行为。

4.2.3. SpEL compilation(编译)

Spring Framework 4.1 includes a basic expression compiler. Expressions are usually interpreted which provides a lot of dynamic flexibility during evaluation but does not provide optimum performance. For occasional expression usage this is fine, but when used by other components like Spring Integration, performance can be very important and there is no real need for the dynamism.

  • Spring Framework 4.1包含一个基本表达式编译器。表达式通常被解释,这在计算期间提供了很大的动态灵活性,但不能提供最佳性能。对于偶尔使用的表达式来说,这很好,但是当被Spring Integration等其他组件使用时,性能就变得非常重要了,实际上并不需要动态性。

The SpEL compiler is intended to address this need. The compiler will generate a real Java class on the fly during evaluation that embodies the expression behavior and use that to achieve much faster expression evaluation. Due to the lack of typing around expressions the compiler uses information gathered during the interpreted evaluations of an expression when performing compilation. For example, it does not know the type of a property reference purely from the expression, but during the first interpreted evaluation it will find out what it is. Of course, basing the compilation on this information could cause trouble later if the types of the various expression elements change over time. For this reason compilation is best suited to expressions whose type information is not going to change on repeated evaluations.

  • SpEL编译器旨在满足这一需求。编译器将在计算期间动态生成一个包含表达式行为的真正Java类,并使用它实现更快的表达式计算。由于表达式周围缺乏输入,编译器在执行编译时使用在解释表达式求值期间收集的信息。例如,它不能完全从表达式中知道属性引用的类型,但是在第一次解释求值时,它会知道它是什么。当然,如果各种表达式元素的类型随着时间的推移而改变,那么根据这些信息进行编译可能会在以后引起麻烦。因此,编译最适合那些类型信息在重复计算时不会改变的表达式。

For a basic expression like this:

  • 对于这样的基本表达式:
someArray[0].someProperty.someOtherProperty < 0.1

which involves array access, some property derefencing and numeric operations, the performance gain can be very noticeable. In an example micro benchmark run of 50000 iterations, it was taking 75ms to evaluate using only the interpreter and just 3ms using the compiled version of the expression.

  • 其中涉及数组访问、一些属性解除和数字操作,性能增益可以非常明显。在一个运行50000次迭代的微基准测试的例子中,仅使用解释器就需要75ms,而使用表达式的编译版本只需要3ms。
Compiler configuration(编译器配置)

The compiler is not turned on by default, but there are two ways to turn it on. It can be turned on using the parser configuration process discussed earlier or via a system property when SpEL usage is embedded inside another component. This section discusses both of these options.

  • 默认情况下编译器是不打开的,但是有两种方法可以打开它。可以使用前面讨论的解析器配置过程打开它,也可以在SpEL使用嵌入到另一个组件中时通过系统属性打开它。本节将讨论这两种选项。

It is important to understand that there are a few modes the compiler can operate in, captured in an enum (org.springframework.expression.spel.SpelCompilerMode). The modes are as follows:

  • 重要的是要理解编译器可以在一些模式中操作,这些模式在enum中捕获(org. springframework.expression.spelcompilermode)。模式如下:

  • OFF - The compiler is switched off; this is the default.

    • 编译器被关闭;这是默认值。
  • IMMEDIATE - In immediate mode the expressions are compiled as soon as possible. This is typically after the first interpreted evaluation. If the compiled expression fails (typically due to a type changing, as described above) then the caller of the expression evaluation will receive an exception.

    • 立即——在立即模式下,表达式会尽快编译。这通常是在第一次解释求值之后。如果编译后的表达式失败(通常是由于类型改变,如上所述),那么表达式求值的调用者将收到一个异常。
  • MIXED - In mixed mode the expressions silently switch between interpreted and compiled mode over time. After some number of interpreted runs they will switch to compiled form and if something goes wrong with the compiled form (like a type changing, as described above) then the expression will automatically switch back to interpreted form again. Sometime later it may generate another compiled form and switch to it. Basically the exception that the user gets in IMMEDIATE mode is instead handled internally.

    • 混合模式——在混合模式下,表达式会随着时间在解释模式和编译模式之间静默切换。经过多次解释后,它们将切换到编译后的形式,如果编译后的形式出了问题(如上面所述的类型改变),那么表达式将自动再次切换回解释后的形式。一段时间后,它可能会生成另一个已编译的表单并切换到它。用户在即时模式下获得的异常基本上是在内部处理的。

IMMEDIATE mode exists because MIXED mode could cause issues for expressions that have side effects. If a compiled expression blows up after partially succeeding it may have already done something that has affected the state of the system. If this has happened the caller may not want it to silently re-run in interpreted mode since part of the expression may be running twice.

  • 直接模式之所以存在,是因为混合模式可能会导致具有副作用的表达式出现问题。如果编译表达式在部分成功之后崩溃,那么它可能已经做了一些影响系统状态的事情。如果发生了这种情况,调用者可能不希望以解释模式静默地重新运行它,因为表达式的一部分可能运行了两次。

After selecting a mode, use the SpelParserConfiguration to configure the parser:

  • 选择模式后,使用SpelParserConfiguration配置解析器:0
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
    this.getClass().getClassLoader());

SpelExpressionParser parser = new SpelExpressionParser(config);

Expression expr = parser.parseExpression("payload");

MyMessage message = new MyMessage();

Object payload = expr.getValue(message);

When specifying the compiler mode it is also possible to specify a classloader (passing null is allowed). Compiled expressions will be defined in a child classloader created under any that is supplied. It is important to ensure if a classloader is specified it can see all the types involved in the expression evaluation process. If none is specified then a default classloader will be used (typically the context classloader for the thread that is running during expression evaluation).

  • 在指定编译器模式时,也可以指定一个类加载器(允许传递null)。编译后的表达式将在提供的任意下创建的子类加载器中定义。确保类加载器可以看到表达式求值过程中涉及的所有类型是很重要的。如果没有指定,那么将使用默认的类加载器(通常是在表达式求值期间运行的线程的上下文类加载器)。

The second way to configure the compiler is for use when SpEL is embedded inside some other component and it may not be possible to configure via a configuration object. In these cases it is possible to use a system property. The property spring.expression.compiler.mode can be set to one of the SpelCompilerMode enum values (off, immediate, or mixed).

  • 配置编译器的第二种方法是在SpEL嵌入到其他组件中,并且可能无法通过配置对象进行配置时使用。在这些情况下,可以使用系统属性。mode属性可以设置为SpelCompilerMode枚举值中的一个(off、immediate或mixed)
Compiler limitations(编译器的局限性

Since Spring Framework 4.1 the basic compilation framework is in place. However, the framework does not yet support compiling every kind of expression. The initial focus has been on the common expressions that are likely to be used in performance critical contexts. The following kinds of expression cannot be compiled at the moment:

  • 自从Spring Framework 4.1以来,基本的编译框架已经就绪。但是,该框架还不支持编译所有类型的表达式。最初的关注点是可能在性能关键上下文中使用的公共表达式。以下几种表达式目前无法编译:

  • expressions involving assignment

  • expressions relying on the conversion service

  • expressions using custom resolvers or accessors

  • expressions using selection or projection

    • 表达式包括赋值

    依赖于转换服务的表达式

    使用自定义解析器或访问器的表达式

    使用选择或投影的表达式

More and more types of expression will be compilable in the future.

  • 将来会有越来越多的表达式类型可以编译。

4.3. Expressions in bean definitions(bean定义中的表达式)

SpEL expressions can be used with XML or annotation-based configuration metadata for defining BeanDefinitions. In both cases the syntax to define the expression is of the form #{ <expression string> }.

  • SpEL表达式可与XML或基于注释的配置元数据一起用于定义beandefinition。在这两种情况下,定义表达式的语法形式都是#{<表达式字符串>}。

4.3.1. XML configuration(XML配置)

A property or constructor-arg value can be set using expressions as shown below.

  • 可以使用表达式设置属性或构造函数值,如下所示。
<bean id="numberGuess" class="org.spring.samples.NumberGuess">
    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

    <!-- other properties -->
</bean>

The variable systemProperties is predefined, so you can use it in your expressions as shown below. Note that you do not have to prefix the predefined variable with the # symbol in this context.

  • 变量systemProperties是预定义的,因此您可以在表达式中使用它,如下所示。注意,在此上下文中不必在预定义变量前面加上#符号。
<bean id="taxCalculator" class="org.spring.samples.TaxCalculator">
    <property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>

    <!-- other properties -->
</bean>

You can also refer to other bean properties by name, for example.

  • 例如,您还可以通过名称引用其他bean属性。
<bean id="numberGuess" class="org.spring.samples.NumberGuess">
    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

    <!-- other properties -->
</bean>

<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">
    <property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>

    <!-- other properties -->
</bean>

4.3.2. Annotation config(配置)

The @Value annotation can be placed on fields, methods and method/constructor parameters to specify a default value.

  • 可以将@Value注释放在字段、方法和方法/构造函数参数上,以指定默认值。

Here is an example to set the default value of a field variable.

  • 下面是一个设置字段变量默认值的示例。
public static class FieldValueTestBean

    @Value("#{ systemProperties['user.region'] }")
    private String defaultLocale;

    public void setDefaultLocale(String defaultLocale) {
        this.defaultLocale = defaultLocale;
    }

    public String getDefaultLocale() {
        return this.defaultLocale;
    }

}

The equivalent but on a property setter method is shown below.

  • 在属性setter方法上的等效方法如下所示。
public static class PropertyValueTestBean

    private String defaultLocale;

    @Value("#{ systemProperties['user.region'] }")
    public void setDefaultLocale(String defaultLocale) {
        this.defaultLocale = defaultLocale;
    }

    public String getDefaultLocale() {
        return this.defaultLocale;
    }

}

Autowired methods and constructors can also use the @Value annotation.

  • Autowired方法和构造器也可以使用@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;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
            @Value("#{systemProperties['user.country']}") String defaultLocale) {
        this.customerPreferenceDao = customerPreferenceDao;
        this.defaultLocale = defaultLocale;
    }

    // ...
}

4.4. Language Reference(参考)

4.4.1. Literal expressions(字面值表达式)

The types of literal expressions supported are strings, numeric values (int, real, hex), boolean and null. Strings are delimited by single quotes. To put a single quote itself in a string, use two single quote characters.

  • 支持的文字表达式类型有字符串、数值(int、real、hex)、布尔值和null。字符串由单引号分隔。要将单引号本身放入字符串中,请使用两个单引号字符。

The following listing shows simple usage of literals. Typically they would not be used in isolation like this but rather as part of a more complex expression, for example using a literal on one side of a logical comparison operator.

  • 下面的清单显示了文字的简单用法。通常,它们不会像这样单独使用,而是作为更复杂表达式的一部分使用,例如在逻辑比较运算符的一侧使用文字。
ExpressionParser parser = new SpelExpressionParser();

// evals to "Hello World"
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();

double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();

// evals to 2147483647
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();

boolean trueValue = (Boolean) parser.parseExpression("true").getValue();

Object nullValue = parser.parseExpression("null").getValue();

Numbers support the use of the negative sign, exponential notation, and decimal points. By default real numbers are parsed using Double.parseDouble().

  • 数字支持使用负号、指数符号和小数点。默认情况下使用Double.parseDouble()解析实数。

4.4.2. Properties, Arrays, Lists, Maps, Indexers(属性,数组,列表,映射,索引器)

Navigating with property references is easy: just use a period to indicate a nested property value. The instances of the Inventor class, pupin, and tesla, were populated with data listed in the section Classes used in the examples. To navigate "down" and get Tesla’s year of birth and Pupin’s city of birth the following expressions are used.

  • 使用属性引用导航很容易:只需使用句点来表示嵌套的属性值。发明人类pupin和tesla的实例用示例中使用的节类中列出的数据填充。为了找到特斯拉的出生年份和普平的出生城市,我们使用了以下表达。
// evals to 1856
int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context);

String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);

Case insensitivity is allowed for the first letter of property names. The contents of arrays and lists are obtained using square bracket notation.

  • 属性名称的首字母允许不区分大小写。数组和列表的内容使用方括号表示法获得。
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

// Inventions Array

// evaluates to "Induction motor"
String invention = parser.parseExpression("inventions[3]").getValue(
        context, tesla, String.class);

// Members List

// evaluates to "Nikola Tesla"
String name = parser.parseExpression("Members[0].Name").getValue(
        context, ieee, String.class);

// List and Array navigation
// evaluates to "Wireless communication"
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(
        context, ieee, String.class);

The contents of maps are obtained by specifying the literal key value within the brackets. In this case, because keys for the Officers map are strings, we can specify string literals.

  • 映射的内容是通过在方括号中指定文字键值获得的。在本例中,因为officer映射的键是字符串,所以我们可以指定字符串文字。
// Officer's Dictionary

Inventor pupin = parser.parseExpression("Officers['president']").getValue(
        societyContext, Inventor.class);

// evaluates to "Idvor"
String city = parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(
        societyContext, String.class);

// setting values
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(
        societyContext, "Croatia");

4.4.3. Inline lists(内联列表)

Lists can be expressed directly in an expression using {} notation.

  • 列表可以使用{}表示法直接在表达式中表示。
// evaluates to a Java list containing the four numbers
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);

List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);

{} by itself means an empty list. For performance reasons, if the list is itself entirely composed of fixed literals then a constant list is created to represent the expression, rather than building a new list on each evaluation.

  • {}本身表示一个空列表。出于性能原因,如果列表本身完全由固定文字组成,那么将创建一个常量列表来表示表达式,而不是在每次求值时构建一个新的列表。

4.4.4. Inline Maps(内联映射)

Maps can also be expressed directly in an expression using {key:value} notation.

  • 映射也可以使用{key:value}表示法在表达式中直接表示。
// evaluates to a Java map containing the two entries
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);

Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);

{:} by itself means an empty map. For performance reasons, if the map is itself composed of fixed literals or other nested constant structures (lists or maps) then a constant map is created to represent the expression, rather than building a new map on each evaluation. Quoting of the map keys is optional, the examples above are not using quoted keys.

  • {:}本身意味着一个空映射。出于性能原因,如果映射本身由固定文字或其他嵌套常量结构(列表或映射)组成,那么将创建一个常量映射来表示表达式,而不是在每次求值时构建一个新的映射。map键的引号是可选的,上面的例子没有使用引号括起来的键。

4.4.5. Array construction(构建数组)

Arrays can be built using the familiar Java syntax, optionally supplying an initializer to have the array populated at construction time.

  • 可以使用熟悉的Java语法构建数组,也可以提供一个初始化器,以便在构造时填充数组。
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);

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

// Multi dimensional array
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);

It is not currently allowed to supply an initializer when constructing a multi-dimensional array.

  • 当前不允许在构造多维数组时提供初始化器。

4.4.6. Methods(方法)

Methods are invoked using typical Java programming syntax. You may also invoke methods on literals. Varargs are also supported.

  • 方法是使用典型的Java编程语法调用的。你也可以在文字上调用方法。也支持可变参数。
// string literal, evaluates to "bc"
String bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);

// evaluates to true
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
        societyContext, Boolean.class);

4.4.7. Operators(运算符)

Relational operators(关系运算符)

The relational operators; equal, not equal, less than, less than or equal, greater than, and greater than or equal are supported using standard operator notation.

  • 关系运算符;使用标准操作符表示法支持equal、不等于、小于、小于或等于、大于和大于或等于。
// evaluates to true
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);

// evaluates to false
boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);

// evaluates to true
boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);
Greater/less-than comparisons against null follow a simple rule: null is treated as nothing here (i.e. NOT as zero). As a consequence, any other value is always greater than null (X > null is always true) and no other value is ever less than nothing (X < null is always false).If you prefer numeric comparisons instead, please avoid number-based null comparisons in favor of comparisons against zero (e.g. X > 0 or X < 0).
  • 对null的大于或小于比较遵循一个简单的规则:null在这里被视为不存在(即不被视为零)。因此,任何其他值总是大于null (X > null总是真),没有任何其他值总是小于nothing (X < null总是假)。

如果您更喜欢数值比较,请避免基于数字的null比较,而喜欢对0的比较(例如X > 0或X < 0)。

In addition to standard relational operators SpEL supports the instanceof and regular expression based matches operator.

  • 除了标准的关系运算符,SpEL还支持基于instanceof和正则表达式的匹配运算符。
// evaluates to false
boolean falseValue = parser.parseExpression(
        "'xyz' instanceof T(Integer)").getValue(Boolean.class);

// evaluates to true
boolean trueValue = parser.parseExpression(
        "'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);

//evaluates to false
boolean falseValue = parser.parseExpression(
        "'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
Be careful with primitive types as they are immediately boxed up to the wrapper type, so 1 instanceof T(int) evaluates to false while 1 instanceof T(Integer) evaluates to true, as expected.
  • 使用原语类型时要小心,因为它们会立即被封装到包装器类型中,所以1 instanceof T(int)的计算结果为false,而1 instanceof T(Integer)的计算结果为true,这与预期一致。

Each symbolic operator can also be specified as a purely alphabetic equivalent. This avoids problems where the symbols used have special meaning for the document type in which the expression is embedded (eg. an XML document). The textual equivalents are shown here: lt (<), gt (>), le (<=), ge (>=), eq (==), ne (!=), div (/), mod (%), not (!). These are case insensitive.

  • 还可以将每个符号运算符指定为纯字母等效符。这样就避免了使用的符号对于嵌入表达式的文档类型具有特殊意义的问题(例如。XML文档)。这里显示的文本等价物是:lt (<), gt(>),勒(< =)、通用电气(> =)、情商(= =),ne (! =), div (/), mod(%),而不是(!)。它们不区分大小写。
Logical operators(逻辑运算符)

The logical operators that are supported are and, or, and not. Their use is demonstrated below.

  • 支持的逻辑操作符是and、or和not。下面演示了它们的用法。
// -- AND --

// evaluates to false
boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class);

// evaluates to true
String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);

// -- OR --

// evaluates to true
boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class);

// evaluates to true
String expression = "isMember('Nikola Tesla') or isMember('Albert Einstein')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);

// -- NOT --

// evaluates to false
boolean falseValue = parser.parseExpression("!true").getValue(Boolean.class);

// -- AND and NOT --
String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
Mathematical operators(数学运算符)

The addition operator can be used on both numbers and strings. Subtraction, multiplication and division can be used only on numbers. Other mathematical operators supported are modulus (%) and exponential power (^). Standard operator precedence is enforced. These operators are demonstrated below.

  • 加法运算符既可以用于数字,也可以用于字符串。减法、乘法和除法只能用于数字。支持的其他数学运算符还有模数(%)和指数幂(^)。执行标准操作符优先级。下面将演示这些操作符。
// Addition
int two = parser.parseExpression("1 + 1").getValue(Integer.class);  // 2

String testString = parser.parseExpression(
        "'test' + ' ' + 'string'").getValue(String.class);  // 'test string'

// Subtraction
int four = parser.parseExpression("1 - -3").getValue(Integer.class);  // 4

double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class);  // -9000

// Multiplication
int six = parser.parseExpression("-2 * -3").getValue(Integer.class);  // 6

double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class);  // 24.0

// Division
int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class);  // -2

double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class);  // 1.0

// Modulus
int three = parser.parseExpression("7 % 4").getValue(Integer.class);  // 3

int one = parser.parseExpression("8 / 5 % 2").getValue(Integer.class);  // 1

// Operator precedence
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class);  // -21

4.4.8. Assignment(任务)

Setting of a property is done by using the assignment operator. This would typically be done within a call to setValue but can also be done inside a call to getValue.

  • 属性的设置通过使用赋值操作符来完成。这通常在对setValue的调用中完成,但也可以在对getValue的调用中完成。
Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();

parser.parseExpression("Name").setValue(context, inventor, "Aleksandar Seovic");

// alternatively
String aleks = parser.parseExpression(
        "Name = 'Aleksandar Seovic'").getValue(context, inventor, String.class);

4.4.9. Types(类型)

The special T operator can be used to specify an instance of java.lang.Class (the type). Static methods are invoked using this operator as well. The StandardEvaluationContext uses a TypeLocator to find types and the StandardTypeLocator (which can be replaced) is built with an understanding of the java.lang package. This means T() references to types within java.lang do not need to be fully qualified, but all other type references must be.

  • 特殊的T操作符可以用来指定java.lang.Class(类型)的一个实例。静态方法也可以使用此操作符调用。standardevalationcontext使用一个TypeLocator来查找类型,而StandardTypeLocator(可以替换)是根据对java的理解构建的。朗包。这意味着T()对java中的类型的引用。lang不需要完全限定,但是所有其他类型引用必须是完全限定的。
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);

4.4.10. Constructors(构造函数)

Constructors can be invoked using the new operator. The fully qualified class name should be used for all but the primitive type and String (where int, float, etc, can be used).

  • 可以使用new操作符调用构造函数。除了基本类型和字符串(int、float等可以使用)之外,所有类型都应该使用完全限定的类名。
Inventor einstein = p.parseExpression(
        "new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
        .getValue(Inventor.class);

//create new inventor instance within add method of List
p.parseExpression(
        "Members.add(new org.spring.samples.spel.inventor.Inventor(
            'Albert Einstein', 'German'))").getValue(societyContext);

4.4.11. Variables(变量)

Variables can be referenced in the expression using the syntax #variableName. Variables are set using the method setVariable on EvaluationContext implementations.

  • 可以使用#variableName语法在表达式中引用变量。使用EvaluationContext实现上的setVariable方法设置变量。
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");

EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
context.setVariable("newName", "Mike Tesla");

parser.parseExpression("Name = #newName").getValue(context, tesla);
System.out.println(tesla.getName())  // "Mike Tesla"
The #this and #root variables(#this和#root变量)

The variable #this is always defined and refers to the current evaluation object (against which unqualified references are resolved). The variable #root is always defined and refers to the root context object. Although #this may vary as components of an expression are evaluated, #root always refers to the root.

  • 变量#this总是被定义的,它引用当前的计算对象(未限定的引用被解析)。变量#root总是被定义并引用根上下文对象。尽管当表达式的组件被计算时,#可能会有所不同,但是#root总是引用根。
// create an array of integers
List<Integer> primes = new ArrayList<Integer>();
primes.addAll(Arrays.asList(2,3,5,7,11,13,17));

// create parser and set variable 'primes' as the array of integers
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataAccess();
context.setVariable("primes", primes);

// all prime numbers > 10 from the list (using selection ?{...})
// evaluates to [11, 13, 17]
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(
        "#primes.?[#this>10]").getValue(context);

4.4.12. Functions(函数)

You can extend SpEL by registering user defined functions that can be called within the expression string. The function is registered through the EvaluationContext.

  • 可以通过注册可以在表达式字符串中调用的用户定义函数来扩展SpEL。函数是通过EvaluationContext注册的
Method method = ...;

EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("myFunction", method);

For example, given a utility method to reverse a string is shown below:

  • 例如,给定一个反转字符串的实用方法如下所示:
public abstract class StringUtils {

    public static String reverseString(String input) {
        StringBuilder backwards = new StringBuilder(input.length());
        for (int i = 0; i < input.length(); i++)
            backwards.append(input.charAt(input.length() - 1 - i));
        }
        return backwards.toString();
    }
}

The above method can then be registered and used as follows:

  • 以上方法可按以下方式注册和使用:
ExpressionParser parser = new SpelExpressionParser();

EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("reverseString",
        StringUtils.class.getDeclaredMethod("reverseString", String.class));

String helloWorldReversed = parser.parseExpression(
        "#reverseString('hello')").getValue(context, String.class);

4.4.13. Bean references(Bean的引用)

If the evaluation context has been configured with a bean resolver it is possible to look up beans from an expression using the @ symbol.

  • 如果计算上下文已经配置了一个bean解析器,那么就可以使用@符号从表达式中查找bean。
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);

To access a factory bean itself, the bean name should instead be prefixed with an & symbol.

  • 要访问工厂bean本身,bean名称应该以&符号作为前缀。
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);

4.4.14. Ternary Operator (If-Then-Else)【三元操作符(if - then - else)】

You can use the ternary operator for performing if-then-else conditional logic inside the expression. A minimal example is:

  • 可以使用三元运算符在表达式中执行if-then-else条件逻辑。一个最小的例子是:
String falseString = parser.parseExpression(
        "false ? 'trueExp' : 'falseExp'").getValue(String.class);

In this case, the boolean false results in returning the string value 'falseExp'. A more realistic example is shown below.

  • 在这种情况下,布尔值false会导致返回字符串值'false exp '。下面显示了一个更实际的示例。
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"

Also see the next section on the Elvis operator for an even shorter syntax for the ternary operator.

  • 另外,请参阅关于Elvis操作符的下一节,了解更短的三元操作符语法。

4.4.15. The Elvis Operator(操作符)

The Elvis operator is a shortening of the ternary operator syntax and is used in the Groovy language. With the ternary operator syntax you usually have to repeat a variable twice, for example:

  • Elvis运算符是三元运算符语法的缩短,在Groovy语言中使用。在三元运算符语法中,你通常需要重复一个变量两次,例如:
String name = "Elvis Presley";
String displayName = (name != null ? name : "Unknown");

Instead you can use the Elvis operator, named for the resemblance to Elvis' hair style.

  • 相反,您可以使用Elvis操作符,该操作符是根据与Elvis发型的相似性命名的。
ExpressionParser parser = new SpelExpressionParser();

String name = parser.parseExpression("name?:'Unknown'").getValue(String.class);
System.out.println(name);  // 'Unknown'

Here is a more complex example.

  • 下面是一个更复杂的例子。
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
String name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, tesla, String.class);
System.out.println(name);  // Nikola Tesla

tesla.setName(null);
name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, tesla, String.class);
System.out.println(name);  // Elvis Presley

4.4.16. Safe Navigation operator(安全的导航操作符)

The Safe Navigation operator is used to avoid a NullPointerException and comes from the Groovy language. Typically when you have a reference to an object you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the safe navigation operator will simply return null instead of throwing an exception.

  • 安全导航操作符用于避免NullPointerException,它来自Groovy语言。通常,当您有一个对象的引用时,您可能需要在访问该对象的方法或属性之前验证它是否不为空。为了避免这种情况,安全导航操作符将简单地返回null,而不是抛出异常。
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));

String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
System.out.println(city);  // Smiljan

tesla.setPlaceOfBirth(null);
city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
System.out.println(city);  // null - does not throw NullPointerException!!!
The Elvis operator can be used to apply default values in expressions, e.g. in an @Value expression:@Value("#{systemProperties['pop3.port'] ?: 25}")This will inject a system property pop3.port if it is defined or 25 if not.
  • Elvis运算符可用于在表达式中应用默认值,例如在@Value表达式中:

@ value (" # {systemProperties [' pop3。港口的)?:25}”)

这将注入一个系统属性pop3。如果已定义,则端口为25。

4.4.17. Collection Selection(集合选择)

Selection is a powerful expression language feature that allows you to transform some source collection into another by selecting from its entries.

  • 选择是一种强大的表达式语言特性,它允许您通过从某个源集合的条目进行选择来将其转换为另一个源集合。

Selection uses the syntax .?[selectionExpression]. This will filter the collection and return a new collection containing a subset of the original elements. For example, selection would allow us to easily get a list of Serbian inventors:

  • 选择使用语法.?[selectionExpression]。这将过滤集合并返回一个包含原始元素子集的新集合。例如,选择将使我们容易地获得塞尔维亚发明家的名单:
List<Inventor> list = (List<Inventor>) parser.parseExpression(
        "Members.?[Nationality == 'Serbian']").getValue(societyContext);

Selection is possible upon both lists and maps. In the former case the selection criteria is evaluated against each individual list element whilst against a map the selection criteria is evaluated against each map entry (objects of the Java type Map.Entry). Map entries have their key and value accessible as properties for use in the selection.

  • 在列表和地图上都可以选择。在前一种情况下,选择条件是根据每个单独的列表元素计算的,而选择条件是根据每个映射项(Java类型map . entry的对象)计算的。映射条目的键和值可以作为属性访问,以便在选择中使用。

This expression will return a new map consisting of those elements of the original map where the entry value is less than 27.

  • 这个表达式将返回一个新映射,其中包含条目值小于27的原始映射的那些元素。
Map newMap = parser.parseExpression("map.?[value<27]").getValue();

In addition to returning all the selected elements, it is possible to retrieve just the first or the last value. To obtain the first entry matching the selection the syntax is .^[selectionExpression] whilst to obtain the last matching selection the syntax is .$[selectionExpression].

  • 除了返回所有选定的元素外,还可以只检索第一个或最后一个值。要获得第一个匹配选择的条目,语法为。[1],而要获得最后一个匹配选择,语法为。$[selectionExpression]。

4.4.18. Collection Projection(集合投影)

Projection allows a collection to drive the evaluation of a sub-expression and the result is a new collection. The syntax for projection is .![projectionExpression]. Most easily understood by example, suppose we have a list of inventors but want the list of cities where they were born. Effectively we want to evaluate 'placeOfBirth.city' for every entry in the inventor list. Using projection:

  • 投影允许集合驱动子表达式的求值,结果是一个新的集合。投影的语法是.![projectionExpression]。举个例子很容易理解,假设我们有一个发明家名单,但想要他们出生的城市名单。实际上,我们想评估“出生地点”。为发明人列表中的每个条目设置“city”。使用投影:
// returns ['Smiljan', 'Idvor' ]
List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]");

A map can also be used to drive projection and in this case the projection expression is evaluated against each entry in the map (represented as a Java Map.Entry). The result of a projection across a map is a list consisting of the evaluation of the projection expression against each map entry.

  • 映射还可以用于驱动投影,在这种情况下,投影表达式将针对映射中的每个条目求值(表示为Java map . entry)。跨映射的投影的结果是一个列表,其中包含对每个映射项求值的投影表达式。

4.4.19. Expression templating(表达式模板)

Expression templates allow a mixing of literal text with one or more evaluation blocks. Each evaluation block is delimited with prefix and suffix characters that you can define, a common choice is to use #{ } as the delimiters. For example,

  • 表达式模板允许将文本与一个或多个计算块混合使用。每个计算块都使用可以定义的前缀和后缀字符分隔,常见的选择是使用#{}作为分隔符。例如,
String randomPhrase = parser.parseExpression(
        "random number is #{T(java.lang.Math).random()}",
        new TemplateParserContext()).getValue(String.class);

// evaluates to "random number is 0.7038186818312008"

The string is evaluated by concatenating the literal text 'random number is ' with the result of evaluating the expression inside the #{ } delimiter, in this case the result of calling that random() method. The second argument to the method parseExpression() is of the type ParserContext. The ParserContext interface is used to influence how the expression is parsed in order to support the expression templating functionality. The definition of TemplateParserContext is shown below.

  • 通过将文本“random number is”与#{}分隔符内的表达式计算结果(在本例中是调用random()方法的结果)连接起来,对字符串进行计算。方法parseExpression()的第二个参数属于ParserContext类型。ParserContext接口用于影响表达式的解析方式,以支持表达式模板功能。TemplateParserContext的定义如下所示。
public class TemplateParserContext implements ParserContext {

    public String getExpressionPrefix() {
        return "#{";
    }

    public String getExpressionSuffix() {
        return "}";
    }

    public boolean isTemplate() {
        return true;
    }
}

4.5. Classes used in the examples(示例中使用的类)

Inventor.java(创造者)

package org.spring.samples.spel.inventor;

import java.util.Date;
import java.util.GregorianCalendar;

public class Inventor {

    private String name;
    private String nationality;
    private String[] inventions;
    private Date birthdate;
    private PlaceOfBirth placeOfBirth;

    public Inventor(String name, String nationality) {
        GregorianCalendar c= new GregorianCalendar();
        this.name = name;
        this.nationality = nationality;
        this.birthdate = c.getTime();
    }

    public Inventor(String name, Date birthdate, String nationality) {
        this.name = name;
        this.nationality = nationality;
        this.birthdate = birthdate;
    }

    public Inventor() {
    }

    public String getName() {
        return name;
    }

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

    public String getNationality() {
        return nationality;
    }

    public void setNationality(String nationality) {
        this.nationality = nationality;
    }

    public Date getBirthdate() {
        return birthdate;
    }

    public void setBirthdate(Date birthdate) {
        this.birthdate = birthdate;
    }

    public PlaceOfBirth getPlaceOfBirth() {
        return placeOfBirth;
    }

    public void setPlaceOfBirth(PlaceOfBirth placeOfBirth) {
        this.placeOfBirth = placeOfBirth;
    }

    public void setInventions(String[] inventions) {
        this.inventions = inventions;
    }

    public String[] getInventions() {
        return inventions;
    }
}

PlaceOfBirth.java(出生地)

package org.spring.samples.spel.inventor;

public class PlaceOfBirth {

    private String city;
    private String country;

    public PlaceOfBirth(String city) {
        this.city=city;
    }

    public PlaceOfBirth(String city, String country) {
        this(city);
        this.country = country;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String s) {
        this.city = s;
    }

    public String getCountry() {
        return country;
    }

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

}

Society.java(交往)

package org.spring.samples.spel.inventor;

import java.util.*;

public class Society {

    private String name;

    public static String Advisors = "advisors";
    public static String President = "president";

    private List<Inventor> members = new ArrayList<Inventor>();
    private Map officers = new HashMap();

    public List getMembers() {
        return members;
    }

    public Map getOfficers() {
        return officers;
    }

    public String getName() {
        return name;
    }

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

    public boolean isMember(String name) {
        for (Inventor inventor : members) {
            if (inventor.getName().equals(name)) {
                return true;
            }
        }
        return false;
    }

}

后续内容戳我^^


  1. selectionExpression ↩︎

posted @ 2020-09-29 10:44  六爻呈乾  阅读(187)  评论(0编辑  收藏  举报