11 04Spring之表达式语言

文章目录

  • 1 表达式入门
  • 2 表达式的处理原理
  • 3 自定义分隔符
  • 4 基本表达式
    • 4.1 字面表达式
    • 4.2 数学表达式
    • 4.3 关系表达式
    • 4.4 逻辑表达式
    • 4.5 字符串操作
    • 4.6 三目运算符
    • 4.7 正则运算
    • 4.8 括号表达式
  • 5 Class类型表达式
  • 6 变量操作
  • 7 集合表达式
  • 8 实际使用:配置文件

SpEL(Spring Expression Language,Spring的表达式语言),这种语言类似于JSP中学习到的EL,但是在整个的Spring之中其表达式语言要更加的复杂,而且其支持度更加的广泛,,最为重要的是,它还可以进行方法调用、对象实例化、集合操作,但是唯一的难点就是:代码太复杂了,表达式太复杂了。

1 表达式入门

首先来观察一下,什么叫表达式以及表达式到底该怎么使用?
范例:表达式操作
(1)基础参考(如果不使用表达式实现同样的功能):

package org.lks.el.demo;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		String str = ("Hello " + "World").substring(6,11);
		System.out.println(str);
	}
}

(2)表达式实现:以上的实现方式使用的是硬编码的操作形式完成的,必须有String类对象,而后才可以利用对象.方法()的形式进行操作的调用;

package org.lks.el.demo;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		//定义解析器
		ExpressionParser ep = new SpelExpressionParser();
		//解析给出的字符串表达式
		Expression exp = ep.parseExpression("('hhy big ' + 'fool').substring(4,7)");
		System.out.println(exp.getValue());
	}
}

通过执行可以发现最为神奇的地方在于,整个Spring的表达式操作之中可以将一个完全的字符串变为了一个可以用于程序执行的语句,当然,这一系列的执行语句需要有一系列的支持类完成,但是至少可以发现,字符串的功能有一次被加强了。在本程序之中给出了如下的几个程序类:
1、表达式解析器:org.springframework.expression.ExpressionParser
(1)主要负责根据给定的表达式字符串内容对解析操作进行处理;

2、解析器处理类:org.springframework.expression.spel.standard.SpelExpressionParser
(1)ExpressionParser本身只是一个标准,但是它对应的处理类必须单独设置,本次使用的是Spel标准处理。

3、表达式:org.springframework.expression.Expression
(1)将字符串根据指定的解析器进行解析,而后使用这个生成的表达式。

4、设置表达式的一些属性信息:org.springframework.expression.EvaluationContext
(1)因为表达式的操作之中可能会存在有某些占位符需要进行处理。

范例:定义操作参数

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		//1、定义要操作的表达式,使用者更多的是关注于此部分,而不关注与具体的解析处理部分
		String pstr = "('hhy big ' + 'fool').substring(#start,#end)";
		//2、要定义一个表达式解析器,本次使用的是SpEL表达式解析器
		ExpressionParser parser = new SpelExpressionParser();
		//3、使用特定的解析器来处理指定的字符串操作
		Expression exp = parser.parseExpression(pstr);
		//4、定义相关的环境属性
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("start", 4);
		context.setVariable("end", 7);
		System.out.println(exp.getValue(context));
	}
}

现在就已经可以正常使用一个表达式了,同时也可以发现,字符串的功能继续加强。

2 表达式的处理原理

需要明确的是,在使用表达式的过程之中,我们除了可以利用字符串数据操作之外,也可以进行数学的操作。
范例:进行数学操作

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("1+2");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context));
	}
}

可以发现除了编写字符串之外还可以编写数字,甚至各种字符串的数据,那么如果是由我们自己编写这种表达式,那么一定要首先对其进行一个判断,判断表达式应该由哪些组成,而后拆分组成的内容,最后要进行组成的字符串的相关数据类型的转换,从而得出最终的计算结果。
11 04Spring之表达式语言_第1张图片
1、首先必须明确的按照指定的结构要求定义出表达式,例如1+2

2、随后需要准备出SpEL的表达式解析器,而进行解析的时候要按照如下的步骤进行:
(1)使用一个专门的断词器将给定的表达式字符串拆分为Spring可以认可的数据格式;
(2)随后要根据断词器处理的操作结果生成相应的语法结构;
(3)并且在这一个过程之中就需要进行表达式的对错检查了。

