前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

1、表达式

1.1、文本表达式

文本表达式支持字符串、 日期 、 数字(正数 、 实数及十六进制数) 、 布尔类型及 null。

1、其中的字符表达式可使用单引号来表示,形如:‘Deniro’。

2、如果表达式中包含单引号或者双引号字符,那么可以使用转义字符 /。

@Test
public void test1(){
  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

1.2、对象属性表达式

SpEL 中,我们可以使用对象属性路径(形如类名.属性名.属性名)来访问对象属性的值。

@Test
public void test2() {
  //初始化对象
  Account account = new Account("Deniro");
  account.setFootballCount(10);
  account.setFriend(new Friend("Jack"));

  //解析器
  ExpressionParser parser = new SpelExpressionParser();
  //解析上下文
  EvaluationContext context = new StandardEvaluationContext(account);

  //1、获取不同类型的属性
  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);

  //2、 获取嵌套类中的属性
  String friend = (String) parser.parseExpression("friend.name").getValue(context);
  System.out.println(friend);
}

1.3、数组、ListMap 表达式

数组表达式支持 Java 创建数组的语法,形如 new int[]{3,4,5},数组项之间以逗号作为分隔符。注意:目前还不支持多维数组。Map 表达式以键值对的方式来定义,形如

@Test
public void test3(){
  //解析器
  ExpressionParser parser  = new SpelExpressionParser();

  // 1、解析一维数组,不支持二维数组
  int[] oneArray = (int[]) parser.parseExpression("new int[]{3,4,5}").getValue();
  System.out.println("一维数组开始:");
  for (int i : oneArray) {
    System.out.println(i);
  }
  System.out.println("一维数组结束");
  //int[][] twoArray = (int[][]) parser.parseExpression("new int[][]{3,4,5}{3,4,5}") .getValue();
  //这里会抛出 SpelParseException

  // 2、解析 list
  List list = (List) parser.parseExpression("{3,4,5}").getValue();
  System.out.println("list:" + list);


  // 3、解析 Map
  Map map = (Map) parser.parseExpression("{account:'deniro',footballCount:10}") .getValue();
  System.out.println("map:" + map);

  // 4、解析对象中的 list
  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);
}

1.4、方法表达式

SpEL 支持调用有访问权限的方法,这些方法包括对象方法、静态方法,而且支持可变方法参数。除此之外,还可以调用 String 类型中的所有可访问方法,比如

@Test
public void test4(){
  //解析器
  ExpressionParser parser  = new SpelExpressionParser();

  //1、调用 String 方法
  boolean isEmpty = parser.parseExpression("'Hi,everybody'.contains('Hi')").getValue(Boolean.class);
  System.out.println("isEmpty:" + isEmpty);

  //2、调用对象相关方法
  Account account = new Account("Deniro");
  EvaluationContext context = new StandardEvaluationContext(account);

  //调用公开方法
  parser.parseExpression("setFootballCount(11)").getValue(context, Boolean.class);
  System.out.println("getFootballCount:" + account.getFootballCount());
}

1.5、操作符表达式

1.5.1、关系操作符

SpEL 支持 Java 标准操作符:等于、不等于、小于、小等于、大于、大等于、正则表达式和 instanceof 操作符。

instanceof 操作符后面是类型表达式,格式为 T( Java 包装器类型),如整型 T (Integer)。注意:不能使用原生类型,如果这样 T ( int ) 会返回错误的判断结果。

matches 用于定义正则表达式,之后跟着单引号包裹着的正则表达式。

@Test
public void test5(){
  //解析器
  ExpressionParser parser = new SpelExpressionParser();

  //1、数值比较
  boolean result=parser.parseExpression("2>1").getValue(Boolean.class);
  System.out.println("2>1:"+result);

  // 2、字符串比较
  result=parser.parseExpression("'z'>'a'").getValue(Boolean.class);
  System.out.println("'z'>'a':"+result);

  // 3、instanceof 运算符
  result=parser.parseExpression("'str' instanceof T(String)").getValue(Boolean.class);
  System.out.println("'str' 是否为字符串 :"+result);

  result=parser.parseExpression("1 instanceof T(Integer)").getValue(Boolean.class);
  System.out.println("1 是否为整型 :"+result);

  //4、正则表达式
  result=parser.parseExpression("22 matches '\\d{2}'").getValue(Boolean.class);
  System.out.println("22 是否为两位数字 :"+result);

}

