SpEL 表达式使用

简介

Java SpEL(Spring Expression Language) 是 Spring 框架提供的一种强大的表达式语言,它支持在运行时查询和操作对象图。SpEL 可以用于 XML 配置、注解配置以及代码中。下面详细介绍 SpEL 的基本用法和常见表达式。

 

SpEL 基础

SpEL 表达式以 #{} 的形式包围,可以在其中使用各种运算符、函数、变量等。

字面量表达式

  • 字符串: #{'Hello World'}

  • 数字: #{3.14}

  • 布尔值: #{true}

引用Bean、属性和方法

  • 引用Bean: #{beanName}

  • 引用Bean的属性: #{beanName.property}

  • 调用Bean的方法: #{beanName.method()}

运算符

  • 算术运算符: +-*/%^

  • 关系运算符: ==!=<><=>=

  • 逻辑运算符: andornot

  • 条件运算符: ?: (三元运算符), ?: (Elvis运算符)

  • 正则表达式: matches

集合操作

  • 访问列表: #{list[0]}

  • 访问映射: #{map['key']}

  • 集合投影: #{list.![property]} (从集合中每个元素提取属性形成新列表)

  • 集合选择: #{list.?[condition]} (根据条件过滤集合)

变量

可以使用 #variableName 来引用上下文中的变量,例如在 Spring Security 中常用 hasRole('ROLE_ADMIN') 等

 

在 XML 配置中使用

在 Spring 的 XML 配置文件中,可以使用 SpEL 来注入值。

<bean id="myBean" class="com.example.MyBean">
    <property name="value" value="#{systemProperties['user.timezone']}"/>
</bean>

 

 

在注解中使用

在 Spring 的注解中,例如 @Value,可以使用 SpEL。

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

 

 

在 Spring Security 中使用

Spring Security 中经常使用 SpEL 来定义访问控制。

@PreAuthorize("hasRole('ADMIN')")
public void someMethod() {
    // ...
}

 

 

在代码中直接使用

可以通过 SpelExpressionParser 来在代码中解析 SpEL 表达式。

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();

 

 

SpEL 的基本使用

SpEL 字面量表达式

// 字符串
parser.parseExpression("'Hello World'").getValue();

// 数字
parser.parseExpression("3.14159").getValue();

// 布尔值
parser.parseExpression("true").getValue();

// null
parser.parseExpression("null").getValue();

 

 

数学运算表达式

// 加法
parser.parseExpression("2 + 3").getValue(); // 5

// 减法
parser.parseExpression("5 - 2").getValue(); // 3

// 乘法
parser.parseExpression("4 * 3").getValue(); // 12

// 除法
parser.parseExpression("10 / 2").getValue(); // 5

// 取模
parser.parseExpression("10 % 3").getValue(); // 1

// 幂运算
parser.parseExpression("2 ^ 3").getValue(); // 8

 

 

关系表达式

// 等于
parser.parseExpression("2 == 2").getValue(); // true

// 不等于
parser.parseExpression("2 != 3").getValue(); // true

// 大于小于
parser.parseExpression("5 > 3").getValue(); // true
parser.parseExpression("5 < 3").getValue(); // false

// 实例检查
parser.parseExpression("'abc' instanceof T(String)").getValue(); // true

 

 

逻辑表达式

// 与运算
parser.parseExpression("true and false").getValue(); // false

// 或运算
parser.parseExpression("true or false").getValue(); // true

// 非运算
parser.parseExpression("!false").getValue(); // true

 

 

条件表达式

// 三元运算符
parser.parseExpression("2 > 1 ? 'yes' : 'no'").getValue(); // "yes"

// Elvis 运算符(简化三元)
parser.parseExpression("name?:'Unknown'").getValue(context); // 如果name为null返回'Unknown'

 

 

正则表达式

parser.parseExpression("'123' matches '\\d+'").getValue(); // true

 

 

对象操作表达式

属性访问

// 创建测试类
class User {
    private String name;
    private int age;
    private List<String> hobbies;
    
    // getters and setters
}

User user = new User("John", 25, Arrays.asList("reading", "swimming"));

// 属性访问
StandardEvaluationContext context = new StandardEvaluationContext(user);
parser.parseExpression("name").getValue(context); // "John"
parser.parseExpression("age").getValue(context); // 25

// 安全导航(避免NullPointerException)
parser.parseExpression("address?.city").getValue(context); // 如果address为null返回null

 

 

方法调用

parser.parseExpression("getName()").getValue(context);
parser.parseExpression("setName('Mike')").getValue(context);
parser.parseExpression("'hello'.toUpperCase()").getValue(); // "HELLO"

 

 

