Velocity空間

          快速構建JAVA應用
          隨筆 - 11, 文章 - 15, 評論 - 5, 引用 - 0
          數據加載中……

          CHAPTER 9 Velocimacros

           

          在之前的章節里,我們討論了所有Velocity的指令,包括#macro指令。然而,我們只是簡要介紹了#macro指令。在這里,我們將重新討論#macro指令(也可以稱為Velocimacros)。我們將討論參數傳遞、宏庫、運行時配置和其他與Velocimacros相關的主題。

          參數傳遞Argument Passing

          當我們在Chapter 8里介紹#macro指令時,我們展示了一個簡單的Hello World示例。The template used for that example defines an inline Velocimacro that outputs Hello world each time it is invoked. This macro is defined so that no arguments are allowed in the macro invocation. Note that the #macro directive itself always requires at least one argument, the first of which specifies the name used to invoke the macro. However, the invocation of a macro takes zero or more arguments, depending on its specification.(示例里使用的模板定義了一個用于輸出Hello world的內聯Velocimacro。這個宏定義為沒有參數。注意,#macro指令最小需要一個參數,第一個參數用于指定調用宏的名稱。然而,宏的invocation獲得0個或更多參數,完全依賴于它的規范)。

          為了允許把參數傳遞到Velocimacro,你只需要一個為每一個需要傳遞的參數提供了名稱的#macro指令,這些參數用空格進行分隔。每一個引用名可以作為Velocity變量引用用于宏的代碼塊。和#foreach#if關系指令一樣,代碼塊用#end指令終止。為了演示這個例子,我們把Listing 8.40示例的Velocimacro部分進行改動,具體改動為:把簡單的輸出hello改為輸出個人詳細信息。這個新改進的宏見Listing 9.1。在處理的時候,這個模板將在字符串“Hello Zaphod!”之后新增一個字符串“Hello Arthur!”。

          ## Define inline macro for this template

          #macro( sayHiTo $who )

          Hello $who!

          #end

          ## Invoke the macro using normal directive syntax

          #sayHiTo( "Arthur" )

          #sayHiTo( "Zaphod" )

          Listing 9.1 A template demonstrating the #macro directive with support for argument passing.

          為了能夠成功調用Velocimacro,invocation的參數個數必須和宏定義指定的參數個數匹配。比如,如果Listing 9.1里的宏被作為#sayHiTo() #say-HiTo(“Zaphod” “Beeblebrox”)進行調用,則invocation將被忽略。由此得出結論,Velocimacro不支持默認參數;也不支持重載。同樣地,在Velocimacro 故意改變參數個數的情況下,這兒并沒有什么獨特的解決方法。在很多類似情況下,為宏指定唯一名稱是必需的。

          迄今為止,我們僅僅演示了使用字符串作為輸入參數。其實,Velocimacro也支持integer、布爾類型、值域操作符、數組列表和Velocity引用。Listing 9.2展示了使用以上所有類型作為輸入參數的模板。第一個Velocimacro需要使用字符串、integer和布爾類型。第二個需要使用值域操作符和數組列表。最后一個需要使用Velocity引用。注意,這些宏定義和invocation的參數列表都是用空格來定界的,和許多通用編程語言使用逗號進行分隔一樣。宏只是簡單輸出提供的參數值,見Listing 9.3。

          ## Define Velocimacros

          ## (string literal - integer literal - boolean)

          #macro( sib $string $int $bool )

          The string is $string.

          The integer is $int.

          The boolean is $bool.

          #end

          ## (range - array list)

          #macro( ra $range $arrayList )

          #foreach ( $val in $range ) $val #end

          #foreach ( $val in $arrayList ) $val #end

          #end

          ## (Velocity reference)

          #macro( r $vref )

          The reference correspond to $vref

          #end

          ## Invoke Velocimacros

          #sib( "Hello" 42 true )

          #ra( [-9..-1] ["favorite", "color"] )

          #set( $color = "Blue. No! Yellow!" )

          #r( $color )

          Listing 9.2 A template demonstrating the #macro directive used with various argument types.

          The string is Hello.

          The integer is 42.

          The boolean is true.

          -9 -8 -7 -6 -5 -4 -3 -2 -1

          favorite color

          The reference correspond to Blue. No! Yellow!

          Listing 9.3 Results from processing the template in Listing 9.2.

          我們在前面的示例里已經演示了Velocimacro直接支持的多種類型參數。下面我們將討論用Velocity引用作為Velocimacro的輸入參數。把引用作為宏的輸入參數并不僅限于變量引用,還可以使用Velocity方法引用和Velocity屬性引用。雖然使用這些引用作為輸入參數是可行的,但在使用中仍然要小心。正確使用這些引用的訣竅就是深入理解他們是通過名字進行參數傳遞的(pass by name)。That is, the reference is not evaluated until after it is received by the Velocimacro。為了闡明這些概念,讓我們來考慮FromFive類(見Listing 9.4),這個類簡單初始化一個int屬性,賦值為5,每一次通過類的getNext()方法請求時,將消耗一點這個值。

          public class FromFive

          {

          public FromFive()

          {

          nextValue = 5;

          }

          public Integer getNext()

          {

          return (new Integer( nextValue-- ));

          }

          public String toString()

          {

          return (String.valueOf( nextValue ));

          }

          private int nextValue;

          }

          Listing 9.4 The FromFive class, which generates a sequence of decreasing integer values.

          接著,假定我們的應用程序使用三個FromFive類的實例(對應關鍵字為字符串為method-Ref、propRefvarRef)來維護Velocity上下文組裝。如果這個應用程序需要處理的模板為Listing 9.5所示,其輸出結果為Listing 9.6。As the output demonstrates, the value associated with the $ref reference in the countdown Velocimacro changes each time it is evaluated for the cases of method and property reference input. This is due to the fact that in these two cases $ref stores the names $methodRef.getNext() and $propRef.next, respectively, rather than the values those references evaluate to. In effect, $ref simply becomes an alias for the provided method or property reference. Although not as obvious, the same is in fact true for the variable reference $varRef; the associated output differs only due to the fact that FromFive’s toString() method does not decrement the value of an object’s nextValue property. If toString() were modified to behave in the same manner as getNext(), then passing $varRef to the countDown Velocimacro would also result in decrementing output.

          ## Evaluate provided reference six times.

          #macro( countDown $ref )

          $ref.. $ref.. $ref.. $ref.. $ref.. $ref

          #end

          ## Call countDown with a method reference

          #countDown( $methodRef.getNext() )

          ## Call countDown with a property reference

          #countDown( $propRef.next )

          ## Call countDown with a variable reference

          #countDown( $varRef )

          Listing 9.5 A template demonstrating the use of all three types of Velocity references with the #macro directive.

          5.. 4.. 3.. 2.. 1.. 0

          5.. 4.. 3.. 2.. 1.. 0

          5.. 5.. 5.. 5.. 5.. 5

          Listing 9.6 Results from processing the template in Listing 9.5.

          如果必需要通過值類型傳遞(pass by value)方式來傳遞Velocity引用的判斷結果值,最容易的解決方法是#set指令來捕獲這個獨立的變量引用值,之后傳遞那個引用。讓我們來看一下Listing 9.7里的模板,這個模板的內聯宏定義和Listing 9.5相同。然而,我們改變invocation來模仿值類型傳遞(pass-by-value)行為。注意,這個新的模板只通過#set指令途徑來仿效值類型傳遞。在下面的封裝,調用仍然是名字傳遞(pass-by-name)。

          ## Evaluate provided reference six times.

          #macro( countDown $ref )

          $ref.. $ref.. $ref.. $ref.. $ref.. $ref

          #end

          ## Call countDown with the value of a method reference

          #set( $methodValue = $methodRef.getNext() )

          #countDown( $methodValue )

          ## Call countDown with the value of a property reference

          #set( $propValue = $propRef.next )

          #countDown( $propValue )

          ## Call countDown with the value of a variable reference

          #set( $varValue = $varRef )

          #countDown( $varValue )

          Listing 9.7 A template demonstrating emulated pass-by-value behavior with a #macro directive.

          Inline vs. Library Macros

          迄今為止,我們的Velocimacro示例都集中在內聯定義上。雖然內聯定義可以用于很多場合,但其固有的特性限制了內聯定義只能用于代碼再使用。內聯Velocimacro的作用域僅限于其定義的模板文件,更明確一點,只限于具有宏定義的那部分模板文件。因此,其他模板文件不能訪問這樣的宏。如果嘗試通過#include#parse指令把一個模板中的Velocimacro定義應用到其他作用域中時,將會失敗。

          #include指令導入的只是靜態內容,因此#macro指令將失去其特定的意義。#parse指令把包含進來的文本當作普通模板代碼來處理。與此相反,當模板第一次被模板引擎解析時,Velocimacro調用被終止,在任何#parse指令導入外部的Velocimacro定義時。(The #include directive imports only static content, so #macro directives would lose any special meaning. The #parse directive does process the included text as normal template code, but it does so at runtime. In contrast, Velocimacro calls are determined when the template is first parsed by the template engine, well before any #parse directives have a chance to import external Velocimacro definitions)。

          因此,如何通過多模板共享Velocimacro,從而避免單調重復的拷貝和粘貼?答案就是Velocity對宏庫的支持。這個特性允許你創建多宏庫,創建方法是應用程序通過Velocimacro屬性的變量進行注冊來創建。一旦這樣的庫被注冊,那么應用程序處理的任何模板都可以庫中調用這個Velocimacro。我們將在本章稍后討論Velocimacro屬性,并在Chapter 10 “Taking Control of Velocity”)對Velocity的屬性系統進行討論。現在,我們只需了解,通過屬性系統,包含#macro指令的文件可以作為Velocimacro庫,讓所有的模板訪問。

          (如果你的Velocimacro庫需求是適度的,那么)根本就不必為Velocity的屬性系統煩擾。默認情況下,模板引擎會把任何一個文件假定為位于應用程序目錄下的VM_global_library.vm文件,并將其解釋為宏庫。比如,如果我們的模板(來自Listing 9.5)被分割成兩個Listings 9.8Listings9.9的文件,輸出結果仍是一樣的(見Listing 9.6)。僅僅需要把Velocimacro庫命名成VM_global_library.vm即可。

          ## Evaluate provided reference six times.

          #macro( countDown $ref )

          $ref.. $ref.. $ref.. $ref.. $ref.. $ref

          #end

          Listing 9.8 A macro library containing the Velocimacro originally defined in Listing 9.5. If Velocity defaults are assumed, this file must be named VM_global_library.vm.

          ## Call countDown with the value of a method reference

          #countDown( $methodRef.getNext() )

          ## Call countDown with the value of a property reference

          #countDown( $propRef.next )

          ## Call countDown with the value of a variable reference

          #countDown( $varRef )

          Listing 9.9 The template from Listing 9.5 after moving its Velocimacro to a macro library.

          Velocimacro Properties

          Velocity提供了許多配置屬性,用于調整Velocimacros的行為。我們將在Chapter 10討論這些屬性的具體功能,現在,我們只了解其名稱、說明和默認設置。

           

          velocimacro.library

          我們曾經在前面章節里提到過庫屬性。這個屬性用于定義應用程序Velocimacros庫里文件的名稱,該文件名稱是相對于當前模板路徑配置的。如果有多個文件需要包含到庫里,那么在這些文件名之間用逗號分隔。庫屬性的默認值是VM_global_library.vm。

           

          velocimacro.permissions.allow.inline

          permissions.allow.inline屬性用于定義是否允許內聯(inlineVelocimacro定義。也就是說,是否可以把Velocimacro宏定義在一個非庫模板文件里。如果為false,內聯Velocimacro定義將導致日志警告信息,并且該定義將被模板引擎忽略。默認值為true

          velocimacro.permissions.allow.inline.to.replace.global

          permissions.allow.inline.to.replace.global屬性用于定義是否允許內聯(inline) Velocimacro用相同的名稱去重載一個Velocimacro庫。當然,只有在permissions.allow.inline屬性為true里才有意義,否則,內聯定義就不能通過。如果permissions. allow.inline.to.replace.global屬性為true,和內聯Velocimacro 同名的Velocimacro庫將被內聯Velocimacro替代。如果為false,Velocimacro庫將受到保護,不管有意還是無意的內聯Velocimacro庫都不能替代Velocimacro庫。默認值為false。

           

          velocimacro.permissions.allow.inline.local.scope

          permissions.allow.inline.local.scope屬性用于定義是否允許模板為Velocimacro提供私有(private)命名空間。當這個屬性為true時,就允許提供私有命名空間,同時內聯Velocimacro定義可用于定義模板。無論何時Velocimacro定義被請求時,允許私有命名空間也將導致模板的命名空間首先被搜索。最后一個特性是允許本地Velocimacro定義重載任何其他在外部模板定義的定義。默認值是false。

          velocimacro.context.localscope

          context.localscope屬性用于定義#set指令影響在Velocimacro 中使用Velocity上下文的方式。當屬性值為true時,Velocimacro將有效接收它自己本地的上下文。調用者的對象上下文關鍵字對Velocimacro來說不可見,轉而變成使用來自Velocimacro內部的上下文,而且不復制回轉給調用者。與此相反,當屬性值為false時,將把調用者的上下文放到一個Velocimacro可達到的、可更改的地方。也就是說Velocimacro將使用調用者的上下文。默認值為false

          velocimacro.library.autoreload

          library.autoreload屬性用于定義當庫中的宏被調用時,是否允許自動重新加載這個修改過的Velocimacro庫。如果屬性值為true,每一次調用Velocimacro庫都將檢查相應庫的修改信息,如果檢查發現這個庫在最后一次加載后被修改過,Velocity將自動重新加載這個庫。如果屬性值為falseVelocimacro庫一旦加載后就不再進行修改信息檢測。默認值為false。該重加載功能主要用于程序測試和調試。如果你需要允許這個屬性,那么很可能你也需要禁止資源加載緩存,我們將在下一章討論屬性控制這個緩存。

          velocimacro.messages.on

          messages.on屬性用于指定是否讓模板引擎產生附加的關于Velocimacros的日志信息。當這個屬性的值為true時,就需要產生附加信息;為false時,將不產生附加信息;默認值為true。

          嵌套和遞歸

          迄今為止,本章所有的Velocimacro示例都僅限于不使用嵌套和遞歸的情況。嵌套,最簡單的情況就是在Velocimacro里調用另外一個Velocimacro,這是在實際代碼開發中使用得最頻繁的一種。遞歸,是一種特殊類型的嵌套,它是在Velocimacro里調用自身,但這種情況并不太常見。幸運的是,Velocimacro對嵌套和遞歸都提供了支持。Listing 9.10里演示了Velocimacro使用嵌套和遞歸的例子。Velocimacro重復調用它自己,調用次數由它的參數$depth指定。writeABC宏通過調用getAgetBC Velocimacros演示了Velocimacro嵌套。Listing 9.11顯示了輸出結果。

          ## A recursive Velocimacro

          #macro( recurs $depth )

          Entering at level $depth

          #set( $depth = $depth - 1 )

          #if ( $depth > 0 )

          #recurs( $depth )

          #end

          #set( $depth = $depth + 1 )

          Leaving from level $depth

          #end

          ## Nesting of Velocimacros

          #macro( getA ) A #end

          #macro( getB ) B #end

          #macro( getC ) C #end

          #macro( getBC )

          #getB()#getC()

          #end

          #macro( writeABC )

          #getA()#getBC()

          #end

          #recurs( 3 )

          #writeABC()

          Listing 9.10 A template demonstrating the use of nesting and recursion of Velocimacros.

          Entering at level 3

          Entering at level 2

          Entering at level 1

          Leaving from level 1

          Leaving from level 2

          Leaving from level 3

          A B C

          Listing 9.11 Results from processing the template in Listing 9.10.

          本章小節和下章介紹

          在這一章里,我們對#macro指令(或叫Velocimacro展開了深入的討論。討論覆蓋了參數傳遞、宏庫、嵌套和遞歸、以及Velocimacro屬性。這在一點上,你應該已經對Velocity的上下文、模板語言以及引用和指令有了較好的理解。你現在應該已經可以開發模板了。然而,仍有許多Velocity功能需要你去了解。這就我們下一章將要討論的內容。

          posted on 2008-10-19 21:28 KINGWEE 閱讀(826) 評論(0)  編輯  收藏 所屬分類: Velocity

          主站蜘蛛池模板: 辽源市| 永修县| 汤阴县| 三河市| 南漳县| 高阳县| 林甸县| 大渡口区| 平定县| 恩施市| 阿克苏市| 建湖县| 驻马店市| 安岳县| 桑植县| 扎囊县| 磐安县| 宣威市| 新蔡县| 古丈县| 广宗县| 桃园县| 滦平县| 蓬安县| 浮梁县| 温宿县| 社旗县| 四子王旗| 清河县| 兴业县| 白山市| 平江县| 桦甸市| 祁东县| 永登县| 怀柔区| 大丰市| 灯塔市| 土默特右旗| 尼玛县| 宣武区|