属性、数组、列表、映射和索引器

Spring 表达式语言支持导航对象图和索引 融入各种结构。spring-doc.cadn.net.cn

数值索引值从零开始,例如在访问 nth元素 Java 中的数组。
有关如何导航对象图和索引到各种结构中的详细信息,请参阅 Safe Navigation Operator 部分 使用 null 安全运算符。

属性导航

您可以使用句点来导航对象图中的属性引用,以指示 嵌套属性值。的Inventorpupintesla,是 填充了 Classes used in the examples 部分中列出的数据。自 在对象图中向下导航,获取 Tesla 的出生年份和 Pupin 的出生城市。 我们使用以下表达式:spring-doc.cadn.net.cn

// evaluates to 1856
int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(context);

// evaluates to "Smiljan"
String city = (String) parser.parseExpression("placeOfBirth.city").getValue(context);
// evaluates to 1856
val year = parser.parseExpression("birthdate.year + 1900").getValue(context) as Int

// evaluates to "Smiljan"
val city = parser.parseExpression("placeOfBirth.city").getValue(context) as String

属性名称的首字母允许不区分大小写。因此, 上面示例中的表达式可以写成Birthdate.Year + 1900PlaceOfBirth.City分别。此外,还可以选择通过 method invocations — 例如,getPlaceOfBirth().getCity()而不是placeOfBirth.city.spring-doc.cadn.net.cn

索引到数组和集合中

这 nth元素(例如,一个SetList) 可以是 通过使用方括号表示法获得,如下例所示。spring-doc.cadn.net.cn

如果索引集合是java.util.List、 nth元素将被访问 直接通过list.get(n).spring-doc.cadn.net.cn

对于任何其他类型的Collection、 nth元素将通过迭代 使用其Iterator并返回 nth元素。spring-doc.cadn.net.cn

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 Indexing

// evaluates to "Wireless communication"
String invention = parser.parseExpression("members[0].inventions[6]").getValue(
		context, ieee, String.class);
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()

// Inventions Array

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

// Members List

// evaluates to "Nikola Tesla"
val name = parser.parseExpression("members[0].name").getValue(
		context, ieee, String::class.java)

// List and Array Indexing

// evaluates to "Wireless communication"
val invention = parser.parseExpression("members[0].inventions[6]").getValue(
		context, ieee, String::class.java)

索引到字符串中

这 nth字符可以通过在 square 内指定索引来获得 括号,如以下示例所示。spring-doc.cadn.net.cn

这 nth字符的计算结果将为java.lang.String,而不是java.lang.Character.
// evaluates to "T" (8th letter of "Nikola Tesla")
String character = parser.parseExpression("members[0].name[7]")
		.getValue(societyContext, String.class);
// evaluates to "T" (8th letter of "Nikola Tesla")
val character = parser.parseExpression("members[0].name[7]")
		.getValue(societyContext, String::class.java)

索引到 Map 中

通过在方括号内指定键值来获取映射的内容。在 以下示例中,由于officersmap 是字符串,我们可以指定 字符串文本,例如'president':spring-doc.cadn.net.cn

// Officer's Map

// evaluates to Inventor("Pupin")
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);

String countryExpression = "officers['advisors'][0].placeOfBirth.country";

// setting values
parser.parseExpression(countryExpression)
		.setValue(societyContext, "Croatia");

// evaluates to "Croatia"
String country = parser.parseExpression(countryExpression)
		.getValue(societyContext, String.class);
// Officer's Map

// evaluates to Inventor("Pupin")
val pupin = parser.parseExpression("officers['president']")
		.getValue(societyContext, Inventor::class.java)

// evaluates to "Idvor"
val city = parser.parseExpression("officers['president'].placeOfBirth.city")
		.getValue(societyContext, String::class.java)

val countryExpression = "officers['advisors'][0].placeOfBirth.country"

// setting values
parser.parseExpression(countryExpression)
		.setValue(societyContext, "Croatia")

// evaluates to "Croatia"
val country = parser.parseExpression(countryExpression)
		.getValue(societyContext, String::class.java)

索引到对象

可以通过在 方括号。这类似于根据 map 的 key 访问 map 的值。这 以下示例演示了如何对对象进行索引以检索特定的 财产。spring-doc.cadn.net.cn

