RuoYi-Vue-Plus (SPEL 表达式)

 RuoYi-Vue-Plus 中SPEL使用

DataScopeType 枚举类中:
/**
     * 部门数据权限
     */
    DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "),
PlusDataPermissionHandler 拦截器中定义了解析器:

        buildDataFilter 方法中根据注解的key value来进行SPEL解析:key作为占位符,value 设置进原生sql

@Slf4j
public class PlusDataPermissionHandler {  
  /**
     * spel 解析器
     */
    private final ExpressionParser parser = new SpelExpressionParser();
    private final ParserContext parserContext = new TemplateParserContext();



 /**
     * 构造数据过滤sql
     */
    private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) {
       。。。。。省略代码
            for (DataColumn dataColumn : dataColumns) {
                if (dataColumn.key().length != dataColumn.value().length) {
                    throw new ServiceException("角色数据范围异常 => key与value长度不匹配");
                }
                if (!StringUtils.containsAny(type.getSqlTemplate(),
                    Arrays.stream(dataColumn.key()).map(key -> "#" + key).toArray(String[]::new)
                )) {
                    continue;
                }
                //1- 设置注解变量 key 为表达式变量 value 为变量值
                for (int i = 0; i < dataColumn.key().length; i++) {
                    context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
                }

                //2- 解析sql模板并填充
                String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class);
                conditions.add(joinStr + sql);
                isSuccess = true;
            }
           。。。。。省略代码
    }

一、概念

表达式语言给静态Java语言增加了动态功能。

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

SpEL支持如下表达式:

一、基本表达式: 字面量表达式、关系,逻辑与算数运算表达式、字符串连接及截取表达式、三目运算及Elivis表达式、正则表达式、括号优先级表达式;

二、类相关表达式: 类类型表达式、类实例化、instanceof表达式、变量定义及引用、赋值表达式、自定义函数、对象属性存取及安全导航表达式、对象方法调用、Bean引用;

三、集合相关表达式: 内联List、内联数组、集合,字典访问、列表,字典,数组修改、集合投影、集合选择;不支持多维内联数组初始化;不支持内联字典定义;

四、其他表达式:模板表达式。

二、DEMO 测试:


    @Test
    public void test1() {
        //1-首先构造一个解析器
        ExpressionParser parser = new SpelExpressionParser();
        //2-其次解析器解析字符串表达式
        Expression expression = parser.parseExpression("('Hello' + ' World').concat(#end)");
        //3- 创建上下文
        EvaluationContext context = new StandardEvaluationContext();
        //4-替换
        context.setVariable("end", "!");
        //5-求值:通过Expression接口的getValue方法,传入上下文获得表达式值。
        System.out.println(expression.getValue(context));
    }

1- parser.parseExpression("('Hello' + ' World').concat(#end)");

上面表达式拼接了 #end

2- context.setVariable("end", "!");

上下文中#end 替换为 !

输出:

Hello World!

三、ExpressionParser接口

public interface ExpressionParser {
 Expression parseExpression(String expressionString) throws ParseException;
 Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
}

 Expression parseExpression(String expressionString, ParserContext context) 

传入 ParserContext  的实现类 TemplateParserContext 可以自定义解析前缀。

public interface ParserContext {
 //是否是模板
 boolean isTemplate();
 //模板表达式前缀
 String getExpressionPrefix();
 //模板表达式后缀
 String getExpressionSuffix();
}

 对上面DEMO案列更改:


    @Test
    public void test1() {
      
        ExpressionParser parser = new SpelExpressionParser();
        //    ${ 定义解析前缀
        Expression expression = parser.parseExpression("HelloWorld${#end}", new TemplateParserContext("${","}") );
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("end", "!");。
        System.out.println(expression.getValue(context));
    }

 表达式模版例子:

TemplateParserContext 解析器使用

