springEL表达式_赋值表达式的条件

springEL表达式_赋值表达式的条件一、SpEL介绍二、SpEL用法1.在@Value注解中使用2.在XML配置中使用3.在代码中创建Expression对象三、SpEL原理1.解析器:ExpressionParser2.表达式:Expression3.上下文:EvaluationContext使用流程四、表达式语法1.基本表达式①字面量表达式②算数运算表达式③关系运算表达式④逻辑运算表达式⑤字符串连接及截取表达式⑥三目运算⑦Elivis表达式⑧正则表达式2.类相关表达式

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺


一、SpEL介绍

SpEL(Spring Expression Language):Spring表达式语言。

SpEL能在运行时构建复杂表达式、存取对象图属性、对象方法调用等等,并且能与Spring功能完美整合,如能用来配置Bean定义。

依赖配置

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>5.1.9.RELEASE</version>
    </dependency>

SpEL是单独模块,只依赖于core模块,不依赖于其他模块,可以单独使用。

二、SpEL用法

常见的三种用法:

  • 在@Value注解中使用
  • 在XML配置中使用
  • 在代码中创建Expression对象,利用Expression对象来执行SpEL

1. 在@Value注解中使用

@Configuration("testConfig11")
public class TestConfig { 
   

    @Bean(name = "user11")
    public User user11() { 
   
        User user = new User();
        user.setId("123");
        return user;
    }
}
@RestController
public class TestController { 
   
    @Value("#{user11.id}")
    private String userId;
}

将Spring容器中name为user11的bean的id属性值赋值给userId。

2. 在XML配置中使用

<bean id="testController " class="com.joker.controller.TestController ">
    <property name="userId" value="#{user11.id}">
</bean>

和@Value类似,将Spring容器中name为user11的bean的id属性值赋值给userId。

3. 在代码中创建Expression对象

    @GetMapping("test4")
    public String test4() { 
   
        // 创建ExpressionParser解析表达式
        ExpressionParser parser = new SpelExpressionParser();
        
        // 得到SpelExpression
        // 使用ctx.setVariable时,需要前缀
        SpelExpression exp = (SpelExpression)parser.parseExpression("#user.id");
        // 使用ctx.setRootObject时,不需要#符号和前缀
        // SpelExpression exp = (SpelExpression)parser.parseExpression("id");
        
        // 创建一个虚拟的容器EvaluationContext
        StandardEvaluationContext ctx = new StandardEvaluationContext();
        // 向容器内添加bean
        User user = new User();
        user.setId("123");
        ctx.setVariable("user", user);
        // ctx.setRootObject(user);
        
        // 得到user对象的id属性值
        String value = (String)exp.getValue(ctx);
        return value;
    }

吃段代码主要为了得到user对象的id属性值。这样的写法看着有点废哈,确实是的,但这只是个用法举例哈。

实际上这种在方式在Spring用的挺广泛的,比如Spring Security的权限校验注解(PreAuthorize、PostAuthorize、PreFilter、PostFilter)都用到了SpEL。

用法举例:

当你想对接口做防止重复提交的拦截,你一般会考虑加锁,锁的key会根据请求中的一些特殊参数来生成。如果直接在每个接口里面写这个生成key和加锁的逻辑,显然很臃肿。