3、将已经处理后的表达式定义到一个专门的表达式对象之中等待进行最终的结果计算。

4、但是考虑到表达式里面可能会存在有部分的占位变量的内容,所以在进行表达式计算之前需要设置一个表达式上下文对象进行占位变量内容的处理;

5、最后设置好了变量内容,并且利用表达式对象就可以计算出表达式最终所执行的结果。

3 自定义分隔符

任何的表达式其组成之中一定会包含有相应的边界形式,例如:在JSP的EL里面使用${表达式},其中给定的${ 作为边界开始,而}作为边界结束,而在Spring里面如果用户有需要也可以定义边界。首先来观察解析表达式的操作接口的一个方法:public Expression parseExpression(String expressionString, ParserContext context) throws ParseException,其中给定的org.springframework.expression.ParserContext就是由用户自己来设置边界符的。提供有如下方法:
(1)是否使用此模板:public boolean isTemplate()
(2)边界开始符号:public String getExpressionPrefix()
(3)边界结束符号:public String getExpressionSuffix()
范例:定义自定义表达式边界

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#[1+2]", new ParserContext(){
     

			@Override
			public String getExpressionPrefix() {
     
				return "#[";
			}

			@Override
			public String getExpressionSuffix() {
     
				return "]";
			}

			@Override
			public boolean isTemplate() {
     
				return true;
			}
			
		});
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context));
	}
}

此时在进行表达式解析的过程之中,所出现的边界都会自动的忽略掉。

4 基本表达式

基本表达式本身非常容易理解,只是提供了一些简单的数学计算、逻辑计算等等应用。

4.1 字面表达式

1、字符串

//样例一:class java.lang.String: hhy big fool!
Expression exp = parser.parseExpression("'hhy big'+' fool! '");

//样例二:class java.lang.String: hhy big fool!,当使用双引号时,需要进行转义
Expression exp = parser.parseExpression("\"hhy big\"+\" fool! \"");

2、数值型

//样例一:class java.lang.Integer: 10
Expression exp = parser.parseExpression("10");
//样例二:class java.lang.Double: 10.000001
Expression exp = parser.parseExpression("10.00001");
//样例三:class java.lang.Double: 101000000000
Expression exp = parser.parseExpression("10.1E10");

3、布尔型

//样例一:class java.lang.Boolean: true
Expression exp = parser.parseExpression("true");

4、null类型

//样例一:null: null
Expression exp = parser.parseExpression("null");

4.2 数学表达式

1、四则运算

//样例一:class java.lang.Integer: 4
Expression exp = parser.parseExpression("1 * 4 + 6 / 9");
//样例二:class java.lang.Double: 4.666666666666667
Expression exp = parser.parseExpression("1 * 4 + 6.0 / 9");

2、求模

//样例一:class java.lang.Integer: 1
Expression exp = parser.parseExpression("5 % 2");
//样例二:class java.lang.Integer: 1,使用mod不区分大小写
Expression exp = parser.parseExpression("5 MOD 2");

3、幂运算

//样例一:class java.lang.Integer: 25
Expression exp = parser.parseExpression("5 ^ 2");

4、除法

//样例二:class java.lang.Double: 4.5
Expression exp = parser.parseExpression("9.0 DIV 2");

4.3 关系表达式

1、等于关系

//样例一:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 == 2");
//样例二:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 EQ 2");

2、不等于关系

//样例一:class java.lang.Boolean: true
Expression exp = parser.parseExpression("5 != 2");
//样例二:class java.lang.Boolean: true
Expression exp = parser.parseExpression("5 NE 2");

3、大于关系

//样例一:class java.lang.Boolean: true
Expression exp = parser.parseExpression("5 > 2");
//样例二:class java.lang.Boolean: true
Expression exp = parser.parseExpression("5 GT 2");

4、大于等于关系

//样例一:class java.lang.Boolean: true
Expression exp = parser.parseExpression("5 >= 2");
//样例二:class java.lang.Boolean: true
Expression exp = parser.parseExpression("5 GE 2");

5、小于关系

//样例一:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 < 2");
//样例二:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 LT 2");

