首頁>技術>

一、概述

Spring表示式語言全稱為“Spring Expression Language”,縮寫為“SpEL”。是一個支援查詢,並在執行時操縱一個物件圖功能、是一門強大的表示式語言。SpEL是單獨模組,只依賴於core模組,可以被獨立使用、執行

Spring 框架元件

二、作用

一、基本表示式: 字面量表達式、關係,邏輯與算數運算表示式、字串連線及擷取表示式、三目運算、正則表示式、括號優先順序表示式;

二、類相關表示式: 類型別表示式、類例項化、instanceof表示式、變數定義及引用、賦值表示式、自定義函式、物件屬性存取及安全導航表示式、物件方法呼叫、Bean引用;

三、集合相關表示式: 內聯List、內聯陣列、集合,字典訪問、列表,字典,陣列修改、集合投影、集合選擇;不支援多維內聯陣列初始化;不支援內聯字典定義;

四、其他表示式:模板表示式。

三、主要類

1、ExpressionParser

表示式解析器介面,包含了(Expression) parseExpression(String), (Expression) parseExpression(String, ParserContext)兩個介面方法

2、ParserContext

解析器上下文介面,主要是對解析器Token的抽象類,包含3個方法:getExpressionPrefix,getExpressionSuffix和isTemplate,就是表示表示式從什麼符號開始什麼符號結束,是否是作為模板(包含字面量和表示式)解析。

3、Expression

表示式的抽象,是經過解析後的字串表示式的形式表示。透過expressionInstance.getValue方法,可以獲取表示式的值。也可以透過呼叫getValue(EvaluationContext),從評估(evaluation)上下文中獲取表示式對於當前上下文的值

4、EvaluationContext

估值上下文介面,只有一個setter方法:setVariable(String, Object),透過呼叫該方法,可以為evaluation提供上下文變數

四、案例運用

一、基礎的Hello

1.1、程式碼實現