你可以这么做:

  • 定义一个注解,该注解用在接口的方法上
  • 注解里定义一个String[]类型的属性来指定需要用于加锁的字段(SpEL表达式的方式,如:#user.id、#order.id)
  • 使用AOP切面来处理这个注解,得到使用了该注解的接口方法的请求参数
  • 根据注解中String[]类型的属性的值(SpEL表达式)解析出用于生成key的属性值
  • 生成锁key,获取锁
    • 如果拿到锁,调用接口方法执行具体逻辑,然后释放锁;
    • 如果没拿到锁,说明是重复提交,直接返回。

三、SpEL原理

1. 解析器:ExpressionParser

表达式解析器:负责解析表达式字符串,将字符串表达式解析为表达式对象。

接口的方法:

	Expression parseExpression(String expressionString) throws ParseException;

	Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
  • parseExpression:将字符串表达式转化为表达式对象
  • parseExpression:将字符串表达式转化为表达式对象(根据表达式解析模板上下文)

接口的实现:

  • SpelExpressionParser:SpEL解析器。实例是可重用的,且是线程安全的(最常用)。
  • TemplateAwareExpressionParser:模板感知表达式解析器,可以被不提供一流模板支持的表达式解析器子类化
  • InternalSpelExpressionParser:手写的SpEL解析器。 实例是可重用的,但不是线程安全的,是TemplateAwareExpressionParser的子类。

2. 表达式:Expression

表达式:提供getValue方法用于获取表达式值,提供setValue方法用于设置对象值。

接口的方法:


String getExpressionString();
Object getValue() throws EvaluationException;
<T> T getValue(@Nullable Class<T> desiredResultType) throws EvaluationException;
Object getValue(@Nullable Object rootObject) throws EvaluationException;
<T> T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType) throws EvaluationException;
Object getValue(EvaluationContext context) throws EvaluationException;
Object getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
<T> T getValue(EvaluationContext context, @Nullable Class<T> desiredResultType) throws EvaluationException;
<T> T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> desiredResultType)
throws EvaluationException;
Class<?> getValueType() throws EvaluationException;
Class<?> getValueType(@Nullable Object rootObject) throws EvaluationException;
Class<?> getValueType(EvaluationContext context) throws EvaluationException;
Class<?> getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
TypeDescriptor getValueTypeDescriptor() throws EvaluationException;
TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException;
TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException;
TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
boolean isWritable(@Nullable Object rootObject) throws EvaluationException;
boolean isWritable(EvaluationContext context) throws EvaluationException;
boolean isWritable(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
void setValue(@Nullable Object rootObject, @Nullable Object value) throws EvaluationException;
void setValue(EvaluationContext context, @Nullable Object value) throws EvaluationException;
void setValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Object value) throws EvaluationException;

主要方法

  • getValue:获取表达式值
  • setValue:设置对象值

接口的实现:

  • CompositeStringExpression:复合字符串表达式(里面封装一个表达式对象集合)
  • SpelExpression:SpEL表达式(最常用)
  • LiteralExpression:文字表达式

3. 上下文:EvaluationContext

上下文环境:使用setRootObject方法来设置根对象,使用setVariable方法来注册自定义变量,使用registerFunction来注册自定义函数等。

接口的方法:

	TypedValue getRootObject();
List<PropertyAccessor> getPropertyAccessors();
List<ConstructorResolver> getConstructorResolvers();
List<MethodResolver> getMethodResolvers();
BeanResolver getBeanResolver();
TypeLocator getTypeLocator();
TypeConverter getTypeConverter();
TypeComparator getTypeComparator();
OperatorOverloader getOperatorOverloader();
void setVariable(String name, @Nullable Object value);
Object lookupVariable(String name);

主要方法:

  • setVariable:注册自定义变量

接口的实现:

  • StandardEvaluationContext:标准上下文(最常用)
  • SimpleEvaluationContext:
  • ThymeleafEvaluationContext
  • MethodBasedEvaluationContext
  • CacheEvaluationContext

使用流程

  1. 创建解析器:创建解析器ExpressionParser(如:SpelExpressionParser)
  2. 解析表达式:使用ExpressionParser的parseExpression来解析表达式得到表达式对象Expression(如:SpelExpression)。
  3. 构造上下文:创建上下文EvaluationContext(如:StandardEvaluationContext),设置需要的数据。
  4. 得到值:通过Expression的getValue方法根据上下文获得表达式值。

四、表达式语法

  • 基本表达式

    • 字面量表达式
    • 算数运算表达式
    • 关系运算表达式
    • 逻辑运算表达式
    • 字符串连接及截取表达式
    • 三目运算
    • Elivis表达式
    • 正则表达式
  • 类相关表达式

    • 类类型
    • 类实例
    • instanceof
    • 变量定义及引用
    • 赋值
    • 自定义函数
    • 对象属获取及安全导航
    • 对象方法调用
    • Bean引用
  • 集合相关表达式

    • 内联数组定义
    • 内联集合定义
    • 数组(集合、字典)元素访问
    • 数组(集合、字典)元素修改
    • 数组(集合、字典)投影
    • 数组(集合、字典)选择
  • 其他表达式

    • 模板表达式