@Test
public void test11() {
    //创建解析器
    SpelExpressionParser parser = new SpelExpressionParser();
    //创建解析器上下文
    ParserContext context = new TemplateParserContext("%{", "}");
    Expression expression = parser.parseExpression("你好:%{#name},我们正在学习:%{#lesson}", context);

    //创建表达式计算上下文
    EvaluationContext evaluationContext = new StandardEvaluationContext();
    evaluationContext.setVariable("name", "路人甲java");
    evaluationContext.setVariable("lesson", "spring高手系列!");
    //获取值
    String value = expression.getValue(evaluationContext, String.class);
    System.out.println(value);
}

四、EvaluationContext接口

表示上下文环境,默认实现是org.springframework.expression.spel.support包中的StandardEvaluationContext类,

  1. 使用setRootObject方法来设置根对象,
  2. 使用setVariable方法来注册自定义变量,
  3. 使用registerFunction来注册自定义函数等等。

五、 SPEL 语法

1-基础字面量

SpEL支持的字面量包括:字符串、数字类型(int、long、float、double)、布尔类型、null类型。

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

    String str1 = parser.parseExpression("'Hello World!'").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+2").getValue(double.class);
    int hex1 = parser.parseExpression("0xa").getValue(Integer.class);
    long hex2 = parser.parseExpression("0xaL").getValue(long.class);
    boolean true1 = parser.parseExpression("true").getValue(boolean.class);
    boolean false1 = parser.parseExpression("false").getValue(boolean.class);
    Object null1 = parser.parseExpression("null").getValue(Object.class);

    System.out.println("str1=" + str1);
    System.out.println("int1=" + int1);
    System.out.println("long1=" + long1);
    System.out.println("float1=" + float1);
    System.out.println("double1=" + double1);
    System.out.println("hex1=" + hex1);
    System.out.println("hex2=" + hex2);
    System.out.println("true1=" + true1);
    System.out.println("false1=" + false1);
    System.out.println("null1=" + null1);
}

输出:

str1=Hello World!
int1=1
long1=-1
float1=1.1
double1=110.0
hex1=10
hex2=10
true1=true
false1=false
null1=null
2-算数表达式:

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

SpEL还提供求余(MOD)和除(DIV)而外两个运算符,与“%”和“/”等价,不区分大小写。

//类型示例加减乘除

int result1 = parser.parseExpression("1+2-3*4/2").getValue(Integer.class);

//求余
int result2 = parser.parseExpression("4%3").getValue(Integer.class);

//幂运算
int result3 = parser.parseExpression("2^3").getValue(Integer.class);

 输出:

-3 
1 
8

3-关系表达式 

等于(==)、不等于(!=)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=),区间(between)运算。

@Test
public void test3() {
    ExpressionParser parser = new SpelExpressionParser();
    boolean v1 = parser.parseExpression("1>2").getValue(boolean.class);
    boolean between1 = parser.parseExpression("1 between {1,2}").getValue(boolean.class);
    System.out.println("v1=" + v1);
    System.out.println("between1=" + between1);
}

 输出:

v1=false
between1=true
 4-逻辑表达式

且(and或者&&)、或(or或者||)、非(!或NOT)。

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

    boolean result1 = parser.parseExpression("2>1 and (!true or !false)").getValue(boolean.class);
    boolean result2 = parser.parseExpression("2>1 && (!true || !false)").getValue(boolean.class);

    boolean result3 = parser.parseExpression("2>1 and (NOT true or NOT false)").getValue(boolean.class);
    boolean result4 = parser.parseExpression("2>1 && (NOT true || NOT false)").getValue(boolean.class);

    System.out.println("result1=" + result1);
    System.out.println("result2=" + result2);
    System.out.println("result3=" + result3);
    System.out.println("result4=" + result4);
}

输出:

result1=true
result2=true
result3=true
result4=false
5-正则表达式

使用“str matches regex

如“”将返回true;

ExpressionParser parser = new SpelExpressionParser();

    boolean result1 = parser.parseExpression("'123' matches '\d{3}'").getValue(boolean.class);

输出:

true

6-表达式赋值 、表达式模版

如上面标题二,就是表达式赋值

如上面标题三,表达式模版

其他调用类方法,转换类型之类不常用,可以自行查看下面知乎文档链接 