@Testpublic void baseTest() {// 字串表示式    String exp = "Hello , #{ #username }";    // 表示式解析器    ExpressionParser parser = new SpelExpressionParser();    // 表示式上下文    EvaluationContext context = new StandardEvaluationContext();    context.setVariable("username", "紋銀三百兩");    // 解析    Expression expression = parser.parseExpression(exp, new TemplateParserContext());    System.out.println(expression.getValue(context, String.class));  }

基礎結果:

Hello , 紋銀三百兩

1.2、分析解析

建立解析器:SpEL使用ExpressionParser介面表示解析器,提供SpelExpressionParser預設實現;解析表示式:使用ExpressionParser的parseExpression來解析相應的表示式為Expression物件。構造上下文:準備比如變數定義等等表示式需要的上下文資料。求值:透過Expression介面的getValue方法根據上下文獲得表示式值。

解析表示式示意圖

二、關係運算符

//trueboolean trueValue1 = parser.parseExpression("2 == 2").getValue(Boolean.class);//falseboolean falseValue1 = parser.parseExpression("2 < -5.0").getValue(Boolean.class);//trueboolean trueValue2 = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);//false,字元xyz是否為int型別boolean falseValue2 = parser.parseExpression("'xyz' instanceof T(int)").getValue(Boolean.class);//true,正則是否匹配boolean trueValue3 =parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);//falseboolean falseValue3=parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);

三、邏輯運算子

// -- AND 與運算 --//false boolean falseValue4 = parser.parseExpression("true and false").getValue(Boolean.class); // -- OR 或運算--//trueboolean trueValue5 = parser.parseExpression("true or false").getValue(Boolean.class);//falseboolean falseValue5 = parser.parseExpression("!true").getValue(Boolean.class);

四、算術運算子

// Additionint two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2String testString =parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class); // 'test string'// Subtractionint four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000// Multiplicationint six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0// Divisionint minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0// Modulusint three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3int one = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1// Operator precedenceint minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21

五、組合使用

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

六、操作類

6.1、類型別

@Testpublic void classTypeTest() {    ExpressionParser parser = new SpelExpressionParser();    //java.lang包類訪問    Class<String> result1 = parser.parseExpression("T(String)").getValue(Class.class);    //class java.lang.String    System.out.println(result1);    //其他包類訪問    String expression2 = "T(spel.SpElTest)";    Class<SpElTest> value = parser.parseExpression(expression2).getValue(Class.class);    //true    System.out.println(value == SpElTest.class);    //類靜態欄位訪問    int result3 = parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class);    //true    System.out.println(result3 == Integer.MAX_VALUE);    //類靜態方法呼叫    int result4 = parser.parseExpression("T(Integer).parseInt('1')").getValue(int.class);    //1    System.out.println(result4);  }

6.2、自定義函式

/**   * 兩數之和   */public static Integer add(Integer x, Integer y) {    return x + y;  }@Testpublic void functionTest() throws NoSuchMethodException {    // 表示式    String exp = "#{ #add(4,5)}";    // 表示式上下文    StandardEvaluationContext context = new StandardEvaluationContext();    Method add = SpElTest.class.getDeclaredMethod("add", Integer.class, Integer.class);    context.registerFunction("add", add);    // 表示式解析器    ExpressionParser parser = new SpelExpressionParser();    // 解析    Expression expression = parser.parseExpression(exp, new TemplateParserContext());    // 9    System.out.println(expression.getValue(context, Integer.class));  }

6.3、類屬性

  @Test  public void assignTest() {    String exp = "username: #{#user.username},age: #{#user.age}";    StandardEvaluationContext context = new StandardEvaluationContext();    Person person = new Person()        .setUsername("紋銀三百兩")        .setAge(23);    context.setVariable("user", person);    ExpressionParser parser = new SpelExpressionParser();    Expression expression = parser.parseExpression(exp, new TemplateParserContext());    //username: 紋銀三百兩,age: 23    System.out.println(expression.getValue(context, String.class));  }

七、模板表示式

  @Testpublic void templateTest() {    SpelExpressionParser parser = new SpelExpressionParser();    ParserContext context = new TemplateParserContext("%{", "}");    Expression expression = parser.parseExpression("你好:%{#name},正在學習:%{#lesson},加油、奮鬥!!!", context);    EvaluationContext evaluationContext = new StandardEvaluationContext();    evaluationContext.setVariable("name", "紋銀三百兩");    evaluationContext.setVariable("lesson", "spring高手系列。");    String value = expression.getValue(evaluationContext, String.class);    //你好:紋銀三百兩,正在學習:spring高手系列。加油、奮鬥!!!    System.out.println(value);  }

八、規則引擎

8.1、背景

假設人員註冊資訊(姓名、年齡、性別),自定義其中規則,如下:

李家好漢(李姓,男,且滿18歲)豆蔻少女(13-15歲,女性)

8.2、實現

@Test  public void ruleTest() {    Person person1 = new Person().setUsername("小龍女").setAge(14).setSex(1);    checkRule(FastJsonUtil.parseMap(JSON.toJSONString(person1)));    Person person2 = new Person().setUsername("張三").setAge(18).setSex(0);    checkRule(FastJsonUtil.parseMap(JSON.toJSONString(person2)));    Person person3 = new Person().setUsername("李四").setAge(20).setSex(0);    checkRule(FastJsonUtil.parseMap(JSON.toJSONString(person3)));  }  /**   * 規則check   *   * @param exp 引數map   */  private static void checkRule(Map<String, Object> exp) {    ExpressionParser parser = new SpelExpressionParser();    //規則容器    Map<String, String> ruleMap = Maps.newHashMap();    String rule1 = "( #username.contains({'李'}) and  #age > 18 and #sex == 0 )";    ruleMap.put("李家好漢", rule1);    String rule2 = "( #age between {13,15} and #sex == 1 )";    ruleMap.put("豆蔻少女", rule2);    EvaluationContext spElContext = getSpElContext(exp);    ruleMap.keySet().forEach(key -> {      String ruleV = ruleMap.get(key);      Boolean isPass = parser.parseExpression(ruleV).getValue(spElContext, Boolean.class);      if (Objects.nonNull(isPass) && isPass) {        System.out.println("username:【" + exp.get("username") + "】,命中規則:【" + key+"】");      }    });  }  /**   * 解析表示式需要的上下文,透傳請求引數   *   * @param param 引數   * @return 返回結果   */  private static EvaluationContext getSpElContext(Map<String, Object> param) {    StandardEvaluationContext evaluationContext = new StandardEvaluationContext();    for (Entry<String, Object> entry : param.entrySet()) {      if (entry.getValue() != null) {        evaluationContext.setVariable(entry.getKey(), entry.getValue());      }    }    return evaluationContext;  }

結果:

username:【小龍女】,命中規則:【豆蔻少女】username:【李四】,命中規則:【李家好漢】
五、總結

Spring EL表示式,作為JAVA的內建語言,十分強大。主要可以用來做表示式解析,或者規則鏈路,且可以操作函式方法;從而達到一種動態的鏈路規則解析效果。

參考文章:https://docs.spring.io/spring-integration/docs/5.3.0.RELEASE/reference/html/spel.html#spel

15
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 3分鐘快速入門RedisTemplate