1.5.2、逻辑操作符

SpEL 中,不仅支持 Java 标准的逻辑操作符,还支持 andor 关键字。

@Test
public void test(){
  //解析器
  ExpressionParser parser  = new SpelExpressionParser();

  //1、与操作
  boolean result=parser.parseExpression("true && true").getValue(Boolean.class);
  System.out.println("与操作:"+result);

  //2、或操作
  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);

  //3、非操作
  result=parser.parseExpression("!false").getValue(Boolean.class);
  System.out.println("非操作:"+result);
}

1.5.3、运算操作符

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

  //1、加法运算
  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);

  //2、减法运算
  iResult = parser.parseExpression("2-3").getValue(Integer.class);
  System.out.println("减法运算:" + iResult);

  //3、乘法运算
  iResult = parser.parseExpression("2*3").getValue(Integer.class);
  System.out.println("乘法运算:" + iResult);

  //4、除法运算
  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);

  //5、求余运算
  iResult = parser.parseExpression("5%2").getValue(Integer.class);
  System.out.println("求余运算:" + iResult);

}

1.6、安全导航操作符

安全导航操作符来源于 Groovy 语言,使用它能够避免空指针异常。一般在访问对象时,需要验证该对象是否为空,使用安全导航操作符就能避免繁琐的空对象验证方法。它的格式是在获取对象属性操作符“.” 之前加一个 “?”。

@Test
public void test(){
  Account account = new Account("Deniro");
  account.setFriend(new Friend("Jack"));

  //解析器
  ExpressionParser parser = new SpelExpressionParser();
  EvaluationContext context = new StandardEvaluationContext(account);

  String friendName=parser.parseExpression("friend?.name").getValue(context,String.class);
  System.out.println("friendName:"+friendName);

  //设置为 null
  account.setFriend(null);
  friendName=parser.parseExpression("friend?.name").getValue(context,String.class);

  //打印出 null
  System.out.println("friendName:" + friendName);
}

1.7、三元操作符

SpEL 支持标准的 Java 三元操作符:<表达式 1>?<表达式 2>:<表达式 3>

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

  boolean result=parser.parseExpression("(1+2) == 3?true:false").getValue(Boolean.class);
  System.out.println("result:"+result);
}

1.8、变量表达式

⬤ 可以通过 #变量名 来引用在 EvaluationContext 中定义的变量。通过 EvaluationContext#setVariable(name, val) 即可定义新的变量;name 表示变量名,val 表示变量值。

⬤ 如果变量是集合,比如 list,那么可以通过 #scores.[#this] 来引用集合中的元素。

@Test
public void test8(){

  ExpressionParser parser = new SpelExpressionParser();
  EvaluationContext context = new StandardEvaluationContext();

  //定义一个新变量,名为 newVal
  context.setVariable("newVal", "Jack");
  String newVal = (String) parser.parseExpression(" #newVal").getValue(context);
  System.out.println("newVal:" + newVal);

  //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);
}

1.9、自定义函数

@Data
public class Account {
    private String name;
    private int footballCount;
    private Friend friend;
    private List<Friend> friends;

    public Account(String name) {
        this.name = name;
    }

    public static String method(String age){
        return "success:" + age;
    }
}
@Test
public void test() throws NoSuchMethodException {
  StandardEvaluationContext context = new StandardEvaluationContext();
  Method method = Account.class.getDeclaredMethod("method", String.class);
  context.registerFunction("method", method);

  ExpressionParser parser = new SpelExpressionParser();
  String value = parser.parseExpression("#method('healerjean')").getValue(context, String.class);
  System.out.println(value);
}

1.10、类型操作符

类型操作符 T 可以从类路径加载指定类名称(全限定名)所对应的 Class 的实例,格式为:T(全限定类名),效果等同于 ClassLoader#loadClass()。

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

  //加载 java.lang.Integer
  Class integerClass=parser.parseExpression("T(Integer)").getValue(Class.class);
  System.out.println(integerClass==java.lang.Integer.class);

  //调用类静态方法
  double result = (double) parser.parseExpression("T(Math).abs(-2.5)").getValue();
  System.out.println("result:" + result);
}

2、实战

ContactAuthor