需要注意:SpEL表达式中的关键字是不区分大小写的。

1. 基本表达式

① 字面量表达式

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// 字符串
String str1 = parser.parseExpression("'test'").getValue(String.class);
String str2 = parser.parseExpression("\"test\"").getValue(String.class);
// 数字类型
int int1 = parser.parseExpression("1").getValue(Integer.class);
long long1 = parser.parseExpression("1L").getValue(long.class);
float float1 = parser.parseExpression("1.1").getValue(Float.class);
double double1 = parser.parseExpression("1.1E+1").getValue(double.class);
int hex1 = parser.parseExpression("0xf").getValue(Integer.class);
// 布尔类型
boolean true1 = parser.parseExpression("true").getValue(boolean.class);
// null类型
Object null1 = parser.parseExpression("null").getValue(Object.class);
}

② 算数运算表达式

SpEL支持:加(+)、减(-)、乘(*)、除(/)、求余(%)、幂(^)等算数运算。

并且支持用英文替代符号,如:MOD等价%、DIV等价/,且不区分大小写。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
int int1 = parser.parseExpression("3+2").getValue(Integer.class);// 5
int int2 = parser.parseExpression("3*2").getValue(Integer.class);// 6
int int3 = parser.parseExpression("3%2").getValue(Integer.class);// 1
int int4 = parser.parseExpression("3^2").getValue(Integer.class);// 9
}

③ 关系运算表达式

SpEL支持:等于(==)、不等于(!=)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=),区间(between)等关系运算。

“EQ” 、“NE”、 “GT”、“GE”、 “LT” 、“LE”来表示等于、不等于、大于、大于等于、小于、小于等于

并且支持用英文替代符号,如:EQ等价==、NE等价!=、GT等价>、GE等价>=、LT等价<、LE等价<=,且不区分大小写。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
boolean b1 = parser.parseExpression("3==2").getValue(Boolean.class);// false
boolean b2 = parser.parseExpression("3>=2").getValue(Boolean.class);// true
boolean b3 = parser.parseExpression("2 between {2, 3}").getValue(Boolean.class);// true
}

④ 逻辑运算表达式

SpEL支持:或(or)、且(and)、非(!或NOT)。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
boolean b1 = parser.parseExpression("2>1 and false").getValue(Boolean.class);// false
boolean b2 = parser.parseExpression("2>1 or false").getValue(Boolean.class);// true
boolean b3 = parser.parseExpression("NOT false and (2>1 and 3>1)").getValue(Boolean.class);// true
}

⑤ 字符串连接及截取表达式

SpEL支持字符串拼接和字符串截取(目前只支持截取一个字符)。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
String str1 = parser.parseExpression("'hello' + ' java'").getValue(String.class);// hello java
String str2 = parser.parseExpression("'hello java'[0]").getValue(String.class);// h
String str3 = parser.parseExpression("'hello java'[1]").getValue(String.class);// e
}

⑥ 三目运算

SpEL支持三目运算。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
Boolean b1 = parser.parseExpression("3 > 2 ? true : false").getValue(Boolean.class);// true
System.out.println(b1);
}

⑦ Elivis表达式

SpEL支持Elivis表达式。

Elivis运算符

表达式格式:表达式1?:表达式2
Elivis运算符是从Groovy语言引入用于简化三目运算符(表达式1? 表达式1:表达式2)的。

  • 当表达式1为非null时则返回表达式1,当表达式1为null时则返回表达式2
    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
String str1 = parser.parseExpression("'a' ?: 'b'").getValue(String.class);// a
String str2 = parser.parseExpression("null ?: 'b'").getValue(String.class);// b
Boolean b1 = parser.parseExpression("3 > 2 ?: false").getValue(Boolean.class);// true
Boolean b2 = parser.parseExpression("null ?: false").getValue(Boolean.class);// false
Boolean b3 = parser.parseExpression("false ?: true").getValue(Boolean.class);// false
}

⑧ 正则表达式

SpEL支持正则表达式

