Spring之Spel表达式

Easter79
• 阅读 309

正常业务场景一般不用这个技术,但需要知道有这么个东西支持Spring。

记忆力不好,抄了些套路代码便于以后用到。

package com.paic.phssp.springtest.spel;

import java.util.Arrays;
import java.util.List;

public class Account {
    private String name;
    private int footballCount;
    private Friend friend;
    private List<Friend> friends;

    public Account(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setFootballCount(int footballCount) {
        this.footballCount = footballCount;
    }

    public void addFriend(Friend friend) {

        this.friend = friend;
    }

    public int getFootballCount() {
        return footballCount;
    }

    public Friend getFriend() {
        return friend;
    }

    public void setFriend(Friend friend) {
        this.friend = friend;
    }

    public List<Friend> getFriends() {
        return friends;
    }

    public void setFriends(List<Friend> friends) {
        this.friends = friends;
    }

    public void read(){
        System.out.println("读书");
    }

    public void addFriendNames(String ... friendNames){
        System.out.println("friendNames="+ Arrays.toString(friendNames));
    }
}

package com.paic.phssp.springtest.spel;

public class Friend {
    private String name;

    public Friend(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

package com.paic.phssp.springtest.spel;

import com.paic.phssp.springtest.proxy.cglib.HeroCglibProxyFactory;
import com.paic.phssp.springtest.proxy.cglib.WickedLittleMage;
import com.paic.phssp.springtest.proxy.jdk.HeroProxyFactory;
import com.paic.phssp.springtest.proxy.jdk.IHero;
import com.paic.phssp.springtest.proxy.jdk.MonkeyHero;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpelTest {

    @Test
    public void testTextEl() {
        //文字表达式
        ExpressionParser parser = new SpelExpressionParser();

        //字符串解析
        String str = (String) parser.parseExpression("'你好'").getValue();
        System.out.println(str);

        //整型解析
        int intVal = (Integer) parser.parseExpression("0x2F").getValue();
        System.out.println(intVal);

        //双精度浮点型解析
        double doubleVal = (Double) parser.parseExpression("4329759E+22").getValue();
        System.out.println(doubleVal);

        //布尔型解析
        boolean booleanVal = (boolean) parser.parseExpression("true").getValue();
        System.out.println(booleanVal);

      /*  你好
        47
        4.329759E28
        true*/
    }

    @Test
    public void testObjEl() {
        //初始化对象
        Account account = new Account("Deniro");
        account.setFootballCount(10);
        account.addFriend(new Friend("Jack"));

        //解析器
        ExpressionParser parser = new SpelExpressionParser();
        //解析上下文
        EvaluationContext context = new StandardEvaluationContext(account);

        //获取不同类型的属性
        String name = (String) parser.parseExpression("name").getValue(context);
        System.out.println(name);
        int count = (Integer) parser.parseExpression("footballCount+1").getValue(context);
        System.out.println(count);

        //获取嵌套类中的属性
        String friend = (String) parser.parseExpression("friend.name").getValue(context);
        System.out.println(friend);

        /*Deniro
        11
        Jack*/

        //安全导航操作符,能够避免空指针异常
        account.setFriend(null);
        friend = (String) parser.parseExpression("friend?.name").getValue(context,String.class);
        System.out.println("friendName:" + friend);//friendName:null

    }

    @Test
    public void testArrMapListEl() {
        //解析器
        ExpressionParser parser = new SpelExpressionParser();

        //解析一维数组
        int[] oneArray = (int[]) parser.parseExpression("new int[]{3,4,5}").getValue();
        System.out.println("一维数组开始:");
        for (int i : oneArray) {
            System.out.print(i);
        }
        System.out.println();
        System.out.println("一维数组结束");

       /* 一维数组开始:
        345
        一维数组结束*/

        //这里会抛出 SpelParseException
        //        int[][] twoArray = (int[][]) parser.parseExpression("new int[][]{3,4,5}{3,4,5}")
        //                .getValue();

        //解析 list
        List list = (List) parser.parseExpression("{3,4,5}").getValue();
        System.out.println("list:" + list);
        //list:[3, 4, 5]

        //解析 Map
        Map map = (Map) parser.parseExpression("{account:'deniro',footballCount:10}").getValue();
        System.out.println("map:" + map);
        //map:{account=deniro, footballCount=10}

        //解析对象中的 list
        final Account account = new Account("Deniro");
        Friend friend1 = new Friend("Jack");
        Friend friend2 = new Friend("Rose");
        List<Friend> friends = new ArrayList<>();
        friends.add(friend1);
        friends.add(friend2);
        account.setFriends(friends);

        EvaluationContext context = new StandardEvaluationContext(account);
        String friendName = (String) parser.parseExpression("friends[0].name").getValue(context);
        System.out.println("friendName:" + friendName);
        //friendName:Jack
    }

    @Test
    public void testMethodEl() {
        //解析器
        ExpressionParser parser = new SpelExpressionParser();

        //调用 String 方法
        boolean isEmpty = parser.parseExpression("'Hi,everybody'.contains('Hi')").getValue(Boolean.class);
        System.out.println("isEmpty:" + isEmpty);

        /**
         * 调用对象相关方法
         */
        final Account account = new Account("Deniro");
        EvaluationContext context = new StandardEvaluationContext(account);

        //调用公开方法
        parser.parseExpression("setFootballCount(11)").getValue(context, Account.class);
        System.out.println("getFootballCount:" + account.getFootballCount());

        //调用私有方法,抛出 SpelEvaluationException: EL1004E: Method call: Method write() cannot be found on net.deniro
        // .spring4.spel.Account type
        //        parser.parseExpression("write()").getValue(context,Boolean
        //                .class);

        //调用静态方法
        parser.parseExpression("read()").getValue(context, Account.class);

        //调用待可变参数的方法
        parser.parseExpression("addFriendNames('Jack','Rose')").getValue(context, Account.class);

       /* isEmpty:true
        getFootballCount:11
        读书
        friendNames=[Jack, Rose]*/
    }

    @Test
    public void testRelationEl() {
        //关系操作符
        //解析器
        ExpressionParser parser = new SpelExpressionParser();


        //数值比较
        boolean result = parser.parseExpression("2>1").getValue(Boolean.class);
        System.out.println("2>1:" + result);  //2>1:true

        //字符串比较
        result = parser.parseExpression("'z'>'a'").getValue(Boolean.class);
        System.out.println("'z'>'a':" + result); //'z'>'a':true

        //instanceof 运算符
        result = parser.parseExpression("'str' instanceof T(String)").getValue(Boolean.class);
        System.out.println("'str' 是否为字符串 :" + result);  //'str' 是否为字符串 :true

        result = parser.parseExpression("1 instanceof T(Integer)").getValue(Boolean.class);
        System.out.println("1 是否为整型 :" + result);  //1 是否为整型 :true

        //正则表达式
        result = parser.parseExpression("22 matches '\\d{2}'").getValue(Boolean.class);
        System.out.println("22 是否为两位数字 :" + result); //22 是否为两位数字 :true
    }

    @Test
    public void testlogicEl() {
        //解析器
        ExpressionParser parser = new SpelExpressionParser();

        //与操作
        boolean result = parser.parseExpression("true && true").getValue(Boolean.class);
        System.out.println("与操作:" + result);

        //或操作
        result = parser.parseExpression("true || false").getValue(Boolean.class);
        System.out.println("或操作:" + result);

        parser.parseExpression("true or false").getValue(Boolean.class);
        System.out.println("或操作(or 关键字):" + result);

        //非操作
        result = parser.parseExpression("!false").getValue(Boolean.class);
        System.out.println("非操作:" + result);
    }

    @Test
    public void testOperateEl() {
        ExpressionParser parser = new SpelExpressionParser();
        //加法运算
        Integer iResult = parser.parseExpression("2+3").getValue(Integer.class);
        System.out.println("加法运算:" + iResult);

        String sResult = parser.parseExpression("'Hi,'+'everybody'").getValue(String.class);
        System.out.println("字符串拼接运算:" + sResult);

        //减法运算
        iResult = parser.parseExpression("2-3").getValue(Integer.class);
        System.out.println("减法运算:" + iResult);

        //乘法运算
        iResult = parser.parseExpression("2*3").getValue(Integer.class);
        System.out.println("乘法运算:" + iResult);

        //除法运算
        iResult = parser.parseExpression("4/2").getValue(Integer.class);
        System.out.println("除法运算:" + iResult);

        Double dResult = parser.parseExpression("4/2.5").getValue(Double.class);
        System.out.println("除法运算:" + dResult);

        //求余运算
        iResult = parser.parseExpression("5%2").getValue(Integer.class);
        System.out.println("求余运算:" + iResult);

        //三元运算符
        boolean result=parser.parseExpression("(1+2) == 3?true:false").getValue(Boolean.class);
        System.out.println("result:"+result);
    }

    @Test
    public void testClassEl() {
        ExpressionParser parser = new SpelExpressionParser();

        //加载 java.lang.Integer
        Class integerClass=parser.parseExpression("T(Integer)").getValue(Class
                .class);
        System.out.println(integerClass==java.lang.Integer.class);

        //加载 net.deniro.spring4.spel.Account
        Class accountClass=parser.parseExpression("T(com.paic.phssp.springtest.spel.Account)")
                .getValue(Class
                        .class);
        System.out.println(accountClass==com.paic.phssp.springtest.spel.Account.class);

        //调用类静态方法
        double result = (double) parser.parseExpression("T(Math).abs(-2.5)").getValue();
        System.out.println("result:" + result);

        //创建对象操作符
        Account account=parser.parseExpression("new com.paic.phssp.springtest.spel.Account" +
                "('Deniro')").getValue(Account.class);
        System.out.println("name:"+account.getName());
    }

    @Test
    public void testVariableEl(){
        Account account = new Account("Deniro");

        ExpressionParser parser = new SpelExpressionParser();
        EvaluationContext context = new StandardEvaluationContext(account);

        //定义一个新变量,名为 newVal
        context.setVariable("newVal", "Jack");

        //获取变量 newVal 的值,并赋值给 User 的 name 属性
        parser.parseExpression("name=#newVal").getValue(context);
        System.out.println("getName:" + account.getName());

        //this 操作符表示集合中的某个元素
        List<Double> scores = new ArrayList<>();
        scores.addAll(Arrays.asList(23.1, 82.3, 55.9));
        context.setVariable("scores", scores);//在上下文中定义 scores 变量
        List<Double> scoresGreat80 = (List<Double>) parser.parseExpression("#scores.?[#this>80]").getValue(context);
        System.out.println("scoresGreat80:" + scoresGreat80);
    }

    @Test
    public void testCollectSelectEl(){
        //集合选择表达式
        ExpressionParser parser = new SpelExpressionParser();
        List list = (List) parser.parseExpression("{3,4,5}").getValue();

        //----------------过滤 list 集合中的元素
        final StandardEvaluationContext listContext = new StandardEvaluationContext(list);
        List<Integer> great4List = (List<Integer>) parser.parseExpression("?[#this>4]").getValue(listContext);
        System.out.println("great4List:" + great4List);

        //获取匹配元素中的第一个值
        Integer first = (Integer) parser.parseExpression("^[#this>2]").getValue(listContext);
        System.out.println("first:" + first);

        //获取匹配元素中的最后一个值
        Integer end = (Integer) parser.parseExpression("$[#this>2]") .getValue(listContext);
        System.out.println("end:" + end);

        //----------------过滤 Map
        Map<String, Double> rank = new HashMap<String, Double>();
        rank.put("Deniro", 96.5);
        rank.put("Jack", 85.3);
        rank.put("Lily", 91.1);

        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("Rank", rank);
        //value 大于 90
        Map<String,Double> rankGreat95= (Map<String, Double>) parser.parseExpression("#Rank.?[value>90]").getValue(context);
        System.out.println("rankGreat95:" + rankGreat95);

        //key 按字母顺序,排在 L 后面
        Map<String,Double> afterL= (Map<String, Double>) parser.parseExpression("#Rank.?[key>'L']").getValue(context);
        System.out.println("afterL:"+afterL);
    }
}

参考:

https://www.jianshu.com/p/5537b2c86acd

点赞
收藏
评论区
推荐文章
技术小男生 技术小男生
2个月前
linux环境jdk环境变量配置
1:编辑系统配置文件vi /etc/profile2:按字母键i进入编辑模式,在最底部添加内容: JAVAHOME/opt/jdk1.8.0152 CLASSPATH.:$JAVAHOME/lib/dt.jar:$JAVAHOME/lib/tools.jar PATH$JAVAHOME/bin:$PATH3:生效配置
光头强的博客 光头强的博客
2个月前
Java面向对象试题
1、 请创建一个Animal动物类,要求有方法eat()方法,方法输出一条语句“吃东西”。 创建一个接口A,接口里有一个抽象方法fly()。创建一个Bird类继承Animal类并实现 接口A里的方法输出一条有语句“鸟儿飞翔”,重写eat()方法输出一条语句“鸟儿 吃虫”。在Test类中向上转型创建b对象,调用eat方法。然后向下转型调用eat()方
刚刚好 刚刚好
2个月前
css问题
1、 在IOS中图片不显示(给图片加了圆角或者img没有父级) <div<img src""/</div div {width: 20px; height: 20px; borderradius: 20px; overflow: h
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录 问题 用navicat导入数据时,报错: 原因这是因为当前的MySQL不支持datetime为0的情况。 解决修改sql\mode: sql\mode:SQL Mode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。 全局s
晴空闲云 晴空闲云
2个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。 盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
艾木酱 艾木酱
1个月前
快速入门|使用MemFire Cloud构建React Native应用程序
> MemFire Cloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
Easter79 Easter79
1年前
Twitter的分布式自增ID算法snowflake (Java版)
概述 == 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。 有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。 而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序 select * from table_name order id desc; 2.按照指定(多个)字段排序 select * from table_name order id desc,status desc; 3.按照指定字段和规则排序 selec
Wesley13 Wesley13
1年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
#### 背景描述 # Time: 2019-01-24T00:08:14.705724+08:00 # User@Host: **[**] @ [**] Id: ** # Schema: sentrymeta Last_errno: 0 Killed: 0 # Query_time: 0.315758 Lock_
helloworld_28799839 helloworld_28799839
2个月前
常用知识整理
# Javascript ## 判断对象是否为空 ```js Object.keys(myObject).length === 0 ``` ## 经常使用的三元运算 > 我们经常遇到处理表格列状态字段如 `status` 的时候可以用到 ``` vue
helloworld_34035044 helloworld_34035044
4个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。 uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid() 或 uuid(sep)参数说明:sep 布尔值,生成的uuid中是否包含分隔符'',缺省为