Spring EL表达式使用指南

举报
西魏陶渊明 发表于 2022/09/25 02:20:48 2022/09/25
【摘要】 真正的猛士,每天干一碗毒鸡汤! 问世间钱为何物,只叫人生死相许。!😄 好久没有发现这么好的文章了,今天逛头条发现了一篇好文章,在这里转载一下 大家可以学习一下,文章原文地址见参考。希望支持原作者,在头条点一个关注。 # 一、概述 Spring表达式语言全称为“Spring...

真正的猛士,每天干一碗毒鸡汤!

问世间钱为何物,只叫人生死相许。!😄

好久没有发现这么好的文章了,今天逛头条发现了一篇好文章,在这里转载一下 大家可以学习一下,文章原文地址见参考。希望支持原作者,在头条点一个关注。

# 一、概述

Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”。是一个支持查询,并在运行时操纵一个对象图功能、是一门强大的表达式语言。SpEL是单独模块,只依赖于core模块,可以被独立使用、运行。

参考文章

SpringEpel (opens new window)

玩转SpEL (opens new window)

# 二、作用

# 2.1 基本表达式

字面量表达式、关系,逻辑与算数运算表达式、字符串连接及截取表达式、三目运算、正则表达式、括号优先级表达式;

# 2.2 类相关表达式

类类型表达式、类实例化、instanceof表达式、变量定义及引用、赋值表达式、自定义函数、对象属性存取及安全导航表达式、对象方法调用、Bean引用;

# 2.3 集合相关表达式

内联List、内联数组、集合,字典访问、列表,字典,数组修改、集合投影、集合选择;不支持多维内联数组初始化;不支持内联字典定义;

# 2.4 其他表达式

模板表达式。

# 三、主要类

# 3.1 ExpressionParser

表达式解析器接口,包含了(Expression) parseExpression(String), (Expression) parseExpression(String, ParserContext)两个接口方法

# 3.2 ParserContext

解析器上下文接口,主要是对解析器Token的抽象类,包含3个方法:getExpressionPrefix,getExpressionSuffix和isTemplate,就是表示表达式从什么符号开始什么符号结束,是否是作为模板(包含字面量和表达式)解析。

# 3.3 Expression

表达式的抽象,是经过解析后的字符串表达式的形式表示。通过expressionInstance.getValue方法,可以获取表示式的值。也可以通过调用getValue(EvaluationContext),从评估(evaluation)上下文中获取表达式对于当前上下文的值

# 3.4 EvaluationContext

估值上下文接口,只有一个setter方法:setVariable(String, Object),通过调用该方法,可以为evaluation提供上下文变量

# 四、案例运用

# 4.1 基础的Hello


    
  1. @Test
  2. public void baseTest() {
  3. // 字符串表达式
  4. String exp = "Hello , #{ #username }";
  5. // 表达式解析器
  6. ExpressionParser parser = new SpelExpressionParser();
  7. // 表达式上下文
  8. EvaluationContext context = new StandardEvaluationContext();
  9. context.setVariable("username", "纹银三百两");
  10. // 解析
  11. Expression expression = parser.parseExpression(exp, new TemplateParserContext());
  12. System.out.println(expression.getValue(context, String.class));
  13. }
1234567891011121314

基础结果:

Hello , 纹银三百两
   
1

# 4.2 关系运算符


    
  1. //true
  2. boolean trueValue1 = parser.parseExpression("2 == 2").getValue(Boolean.class);
  3. //false
  4. boolean falseValue1 = parser.parseExpression("2 < -5.0").getValue(Boolean.class);
  5. //true
  6. boolean trueValue2 = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);
  7. //false,字符xyz是否为int类型
  8. boolean falseValue2 = parser.parseExpression("'xyz' instanceof T(int)").getValue(Boolean.class);
  9. //true,正则是否匹配
  10. boolean trueValue3 =parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
  11. //false
  12. boolean falseValue3=parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
123456789101112

# 4.3 逻辑运算符


    
  1. // -- AND 与运算 --
  2. //false
  3. boolean falseValue4 = parser.parseExpression("true and false").getValue(Boolean.class);
  4. // -- OR 或运算--
  5. //true
  6. boolean trueValue5 = parser.parseExpression("true or false").getValue(Boolean.class);
  7. //false
  8. boolean falseValue5 = parser.parseExpression("!true").getValue(Boolean.class);
12345678

# 4.4 算术运算符


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

# 五、组合使用


    
  1. @Test
  2. public void expressionTest() {
  3. String exp = "1 between {1, 2} and 1>2";
  4. ExpressionParser parser = new SpelExpressionParser();
  5. Expression expression = parser.parseExpression(exp);
  6. //false
  7. System.out.println(expression.getValue(boolean.class));
  8. }
12345678

# 六、操作类

# 6.1 类类型


    
  1. @Test
  2. public void classTypeTest() {
  3. ExpressionParser parser = new SpelExpressionParser();
  4. //java.lang包类访问
  5. Class<String> result1 = parser.parseExpression("T(String)").getValue(Class.class);
  6. //class java.lang.String
  7. System.out.println(result1);
  8. //其他包类访问
  9. String expression2 = "T(spel.SpElTest)";
  10. Class<SpElTest> value = parser.parseExpression(expression2).getValue(Class.class);
  11. //true
  12. System.out.println(value == SpElTest.class);
  13. //类静态字段访问
  14. int result3 = parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class);
  15. //true
  16. System.out.println(result3 == Integer.MAX_VALUE);
  17. //类静态方法调用
  18. int result4 = parser.parseExpression("T(Integer).parseInt('1')").getValue(int.class);
  19. //1
  20. System.out.println(result4);
  21. }