具体使用格式:str matches regex,其中str表示需要校验的字符串,regex表示正则表达式。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
Boolean b1 = parser.parseExpression("'123' matches '\\d{3}'").getValue(Boolean.class);// true
Boolean b2 = parser.parseExpression("'123' matches '\\d{2}'").getValue(Boolean.class);// false
}

2. 类相关表达式

① 类类型

SpEL支持使用T(Type)来表示java.lang.Class实例,Type必须是类全限定名,java.lang包除外,即该包下的类可以不指定包名;使用类类型表达式还可以进行访问类静态方法及类静态字段。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// java.lang包
Class class1 = parser.parseExpression("T(String)").getValue(Class.class);
// 其他包
Class class2 = parser.parseExpression("T(com.joker.pojo.User)").getValue(Class.class);
// 类静态字段访问
int result3 = parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class);
// 类静态方法调用
int result4 = parser.parseExpression("T(Integer).parseInt('2')").getValue(int.class);
}

② 类实例

SpEL支持类实例化,使用java关键字new,类名必须是全限定名,但java.lang包内的类型除外,如String、Integer。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// java.lang包
String str = parser.parseExpression("new String('str')").getValue(String.class);
// 其他包
Date date = parser.parseExpression("new java.util.Date()").getValue(Date.class);
}

③ instanceof

SpEL支持instanceof运算符,跟Java内使用方法相同。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
Boolean b1 = parser.parseExpression("'haha' instanceof T(String)").getValue(Boolean.class);// true
Boolean b2 = parser.parseExpression("123 instanceof T(String)").getValue(Boolean.class);// false
Boolean b3 = parser.parseExpression("123 instanceof T(java.util.Date)").getValue(Boolean.class);// false
}

④ 变量定义及引用

SpEL支持:

  • 使用#variableName引用通过EvaluationContext接口的setVariable(variableName, value)方法定义的变量;
  • 使用#root引用根对象
  • 使用#this引用当前上下文对象
    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// #variableName
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("name1", "value1");
String str1 = parser.parseExpression("#name1").getValue(context, String.class);// value1
User user = new User();
user.setId("1");
context = new StandardEvaluationContext(user);
// #root(#root可以省略)
String str2 = parser.parseExpression("#root.id").getValue(context, String.class);// 1
String str3 = parser.parseExpression("id").getValue(context, String.class);// 1
// #this
String str4 = parser.parseExpression("#this.id").getValue(user, String.class);// 1
}

⑤ 赋值

SpEL支持给自定义变量赋值,也允许给根对象赋值,直接使用#variableName=value即可赋值。

  • 使用#variable=value给自定义变量赋值
  • 使用#root=value给根对象赋值
  • 使用#this=value给当前上下文对象赋值
    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// #variableName
EvaluationContext context = new StandardEvaluationContext();
User user = new User();
user.setId("1");
context.setVariable("name1", user);
String str1 = parser.parseExpression("#name1.id='2'").getValue(context, String.class);// 2
context = new StandardEvaluationContext(user);
// #root(#root可以省略)
String str2 = parser.parseExpression("#root.id='3'").getValue(context, String.class);// 3
String str3 = parser.parseExpression("id='4'").getValue(context, String.class);// 4
// #this
String str4 = parser.parseExpression("#this.id='5'").getValue(user, String.class);// 5
}

⑥ 自定义函数

SpEL支持类静态方法注册为自定义函数。SpEL使用StandardEvaluationContext的registerFunction方法进行注册自定义函数(等同于使用setVariable)。

    public static void main(String[] args) throws NoSuchMethodException { 

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
Method parseInt = Integer.class.getDeclaredMethod("valueOf", String.class);
context.registerFunction("value", parseInt);
// 等同于Integer.valueOf("2").byteValue()
Byte b = parser.parseExpression("#value('2').byteValue()").getValue(context, Byte.class);// 2
}

⑦ 对象属性获取及安全导航

