> For the complete documentation index, see [llms.txt](https://yanghaiji.gitbook.io/advanced-books/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yanghaiji.gitbook.io/advanced-books/note/spring/book/spel/spelgrammar.md).

# SpEl 表达式语法

## 文字表达

支持的文字表达式类型是字符串、数值（整数、实数、十六进制）、布尔值和空值。字符串由单引号分隔。要将单引号本身放在字符串中，请使用两个单引号字符。

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

## Properties, Arrays, Lists, Maps, and Indexers

使用属性引用进行导航很容易。为此，请使用句点来指示嵌套的属性值

```
ExpressionParser parser = new SpelExpressionParser();
// evals to 1856
int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(context);

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

属性名称的第一个字母允许不区分大小写。因此，上面例子中的表达式可以分别写成`Birthdate.Year + 1900`和 `PlaceOfBirth.City`。此外，属性可以选择性地通过方法调用来访问——例如，`getPlaceOfBirth().getCity()`而不是 `placeOfBirth.city`.

数组和列表的内容使用方括号表示法获取，如下例所示：

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

map的内容是通过在括号内指定文字键值来获得的。在下面的例子中，因为`officers`映射的键是字符串，我们可以指定字符串文字：

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

## Inline Lists

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

`{}`本身意味着一个空列表。出于性能原因，如果列表本身完全由固定文字组成，则会创建一个常量列表来表示表达式（而不是在每次评估时构建一个新列表）。

## Map

您还可以使用`{key:value}`符号直接在表达式中表示映射

```java
// 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);
```

`{:}`本身就意味着一个空Map。出于性能原因，如果映射本身由固定文字或其他嵌套常量结构（列表或映射）组成，则会创建一个常量映射来表示表达式（而不是在每次评估时构建一个新映射）。映射键的引用是可选的（除非键包含句点 ( `.`)）

## 数组构造

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

## 方法

您可以使用典型的 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);
```

## 关系运算符

使用标准运算符表示法支持关系运算符（等于、不等于、小于、小于或等于、大于和大于或等于）

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

大于和小于的比较`null`遵循一个简单的规则：`null`被视为无（即不是零）。因此，任何其他值总是大于`null`（`X > null`总是`true`）并且没有其他值永远小于没有（`X < null`总是`false`）

每个符号运算符也可以指定为纯字母等效项。这避免了使用的符号对嵌入表达式的文档类型（例如在 XML 文档中）具有特殊含义的问题。

* `lt`( `<`)
* `gt`( `>`)
* `le`( `<=`)
* `ge`( `>=`)
* `eq`( `==`)
* `ne`( `!=`)
* `div`( `/`)
* `mod`( `%`)
* `not`( `!`)

### 逻辑运算符

SpEL 支持以下逻辑运算符：

* `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);
```

### 数学运算符

您可以`+`对数字和字符串使用加法运算符 ( )。您只能对数字使用减法 ( `-`)、乘法 ( `*`) 和除法 ( `/`) 运算符。您还可以对数字使用模数 ( `%`) 和指数幂 ( `^`) 运算符。强制执行标准运算符优先级

```
// 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
```

## 赋值运算符

要设置属性，请使用赋值运算符 ( `=`)。这通常在对 的调用中完成，`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);
```

## 变量

您可以使用`#variableName`语法引用表达式中的变量

有效的变量名称必须由以下支持的一个或多个字符组成。

* 字母：`A`到`Z`和`a`到`z`
* 数字：`0`到`9`
* 下划线： `_`
* 美元符号： `$`

```
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"
```

### 在`#this`和`#root`变量

该`#this`变量总是被定义并且是指当前的评价对象（针对其不合格的引用解析）。该`#root`变量始终被定义并引用根上下文对象。尽管`#this`可能会随着表达式的组件的计算而变化，但`#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);
```

## Bean 引用

如果已使用 bean 解析器配置了评估上下文，则可以使用`@`符号从表达式中查找 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);
```

要访问工厂 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);
```

## 三元运算符（If-Then-Else）

您可以使用三元运算符在表达式中执行 if-then-else 条件逻辑

```
String falseString = parser.parseExpression(
        "false ? 'trueExp' : 'falseExp'").getValue(String.class);
```

在这种情况下，布尔值`false`会返回字符串 value `'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"
```

## 表达式模板

表达式模板允许将文字文本与一个或多个评估块混合。每个评估块都用您可以定义的前缀和后缀字符分隔。一个常见的选择是`#{ }`用作分隔符，如以下示例所示：

```
String randomPhrase = parser.parseExpression(
        "random number is #{T(java.lang.Math).random()}",
        new TemplateParserContext()).getValue(String.class);

// evaluates to "random number is 0.7038186818312008"
```

字符串的计算方法是将文字文本`'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;
    }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yanghaiji.gitbook.io/advanced-books/note/spring/book/spel/spelgrammar.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