总结

  1. Spel功能还是比较强大的,可以脱离spring环境独立运行
  2. spel可以用在一些动态规则的匹配方面,比如监控系统中监控规则的动态匹配;其他的一些条件动态判断等等
  3. 本文内容比较长,建议大家把案例都敲一遍,可以设置一些断点去研究一下源码,有问题的,欢迎大家留言交流。

 本文参考 :

玩转Spring中强大的spel表达式! - 知乎 (zhihu.com)icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/174786047

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/586801.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于电磁激励原理利用视触觉传感器估计抓取力矩的方法

由于触觉感知能使机器人通过其触觉传递获取丰富的接触信息&#xff0c;触觉感知已经成为机器人机械臂的一种流行的感知方式。而在触觉传感器可获取的各种信息中&#xff0c;通过外界接触从抓取物体传递到机器人手指的力矩等信息&#xff0c;在完成各种指令的实现尤为重要。如图…

数据结构––队列

1.队列的定义 2.队列的分类 2.1循环队 2.2链式队 3.队列的实现 3.1循环队 3.1.1声明 typedef int QDataType; #define MAXSIZE 50 //定义元素的最大个数 /*循环队列的顺序存储结构*/ typedef struct {QDataType *data;int front; //头指针int rear; //尾指针 }Queue;…

【最大公约数 排序】2344. 使数组可以被整除的最少删除次数

本文涉及知识点 最大公约数 排序 LeetCode2344. 使数组可以被整除的最少删除次数 给你两个正整数数组 nums 和 numsDivide 。你可以从 nums 中删除任意数目的元素。 请你返回使 nums 中 最小 元素可以整除 numsDivide 中所有元素的 最少 删除次数。如果无法得到这样的元素&a…

Apache中如何配置 ws 接口

Apache中如何配置 wss 接口 在Apache中配置WebSockets的支持&#xff0c;你需要使用mod_proxy_wstunnel模块&#xff0c;该模块是Apache的一个代理模块&#xff0c;它允许你代理WebSocket请求。 以下是配置步骤的简要说明和示例&#xff1a; 确保你的Apache服务器安装了mod_…

【Python小练】求斐波那契数列第n个数

题目 输出斐波那契数列第n个数。 分析 首先我们要知道&#xff0c;斐波那契数列&#xff0c;这个数列从第三位开始等于前两个数的和&#xff0c;要知道数列第n个数&#xff08;n>2&#xff09;&#xff0c;就要知道其前两相的值&#xff0c;着就需要用到递归了。来看一下吧…

【Java EE】多线程(二)Thread 类与常用方法

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更…

【C++】:日期类的实现 -- 日期计算器

前言 1.日期类是一种十分经典的类型。对于C的初学者&#xff0c;它能够帮助我们融会贯通许多C的基础知识&#xff0c;它涉及许多的基础语法&#xff0c;比如引用&#xff0c;函数重载&#xff0c;传值/传参返回&#xff0c;构造函数&#xff0c;运算符重载&#xff0c;const成…

【Linux】详解core dump文件的作用以及用法ubuntu20.04下无法形成core dump文件的解决办法

说明 从第三大点开始讲解ubuntu20.04下无法形成core dump文件的解决办法。 一、core与term的区别 在之前讲过的信号中&#xff0c;终止进程的信号的动作分为两种&#xff0c;一种是core&#xff0c;一种是term。term&#xff08;全称termination&#xff09;是直接终止进程&am…

1084 外观数列(测试点3分析)

solution1 测试点3是n1的情况int转string&#xff1a;str to_string(i) string转int&#xff1a;i atoi(str.c_str()) #include<iostream> #include<string> using namespace std; int main(){int n, cnt;char x;string ans, t;cin >> t >> n;…

土壤侵蚀分布数据、土壤侵蚀强度、土壤类型分布、降水量分布、坡度坡向数据、植被覆盖度、土地利用数据、土壤质地分布

引言 土壤侵蚀是指土壤或成土母质在外力作用下被破坏剥蚀、搬运和沉积的过程。土壤侵蚀强度是根据土壤侵蚀的实际情况&#xff0c;按轻微、中度、严重等分为不同级别。中国是世界上土壤侵蚀最严重的国家之一&#xff0c;主要发生在黄河中上游黄土高原地区、长江中上游丘陵地区和…