6、小于等于关系

//样例一:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 <= 2");
//样例二:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 LE 2");

7、区间匹配

//样例一:class java.lang.Boolean: true
Expression exp = parser.parseExpression("5 BETWEEN {2,10}");

4.4 逻辑表达式

逻辑表达式只有三种关系:与、或、非。

1、与操作

//样例一:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 < 2 && 'a' == 'b'");
//样例二:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 < 2 AND 'a' == 'b'");

2、或操作

//样例一:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 < 2 || 'a' == 'b'");
//样例二:class java.lang.Boolean: false
Expression exp = parser.parseExpression("5 < 2 OR 'a' == 'b'");

3、非操作

//样例一:class java.lang.Boolean: true
Expression exp = parser.parseExpression("!(5 < 2 || 'a' == 'b')");
//样例二:class java.lang.Boolean: true
Expression exp = parser.parseExpression("NOT(5 < 2 OR 'a' == 'b')");

4.5 字符串操作

在String类中所有的操作方法都是在开发之中最为常用的。

1、连接操作

//样例一:class java.lang.String: hhy big fool!!
Expression exp = parser.parseExpression("'hhy'.concat(' big fool!!')");

2、取内容操作

//样例一:class java.lang.String: h
Expression exp = parser.parseExpression("'hhy'.concat(' big fool!!')[0]");

3、替换操作

//样例一:class java.lang.String: big
Expression exp = parser.parseExpression("'hhy'.concat(' big fool!!')[0].replace('h','big')");

只要String类的操作方法使用熟练了,那么基本上这些操作都可以直接在表达式之中使用。

4.6 三目运算符

所有的开发之中三目运算符的重要性是不言而喻的,而且可以发现,使用了三目运算符之后可以节约代码空间。

1、基础三目运算操作

//样例一:class java.lang.String: hhy big fool!
Expression exp = parser.parseExpression("5 > 2 ? 'hhy big fool!' : 'lks big fool!'");

2、NULL处理操作(将null作为了false)

//样例一:class java.lang.String: hhy big fool!
Expression exp = parser.parseExpression("null==null ? 'hhy big fool!' : 'lks big fool!'");
//样例二:class java.lang.String: lks big fool!
Expression exp = parser.parseExpression("null ?: 'lks big fool!'");

3、true操作

//样例一:class java.lang.String: hhy big fool!
Expression exp = parser.parseExpression("true ? 'hhy big fool!' : 'lks big fool!'");

4.7 正则运算

//样例一:class java.lang.Boolean: true
Expression exp = parser.parseExpression("20 matches '\\d+'");
//样例二:class java.lang.Boolean: true
Expression exp = parser.parseExpression("'20'.matches('\\d+')");

使用哪种方式都表示正则的操作。

4.8 括号表达式

利用括号表达式可以实现优先级的变更操作。

//样例一:class java.lang.Double: 0.43243243243243246
Expression exp = parser.parseExpression("(1+3)*4.0/(34+3)");

括号在表达式操作之中也是经常使用到的概念。

5 Class类型表达式

以上都是最基础的表达式,其与程序的结构是相同的,但是在Spring里面对于Class反射机制也有自己的表达式处理。

1、取得Class

//样例一:class java.lang.Class: class java.lang.String
Expression exp = parser.parseExpression("T(String)");
//样例二:class java.lang.Class: class java.util.Date
Expression exp = parser.parseExpression("T(java.util.Date)");

2、取得静态属性

//样例一:class java.lang.Integer: 2147483647
Expression exp = parser.parseExpression("T(java.lang.Integer).MAX_VALUE");

3、取得静态方法

//样例一:class java.lang.Integer: 52013
Expression exp = parser.parseExpression("T(java.lang.Integer).parseInt('52013')");

4、取得实例化对象

//样例一:class java.util.Date: Fri Jul 17 15:10:53 CST 2020
Expression exp = parser.parseExpression("new java.util.Date()");
//样例二:class java.lang.String: hhy big fool!
Expression exp = parser.parseExpression("new String('hhy big fool!')");

5、instanceof

//样例一:class java.lang.Boolean: true
Expression exp = parser.parseExpression("'hhy big fool!' instanceof T(String)");

使用T(类)的形式可以取得一个指定泛型类型的Class对象。