SpEL支持:

  • 对象属性获取:使用如object.property.property这种点缀式获取
  • 安全导航:SpEL引入了Groovy语言中的安全导航运算符”(对象|属性)?.属性”,用来避免”?.”前边的表达式为null时抛出空指针异常,而是返回null;修改对象属性值则可以通过赋值表达式或Expression接口的setValue方法修改。
    public static void main(String[] args) throws NoSuchMethodException { 

ExpressionParser parser = new SpelExpressionParser();
User user = new User();
user.setId("1");
StandardEvaluationContext context = new StandardEvaluationContext(user);
// 对象属性获取
String str1 = parser.parseExpression("id").getValue(context, String.class);// 1
String str2 = parser.parseExpression("Id").getValue(context, String.class);// 1
// 安全导航
User user1 = parser.parseExpression("#root?.#root").getValue(context, User.class);// {"id":"1"}
String str3 = parser.parseExpression("id?.#root.id").getValue(context, String.class);// 1
String str4 = parser.parseExpression("userName?.#root.userName").getValue(context, String.class);// null
}

注意:

  • SpEL对于属性名首字母是不区分大小写的。
  • 安全导航运算符前面的#root可以省略,但后面的#root不可省略。

⑧ 对象方法调用

SpEL支持对象方法调用,使用方法跟Java语法一样。对于根对象可以直接调用方法。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext("user");
// 对象方法调用
String str1 = parser.parseExpression("#root.substring(1, 2)").getValue(context, String.class);// s
String str2 = parser.parseExpression("substring(1, 2)").getValue(context, String.class);// 1
}

⑨ Bean引用

SpEL支持使用@符号来引用Bean,在引用Bean时需要使用BeanResolver接口实现来查找Bean,Spring提供BeanFactoryResolver实现。

    @Autowired
private ApplicationContext applicationContext;
@GetMapping("test1")
public ApiResult test1() { 

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
// 获取Spring容器中beanName为systemProperties的bean
Properties systemProperties = parser.parseExpression("@systemProperties").getValue(context, Properties.class);
System.out.println(JSON.toJSONString(systemProperties));
// RedisProperties redisProperties = parser.parseExpression("@spring.redis-org.springframework.boot.autoconfigure.data.redis.RedisProperties").getValue(context, RedisProperties.class);
// System.out.println(JSON.toJSONString(redisProperties));
return ApiUtil.success();
}

注意:特殊的bean名称直接使用@beanName会报错。

比如RedisProperties,它的beanName为spring.redis-org.springframework.boot.autoconfigure.data.redis.RedisProperties,会误解析为:

  • Spring容器的beanName为spring
  • redis-org、springframework、boot、autoconfigure、data、redis、RedisProperties为它的一层层的属性。

这种具体怎么处理暂未研究。

3. 集合相关表达式

注意:SpEL不支持内联字典(Map)定义。

① 内联数组定义

SpEL支持内联数组(Array)定义。但不支持多维内联数组初始化。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// 定义一维数组并初始化
int[] array1 = parser.parseExpression("new int[2]{1,2}").getValue(int[].class);
System.out.println(JSON.toJSONString(array1));
// 定义二维数组但不初始化
String[][] array2 = parser.parseExpression("new String[2][2]").getValue(String[][].class);
System.out.println(JSON.toJSONString(array2));
// 定义二维数组并初始化(会报错)
String[][] array3 = parser.parseExpression("new String[2][2]{ 
{'1','2'},{'3','4'}}").getValue(String[][].class);
System.out.println(JSON.toJSONString(array3));
}

② 内联集合定义

SpEL支持内联集合(List)定义。使用{表达式,……}定义内联List,如{1,2,3}将返回一个整型的ArrayList,而{}将返回空的List。

对于字面量表达式列表,SpEL会使用java.util.Collections.unmodifiableList方法将列表设置为不可修改。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// 将返回不可修改的空List
List<Integer> list1= parser.parseExpression("{}").getValue(List.class);
// 对于字面量列表也将返回不可修改的List
List<Integer> list2 = parser.parseExpression("{1,2,3}").getValue(List.class);
//对于列表中只要有一个不是字面量表达式,将只返回原始List(可修改)
String expression3 = "{ 
{1+2,2+4},{3,4+4}}";
List<List<Integer>> list3 = parser.parseExpression(expression3).getValue(List.class);
result3.get(0).set(0, 1);
}

③ 数组、集合、字典元素访问

