1. 程式人生 > >7. Spring:表示式語言

7. Spring:表示式語言

7. Spring:表示式語言

  1. Spring 表示式語言的入門介紹

    • 基本概述

      Spring表示式語言全稱為“Spring Expression Language”,縮寫為“SpEL”,能在執行時構建複雜表示式、存取物件屬性、物件方法呼叫等等,並且能與Spring功能完美整合。主要支援如下表達式

      • 基本表示式
      • 類相關表示式
      • 集合相關表示式
      • 其他表示式
    • 例項分析(note_7/spel)

      ExpressionParser parser = new SpelExpressionParser
      (); Expression expression = parser.parseExpression("('Hello' + ' World').concat(#end)"); EvaluationContext context = new StandardEvaluationContext(); context.setVariable("end", "!"); System.out.println(expression.getValue(context));
    • 步驟解析:

      • 建立解析器
      • 解析表示式
      • 構造上下文
      • 求值
    • 工作原理

      • 基本概念
        1. 表示式:幹什麼
        2. 解析器:將表示式解析為表示式物件,誰來幹
        3. 上下文:在哪裡幹
        4. 根物件以及活動上下文物件:對誰幹
      • 工作原理
        1. 定義表示式
        2. 定義解析器ExpressionParser
          • 生成記號流
          • 生成抽象語法樹
          • 生成Expression介面
        3. 定義上下文物件
        4. 根據表示式求值
      • 主要介面
        • ExpressionParser介面
        • EvaluationContext介面
        • Expression介面
    • 配置風格

      • XML風格的配置(note_7/spel/XmlExpression)

        SpEL支援在Bean定義時注入,預設使用“#{SpEL表示式}”表示,其中“#root”根物件預設可以認為是ApplicationContext,只有ApplicationContext實現預設支援SpEL,獲取根物件屬性其實是獲取容器中的Bean。

      • 註解風格的配置(note_7/spel/AnnotationExpression)

        基於註解風格的SpEL配置也非常簡單,使用@Value註解來指定SpEL表示式,該註解可以放到欄位、方法及方法引數上。

  2. SpEL的操作範圍

    SpEL表示式的首要目標是通過計算獲得某個值,在計算這個值得過程中,會使用到其他的值並會對這些值進行操作,值的操作範圍如下:

    • 字面值(note_7/spelOpRange/SpelMain/testSpelLiteral)

      <property name="count" value="#{5}"/>
      <property name="message" value="The value is #{5}"/>
      <property name="frequency" value="#{89.7}"/>
      <property name="capacity" value="#{1e4}"/> 
      <property name="name1" value="#{'Chuck'}"/>
      <property name='name2' value='#{"Chuck"}'/>
      <property name="enabled" value="#{false}"/>
      

    • Bean及Bean的屬性或方法

      SpEL表示式可以引用Bean本身、Bean的屬性以及Bean的方法

      • 引用Bean本身

        <property name="bean2" value="#{bean1}"/> 
        <property name="bean2" ref="bean2"/> 
        
      • 引用bean的屬性

        <bean id="bean2"  class="Bean2"> 
                  <property name="name" value="#{bean1.name}" /> 
        </bean> 
        
        
        Bean2 bean2=new Bean2();
        bean2.setName(bean1.getName());
        
      • 引用Bean的方法

        <property name="name" value="#{{bean2.getName()"/>
        <property name="name" value="#{{bean2.getName().toUpperCase()"/>
        <property name="name" value="#{{bean2.getName?.toUpperCase()"/>
        

    • 類的方法和常量(note_7/spelOpRange/SpelMain/testSpelClass)

      在SpEL 中,使用T() 運算子會呼叫類作用域的方法和常量:

      <bean id="spelClass" class="note_7.spelOpRange.SpelClass">
              <property name="pi" value="#{T(java.lang.Math).PI}"/>
              <property name="randomNumber" value="#{T(java.lang.Math).random()}"/>
      </bean>
      
  3. SpEL表示式的運算子

    • 運算子型別

      7.1

    • 數值運算(note_7/spelMath)

      數值運算子可以對SpEL 表示式中的值執行基礎數學運算

      加運算: <property name="adjustedAmount" value="#{counter.total + 42}"/> 
      減運算: <property name="adjustedAmount" value="#{counter.total - 20}"/> 
      乘運算: <property name="circumference"   value="#{2 * T(java.lang.Math).PI * circle.radius}"/>
      除運算: <property name="average" value="#{counter.total / counter.count}"/> 
      求餘運算: <property name="remainder" value="#{counter.total % counter.count}"/> 
      乘方運算: <property name="area" value="#{T(java.lang.Math).PI * circle.radius ^ 2}"/> 
      字串連線: <property name="fullName"   value="#{performer.firstName + ' ' + performer.lastName}"/>
      
      
    • 比較運算

      SpEL 同樣提供了Java 所支援的比較運算子

      xml使用大於等於或者小於等於時使用文字型運算子

      <property name="equal"   value="#{counter.total == 100}"/>
      <property name="hasCapacity" value="#{counter.total le 100000}"/>
      counter.total <= 100000 
      

      7.2

    • 邏輯運算

      7.3

      <property name="largeCircle"  value="#{shape.kind == 'circle' and shape.perimeter gt 10000}"/>
      <property name="outOfStock" value="#{!product.available}"/>
      <property name="outOfStock" value="#{not product.available}"/>
      
    • 條件運算

      當某個條件為true 時,SpEL 表示式的求值結果是某個值;如果該條件為false 時,它的求值結果是另一個值時,可以使用SpEL 的三元運算子(?:)

      <property name="instrument"  value="#{songSelector.selectSong()=='Jingle Bells'?piano:saxophone}" />
      <property name="song"   value="#{kenny.song != null ? kenny.song : 'Greensleeves'}" /> 
      <property name="song" value="#{kenny.song ?: 'Greensleeves'}" />
      
      
    • 正則表示式

      當處理文字時,檢查文字是否匹配某種模式有時是非常有用的。SpEL 通過matches 運算子支援表示式中的模式匹配:

      <property name="validEmail"    
         value= "#{admin.email  matches '[a-zA-Z0-9._%+-][email protected][a-zA-Z0-9.-]+\\.com'}"   />
      
      
  4. Spring 表示式語言的集合操作

    SpEL可以引用集合中的某個成員,就像在Java 裡操作一樣,同樣具有基於屬性值來過濾集合成員的能力:

    • 訪問集合成員

      為了展示SpEL訪問集合成員的用途,需要定義一個City 類,然後使用util:list 元素在Spring 裡配置了一個包含City 物件的List 集合,示例如下:

      public class City {  
      	private String name;  
      	private String state;  
      	private int population;  
      } 
      
      <util:list id="cities"> 
      	<bean class="City" 
           		p:name="Chicago" p:state="IL" p:population="2853114"/> 
      	<bean class="com.habuma.spel.cities.City" 
          		p:name="Las Cruces" p:state="NM" p:population="91865"/> 
      </util:list> 
      
      
    • 查詢集合成員

      利用SpEL來查詢集合成員:

      <property name="bigCities" value="#{cities.?[population gt  100000]}"/> 
      <property name="aBigCity" value="#{cities.^[population gt  100000]}"/> 
      <property name="aBigCity" value="#{cities.$[population gt  100000]}"/>
      
      
    • 投影集合

      集合投影是從集合的每一個成員中選擇特定的屬性放入一個新的集合中。SpEL的投影運算子(.![])完全可以做到這點

      <property name="cityNames" value="#{cities.![name]}"/>
      <property name="cityNames" value="#{cities.![name + ', ' + state]}"/>
      <property name="cityNames" value="#{cities.?[population gt 100000].![name + ', ' + state]}"/>
      
    • 示例(note_7/spelCollection)