Appearance
SPEL 表达式
文本表达式
java
ExpressionParser parser = new SpelExpressionParser();
// 解析普通字符串,输出:"Hello World"
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();
// 解析包含单引号的字符串(单引号需用两个单引号转义),输出:"Tony's Pizza"
String pizzaParlor = (String) parser.parseExpression("'Tony''s Pizza'").getValue();
// 解析科学计数法表示的浮点数,输出:6.0221415E23(阿伏伽德罗常数)
double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();
// 解析十六进制整数,输出:2147483647(int类型的最大值)
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();
// 解析布尔值,输出:true
boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
// 解析null值,输出:null
Object nullValue = parser.parseExpression("null").getValue();
java
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 1. 对象属性导航(支持链式调用)
// 获取 Tesla 的出生年份(假设 birthdate 是 Date 类型,1900 是年份偏移量)
int year = parser.parseExpression("birthdate.year + 1900").getValue(context, tesla, Integer.class);
// 2. 数组/List 索引访问(从0开始)
// 获取 inventions 数组的第4个元素(索引3)
String invention = parser.parseExpression("inventions[3]").getValue(context, tesla, String.class);
// 3. Map 访问(通过键值)
// 获取 officers Map 中 key 为 'president' 的值
Inventor president = parser.parseExpression("officers['president']").getValue(context, String.class);
// 4. 字符串字符访问
// 获取 name 字符串的第8个字符(索引7)
char letter = parser.parseExpression("name[7]").getValue(context, tesla, Character.class);
// 5. 集合投影(![])和筛选(?[])
// 获取所有成员的 name 属性列表
List<String> names = parser.parseExpression("members.![name]").getValue(context, List.class);
// 筛选 age > 18 的成员
List<Person> adults = parser.parseExpression("members.?[age > 18]").getValue(context, List.class);
// 6. 安全导航(避免 NPE)
// 如果 placeOfBirth 为 null 不会抛异常,返回 null
String city = parser.parseExpression("placeOfBirth?.city").getValue(context, String.class);
// 7. 自定义类型索引访问(Spring 6.2+)
// 注册自定义索引访问器后,可像 Map 一样操作非 Map 对象
context.addIndexAccessor(new ReflectiveIndexAccessor(FruitMap.class, Color.class, "getFruit"));
String fruit = parser.parseExpression("#fruitMap[T(example.Color).RED]").getValue(context, String.class);
java
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 定义一个包含 1, 2, 3, 4 的列表
List<Integer> numbers = (List<Integer>) parser.parseExpression("{1, 2, 3, 4}").getValue(context);
System.out.println(numbers); // 输出: [1, 2, 3, 4]
java
// 定义一个嵌套列表:{{'a', 'b'}, {'x', 'y'}}
List<List<String>> listOfLists = (List<List<String>>) parser.parseExpression("{{'a', 'b'}, {'x', 'y'}}").getValue(context);
System.out.println(listOfLists); // 输出: [[a, b], [x, y]]
java
// 定义一个空列表
List<Object> emptyList = (List<Object>) parser.parseExpression("{}").getValue(context);
System.out.println(emptyList); // 输出: []
java
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 定义一个包含 name 和 dob 的 Map
Map<String, Object> inventorInfo = (Map<String, Object>)
parser.parseExpression("{name:'Nikola', dob:'10-July-1856'}").getValue(context);
System.out.println(inventorInfo);
// 输出: {name=Nikola, dob=10-July-1856}
java
// 定义一个嵌套 Map:包含 name(嵌套)和 dob(嵌套)
Map<String, Map<String, Object>> mapOfMaps = (Map<String, Map<String, Object>>)
parser.parseExpression("{name:{first:'Nikola', last:'Tesla'}, dob:{day:10, month:'July', year:1856}}")
.getValue(context);
System.out.println(mapOfMaps);
// 输出: {name={first=Nikola, last=Tesla}, dob={day=10, month=July, year=1856}}
java
// 定义一个空 Map
Map<Object, Object> emptyMap = (Map<Object, Object>) parser.parseExpression("{}").getValue(context);
System.out.println(emptyMap); // 输出: {}
创建空数组
java
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 创建一个长度为 4 的 int 数组
int[] emptyArray = (int[]) parser.parseExpression("new int[4]").getValue(context);
System.out.println(Arrays.toString(emptyArray)); // 输出: [0, 0, 0, 0]创建并初始化数组
java
// 创建并初始化 int 数组
int[] initializedArray = (int[]) parser.parseExpression("new int[] {1, 2, 3}").getValue(context);
System.out.println(Arrays.toString(initializedArray)); // 输出: [1, 2, 3]创建多维数组
java
// 创建一个 4x5 的二维 int 数组(不能直接初始化)
int[][] multiDimArray = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
System.out.println(multiDimArray.length); // 输出: 4(第一维长度)
System.out.println(multiDimArray[0].length); // 输出: 5(第二维长度)方法
java
ExpressionParser parser = new SpelExpressionParser();
// 调用字符串的 substring(1, 3) 方法
String result = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);
System.out.println(result); // 输出: "bc"
java
// 假设 societyContext 中有 isMember 方法
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')")
.getValue(societyContext, Boolean.class);
System.out.println(isMember); // 输出: true(根据实际方法逻辑)
java
// 调用 Math.max(5, 10)
int max = parser.parseExpression("T(java.lang.Math).max(5, 10)").getValue(Integer.class);
System.out.println(max); // 输出: 10
java
// 调用 String.format(String format, Object... args)
String formatted = parser.parseExpression("'Hello, %s!'.format('World')").getValue(String.class);
System.out.println(formatted); // 输出: "Hello, World!"
java
ExpressionParser parser = new SpelExpressionParser();
// 1. 基本关系运算
boolean isEqual = parser.parseExpression("2 eq 2").getValue(Boolean.class); // true
// 2. between 判断范围
boolean inRange = parser.parseExpression("5 between {1, 10}").getValue(Boolean.class); // true
// 3. instanceof 类型检查
boolean isString = parser.parseExpression("'abc' instanceof T(String)").getValue(Boolean.class); // true
// 4. matches 正则匹配
boolean isValid = parser.parseExpression("'123' matches '\\d+'").getValue(Boolean.class); // true
java
// 1. AND 运算
boolean result = parser.parseExpression("true and false").getValue(Boolean.class); // false
// 2. OR 运算
boolean result = parser.parseExpression("true or false").getValue(Boolean.class); // true
// 3. NOT 运算
boolean result = parser.parseExpression("not false").getValue(Boolean.class); // true
java
// 1. 字符串拼接
String concat = parser.parseExpression("'Hello' + ' ' + 'World'").getValue(String.class); // "Hello World"
// 2. 字符减法(ASCII 码计算)
char ch = parser.parseExpression("'d' - 3").getValue(Character.class); // 'a' (d=100, a=97)
// 3. 字符串重复
String repeated = parser.parseExpression("'abc' * 2").getValue(String.class); // "abcabc"
java
// 1. 基本运算
int sum = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
int power = parser.parseExpression("2 ^ 3").getValue(Integer.class); // 8
// 2. 自增/自减
Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
int val = parser.parseExpression("counter++").getValue(context, inventor, Integer.class); // 0 (后自增)
int newVal = parser.parseExpression("counter").getValue(context, inventor, Integer.class); // 1
java
Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
// 1. 使用 setValue 赋值
parser.parseExpression("name").setValue(context, inventor, "Nikola Tesla");
// 2. 直接在表达式内赋值
String name = parser.parseExpression("name = 'Tesla'").getValue(context, inventor, String.class);
java
public class ListConcatenation implements OperatorOverloader {
@Override
public boolean overridesOperation(Operation op, Object left, Object right) {
return op == Operation.ADD && left instanceof List && right instanceof List;
}
@Override
public Object operate(Operation op, Object left, Object right) {
List<Object> result = new ArrayList<>((List<?>) left);
result.addAll((List<?>) right);
return result;
}
}
// 使用自定义运算符
StandardEvaluationContext context = new StandardEvaluationContext();
context.setOperatorOverloader(new ListConcatenation());
List<?> combined = parser.parseExpression("{1, 2} + {3, 4}").getValue(context, List.class); // [1, 2, 3, 4]
java
ExpressionParser parser = new SpelExpressionParser();
// 获取 java.util.Date 的 Class 对象
Class<?> dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
// 获取 String 的 Class 对象(java.lang 包可省略包名)
Class<?> stringClass = parser.parseExpression("T(String)").getValue(Class.class);
java
// 调用 Math.random()
double random = parser.parseExpression("T(java.lang.Math).random()").getValue(Double.class);
// 调用 Integer.parseInt()
int num = parser.parseExpression("T(Integer).parseInt('123')").getValue(Integer.class);
java
// 比较枚举值
boolean result = parser.parseExpression(
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR"
).getValue(Boolean.class); // true(枚举 ordinal 比较)
java
// 等效于 T(java.lang.String)
Class<?> clazz = parser.parseExpression("T(String)").getValue(Class.class);
java
// 必须写全名
Class<?> clazz = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
java
StandardEvaluationContext context = new StandardEvaluationContext();
StandardTypeLocator typeLocator = new StandardTypeLocator();
typeLocator.registerImport("com.example"); // 添加自定义包
context.setTypeLocator(typeLocator);
// 现在可以省略包名
Class<?> clazz = parser.parseExpression("T(User)").getValue(context, Class.class);
java
ExpressionParser parser = new SpelExpressionParser();
// 调用 java.util.Date 的无参构造
Date now = parser.parseExpression("new java.util.Date()").getValue(Date.class);
System.out.println(now); // 输出当前时间
// 调用自定义类的构造方法(需全限定类名)
Inventor einstein = parser.parseExpression(
"new org.example.Inventor('Albert Einstein', 'German')"
).getValue(Inventor.class);
System.out.println(einstein.getName()); // 输出: Albert Einstein
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("members", new ArrayList<Inventor>());
// 在 List.add() 中直接构造对象
parser.parseExpression(
"#members.add(new org.example.Inventor('Nikola Tesla', 'Serbian'))"
).getValue(context);
List<Inventor> members = (List<Inventor>) context.lookupVariable("members");
System.out.println(members.get(0).getName()); // 输出: Nikola Tesla变量
基本变量
java
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
// 设置变量 #newName
context.setVariable("newName", "Mike Tesla");
// 在表达式中使用变量
parser.parseExpression("name = #newName").getValue(context, tesla);
System.out.println(tesla.getName()); // 输出: Mike Tesla
/**
* 变量命名规则
* 首字符:字母(支持 Unicode)、下划线(_)或美元符号($)。
* 后续字符:字母、数字、_ 或 $。
* 示例合法变量名:
* #user、#_count、#$value、#姓名
*/#this:当前对象
java
List<Integer> primes = List.of(2, 3, 5, 7, 11, 13, 17);
context.setVariable("primes", primes);
// 筛选大于 10 的元素
List<Integer> result = parser.parseExpression("#primes.?[#this > 10]")
.getValue(context, List.class);
System.out.println(result); // 输出: [11, 13, 17]#root:根对象
java
Inventor tesla = new Inventor("Nikola Tesla");
tesla.setInventions("Telephone repeater", "Tesla coil transformer");
// 使用 #root 和 #this 拼接字符串
String expr = "#root.inventions.![#root.name + ' invented the ' + #this + '.']";
List<String> inventions = parser.parseExpression(expr)
.getValue(context, tesla, List.class);
// 输出:
// ["Nikola Tesla invented the Telephone repeater.",
// "Nikola Tesla invented the Tesla coil transformer."]自定义函数
注册反射方法
java
// 定义静态工具方法
public class StringUtils {
public static String reverseString(String input) {
return new StringBuilder(input).reverse().toString();
}
}
java
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 注册反射方法
Method method = StringUtils.class.getMethod("reverseString", String.class);
context.setVariable("reverseString", method);
// 调用函数
String result = parser.parseExpression("#reverseString('hello')")
.getValue(context, String.class);
System.out.println(result); // 输出: "olleh"
java
// 注册 String.format() 方法
MethodHandle mh = MethodHandles.lookup()
.findVirtual(String.class, "formatted",
MethodType.methodType(String.class, Object[].class));
context.setVariable("format", mh);
// 调用函数(支持可变参数)
String message = parser.parseExpression(
"#format('Hello, %s! Today is %s.', 'Alice', 'Monday')"
).getValue(context, String.class);
System.out.println(message); // 输出: "Hello, Alice! Today is Monday."
java
// 提前绑定模板和参数
String template = "Result: %s (Score: %d)";
Object[] args = new Object[]{"Pass", 90};
MethodHandle boundMh = MethodHandles.lookup()
.findVirtual(String.class, "formatted",
MethodType.methodType(String.class, Object[].class))
.bindTo(template)
.bindTo(args);
context.setVariable("preboundFormat", boundMh);
// 调用时无需参数
String result = parser.parseExpression("#preboundFormat()")
.getValue(context, String.class);
System.out.println(result); // 输出: "Result: Pass (Score: 90)"可变参数 (Varargs) 支持
java
ExpressionParser parser = new SpelExpressionParser();
// 调用 String.format(),直接传递参数
String result = parser.parseExpression("'%s is color #%d'.formatted('blue', 1)")
.getValue(String.class);
System.out.println(result); // 输出: "blue is color #1"
java
// 通过数组传递可变参数
String result = parser.parseExpression(
"'%s is color #%d'.formatted(new Object[] {'blue', 1})"
).getValue(String.class);
System.out.println(result); // 输出: "blue is color #1"
java
// 使用 SpEL 内联列表 {} 传递参数
String result = parser.parseExpression(
"'%s is color #%d'.formatted({'blue', 1})"
).getValue(String.class);
System.out.println(result); // 输出: "blue is color #1"
java
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 注册自定义函数(反转多个字符串)
Method method = StringUtils.class.getMethod("reverseStrings", String[].class);
context.setVariable("reverseStrings", method);
// 混合传递字符串、数字、浮点数(自动转换为 String)
String output = parser.parseExpression(
"#reverseStrings('SpEL', 1, 10F / 5, 3.0000)"
).getValue(context, String.class);
System.out.println(output); // 输出: "3.0, 2.0, 1, SpEL"Bean 引用
java
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
// 设置 Bean 解析器(需实现 BeanResolver 接口)
context.setBeanResolver(new MyBeanResolver());
// 通过 @ 引用 Bean
Object myService = parser.parseExpression("@myService").getValue(context);
java
// 引用名为 "order.service" 的 Bean
Object orderService = parser.parseExpression("@'order.service'").getValue(context);
java
// 引用名为 "someFactoryBean" 的 FactoryBean 实例
Object factoryBean = parser.parseExpression("&someFactoryBean").getValue(context);三元运算符
java
ExpressionParser parser = new SpelExpressionParser();
// 基本用法
String result = parser.parseExpression("true ? 'A' : 'B'").getValue(String.class);
System.out.println(result); // 输出: "A"
// 使用变量
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("score", 85);
String grade = parser.parseExpression("#score >= 90 ? 'A' : (#score >= 60 ? 'B' : 'C')")
.getValue(context, String.class);
System.out.println(grade); // 输出: "B"
java
ExpressionParser parser = new SpelExpressionParser();
// 如果 name 为 null,返回 "Unknown"
String result = parser.parseExpression("name?:'Unknown'")
.getValue(new Inventor(), String.class);
System.out.println(result); // 输出: "Unknown"(因为 name 为 null)
java
Inventor tesla = new Inventor("", "Serbian"); // name 是空字符串
// 如果 name 为 null 或空,返回 "Elvis Presley"
String name = parser.parseExpression("name?:'Elvis Presley'")
.getValue(tesla, String.class);
System.out.println(name); // 输出: "Elvis Presley"安全导航运算符
安全访问属性
java
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"
// placeOfBirth 为 null 时安全返回 null
tesla.setPlaceOfBirth(null);
city = parser.parseExpression("placeOfBirth?.city")
.getValue(context, tesla, String.class);
System.out.println(city); // 输出: null(不会抛 NPE)安全调用方法
java
// 如果 calculator 为 null,返回 null
Double result = parser.parseExpression("#calculator?.add(1, 2)")
.getValue(context, Double.class);
java
IEEE society = new IEEE();
society.setMembers(Arrays.asList(new Inventor("Nikola Tesla")));
// 安全访问集合元素
Inventor inventor = parser.parseExpression("members?.[0]")
.getValue(context, society, Inventor.class);
System.out.println(inventor.getName()); // 输出: "Nikola Tesla"
// members 为 null 时安全返回 null
society.setMembers(null);
inventor = parser.parseExpression("members?.[0]")
.getValue(context, society, Inventor.class);
System.out.println(inventor); // 输出: null
java
// 筛选国籍为 Serbian 的成员(如果 members 为 null,返回 null)
List<Inventor> serbians = parser.parseExpression(
"members?.?[nationality == 'Serbian']"
).getValue(context, society, List.class);
java
// 选择第一个符合条件的成员
Inventor first = parser.parseExpression(
"members?.^[nationality == 'Serbian']"
).getValue(context, society, Inventor.class);
// 选择最后一个符合条件的成员
Inventor last = parser.parseExpression(
"members?.$[nationality == 'Serbian']"
).getValue(context, society, Inventor.class);
java
// 提取所有成员的出生地城市(如果 members 为 null,返回 null)
List<String> cities = parser.parseExpression(
"members?.![placeOfBirth.city]"
).getValue(context, society, List.class);
java
// 错误:如果 address 为 null,仍会抛 NPE
String risky = parser.parseExpression("person.address.city")
.getValue(context, String.class);
// 正确:全程安全导航
String safe = parser.parseExpression("person?.address?.city")
.getValue(context, String.class);集合筛选
基本用法
java
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 原始集合
List<Inventor> members = Arrays.asList(
new Inventor("Nikola Tesla", "Serbian"),
new Inventor("Marie Curie", "Polish"),
new Inventor("Albert Einstein", "German")
);
context.setVariable("members", members);
// 筛选国籍为 Serbian 的成员
List<Inventor> serbians = (List<Inventor>) parser.parseExpression(
"#members.?[nationality == 'Serbian']"
).getValue(context);
System.out.println(serbians); // 输出: [Inventor(name=Nikola Tesla, nationality=Serbian)]
java
Map<String, Integer> scores = Map.of("Alice", 25, "Bob", 30, "Charlie", 20);
context.setVariable("scores", scores);
// 筛选值小于 27 的条目
Map<String, Integer> filtered = (Map<String, Integer>) parser.parseExpression(
"#scores.?[value < 27]"
).getValue(context);
System.out.println(filtered); // 输出: {Alice=25, Charlie=20}特殊筛选操作
java
// 获取第一个国籍为 Serbian 的成员
Inventor firstSerbian = parser.parseExpression(
"#members.^[nationality == 'Serbian']"
).getValue(context, Inventor.class);
System.out.println(firstSerbian.getName()); // 输出: Nikola Tesla
java
// 获取最后一个国籍为 German 的成员
Inventor lastGerman = parser.parseExpression(
"#members.$[nationality == 'German']"
).getValue(context, Inventor.class);
System.out.println(lastGerman.getName()); // 输出: Albert Einstein安全筛选
java
// 安全筛选(members 为 null 时返回 null)
List<Inventor> result = (List<Inventor>) parser.parseExpression(
"#members?.?[nationality == 'French']"
).getValue(context);
System.out.println(result); // 输出: null(不会抛异常)集合投影
基本用法
提取对象属性
java
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 原始集合
List<Inventor> members = Arrays.asList(
new Inventor("Nikola Tesla", new PlaceOfBirth("Smiljan")),
new Inventor("Michael Pupin", new PlaceOfBirth("Idvor"))
);
context.setVariable("members", members);
// 提取所有成员的出生地城市
List<String> cities = (List<String>) parser.parseExpression(
"#members.![placeOfBirth.city]"
).getValue(context);
System.out.println(cities); // 输出: ["Smiljan", "Idvor"]操作 Map 条目
java
Map<String, Integer> scores = Map.of("Alice", 90, "Bob", 85);
context.setVariable("scores", scores);
// 提取所有键值对的字符串表示
List<String> entries = (List<String>) parser.parseExpression(
"#scores.![key + ': ' + value]"
).getValue(context);
System.out.println(entries); // 输出: ["Alice: 90", "Bob: 85"]安全投影
java
// 安全投影(members 为 null 时返回 null)
List<String> safeCities = (List<String>) parser.parseExpression(
"#members?.![placeOfBirth.city]"
).getValue(context);
System.out.println(safeCities); // 输出: null(不会抛异常)表达式模板
基本用法
定义模板
java
ExpressionParser parser = new SpelExpressionParser();
// 模板:静态文本 + 动态表达式
String result = parser.parseExpression(
"随机数是:#{T(java.lang.Math).random()}",
new TemplateParserContext() // 使用 #{ } 作为分隔符
).getValue(String.class);
System.out.println(result); // 输出: "随机数是:0.7038186818312008"多表达式块
java
String name = "Alice";
int score = 95;
// 多个动态表达式
String report = parser.parseExpression(
"学生 #{#name} 的成绩是 #{#score} 分",
new TemplateParserContext()
).getValue(context, String.class);
System.out.println(report); // 输出: "学生 Alice 的成绩是 95 分"自定义分隔符
java
public class CustomParserContext implements ParserContext {
@Override
public String getExpressionPrefix() { return "{{"; }
@Override
public String getExpressionSuffix() { return "}}"; }
@Override
public boolean isTemplate() { return true; }
}
// 使用自定义分隔符 {{ }}
String output = parser.parseExpression(
"当前时间:{{T(java.time.LocalTime).now()}}",
new CustomParserContext()
).getValue(String.class);
System.out.println(output); // 输出: "当前时间:15:30:45.123"更新: 2025-07-20 16:08:53
原文: https://www.yuque.com/lsxxyg/sz/fiqlmye0cgag3f04