SpEL支持集合、字典元素访问。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// 数组元素访问
int[] array1 = { 
1,2,3};
Integer int1 = parser.parseExpression("[0]").getValue(array1, int.class);
// 集合元素访问
Integer int2 = parser.parseExpression("{1,2,3}[0]").getValue(int.class);
List<Integer> list1 = Stream.of(1, 2, 3).collect(Collectors.toList());
Integer int3 = parser.parseExpression("[0]").getValue(list1, Integer.class);
// 字典元素访问
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
Integer int4 = parser.parseExpression("['b']").getValue(map, Integer.class);
}

④ 数组、集合、字典元素修改

SpEL支持数组、集合、字典元素修改。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// 数组元素修改
int[] array = new int[] { 
1, 2, 3};
parser.parseExpression("[0] = 3").getValue(array, int.class);
// 集合元素修改
List<Integer> list = Stream.of(1, 2, 3).collect(Collectors.toList());
parser.parseExpression("[0] = 3").getValue(list, Integer.class);
// 字典元素修改
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
parser.parseExpression("['b'] = 3").getValue(map, Integer.class);
}

⑤ 数组、集合、字典投影

SpEL支持数组、集合、字典投影。SpEL根据原集合中的元素中通过选择来构造另一个集合,该集合和原集合具有相同数量的元素。数组和集合类似,字典构造后是集合(不是字典)。

SpEL使用list|map.![投影表达式]来进行投影运算。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// 数组投影(#this可省略)
int[] array = new int[] { 
1, 2, 3};
int[] array1 = parser.parseExpression("#root.![#this+1]").getValue(array, int[].class);
// 集合投影(#this可省略)
List<Integer> list = Stream.of(1, 2, 3).collect(Collectors.toList());
List list1 = parser.parseExpression("#root.![#this+1]").getValue(list, List.class);
// 字典投影(#this可省略)
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
List list2 = parser.parseExpression("#root.![#this.key+1]").getValue(map, List.class);
List list3 = parser.parseExpression("#root.![#this.value+1]").getValue(map, List.class);
}
  • 数组、集合中的#this表示每个元素
  • 字典中的#this表示每个Map.Entry,所有可以用#this.key、#this.value来获取键和值。
  • 代码中.!后面的#this都可以省略,但.!前面的#root不可省略

⑥ 数组、集合、字典选择

SpEL支持数组、集合、字典选择。SpEL根据原集合通过条件表达式选择出满足条件的元素并构造为新的集合。数组和字典类似。

SpEL使用“(list|map).?[选择表达式]”,其中选择表达式结果必须是boolean类型,如果true则选择的元素将添加到新集合中,false将不添加到新集合中。

    public static void main(String[] args) { 

ExpressionParser parser = new SpelExpressionParser();
// 数组选择
int[] array = new int[] { 
1, 2, 3};
int[] array1 = parser.parseExpression("#root.?[#this>1]").getValue(array, int[].class);
// 集合选择
List<Integer> list = Stream.of(1, 2, 3).collect(Collectors.toList());
List list1 = parser.parseExpression("#root.?[#this>1]").getValue(list, List.class);
// 字典选择
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
Map map1 = parser.parseExpression("#root.?[#this.key!='a']").getValue(map, Map.class);
Map map2 = parser.parseExpression("#root.?[#this.value>1]").getValue(map, Map.class);
}

4. 其它表达式

① 模板表达式

SpEL支持模板表达式。模板表达式由字面量与一个或多个表达式块组成。

表达式块由:”前缀+表达式+后缀”形式组成。

SpEL使用ParserContext接口实现来定义表达式是否是模板及前缀和后缀定义。

常见的前缀后缀:#{}${}

