Spring-EL

SpringEL实现规则表达式判断

Spring 表达式语言(简称“SpEL”)是一种强大的表达式语言

1
2
3
4
5
6
public static void main(String[] args) {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'1 + 1 = ' + (1 + 1)");
String message = exp.getValue(String.class);
System.out.println(message); //1 + 1 = 2
}

项目中动态计算表达式值的过程

  • 从页面上配置表单式,左值选择表单中的属性或者接口返回对象属性,中间选择比较符号,右值选择枚举或者输入字符串

  • 使用时,生成完整表达式,并获取计算表达式需要的所有的数据

    1
    (#fun1([formModules][MD_OC], "[status]=='1'") && [formModules][MD_PROJECT][projectStatusId]=='13123b02-74a6-4ec4-8978-77ec446d4e29') || (#fun1([formModules][MD_OC], "[status]=='1'") && [formModules][MD_PROJECT][projectStatusId]=='3619a136-7988-440a-84d1-ccf8a7e2cb06')

  • 通过SpringEL模板引擎计算结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 根据表达式和资源数据,计算表达式的值
* @param express
* @param sourceData
* @return
*/
public Object doCompute(String express, Map<String, Object> sourceData) {
EvaluationContext evaluationContext = new StandardEvaluationContext(sourceData);
try {
Method fun1Method = RuleComponent.class.getDeclaredMethod("fun1", List.class, String.class);
evaluationContext.setVariable("fun1", fun1Method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
ExpressionParser parser = new SpelExpressionParser();
try {
Object value = parser.parseExpression(express).getValue(evaluationContext);
return value;
} catch (Exception e) {
log.error("计算表达式值出错:{}", e.getMessage());
}
return null;
}

引用的方法主要处理一些内置表达式无法完成的规则计算,这里是为了计算接口返回的集合中的每一条数据是否都满足条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static boolean fun1(List<Object> arr, String exp) {
if(CollUtil.isEmpty(arr)) {
return false;
}
ObjectMapper objectMapper = new ObjectMapper();
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(exp);
for (Object jsonNode : arr) {
Map<String, Object> param = objectMapper.convertValue(jsonNode, new TypeReference<Map<String, Object>>() {});
EvaluationContext evaluationContext = new StandardEvaluationContext(param);
Boolean value = expression.getValue(evaluationContext, Boolean.class);
if(value == null || !value) {
return false;
}
}
return true;
}

SpEL支持的功能

从对象,集合,Map中获取数据

  • 从对象获取数据

    1
    2
    3
    4
    5
    6
    7
    8
    public static void main(String[] args) {
    User user = new User("张三");
    EvaluationContext evaluationContext = new StandardEvaluationContext(user);
    ExpressionParser parser = new SpelExpressionParser();
    Expression exp = parser.parseExpression("#root.name");
    String message = exp.getValue(evaluationContext, String.class);
    System.out.println(message); //张三
    }
  • 从集合获取数据

    1
    2
    3
    4
    5
    6
    7
    8
    public static void main(String[] args) {
    List<User> users = Arrays.asList(new User("张三"), new User("李四"), new User("王五"));
    EvaluationContext evaluationContext = new StandardEvaluationContext(users);
    ExpressionParser parser = new SpelExpressionParser();
    Expression exp = parser.parseExpression("#root[2].name");
    String message = exp.getValue(evaluationContext, String.class);
    System.out.println(message); //王五
    }
  • 从Map获取对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public static void main(String[] args) {
    Map<String, Object> map = new HashMap<>();
    map.put("name", "张三");
    map.put("age", 18);
    Map<String, Object> detail = new HashMap<>();
    detail.put("address", "合肥");
    map.put("detail", detail);

    EvaluationContext evaluationContext = new StandardEvaluationContext(map);
    ExpressionParser parser = new SpelExpressionParser();
    String express = "'姓名:' + [name] + ',年龄:' + [age] + ',地址:' + [detail][address]";
    Expression exp = parser.parseExpression(express);
    String message = exp.getValue(evaluationContext, String.class);
    System.out.println(message); //姓名:张三,年龄:18,地址:合肥
    }

判空处理

  • Map的判空操作

    • 如果在StandardEvaluationContext中设置的对象是一个map,在判空获取值时,不能使用[xxx]这种方式,需要使用get方式

    • 例如:从approve中获取summary参数值,approve有可能为null,summary也有可能为空

      1
      '摘要:'+(#root.get('approve')?.get('summary')?:'')

计算符号

  • 支持基本的运算符,括号内和符号是等价的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    lt( < ), gt( > ), le( <= ), ge( >= ), eq( == ), ne( != ), div( / ), mod( % ), not( ! )

    and( && ), or( || ), not( ! )

    +, -, *, /, %, ^

    instanceof
    parser.parseExpression("'xyz' instanceof T(Integer)").getValue(Boolean.class);

    matches
    parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);

函数调用

可以调用java的方法

1
2
3
4
5
6
public static void main(String[] args) {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'abc'.substring(1, 3)");
String message = exp.getValue(String.class);
System.out.println(message); //bc
}

自定义函数

当基本的运算符和方法无法满足表达式计算时,可以自定义函数,在表达式中调用自定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ELExpress {

public static void main(String[] args) {
User user = new User("张三");
EvaluationContext evaluationContext = new StandardEvaluationContext(user);
try {
Method funMethod = ELExpress.class.getDeclaredMethod("check", String.class);
evaluationContext.setVariable("check", funMethod);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("#check(#root.name)");
Boolean message = exp.getValue(evaluationContext, Boolean.class);
System.out.println(message); //true
}

public static boolean check(String str) {
System.out.println("处理复杂逻辑..." + str); //处理复杂逻辑...张三
return true;
}
}

其他

语法可以参考官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions-language-ref