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账号...

(1)


相关推荐

  • Clion2022.01激活码_在线激活

    (Clion2022.01激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html40ZKSWCX8G-eyJsaWNlbnNlSWQi…

  • idea激活 jetbrains-agent(jetbrains激活码)

    一、下载jar包JetbrainsCrack-2.7-release-str.jar百度这个jar包名字很多资源最好是找最新的二、找到软件的安装路径下的bin目录;将下载的jar包放到bin目录下,并将datagrip64.exe.vmoptions、datagrip.exe.vmoptions两个文件末尾添加一行代码-javaagent:C:\JetBrains\DataGri…

  • Nginx负载均衡策略_nginx高可用集群和负载均衡集群

    Nginx负载均衡策略_nginx高可用集群和负载均衡集群nginx的负载均衡策略有4种:轮询(默认)最基本的配置方法,它是upstream的默认策略,每个请求会按时间顺序逐一分配到不同的后端服务器。参数有:项目Valuefail_timeout与max_fails结合使用max_fails设置在fail_timeout参数设置的时间内最大失败次数,如果在这个时间内,所有针对该服务器的请求都失败了,那么认为该服务器会被认为是停机了fail_time服务器会被认为停机的时间长度,默认为10s。backup标记该服

    2022年10月13日
  • 请编写一个给list去重的函数_计算表达式

    请编写一个给list去重的函数_计算表达式c#拉姆达表达式实现List去重varlist=studentlist.OrderByDescending(a=>a.CreateDate).ToList();Console.WriteLine(JsonConvert.SerializeObject(list.Where((x,i)=>list.FindIndex(z=&gt…

  • SQL Prompt10 安装激活教程,让你写sql 如鱼得水[通俗易懂]

    SQL Prompt10 安装激活教程,让你写sql 如鱼得水[通俗易懂]需要sql_Prompt10压缩包的请看文章最底下1.首先得有我们的SQLPrompt10压缩包2.选择SQLPromptDownload.exe进行安装打开安装界面,全部勾选选点击continue——–>>继续下一步点击accept选择安装位置,一般不推荐安装C盘,继续install——>>>>等待安装完成点击finish3.打开sqlserver数据库打开sqlserver数据库,可能有些兄弟进入不是这样得,有sql_

  • SPI接口简介-Piyu Dhaker

    SPI接口简介-Piyu DhakerSPI接口简介作者:PiyuDhaker串行外设接口(SPI)是微控制器和外围IC(如传感器、ADC、DAC、移位寄存器、SRAM等)之间使用最广泛的接口之一。本文先简要说明SPI接口,然后介绍ADI公司支持SPI的模拟开关与多路转换器,以及它们如何帮助减少系统电路板设计中的数字GPIO数量。SPI是一种同步、全双工、主从式接口。来自主机或从机的数据在时钟上升沿或下降沿同步。主机和从机可以同时传输数据。SPI接口可以是3线式或4线式。本文重点介绍常用的4线SPI接口。接口图1.含主机和从

发表回复

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

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