范例:取得Class类型的对象

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("T(String)");
		EvaluationContext context = new StandardEvaluationContext();
		Class<String> clazz = exp.getValue(context, Class.class);
		System.out.println(clazz);
	}
}

如果要调用静态属性则使用T(类型).静态属性名称
范例:调用Integer类中的MAX_VALUE静态属性

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("T(java.lang.Integer).MAX_VALUE");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

既然静态属性可以调用了,那么也可以调用静态方法,例如在Integer类里面存在有一个parseInt()的static方法,此方法可以接收一个字符串同时返回一个int型的数据。
范例:调用Integer的parseInt()方法

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("T(java.lang.Integer).parseInt('52013')");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

虽然给出了静态操作,但是严格来讲使用最多的情况一定是类产生实例化对象,那么此处依然可以使用同样的方式完成,可以直接使用new 类型()的方式来实例化对象。
范例:实例化Date类对象

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("new java.util.Date()");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

但是现在所调用的只是无参构造,如果有需要也可以调用有参构造。
范例:调用有参构造操作

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("new String('hhy big fool!')");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

在对象的开发过程之中,也可以进行实例化对象类型的判断。
范例:判断一个字符串是否是一个String的实例

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("'hhy big fool!' instanceof T(String)");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

利用字符串完整的实现了反射机制的各种操作。它的操作不可能很智能化,只能够处理很简单的功能。

6 变量操作

在表达式里面所有的操作都可以以变量的形式出现的,但是一般情况下只会出现在基本的操作之中。
范例:观察变量的定义

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#mylove");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("mylove", "hhy");
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

如果要想设置变量则必须依靠EvaluationContext接口完成,而在StandardEvaluationContext子类的构造方法上也可以接收一个变量:public StandardEvaluationContext(Object rootObject),这个构造方法表示的是设置根变量的操作内容,整个的变量操作体系之中会自动存在有一个#root的根变量。
范例:观察根变量的操作

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#root");
		EvaluationContext context = new StandardEvaluationContext("hhy big fool!");
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

现在的程序并没有针对于根变量调用context.setVariable("root", "hhy big fool!"),那么也就是说此时根变量的设置直接通过了构造方法传递到了程序之中。

实际上设置的变量可以做一些基础的表达式的操作处理。
范例:进行比较

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) {
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#root == 'hhy' ? 'hhy big fool!' : 'hhy super big fool!'");
		EvaluationContext context = new StandardEvaluationContext("hhy big fool!");
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

可能大部分情况下见到最多的都是使用自定义的变量进行使用。

实际上如果要进一步去研究表达式可以发现,它还可以针对于方法进行引用操作。

那么下面打算将Integer.parseInt()方法设置为myInt()的引用。
范例:实现方法引用

package org.lks.el.demo;

import java.lang.reflect.Method;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		ExpressionParser parser = new SpelExpressionParser();
		//找到Integer.parseInt()这个操作方法的对象
		Method method = Integer.class.getMethod("parseInt", String.class);
		//利用引用方法进行转换处理
		Expression exp = parser.parseExpression("#myParseInt('5201314')");
		//利用EvaluationContext类进行方法的引用注册
		EvaluationContext context = new StandardEvaluationContext();
		//方法进行引用
		context.setVariable("myParseInt", method);
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

使用myInt方法在表达式之中就相当于调用Integer.parseInt()方法实现了字符串与int数据的互相转型操作。

实际上除了以上的基本调用之外,还可以继续利用表达式的特征调用类中的属性,以Date类为例,有一个方法getTime(),此方法可以将Date型数据变为long型数据。
范例:调用属性

package org.lks.el.demo;

import java.util.Date;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("time");
		EvaluationContext context = new StandardEvaluationContext(new Date());
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

此时将java.util.Date类型的对象设置到了根变量中,所以一旦表达式之中出现了time单词,就表示要调用getTime()方法,需要特别提醒的是,这个时候表达式是不区分大小写的(只是第一个字母)。

Expression exp = parser.parseExpression("TIME");

但是这种调用本身是有风险的,此时的调用必须有一个前提:根变量有内容,那么如果根变量为null?
范例:观察根变量为null的情况

package org.lks.el.demo;

import java.util.Date;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("time");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

Exception in thread "main" org.springframework.expression.spel.SpelEvaluationException:
EL1007E:(pos 0): Property or field 'time' cannot be found on null

如果此时使用的是此类取得属性信息的话,那么它是不能够进行访问的,因为根变量为null就会出现异常。那么这个时候最好的解决方式不是增加什么判断,而是使用Groovy安全导航操作,利用Groovy安全运算符号避免空异常。
范例:使用?.访问属性

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#root?.time");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context));
	}
}