123456789101112131415161718192021222324

# 6.2 自定义函数


    
  1. /**
  2. * 两数之和
  3. */
  4. public static Integer add(Integer x, Integer y) {
  5. return x + y;
  6. }
  7. @Test
  8. public void functionTest() throws NoSuchMethodException {
  9. // 表达式
  10. String exp = "#{ #add(4,5)}";
  11. // 表达式上下文
  12. StandardEvaluationContext context = new StandardEvaluationContext();
  13. Method add = SpElTest.class.getDeclaredMethod("add", Integer.class, Integer.class);
  14. context.registerFunction("add", add);
  15. // 表达式解析器
  16. ExpressionParser parser = new SpelExpressionParser();
  17. // 解析
  18. Expression expression = parser.parseExpression(exp, new TemplateParserContext());
  19. // 9
  20. System.out.println(expression.getValue(context, Integer.class));
  21. }
12345678910111213141516171819202122

# 6.3 类属性


    
  1. @Test
  2. public void assignTest() {
  3. String exp = "username: #{#user.username},age: #{#user.age}";
  4. StandardEvaluationContext context = new StandardEvaluationContext();
  5. Person person = new Person()
  6. .setUsername("纹银三百两")
  7. .setAge(23);
  8. context.setVariable("user", person);
  9. ExpressionParser parser = new SpelExpressionParser();
  10. Expression expression = parser.parseExpression(exp, new TemplateParserContext());
  11. //username: 纹银三百两,age: 23
  12. System.out.println(expression.getValue(context, String.class));
  13. }
12345678910111213

# 七、模板表达式

指定模板 %{ }


    
  1. @Test
  2. public void templateTest() {
  3. SpelExpressionParser parser = new SpelExpressionParser();
  4. ParserContext context = new TemplateParserContext("%{", "}");
  5. Expression expression = parser.parseExpression("你好:%{#name},正在学习:%{#lesson},加油、奋斗!!!", context);
  6. EvaluationContext evaluationContext = new StandardEvaluationContext();
  7. evaluationContext.setVariable("name", "纹银三百两");
  8. evaluationContext.setVariable("lesson", "spring高手系列。");
  9. String value = expression.getValue(evaluationContext, String.class);
  10. //你好:纹银三百两,正在学习:spring高手系列。加油、奋斗!!!
  11. System.out.println(value);
  12. }
123456789101112

# 八、规则引擎

# 8.1 背景

假设人员注册信息(姓名、年龄、性别),自定义其中规则,如下:

李家好汉(李姓,男,且满18岁) 豆蔻少女(13-15岁,女性)

# 8.2 实现


    
  1. @Test
  2. public void ruleTest() {
  3. Person person1 = new Person().setUsername("小龙女").setAge(14).setSex(1);
  4. checkRule(FastJsonUtil.parseMap(JSON.toJSONString(person1)));
  5. Person person2 = new Person().setUsername("张三").setAge(18).setSex(0);
  6. checkRule(FastJsonUtil.parseMap(JSON.toJSONString(person2)));
  7. Person person3 = new Person().setUsername("李四").setAge(20).setSex(0);
  8. checkRule(FastJsonUtil.parseMap(JSON.toJSONString(person3)));
  9. }
  10. /**
  11. * 规则check
  12. *
  13. * @param exp 参数map
  14. */
  15. private static void checkRule(Map<String, Object> exp) {
  16. ExpressionParser parser = new SpelExpressionParser();
  17. //规则容器
  18. Map<String, String> ruleMap = Maps.newHashMap();
  19. String rule1 = "( #username.contains({'李'}) and #age > 18 and #sex == 0 )";
  20. ruleMap.put("李家好汉", rule1);
  21. String rule2 = "( #age between {13,15} and #sex == 1 )";
  22. ruleMap.put("豆蔻少女", rule2);
  23. EvaluationContext spElContext = getSpElContext(exp);
  24. ruleMap.keySet().forEach(key -> {
  25. String ruleV = ruleMap.get(key);
  26. Boolean isPass = parser.parseExpression(ruleV).getValue(spElContext, Boolean.class);
  27. if (Objects.nonNull(isPass) && isPass) {
  28. System.out.println("username:【" + exp.get("username") + "】,命中规则:【" + key+"】");
  29. }
  30. });
  31. }
  32. /**
  33. * 解析表达式需要的上下文,透传请求参数
  34. *
  35. * @param param 参数
  36. * @return 返回结果
  37. */
  38. private static EvaluationContext getSpElContext(Map<String, Object> param) {
  39. StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
  40. for (Entry<String, Object> entry : param.entrySet()) {
  41. if (entry.getValue() != null) {
  42. evaluationContext.setVariable(entry.getKey(), entry.getValue());
  43. }
  44. }
  45. return evaluationContext;
  46. }
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950

结果:


    
  1. username:【小龙女】,命中规则:【豆蔻少女】
  2. username:【李四】,命中规则:【李家好汉】
12

# 九、总结

Spring EL表达式,作为JAVA的内置语言,十分强大。主要可以用来做表达式解析,或者规则链路,且可以操作函数方法;从而达到一种动态的链路规则解析效果。

文章来源: springlearn.blog.csdn.net,作者:西魏陶渊明,版权归原作者所有,如需转载,请联系作者。

原文链接:springlearn.blog.csdn.net/article/details/125858079

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。