最新最全面的Spring详解(三)——Resources,验证、数据绑定和类型转换与Spring表达式语言(SpEL)(下)

简介: 最新最全面的Spring详解(三)——Resources,验证、数据绑定和类型转换与Spring表达式语言(SpEL)(下)

🍀(3)语法参考


本节描述Spring表达式语言的工作原理。 它涵盖以下主题:


(1) 文字表达方式


支持的文字表达式类型有字符串、数字值(int、real、hex)、布尔值和空值。 字符串由单引号分隔。 若要将单引号本身放入字符串中,请使用两个单引号字符。


下面的例子显示了文字的简单用法。 通常,它们不会像这样单独使用,而是作为更复杂表达式的一部分使用——例如,在逻辑比较运算符的一侧使用文字。

ExpressionParser parser = new SpelExpressionParser();
// evals to "Hello World"
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();
double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();
// evals to 2147483647
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();
boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
Object nullValue = parser.parseExpression("null").getValue();


数字支持使用负号、指数符号和小数点。 默认情况下,使用Double.parseDouble()解析实数。


(2) Arrays, Lists, Maps


使用句点来指示嵌套的属性值。

// evals to 1856
int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(context);
String city = (String) parser.parseExpression("placeOfBirth.city").getValue(context);

More Actions允许属性名称的首字母不区分大小写。 因此,上面例子中的表达式可以写成“生日”。 “年+ 1900”和“出生地点”。 分别城”。 此外,可以通过方法调用访问属性——例如,’ getPlaceOfBirth(). getcity() ‘而不是’ placeOfBirth.city '。


使用方括号表示法获取数组和列表的内容,示例如下:

ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// Inventions Array
// evaluates to "Induction motor"
String invention = parser.parseExpression("inventions[3]").getValue(
        context,tesla,String.class);
// Members List
// evaluates to "Nikola Tesla"
String name = parser.parseExpression("members[0].name").getValue(
        context,ieee,String.class);
// List and Array navigation
// evaluates to "Wireless communication"
String invention = parser.parseExpression("members[0].inventions[6]").getValue(
        context,ieee,String.class);

(3) 内联列表

可以使用{}符号在表达式中直接表示列表。

// evaluates to a Java list containing the four numbers
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);

{} 它本身就是一个空列表。 出于性能原因,如果列表本身完全由固定的字面值组成,则创建一个常量列表来表示表达式(而不是在每次求值时构建一个新列表)。


(4) 内联映射


您还可以使用{key:value} 表示法在表达式中直接表示映射。 下面的例子展示了如何做到这一点:

// evaluates to a Java map containing the two entries
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);
Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);

{:}它本身就是一个空映射。 出于性能原因,如果映射本身由固定的文字或其他嵌套的常量结构(列表或映射)组成,则创建一个常量映射来表示表达式(而不是在每次求值时构建一个新映射)。 map键的引用是可选的(除非键包含句号(’ . '))。 上面的例子没有使用引号键。


(5) 数组结构


可以使用熟悉的Java语法构建数组,也可以提供一个初始化式,以便在构造时填充数组。 下面的例子展示了如何做到这一点:

int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
// Array with initializer
int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context);
// Multi dimensional array
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);

You cannot currently supply an initializer when you construct a multi-dimensional array.


(6) 方法调用


您可以使用典型的Java编程语法来调用方法。 您还可以在文字上调用方法。 也支持变量参数。 下面的例子展示了如何调用方法:


// string literal, evaluates to "bc"
String bc = parser.parseExpression("'abc'.substring(1,3)").getValue(String.class);
// evaluates to true
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
        societyContext, Boolean.class);

7) 运算符


Spring表达式语言支持以下类型的操作符:


  • 关系运算符
  • 逻辑运算符
  • 数学运算符
  • 赋值运算符


关系运算符


使用标准操作符表示法支持关系操作符(等于、不等于、小于、小于或等于、大于和大于或等于)。 下面的例子展示了一些操作符示例:

// evaluates to true
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);
// evaluates to false
boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);
// evaluates to true
boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);


除了标准的关系操作符外,SpEL还支持instanceof和基于正则表达式的matches操作符。 下面的例子展示了两者的例子:

// evaluates to false
boolean falseValue = parser.parseExpression(
        "'xyz' instanceof T(Integer)").getValue(Boolean.class);
// evaluates to true
boolean trueValue = parser.parseExpression(
        "'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
// evaluates to false
boolean falseValue = parser.parseExpression(
        "'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);


每个符号运算符也可以指定为纯字母等效符。 这避免了所使用的符号对嵌入表达式的文档类型(例如XML文档)具有特殊意义的问题。 对应文本为:


lt (<)

gt (>)

le (<=)

ge (>=)

eq (==)

ne (!=)

div (/)

mod (%)

not (!).

所有的文本操作符都是不区分大小写的。


逻辑运算符


SpEL支持以下逻辑操作符:


and (&&)

or (||)

not (!)

下面的示例演示如何使用逻辑运算符:

// -- AND --
// evaluates to false
boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class);
// evaluates to true
String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
// -- OR --
// evaluates to true
boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class);
// evaluates to true
String expression = "isMember('Nikola Tesla') or isMember('Albert Einstein')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
// -- NOT --
// evaluates to false
boolean falseValue = parser.parseExpression("!true").getValue(Boolean.class);
// -- AND and NOT --
String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);

数学运算符


你可以在数字和字符串上使用加法运算符(+)。 您可以只在数字上使用减法(-)、乘法(*)和除法(/)操作符。 您还可以对数字使用模(%)和指数幂(^)运算符。 执行标准操作符优先级。 下面的例子展示了使用中的数学运算符:

// Addition
int two = parser.parseExpression("1 + 1").getValue(Integer.class);  // 2
String testString = parser.parseExpression(
        "'test' + ' ' + 'string'").getValue(String.class);  // 'test string'
// Subtraction
int four = parser.parseExpression("1 - -3").getValue(Integer.class);  // 4
double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class);  // -9000
// Multiplication
int six = parser.parseExpression("-2 * -3").getValue(Integer.class);  // 6
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class);  // 24.0
// Division
int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class);  // -2
double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class);  // 1.0
// Modulus
int three = parser.parseExpression("7 % 4").getValue(Integer.class);  // 3
int one = parser.parseExpression("8 / 5 % 2").getValue(Integer.class);  // 1
// Operator precedence
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class);  // -21

赋值运算


要设置属性,请使用赋值操作符(=)。 这通常是在调用 setValue中完成的,但也可以在调用getValue中完成。 下面的例子展示了使用赋值操作符的两种方法:

Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
parser.parseExpression("name").setValue(context, inventor, "Aleksandar Seovic");
// alternatively
String aleks = parser.parseExpression(
        "name = 'Aleksandar Seovic'").getValue(context, inventor, String.class);

(8) 类型


你可以使用特殊的’ T ‘操作符来指定一个’ java.lang.Class ‘(类型)的实例。 静态方法也可以通过使用此操作符来调用。 ’ StandardTypeLocator ‘(它可以被替换)是建立在对’ java。 朗的包。 这意味着’ T() ‘引用’ java。 Lang '包不需要完全限定,但所有其他类型引用必须是完全限定的。 下面的示例演示如何使用“T”操作符:

Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
boolean trueValue = parser.parseExpression(
        "T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
        .getValue(Boolean.class);

9)构造函数


你可以使用new操作符来调用构造函数。 你应该对所有类型使用完全限定类名,除了那些位于 java. lang package ( Integer , Float , String ,等等)。 下面的例子展示了如何使用new操作符来调用构造函数:

Inventor einstein = p.parseExpression(
        "new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
        .getValue(Inventor.class);
// create new Inventor instance within the add() method of List
p.parseExpression(
        "Members.add(new org.spring.samples.spel.inventor.Inventor(
            'Albert Einstein', 'German'))").getValue(societyContext);


(10) 变量


可以使用#variableName语法引用表达式中的变量。 变量是通过在EvaluationContext实现上使用setVariable方法设置的。


下面的例子展示了如何使用变量。

Inventor tesla = new Inventor("Nikola Tesla","Serbian");
// 我们必须创建一个上下文,在上下文中定义变量
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
context.setVariable("newName","Mike Tesla");
parser.parseExpression("name = #newName").getValue(context,tesla);
System.out.println(tesla.getName())  // "Mike Tesla"

11) Bean 的引用


如果计算上下文已经配置了bean解析器,那么您可以使用@符号从表达式中查找bean。

下面的例子展示了如何做到这一点:

// 定义一个容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(A.class);
// 创建一个解析器
ExpressionParser parser = new SpelExpressionParser();
// 定义一个表达式上下文
StandardEvaluationContext context = new StandardEvaluationContext();
// 这个地方规定了我要从哪里查找bean,我们的具体实现是BeanFactoryResolver,代表了从容器中获取
context.setBeanResolver(new BeanFactoryResolver(ctx));
Object bean = parser.parseExpression("@messageListener").getValue(context);

要访问FactoryBean本身,应该在bean名称前加上’ & '符号。 下面的例子展示了如何做到这一点:

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());
// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation
Object bean = parser.parseExpression("&foo").getValue(context);

(12) 三元运算符 (If-Then-Else)


可以使用三元运算符在表达式中执行if-then-else条件逻辑。 下面的例子显示了一个最小的示例:

String falseString = parser.parseExpression(
        "false ? 'trueExp' : 'falseExp'").getValue(String.class);

在这种情况下,布尔值false导致返回字符串值’false exp ’ 。 下面是一个更现实的例子:


Expression exp = parser.parseExpression("'Hello World'.bytes.length gt 2 ? 2:3")


相关文章
|
7月前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
536 1
|
2月前
|
JSON 安全 算法
|
18天前
|
Java 数据库 数据安全/隐私保护
轻松掌握Spring依赖注入:打造你的登录验证系统
本文以轻松活泼的风格,带领读者走进Spring框架中的依赖注入和登录验证的世界。通过详细的步骤和代码示例,我们从DAO层的创建到Service层的实现,再到Spring配置文件的编写,最后通过测试类验证功能,一步步构建了一个简单的登录验证系统。文章不仅提供了实用的技术指导,还以口语化和生动的语言,让学习变得不再枯燥。
34 2
|
1月前
|
数据采集 Java 数据安全/隐私保护
Spring Boot 3.3中的优雅实践:全局数据绑定与预处理
【10月更文挑战第22天】 在Spring Boot应用中,`@ControllerAdvice`是一个强大的工具,它允许我们在单个位置处理多个控制器的跨切面关注点,如全局数据绑定和预处理。这种方式可以大大减少重复代码,提高开发效率。本文将探讨如何在Spring Boot 3.3中使用`@ControllerAdvice`来实现全局数据绑定与预处理。
69 2
|
4月前
|
Java 开发者 Spring
|
6月前
|
前端开发 安全 Java
Spring EL表达式:概念、特性与应用深入解析
Spring EL表达式:概念、特性与应用深入解析
|
6月前
|
算法 Java API
在Spring Boot中实现接口签名验证通常涉及以下步骤
在Spring Boot中实现接口签名验证通常涉及以下步骤
524 4
|
7月前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
563 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
5月前
|
Java 数据库连接 测试技术
在Spring Boot中实现数据校验与验证
在Spring Boot中实现数据校验与验证
|
5月前
|
安全 Java 数据库
Spring Boot中的Kotlin语言支持
Spring Boot中的Kotlin语言支持