Spring EL(表达式语言)零基础全面教程
一、什么是Spring EL?
Spring Expression Language(简称 SpEL)是 Spring 框架提供的一种强大的表达式语言,用于在运行时查询和操作对象。它支持属性访问、方法调用、运算符、条件判断等功能,广泛应用于 Spring 配置、注解(如 @Value
)、安全规则(Spring Security)等场景。
二、基础语法
SpEL 表达式以 #{ }
包裹,基本结构为:
#{表达式}
1. 字面量
- 字符串:
#{'Hello World'}
- 数字:
#{3.14}
- 布尔值:
#{true}
2. 变量引用
使用 #变量名
引用上下文中的变量:
#{user.name} // 引用 user 对象的 name 属性
$ vs #:${}
用于属性占位符(如 application.properties
),#{}
用于 SpEL 表达式。
3. 方法调用
#{'abc'.toUpperCase()} // 结果为 "ABC"
4. 操作符
- 算术:
+
,-
,*
,/
,%
- 比较:
==
,!=
,<
,>
,<=
,>=
- 逻辑:
and
,or
,not
- 三元运算符:
条件 ? 结果1 : 结果2
三、集合与数组操作
1. 访问列表/数组
#{users[0].name} // 访问第一个用户的 name 属性
2. 访问字典(Map)
#{userMap['admin'].password} // 获取 key 为 'admin' 的用户的密码
3. 安全导航操作符(?.)
避免空指针异常:
#{user?.address?.city} // 若 user 或 address 为 null,返回 null
4. 集合过滤与投影
-
选择(过滤):
?[...]
#{users.?[age > 18]} // 筛选年龄大于 18 的用户
-
投影(提取属性):
! [...]
#{users.![name]} // 提取所有用户的 name 属性,生成列表
四、类型操作符(T())
通过 T()
引用类,调用静态方法或常量:
#{T(java.lang.Math).random()} // 调用 Math.random()
#{T(java.util.Locale).CHINA} // 引用 Locale.CHINA 常量
五、高级特性
1. Bean 引用
在表达式中引用 Spring 容器中的 Bean:
#{@myService.getData()} // 调用名为 myService 的 Bean 的 getData 方法
2. 条件表达式(if-else)
#{user.vip ? '尊享会员' : '普通用户'}
3. 正则表达式匹配
#{user.email matches '[a-zA-Z0-9._%+-]+@gmail\\.com'}
4. 模板表达式
结合文本与表达式:
#{'用户名为:' + user.name + ',年龄:' + user.age}
六、实际应用场景
1. 在 @Value
中注入动态值
@Value("#{systemProperties['user.dir']}")
private String workDir;
2. Spring Security 权限控制
@PreAuthorize("hasRole('ADMIN') or #user.id == authentication.principal.id")
public void updateUser(User user) { ... }
3. XML 配置中的 SpEL
<bean id="dataSource" class="com.example.DataSource">
<property name="timeout" value="#{T(java.lang.Math).random() * 100}"/>
</bean>
4. 动态数据过滤
结合 Spring Data JPA:
@Query("SELECT u FROM User u WHERE u.name = ?#{#name}")
List<User> findByName(String name);
七、常见问题
SpEL 与 OGNL/JSTL 的区别?
SpEL 专为 Spring 设计,支持类型安全和方法调用,与 Spring 生态深度集成。
如何调试 SpEL 表达式?
使用 ExpressionParser
解析表达式,捕获 EvaluationException
:
ExpressionParser parser = new SpelExpressionParser();
try {
parser.parseExpression("#{user.age}").getValue(context);
} catch (EvaluationException e) {
e.printStackTrace();
}
性能如何?
SpEL 在启动时解析表达式并缓存,运行时性能接近 Java 代码。
八、总结
- 适用场景:动态配置、条件注入、安全规则、数据过滤。
- 核心优势:灵活性高,与 Spring 无缝集成。
- 学习建议:多实践,结合 Spring 的
@Value
、@PreAuthorize
等注解使用。