RuoYi-Vue-Plus (SPEL 表达式)

ops/2024/10/18 14:26:10/

 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 测试:

@Testpublic 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案列更改:

@Testpublic 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


http://www.ppmy.cn/ops/27375.html

相关文章

TCP/IP和HTTP协议

TCP/IP OSI 七层模型在提出时的出发点是基于标准化的考虑&#xff0c;而没有考虑到具体的市场需求&#xff0c;使得该模型结构复杂&#xff0c;部分功能冗余&#xff0c;因而完全实现 OSI 参考模型的系统不多。而 TCP/IP 参考模型直接面向市场需求&#xff0c;实现起来也比较…

【C语言】编译与链接

1.翻译环境与运行环境 在ANSI C的任何一种实现中&#xff0c;存在两个不同的环境。 1.翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令&#xff08;二进制指令&#xff09; 2.执行环境&#xff0c;它用于实际执行代码 2.翻译环境 那么翻译环境是怎么将源代码…

STM32 F103C8T6学习笔记17:类IIC通信—MLX90614红外非接触温度计

今日学习配置MLX90614红外非接触温度计 与 STM32 F103C8T6 单片机的通信 文章提供测试代码讲解、完整工程下载、测试效果图 本文需要用到的大概基础知识&#xff1a;1.3寸OLED配置通信显示、IIC通信、 定时器配置使用 这里就只贴出我的 OLED驱动方面的网址链接了&#xff1a…

Rust 命令行参数解析指南

0x00 前言 通过 Rust 的 Governance 可以看到 Rust 的通过三种方式管理社区&#xff1a; RFC processTeamsWorking Groups 在 Working Groups 中我发现竟然有一个叫 Command-line interfaces (CLI) working group 的工作组(简称 WG-CLI)。很明显&#xff0c;如果 Rust 对于 …

BCSP-X 2024第一轮报名开始啦!

BCSP-X 2024第一轮报名开始啦! 2024北京中小学信息学能力测评活动(BCSP-X 2024)第一轮即将开始,4月20日起开始报名。本次活动包括基础知识测评和编程能力测评两部分,不收取任何费用。 重要时间节点 基础知识测评报名:4月20日-5月12日17:00基础知识测评:5月19日9:30-11:30基础…

张鸣独到解读:规矩与自信的政治影响

在当今多变的政治舞台上&#xff0c;学者张鸣教授以其犀利而深邃的视角&#xff0c;对规矩与自信提出了新的解读。他的言论不仅引发了公众的广泛关注&#xff0c;也为我们提供了思考社会政治问题的一个新的角度。张教授指出&#xff0c;规矩并非僵化的教条&#xff0c;而应是动…

iNav开源代码之研读分析篇章目录梳理

iNav开源代码之研读分析篇章目录梳理 1. 源由2. 基础篇章3. 代码篇章4. 场景篇章5. 异常篇章6. 总结7. 参考资料 1. 源由 之前有介绍过Betaflight/PX4/ArduPilot&#xff0c;虽然iNav代码和Betaflight类似&#xff0c;但是针对iNav系列的没有整理过一个总的目录。 今天打算也…

2.9 VM17虚拟机安装Centos系统和docker

VM17虚拟机安装Centos系统和docker 目录一、windows11安装VMware Workstation17虚拟机二、使用VM17虚拟机安装Centos(Linux)系统1. 镜像下载三、Centos系统安装docker1. 终端切换root权限2. 卸载旧版本的 Docker(新系统或者没安装过docker就跳过)3. 安装 Docker4. 配置 Docke…