Spring之Spel表达式

Easter79
• 阅读 622

正常业务场景一般不用这个技术,但需要知道有这么个东西支持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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
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:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k