Spel表达式引擎使用案例

1. 创建对象,调用方法

SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
Expression expression = spelExpressionParser.parseExpression("new String('good').toUpperCase()");
System.out.println("返回的是String:" + expression.getValue(String.class));
System.out.println("返回的是Object" + expression.getValue());

2. 读取传入的对象的属性进行计算

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
private static class Item {
    
    
    private Integer price;
    private Integer count;
}

// 计算规则
String rule = "price+count";
Item item = new Item(10, 20);
StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext(item);
Object objVal = new SpelExpressionParser().parseExpression(rule).getValue(standardEvaluationContext);
Integer integerVal = new SpelExpressionParser().parseExpression(rule).getValue(standardEvaluationContext, Integer.class);
System.out.println(objVal);
System.out.println(integerVal);


// 也可以直接通过这种方式来设置rootObject
Object value = new SpelExpressionParser().parseExpression("price*count").getValue(item);
System.out.println(value);

3. null引用与下标越界

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
private static class Item {
    
    
    private Integer price;
    private Integer count;
    private List<String> productNameList;
}
  
    
Item item = new Item();
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
// 报错,因为productNameList是null
System.out.println(spelExpressionParser.parseExpression("productNameList.get(1)").getValue(item));


Item item = new Item();
// 如果list为null,不会自动初始化
item.setProductNameList(new ArrayList<>());
// 打开数组/集合自动增长
SpelExpressionParser spelExpressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
// 报错,因为productNameList是null
System.out.println(spelExpressionParser.parseExpression("productNameList.size()").getValue(item));
// 需要使用[n]这种方式访问,否则还是会报错
System.out.println(spelExpressionParser.parseExpression("productNameList[10]").getValue(item));
System.out.println(spelExpressionParser.parseExpression("productNameList.size()").getValue(item));

4. 读取属性、数组、集合、Map

Item item = new Item();
item.setPrice(999);
item.setProductNameList(Lists.newArrayList("抽烟", "喝酒", "烫头"));

List<Item> items = new ArrayList<>();
items.add(item);

Map<String, Object> map = new HashMap<>();
map.put("username", "idle fish");

// 通过方括号[n]读取数组,集合
// 通过.读取属性,属性可以直接写属性名,不需要写getter方法
System.out.println(new SpelExpressionParser().parseExpression("[0].price").getValue(items, Integer.class));
// 通过方括号[key]读取map
System.out.println(new SpelExpressionParser().parseExpression("[username]").getValue(map, String.class));

5. 构造集合、Map、数组

// 构造集合
System.out.println(new SpelExpressionParser().parseExpression("{1,2,3}").getValue(List.class));
// 构造集合
System.out.println(new SpelExpressionParser().parseExpression("{1,2,3,3}").getValue(Set.class));
// 构造map
System.out.println(new SpelExpressionParser().parseExpression("{'username':'idle fish','age':188}").getValue(Map.class));
// 构造数组
int[] value = (int[]) new SpelExpressionParser().parseExpression("new int[]{1,2,3}").getValue();
System.out.println(value);

6. 运算

Item item = new Item();
item.setPrice(10);
item.setCount(3);
System.out.println(new SpelExpressionParser().parseExpression("price + count").getValue(item, Integer.class));
System.out.println(new SpelExpressionParser().parseExpression("price - count").getValue(item, Integer.class));
System.out.println(new SpelExpressionParser().parseExpression("price * count").getValue(item, Integer.class));
System.out.println(new SpelExpressionParser().parseExpression("price / count").getValue(item, Integer.class));
System.out.println(new SpelExpressionParser().parseExpression("price % count").getValue(item, Integer.class));
System.out.println(new SpelExpressionParser().parseExpression("price == count").getValue(item, Boolean.class));
System.out.println(new SpelExpressionParser().parseExpression("price > count").getValue(item, Boolean.class));
System.out.println(new SpelExpressionParser().parseExpression("price >= count").getValue(item, Boolean.class));
System.out.println(new SpelExpressionParser().parseExpression("(price*count) >= 50").getValue(item, Boolean.class));
// 逻辑运算 and or not(!)
System.out.println(new SpelExpressionParser().parseExpression("price >= 15 and count>=3").getValue(item));
System.out.println(new SpelExpressionParser().parseExpression("price >= 15 or count>=3").getValue(item));
// 三元运算
System.out.println(new SpelExpressionParser().parseExpression("price=(price>=10?15:price)").getValue(item));

7. 赋值

Item rootObject = new Item();
new SpelExpressionParser().parseExpression("price").setValue(rootObject, "99999999");
System.out.println(rootObject);
// 也可以通过get来赋值
Object value = new SpelExpressionParser().parseExpression("count=555").getValue(rootObject);
// 555
System.out.println(value);
System.out.println(rootObject);

8. 变量

Item item = new Item();
// 设置rootObject
StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext(item);
// 增加变量
standardEvaluationContext.setVariables(new JSONObject().fluentPut("username", "idle fish").fluentPut("age", 29));
SpelExpressionParser spelExpressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
spelExpressionParser.parseExpression("productNameList").setValue(standardEvaluationContext, new ArrayList<>());
System.out.println(item);
// 取值与赋值
spelExpressionParser.parseExpression("productNameList[0]=#username").getValue(standardEvaluationContext);
System.out.println(item);
// 赋值
spelExpressionParser.parseExpression("price=#age").getValue(standardEvaluationContext);
System.out.println(item);