如果此时根变量的内容为空,那么返回的就是null,如果不为空,那么就可以返回具体的操作内容。

以上所有的操作变量都是在程序之中直接定义的,那么也可以引用applicationContext.xml文件里面定义的内容。

范例:观察引用配置中的变量
(1)定义一个Message类,类里面只有一个属性,同时提供好setter、getter操作;

package org.lks.vo;

import java.io.Serializable;

@SuppressWarnings("serial")
public class Message implements Serializable {
     

	private String info;

	public String getInfo() {
     
		return info;
	}

	public void setInfo(String info) {
     
		this.info = info;
	}

}

(2)随后在applicationContext文件里面配置这个类对象;


<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">

	<bean id="msg" class="org.lks.vo.Message">
		<property name="info" value="hhy big fool!"/>
	bean>
beans>

现在msg对象中的info属性里面是包含有配置内容的,随后希望可以在表达式里面去引用这部分的操作内容。
(3)引用配置内容,如果要进行导入外部配置,使用@名称.方法()

package org.lks.el.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELApplication {
     

	public static void main(String[] args) {
     
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("@msg.getInfo()");
		StandardEvaluationContext context = new StandardEvaluationContext();
		//将整个配置文件的内容读取交给上下文
		context.setBeanResolver(new BeanFactoryResolver(ctx));
		System.out.println(exp.getValue(context));
	}
}

就相当于此时,所有在外部配置的对象可以直接在表达式之中使用,并且利用表达式的语法调用对象的所提供的方法。

7 集合表达式

只要是开发框架的操作,永远都不可避免的要去进行集合数据的操作处理。Spring认为数组与List集合是等价的,所以如果要想操作List集合,利用{内容,内容,...}的形式就可以完成了。
范例:操作List集合内容

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("{10,20,30}");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}
//输出:class java.util.Collections$UnmodifiableRandomAccessList: [10, 20, 30]

而如果只是想定义一个空的List集合,那么就不设置内容,例如{}。但是需要记住的是,此时的List集合严格来讲即使相当于使用了Collections,在这个工具类下面可以创建空集合,但是许多的方法都是不支持的实现。

当然如果现在真定义出了集合,那么也可以利用表达式采用索引的方式进行访问。
范例:索引访问集合

package org.lks.el.demo;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("{10,20,30}[1]");
		EvaluationContext context = new StandardEvaluationContext();
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}
//输出:class java.lang.Integer: 20

正常来讲,如果真的要进行开发操作,往往都可以将集合设置为操作的变量进行处理。

范例:设置集合内容

package org.lks.el.demo;

import java.util.ArrayList;
import java.util.List;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		List<String> list = new ArrayList<String>();
		list.add("hhy");
		list.add("big");
		list.add("fool");
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#list");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("list", list);
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

以上的操作设置的是List集合,既然是集合,那么Set集合也一定可以设置。
范例:观察Set集合的配置

package org.lks.el.demo;

import java.util.HashSet;
import java.util.Set;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		Set<String> set = new HashSet<String>();
		set.add("hhy");
		set.add("big");
		set.add("fool");
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#set");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("set", set);
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}

除了List与Set集合之外,那么Map集合一定是不可能少的集合了。
范例:操作Map集合

package org.lks.el.demo;

import java.util.HashMap;
import java.util.Map;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		Map<String,String> map = new HashMap<String,String>();
		map.put("hhy", "super big fool!");
		map.put("lks", "big fool!");
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#map['hhy']");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("map", map);
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
	}
}
//输出:class java.lang.String: super big fool!

除了数据的设置之外,还可以进行数据的修改操作。
范例:修改List集合数据

package org.lks.el.demo;