模板表达式举例:

  • “${1+2}”:前缀${、后缀}、表达式1+2。
  • “Error ${#v0} ${#v1}”:字面量Error 、前缀${、后缀}、表达式#v0、表达式#v1,其中v0和v1表示自定义变量,需要在上下文定义。

五、扩展:Java中#{}和${}的使用

1. #{}的使用

  1. SpEL模板表达式

  2. MyBatis中的占位符,以预编译的方式传入参数,可以有效的防止SQL注入

    向占位符输入参数,MyBatis会自动进行Java类型jdbc类型的转换,且不需要考虑参数的类型,例如:传入字符串,MyBatis最终拼接好的SQL就是参数两边加单引号。

2. ${}的使用

  1. SpEL模板表达式

  2. 作用于@Value等注解的属性,用于获取配置文件的配置值

  3. MyBatis的SQL拼接,将参数的内容字符串替换方式拼接在SQL中,可能存在SQL注入的安全隐患

    在用于传入数据库对象,例如传入表名和列名,还有排序时使用order by动态参数时可以使用 ${ } 。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/194841.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • LINUX下 Udev详解[通俗易懂]

    如果你使用Linux比较长时间了,那你就知道,在对待设备文件这块,Linux改变了几次策略。在Linux早期,设备文件仅仅是是一些带有适当的属性集的普通文件,它由mknod命令创建,文件存放在/dev目录下。后来,采用了devfs,一个基于内核的动态设备文件系统,他首次出现在2.3.46内核中。Mandrake,Gentoo等Linux分发版本采用了这种方式。devfs创建的设备文件是动态的。但

  • translate3d模拟滚动条

    translate3d模拟滚动条做移动端页面,通常是不用原生的scroll,而是用translate3d来模拟,原因主要是原生的scroll对移动端的支持并不是很好,样式也不好看(有滚动条出现),用translate3d来模拟还可以调用GPU来加速,提高性能。html:

    2022年10月27日
  • 免费使用谷歌云服务器一年多少钱_谷歌云服务器永久免费

    免费使用谷歌云服务器一年多少钱_谷歌云服务器永久免费上周自己撸了一年的谷歌云服务器,昨天也帮同事搞了一发。毕竟工作中还是少不了向西方取经。把自己的经验总结一下吧,方便后来之人。说一下前提条件:1.持有外币卡,例有VISA标识、万事达标识、JCB标识的信用卡2.可以上谷歌且有谷歌账号,没有的话自己注册一个。免费申请链接在这:https://cloud.google.com/free/进入申请界面后有一个国家/地区的选项,截止目前没有找到中国的,直接选择了美国即可账户类型选择个人,然后地址直接百度一下美国地址生成器然后找到对应的网站,复制粘贴

  • 面试题 垃圾分类_前端垃圾回收机制面试题

    面试题 垃圾分类_前端垃圾回收机制面试题一、垃圾回收对象JVM运行时的数据区包括程序计数器、栈、堆、方法区、本地方法栈其中程序计数器、栈和本地方法栈是和线程绑定在一起的,当创建了线程,就会申请内存,当线程结束的时候,想关的内存就会被销毁。方法区主要是类对象,类加载的时候就会申请这里的内存,“类卸载”操作实际上是很少会涉及到的。因此,垃圾回收机制主要回收的对象就是堆,并且垃圾回收释放内存,实际上是在以对象为单位进行释放,因为内存的申请是以对象为单位进行申请的,当整个对象的内存都不在使用时,即没有引用指向这个对象时,就可以将其进行释放二、垃圾

    2022年10月13日
  • MQTT服务器搭建

    MQTT服务器搭建1、MQTT是一种消息传输协议,和我们常用的RabbitMq比较类似,不过MQTT我们基本都是用于在物联网(比如说连接边缘计算机采集PLC数据)。2、MQTT通讯模式看下边这张图应该就可以明白。发布者和订阅者提前约定一个主题,当发布者在这个主题下发布任何消息,订阅者就自动接收到了。3、windows搭建MQTT服务器,网上大多资料都是说的客户端,刚入坑的朋友可能就分不清,搞得很懵。我在这里说下我的模式,我租一台阿里服务器,在服务器上搭建MQTT服务,我本地跑一个客户端,用来测试订阅其他客户端给我服务器发

  • win10键盘全部没反应_Win10的键盘失灵解决办法

    win10键盘全部没反应_Win10的键盘失灵解决办法最近发现Win10的笔记本,键盘有点失灵,要么按了没反应,要么重复输入,很是恼火,以为是笔记本键帽坏了没弹起来,琢磨了下,发现是win10系统问题,赶紧记下来做笔记1、打开“设置”->”系统”->”电源和睡眠”->”其他电源设置”点击“选择电源按钮的功能”->”更改当前不可用的设置”->将启用快速启动取消勾选,保存修改退出。接下来右键我的电脑-&…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号