类型操作

// 调用静态方法
parser.parseExpression("T(java.lang.Math).random()").getValue();

// 访问静态字段
parser.parseExpression("T(java.lang.Math).PI").getValue();

// 实例化对象
parser.parseExpression("new java.util.Date()").getValue();

 

 

集合操作表达式

数组和列表操作

List<String> list = Arrays.asList("a", "b", "c");
context.setVariable("list", list);

// 访问元素
parser.parseExpression("#list[0]").getValue(context); // "a"

// 投影(提取属性)
List<User> users = Arrays.asList(new User("John", 25), new User("Mike", 30));
context.setVariable("users", users);
List<String> names = (List<String>) parser.parseExpression("#users.![name]").getValue(context);
// ["John", "Mike"]

// 选择(过滤)
List<User> youngUsers = (List<User>) parser.parseExpression("#users.?[age < 30]").getValue(context);

 

 

Map 操作

Map<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
context.setVariable("map", map);

parser.parseExpression("#map['key1']").getValue(context); // "value1"
parser.parseExpression("#map.key2").getValue(context); // "value2"

 

 

高级特性

 

变量定义和使用

context.setVariable("myVar", "Hello");
parser.parseExpression("#myVar + ' World'").getValue(context); // "Hello World"

 

函数注册

// 自定义函数
public class StringUtils {
    public static String reverse(String input) {
        return new StringBuilder(input).reverse().toString();
    }
}

// 注册函数
context.registerFunction("reverse", 
    StringUtils.class.getDeclaredMethod("reverse", String.class));

parser.parseExpression("#reverse('hello')").getValue(context); // "olleh"

 

集合投影和选择

List<User> users = Arrays.asList(
    new User("John", 25, Arrays.asList("reading", "swimming")),
    new User("Mike", 30, Arrays.asList("gaming", "coding"))
);
context.setVariable("users", users);

// 投影 - 提取所有用户名
List<String> names = (List<String>) parser.parseExpression("#users.![name]").getValue(context);

// 选择 - 过滤年龄大于25的用户
List<User> filtered = (List<User>) parser.parseExpression("#users.?[age > 25]").getValue(context);

// 嵌套投影
List<List<String>> allHobbies = (List<List<String>>) 
    parser.parseExpression("#users.![hobbies]").getValue(context);

 

在 Spring 配置中使用

@Component
public class AppConfig {
    
    @Value("#{systemProperties['java.version']}")
    private String javaVersion;
    
    @Value("#{T(java.lang.Math).random() * 100.0}")
    private double randomNumber;
    
    @Value("#{userService.defaultUser.name}")
    private String defaultUserName;
}

 

在 Spring Security 中使用

@PreAuthorize("hasRole('ADMIN') or #user.name == authentication.name")
public void updateUser(User user) {
    // 方法实现
}

 

在 Spring Data 中使用

public interface UserRepository extends JpaRepository<User, Long> {
    
    @Query("SELECT u FROM User u WHERE u.name = ?#{[0]} AND u.age = ?#{[1]}")
    List<User> findByNameAndAge(String name, int age);
}

 

安全考虑

使用 SimpleEvaluationContext

// 限制可访问的功能,提高安全性
SimpleEvaluationContext simpleContext = SimpleEvaluationContext.forReadOnlyDataBinding().build();
parser.parseExpression("name").getValue(simpleContext, user);

 

避免代码注入

// 不要直接使用用户输入构建表达式
String userInput = "T(java.lang.Runtime).getRuntime().exec('rm -rf /')";
// 这种表达式是危险的!

 

性能优化技巧

  1. 缓存 Expression 对象:重复使用的表达式应该缓存

  2. 重用 EvaluationContext:避免频繁创建上下文

  3. 使用简单表达式:复杂的表达式会影响性能

// 缓存表达式
private static final Expression CACHED_EXPRESSION = 
    parser.parseExpression("name.toUpperCase()");

public String processUser(User user) {
    return CACHED_EXPRESSION.getValue(context, user, String.class);
}

 

如果您喜欢本站,点击这儿不花一分钱捐赠本站

这些信息可能会帮助到你: 下载帮助 | 报毒说明 | 进站必看

修改版本安卓软件,加群提示为修改者自留,非本站信息,注意鉴别

THE END
分享
二维码
打赏
海报
SpEL 表达式使用
简介 Java SpEL(Spring Expression Language) 是 Spring 框架提供的一种强大的表达式语言,它支持在运行时查询和操作对象图。SpEL 可以用于 XML 配置、注解配置以及代码中。下面详细介绍 Sp……
<<上一篇
下一篇>>