import java.util.ArrayList;
import java.util.List;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		List<String> list = new ArrayList<String>();
		list.add("hhy");
		list.add("big");
		list.add("fool");
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#list[1]='hhy big fool!'");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("list", list);
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
		System.out.println(list);
	}
}
class java.lang.String: hhy big fool!
[hhy, hhy big fool!, fool]

那么既然List集合可以修改,那么也可以修改Map集合。
范例:修改Map集合

package org.lks.el.demo;

import java.util.HashMap;
import java.util.Map;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		Map<String,String> map = new HashMap<String,String>();
		map.put("hhy", "super big fool!");
		map.put("lks", "big fool!");
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#map['hhy']='hhy super super big fool!'");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("map", map);
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
		System.out.println(map);
	}
}
class java.lang.String: hhy super super big fool!
{
     lks=big fool!, hhy=hhy super super big fool!}

实际上在Spring又考虑到集合数据的批量处理问题,所以此处也可以针对于集合数据进行处理。
范例:处理List集合

package org.lks.el.demo;

import java.util.ArrayList;
import java.util.List;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		List<String> list = new ArrayList<String>();
		list.add("hhy");
		list.add("lks");
		list.add("fool");
		ExpressionParser parser = new SpelExpressionParser();
		//但是现在处理完成之后改变的并不是已有的集合,已有的集合不会发生变化
		Expression exp = parser.parseExpression("#list.!['big fool: ' + #this]");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("list", list);
		//这是一个新的集合
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
		System.out.println(list);
	}
}
class java.util.ArrayList: [big fool: hhy, big fool: lks, big fool: fool]
[hhy, lks, fool]

修改完成之后相当于重新创建了一个新的List集合。

在整个过程里面不要忘记了,Map集合也可以进行处理。
范例:处理Map集合

package org.lks.el.demo;

import java.util.HashMap;
import java.util.Map;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		Map<String,String> map = new HashMap<String,String>();
		map.put("hhy", "super big fool!");
		map.put("lks", "big fool!");
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#map.![#this.key + '-' + #this.value]");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("map", map);
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
		System.out.println(map);
	}
}
class java.util.ArrayList: [lks-big fool!, hhy-super big fool!]
{
     lks=big fool!, hhy=super big fool!}

这个时候在表达式之中将Map中的key与value进行了一个混合的处理,所以处理完的就是单值的数据,也就形成了一个新的List集合的操作数据。

实际上在整个表达式的集合操作之中也提供有数据的筛选操作支持。
范例:数据的筛选操作

package org.lks.el.demo;

import java.util.HashMap;
import java.util.Map;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELSimple {
     
	public static void main(String[] args) throws Exception{
     
		Map<String,String> map = new HashMap<String,String>();
		map.put("hhy", "super big fool!");
		map.put("lks", "big fool!");
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("#map.?[#this.key == 'hhy']");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("map", map);
		System.out.println(exp.getValue(context).getClass() + ": " + exp.getValue(context));
		System.out.println(map);
	}
}
class java.util.HashMap: {
     hhy=super big fool!}
{
     lks=big fool!, hhy=super big fool!}

整个筛选的过程里面就可以进行各种类方法的调用(主要是String类的支持方法)。

8 实际使用:配置文件

整个Spring的核心就是一个配置文件(增加了Annotation),所以只要将表达式应用在配置文件上才会特别的有意义。
范例:利用配置文件编写表达式应用


<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">

	<bean id="str" class="java.lang.String">
		<constructor-arg value="hhy super big fool fool fool!"/>
	bean>
	<bean id="msg" class="org.lks.vo.Message">
		<property name="info" value="#{str.substring(0,19) + 'lks big fool!hahaha'}"/>
	bean>
beans>

范例:测试本程序

package org.lks.el.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestELApplication {
     

	public static void main(String[] args) {
     
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		ExpressionParser parser = new SpelExpressionParser();
		Expression exp = parser.parseExpression("@msg.getInfo()");
		StandardEvaluationContext context = new StandardEvaluationContext();
		context.setBeanResolver(new BeanFactoryResolver(ctx));
		System.out.println(exp.getValue(context));
	}
}

可以发现所有的处理都是围绕字符串进行的,但是后面有表达式的支持。

你可能感兴趣的:(JavaWeb,spring,java)