使用实例
要使用spel解析器,包基本都在org.springframework.expression里,基础依赖里边就包含,我是在项目中需要做动态前置校验,使用该方案,下边是我项目中使用情景
忽略报错,只是为了拍照放到一起了。
- EvaluationContext context = new tandardEvaluationContext(ctxObj);中参数为JSONObject对象,这句话是构建上下文,为之后执行表达式进行数据准备
- parser.parseExpression(String.class) 中的参数 是表达式,原本使用为 “name != null”,但是会报错 property of type ‘name’ cannot be found on object of type ‘com.alibaba.fastjson’ - maybe not public or not valid 报错解决下边再提
- exp.getValue(context, Boolean.class);获取解析结果,我需要的是boolean类型,所以用Boolean.class,若是表达式返回其他类型,可依据需要修改,例如exp.getValue(context, String.class)
到这里就算是解析完了,原理大概是依据上下文的数据,代入规定的表达式中执行,然后返回结果,但是其中遇到另外问题,我只用最简单的举例,正常来说上下文中只要是map格式,解析器是可以直接依据key获取到值的,但是在使用过程中,并未获取到(也就是第二条中的问题),于是在网上进行了搜索,需要自定义属性访问器来解决
public class JSONObjectPropertyAccessor implements PropertyAccessor {
@Override
public Class<?>[] getSpecificTargetClasses() {
return new Class<?>[]{JSONObject.class};
}
@Override
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
//可读规范定义 仅读取JSONObject格式数据,且需要在target中-就是上下文中对象里得有这个key
return target instanceof JSONObject && ((JSONObject) target).containsKey(name);
}
@Override
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
// 读取逻辑
JSONObject jsonObject = (JSONObject) target;
return new TypedValue(jsonObject.get(name));
}
@Override
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
// 可写规范定义 均可写
return true;
}
@Override
public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
// 写入逻辑
JSONObject jsonObject = (JSONObject) target;
jsonObject.put(name, newValue);
}
}
自定义属性访问需要实现PropertyAccessor接口,并实现其中的方法,如canRead、read、canWrite和write;
使用自定义属性访问器
StandardEvaluationContext context = new StandardEvaluationContext(ctxObj);
context.addPropertyAccessor(new MyPropertyAccessor());
总结
其实spel很多地方都在用
- 配置文件中的使用
在 Spring 配置文件中,可以使用 SpEL 来动态地设置 Bean 的属性。例如:
<bean id="myBean" class="com.example.MyBean">
<property name="name" value="#{systemProperties['user.name']}"/>
<property name="age" value="#{10 + 20}"/>
</bean>
这里,#{systemProperties[‘user.name’]} 动态地从系统属性中获取用户名,#{10 + 20} 计算两个数字的和。
- 在注解中使用
Spring 还支持在注解中使用 SpEL,例如在 @Value 注解中:
@Component
public class MyComponent {
@Value("#{systemProperties['user.home']}")
private String userHome;
@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomNumber;
}
- 条件表达式
SpEL 可以用来编写条件表达式,例如在 @Conditional 注解中:
@Configuration
public class AppConfig {
@Bean
@Conditional(#{systemProperties['my.condition'] == 'true' ? MyCondition.class : NoOpCondition.class})
public MyBean myBean() {
return new MyBean();
}
}
- 方法调用与引用
SpEL 支持直接调用 Java 方法,并引用其他 Bean:
@Component
public class MyComponent {
@Value("#{myService.getSomeData()}")
private String data;
}
- 集合操作
SpEL 可以用来处理集合,例如筛选、投影等:
@Value("#{ {'a', 'b', 'c'} ? [el | el.toUpperCase()] }")
private List<String> upperCaseLetters; // 结果: ['A', 'B', 'C']
- 访问和修改 Bean 的属性
在运行时,可以通过 SpEL 来访问和修改 Bean 的属性:
@Autowired
private MyBean myBean;
public void updateBean() {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext(myBean);
parser.parseExpression("name").setValue(context, "New Name"); // 修改 name 属性值
}