9. #this与#root

// create an array of integers
List<Integer> primes = Lists.newArrayList(2, 3, 5, 7, 11, 13, 17);
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("primes", primes);
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(
        //.?[] 用来从集合中选择符合特定条件的元素。在这种情况下,它会遍历 #primes 集合中的每一个元素
        "#primes.?[#this>10]").getValue(context);
System.out.println(primesGreaterThanTen);

10. 方法注册与引用

public void registerFunction(String name, Method m)

// 原始数据
String hello = "hello world";
// 标准评估上下文,并将rootObject传入
StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext(hello);
// 注册方法
standardEvaluationContext.registerFunction("revert", StringUtils.class.getDeclaredMethod("reverse", String.class));
// 调用注册的方法,并通过this将context中的rootObject传进去
System.out.println(new SpelExpressionParser().parseExpression("#revert(#this)").getValue(standardEvaluationContext));

11. bean引用

  • StandardEvaluationContext中设置BeanResolver
  • Expression中通过@beanName获取bean
StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();
// bean解析
standardEvaluationContext.setBeanResolver(new BeanResolver() {
    
    
    @Override
    public Object resolve(EvaluationContext context, String beanName) throws AccessException {
    
    
        // 模拟bean解析
        return new String("bean@" + beanName);
    }
});
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
// 通过@拿到bean
Object value = spelExpressionParser.parseExpression("@userService").getValue(standardEvaluationContext);
System.out.println(value);

12. 避免空指针

  • 在访问属性之前,通过?判定,如果为空则直接返回null
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
private static class Item {
    
    
    private Integer price;
    private Integer count;
    private List<String> productNameList;
    private Item item;
}
 
    
Item item = new Item();
// 当前item的item字段为null,如果直接调用.priceInt会报错,但是在访问属性之前标记?,那么为空的话程序直接返回null,不会再往下执行
System.out.println(new SpelExpressionParser().parseExpression("item?.price").getValue(item));

13. 集合与map操作

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
private static class Item {
    
    
    private Integer price;
    private Integer count;
    private List<String> productNameList;
    private Map<String, Integer> studentScoreMap;
}
    
    
Item item = new Item();
// 这种方式会将整个花括号中的内容当成一个字符串,最终list中只有一个字符串
new SpelExpressionParser().parseExpression("productNameList").setValue(item, "{'抽烟','喝酒','烫头','',null}");
// 先通过表达式将字符串转为list,再setValue
new SpelExpressionParser().parseExpression("productNameList").setValue(item, new SpelExpressionParser().parseExpression("{'抽烟','喝酒','烫头','',null}").getValue(List.class));
// 将字符串转为map,并设值
new SpelExpressionParser().parseExpression("studentScoreMap").setValue(item, new SpelExpressionParser().parseExpression("{'Tim':59,'李四维':69,'青青':99,'juicy':89}").getValue(Map.class));
// 新建计算上下文,并设置rootObject
StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext(item);
// 注册方法
standardEvaluationContext.registerFunction("StringUtils_isNotBlank", StringUtils.class.getDeclaredMethod("isNotBlank", CharSequence.class));
// 通过.?[表达式]过滤集合,并产生一个新的集合
// 通过#methodName调用上面注册的方法
// 通过#this,引用list当前循环的元素
List filteredList = new SpelExpressionParser().parseExpression("productNameList.?[#StringUtils_isNotBlank(#this)]").getValue(standardEvaluationContext, List.class);
System.out.println(item.getProductNameList());
System.out.println(filteredList);

// 通过value过滤数据
Map value = new SpelExpressionParser().parseExpression("studentScoreMap.?[value<60]").getValue(standardEvaluationContext, Map.class);
// 通过key即可引用当前键值对的key
Map value2 = new SpelExpressionParser().parseExpression("studentScoreMap.?[key=='juicy']").getValue(standardEvaluationContext, Map.class);
// .^[表达式] 获取匹配的第一个元素
Map first = new SpelExpressionParser().parseExpression("studentScoreMap.^[value>60]").getValue(standardEvaluationContext, Map.class);
// .$[表达式] 获取匹配的最后一个元素
Map last = new SpelExpressionParser().parseExpression("studentScoreMap.$[value>60]").getValue(standardEvaluationContext, Map.class);
// .![表达式] 根据表达式生成一个新的集合
Set nameSet = new SpelExpressionParser().parseExpression("studentScoreMap.![key]").getValue(standardEvaluationContext, Set.class);
System.out.println(item.getStudentScoreMap());
System.out.println(value);
System.out.println(value2);
System.out.println(first);
System.out.println(last);
System.out.println(nameSet);

英文教程:https://docs.spring.io/spring-framework/docs/5.3.25/reference/html/core.html#expressions
中文教程:https://itmyhome.com/spring/expressions.html

猜你喜欢

转载自blog.csdn.net/futao__/article/details/134824078