// Create an inventor to use as the root context object.
Inventor tesla = new Inventor("Nikola Tesla");

// evaluates to "Nikola Tesla"
String name = parser.parseExpression("#root['name']")
		.getValue(context, tesla, String.class);
// Create an inventor to use as the root context object.
val tesla = Inventor("Nikola Tesla")

// evaluates to "Nikola Tesla"
val name = parser.parseExpression("#root['name']")
		.getValue(context, tesla, String::class.java)

索引到自定义结构

从 Spring Framework 6.2 开始,Spring 表达式语言支持索引到自定义 结构,允许开发人员实现和注册IndexAccessor使用EvaluationContext.如果您想支持编译 依赖于自定义索引访问器的表达式,则该索引访问器必须实现CompilableIndexAccessorSPI 的 API 中。spring-doc.cadn.net.cn

为了支持常见的用例,Spring 提供了一个内置的ReflectiveIndexAccessor哪 是灵活的IndexAccessor使用反射读取和选择性写入 目标对象的索引结构。索引结构可以通过publicread-method(读取时)或publicwrite-method(写入时)。 read-method 和 write-method 之间的关系基于一个约定: 适用于索引结构的典型实现。spring-doc.cadn.net.cn

ReflectiveIndexAccessor还实现了CompilableIndexAccessor为了 支持编译为字节码以进行读取访问。但是请注意,配置的 read-method 必须是 invokable 通过publicclass 或publicinterface 进行编译。

以下代码清单定义了一个Colorenum 和FruitMap类型,其行为类似于 map 中,但未实现java.util.Map接口。因此,如果要索引到 一个FruitMap在 SPEL 表达式中,您需要注册一个IndexAccessor.spring-doc.cadn.net.cn

public enum Color {
	RED, ORANGE, YELLOW
}
public class FruitMap {

	private final Map<Color, String> map = new HashMap<>();

	public FruitMap() {
		this.map.put(Color.RED, "cherry");
		this.map.put(Color.ORANGE, "orange");
		this.map.put(Color.YELLOW, "banana");
	}

	public String getFruit(Color color) {
		return this.map.get(color);
	}

	public void setFruit(Color color, String fruit) {
		this.map.put(color, fruit);
	}
}

只读IndexAccessorFruitMap可以通过以下方式创建new ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit").使用该访问器 registered 和FruitMap注册为名为#fruitMap、SPEL 表达#fruitMap[T(example.Color).RED]将评估为"cherry".spring-doc.cadn.net.cn

读写IndexAccessorFruitMap可以通过以下方式创建new ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit", "setFruit").有了那个 registeror 已注册,并且FruitMap注册为名为#fruitMap、SPEL 表达#fruitMap[T(example.Color).RED] = 'strawberry'可用于更改 颜色 red from 的水果映射"cherry""strawberry".spring-doc.cadn.net.cn

以下示例演示如何注册ReflectiveIndexAccessor索引 转换为FruitMap然后索引到FruitMap在 SPEL 表达式中。spring-doc.cadn.net.cn

// Create a ReflectiveIndexAccessor for FruitMap
IndexAccessor fruitMapAccessor = new ReflectiveIndexAccessor(
		FruitMap.class, Color.class, "getFruit", "setFruit");

// Register the IndexAccessor for FruitMap
context.addIndexAccessor(fruitMapAccessor);

// Register the fruitMap variable
context.setVariable("fruitMap", new FruitMap());

// evaluates to "cherry"
String fruit = parser.parseExpression("#fruitMap[T(example.Color).RED]")
		.getValue(context, String.class);
// Create a ReflectiveIndexAccessor for FruitMap
val fruitMapAccessor = ReflectiveIndexAccessor(
		FruitMap::class.java, Color::class.java, "getFruit", "setFruit")

// Register the IndexAccessor for FruitMap
context.addIndexAccessor(fruitMapAccessor)

// Register the fruitMap variable
context.setVariable("fruitMap", FruitMap())

// evaluates to "cherry"
val fruit = parser.parseExpression("#fruitMap[T(example.Color).RED]")
	.getValue(context, String::class.java)