综合性练习(后端代码练习3)——留言板

目录 一、准备工作 二、约定前后端交互接口 1、需求分析 2、接口定义 &#xff08;1&#xff09;发布留言 &#xff08;2&#xff09;获取留言 三、实现服务器代码 1、lombok介绍 &#xff08;1&#xff09;引入依赖 &#xff08;2&#xff09;使用lombok &#xff…

int类型的取值范围(为什么负数比正数表示的范围多一位)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;C语言基本概念 &#x1f337;追光的人&#xff0c;终会万丈光芒 目录 &#x1f3dd;1.int的基本概念&#xff1a; 空间大小&#xff1a; 有符号类型的表示形式&#xff1a; &#x1f3dd;2.…

SSH远程登录实操实验!

ssh远程登录协议&#xff1a;默认端口号22 以下实验7-2是服务端&#xff0c;7-1是客户端 服务器的相关信息&#xff1a; 服务名称&#xff1a;sshd 服务端主程序&#xff1a;/usr/sbin/sshd 服务端配置文件&#xff1a;/etc/ssh/sshd_config 客户端相关信息&#xff1a; …

Java并发编程面试问题与答案

1. 什么是线程安全&#xff1f; 答&#xff1a; 线程安全意味着多个线程可以同时访问一个类的实例而不引起任何问题或不一致的结果。线程安全的代码会通过同步机制来确保所有线程都能正确地访问共享资源。 2. 解释Java中的synchronized关键字。 答&#xff1a; synchronized…

秒杀系统的挑战和应对设计

秒杀系统是日常系统开发过程中经常遇到的场景&#xff0c;那么如何可以准备哪些措施来保证秒杀过程中系统的可用性以及一致性呢&#xff1f; 秒杀活动&#xff0c;需要满足各方的需求 作为用户&#xff0c;希望能够抢到自己中意的优惠 作为商户&#xff0c;希望券不超发&#…

MATLAB 字符串

MATLAB 字符串 在MATLAB中创建字符串非常简单。实际上&#xff0c;我们已经使用了很多次。例如&#xff0c;您在命令提示符下键入以下内容- 示例 my_string ‘(cainiaojc.com)’ MATLAB将执行上述语句并返回以下结果 my_string (cainiaojc.com) MATLAB将所有变量视为数组&a…

Macos安装OrbStack

什么是OrbStack OrbStack 是一种在 macOS 上运行容器和 Linux 机器的快速、轻便和简单方法。它是 Docker Desktop 和 WSL 的超强替代品&#xff0c;所有这些都在一个易于使用的应用程序中。 在Macos M系列芯片上&#xff0c;经常遇到docker镜像不兼容的问题&#xff0c;此时使…

【初识Redis】

初识Redis Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存数据库&#xff0c;它提供了一个高性能的键值存储系统&#xff0c;并且支持多种数据结构&#xff0c;包括字符串、哈希、列表、集合和有序集合等。Redis的特点包括&#xff1a; 内存存储&…

[C语言]典型例题:小蚂蚁爬橡皮筋、买汽水问题、导致单词块、菱形打印……

1、小蚂蚁爬橡皮筋问题 假设橡皮筋长4m&#xff0c;小蚂蚁从一端爬向另一端每天爬1m&#xff0c;且每爬了1m&#xff0c;橡皮筋会立马拉伸4m&#xff0c;在理想条件下&#xff0c;小蚂蚁需要爬多少天可以到达橡皮筋的另一端&#xff1f; 不仔细想&#xff0c;我们很可能认为小蚂…

2023年蓝桥杯C++A组第三题:更小的数(双指针解法)

题目描述 小蓝有一个长度均为 n 且仅由数字字符 0 ∼ 9 组成的字符串&#xff0c;下标从 0 到 n − 1&#xff0c;你可以将其视作是一个具有 n 位的十进制数字 num&#xff0c;小蓝可以从 num 中选出一段连续的子串并将子串进行反转&#xff0c;最多反转一次。小蓝想要将选出的…