Velocity空間

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

          CHAPTER 7 References引用探索

           

          在之前的章節里,我們對Velocity引用進行了簡要的介紹,甚至在示例里使用了部分引用。然而,再三延緩討論引用的目的是為了讓學習曲線更平緩、易學。既然你已經了解Velocity是什么和了解一個基本的應用程序是如何工作的,那么就讓我們開始仔細學習Velocity引用吧!只有相當熟悉地掌握了Velocity引用,才能為你學習和掌握Velocity提供強大的動力!

          引用類型

          正如我們在前面章節里暗示的一樣,Velocity引用具有引用一個存儲在上下文中的簡單字符串值的能力,引用事實上可以引用任何一種存儲在上下文的類型。注意,很重要的一點是,我們所使用對象必須引用的是一個真正的JAVA對象——即,對象實例必須滿足是java.lang.Object類的實例這個條件。除了簡單類型和純粹的靜態類外,其余均不能放置到上下文中。

          我們先前曾經提及過Velocity引用的名稱,去掉其前綴就和上下文里存儲的引用對象的關鍵字相同了。然而,這并非完全是這樣的——多半情況下可以這樣說,但并不是全部。雖然所有有效的Velocity引用名稱包含了用于上下文關鍵字的名稱,但除了需要字符串化版本的上下文對象外,還需要更多其他途徑才能滿足要求。這里總共有三種不同類型的Velocity引用,每一種有其自己的命名約定。下面我們將討論這三種類型,分別為:變量、方法和屬性。

          變量

          我們目前所遇到的所有Velocity引用都屬于變量類型。這種類型的引用符合字符串化(stringifiedJAVA對象要求,它的值可以通過它的toString()方法來輸出。由于JAVA類層次的根類是JAVA對象類,它提供了toString()實現,所以任何Velocity上下文對象都可以作為變量引用。當然,對象類提供的toString()實現僅僅返回一個相伴類的名字字符串和對象哈希代碼的十六進制表示(這個十六進制顯示內容除了用于調試外,沒有什么用處)。一個更實際一點的Velocity變量引用示例引用了一個JAVA數字包裝類(比如IntegerFloat)的實例。

          JAVA的包裝類很可能是Velocity變量的引用目標,因此不限于內置JAVA類的實例。只要是和IntegerFloat一樣的JAVA類,開發者就可以重載類的toString()實現,目的是為了提供更多有用的字符串表現。為了更深入的理解,讓我們看一個調用了幾個變量引用的示例。

          我們將事先定義幾個定制類,并主要關注它的toString()方法。Listings 7.1 7.2定義了兩個價值不高(普通)的類,每一個都呈現了一個單一的字符串值,并存儲為一個public的數據成員;使用public的成員數據不是好主意,我們這樣做的原因是為了強調Velocity通過toString()方法獲取它的字符串化(stringified)顯示比通過直接訪問成員數據要好。通過下面列出來的代碼你可以發現,他們之間的差異在于重載類(Listings7.2)重載了toString()方法,非重載類(Listings 7.1)的toString()方法是從對象繼承的。

          public class NoOverride

          {

          public final String value = "toString() not overridden";

          }

          Listing 7.1 The NoOverride class definition沒有重載的類定義.

          public class Override

          {

          public final String value = “toString() overridden”;

          public String toString()

          {

          return (value);

          }

          }

          Listing 7.2 The Override class definition.有重載的類定義

          示例的模板實現代碼見Listing 7.3。除示范用戶自定義類的變量引用之外,模板還包含了變量引用打算映射到普通的JAVA對象,一個JAVA Integer對象和一個Java Float對象。當這個模板使用Listing 7.4列出的代碼進行處理時,輸出為Listing 7.5所示。注意,除上下文組裝以外,Listing 7.4的代碼幾乎和Listing 6.4一樣,它們僅僅在類和模板(文件和變量)的名稱有區別。另外在這里除了有一個重載需要處理。

          ## A variable reference for a generic Java Object

          Value of generic Object is $genericObject

          ## A variable reference for an Integer object

          Value of Integer object is $integerObject

          ## A variable reference for a Float object

          Value of Float object is $floatObject

          ## A variable reference for a custom object with no toString() override

          Value of user object with default toString() is $userNoOverride

          ## A variable reference for a custom object with a toString() override

          Value of user object with overridden toString() is $userOverride

          Listing 7.3 The template for the variable reference example.

          import java.io.StringWriter;

          import org.apache.velocity.Template;

          import org.apache.velocity.VelocityContext;

          import org.apache.velocity.app.Velocity;

          import org.apache.velocity.exception.*;

          public class VarRef

          {

          public static void main( String[] args )

          {

          // Initialize template engine

          try

          {

          Velocity.init();

          }

          catch( Exception x )

          {

          System.err.println( "Failed to initialize Velocity: " + x );

          System.exit( 1 );

          }

          // Obtain a template

          Template varTemplate = null;

          try

          {

          varTemplate = Velocity.getTemplate( "VarRef.vm" );

          }

          catch( ResourceNotFoundException rnfX )

          {

          System.err.println( "Template not found: " + rnfX );

          System.exit( 1 );

          }

          catch( ParseErrorException peX )

          {

          System.err.println( "Failed to parse template: " + peX );

          System.exit( 1 );

          }

          catch( Exception x )

          {

          System.err.println( "Failed to initialize template: " + x );

          System.exit( 1 );

          }

          // Create context

          VelocityContext context = new VelocityContext();

          // Populate context

          context.put( "genericObject", new Object() );

          context.put( "integerObject", new Integer( 10 ) );

          context.put( "floatObject", new Float( 3.1415 ) );

          context.put( "userNoOverride", new NoOverride() );

          context.put( "userOverride", new Override() );

          // Merge template and context

          StringWriter writer = new StringWriter();

          try

          {

          varTemplate.merge( context, writer );

          }

          catch( ResourceNotFoundException rnfX )

          {

          System.err.println( "Template not found on merge: " + rnfX );

          System.exit( 1 );

          }

          catch( ParseErrorException peX )

          {

          System.err.println( "Failed to parse template on merge: " +peX );

          System.exit( 1 );

          }

          catch( MethodInvocationException miX )

          {

          System.err.println( "Application method exception: " + miX );

          System.exit( 1 );

          }

          catch( Exception x )

          {

          System.err.println( "Failed to merge template: " + x );

          System.exit( 1 );

          }

          // Render merged content

          System.out.println( writer.toString() );

          }

          }

          Listing 7.4 The driver code for the variable reference example.

          Value of generic Object is java.lang.Object@cdedfd

          Value of Integer object is 10

          Value of Float object is 3.1415

          Value of user object with default toString() is NoOverride@bf2d5e

          Value of user object with overridden toString() is toString()overridden

          Listing 7.5 Output from the variable reference example application.

          Listing 7.5中你可以看到,Velocity引用符合我們的非重載類,它沒有重載toString()方法,輸出結果和普通JAVA對象相似。這是因為Velocity使用toString()來獲取字符串化(stringified)值,并且不用關心它下面的成員數據。非重載類使用的toString()方法事實是由Java對象類帶過來的,這樣的輸出沒有什么特別的地方。在使用重載類的情況下,變量引用的結果是由重載的toString()方法提供的。Java Integer Float類實現了他們自己的toString()方法,在某種意義上表現為他們各自的類型,相應的引用將產生其對應的輸出結果。

          回到引用名稱上來,快速比較一下上下文組裝代碼(Listing 7.4)的關鍵字和模板引用名稱(Listing 7.3),你可以發現他們之間存在以下關系:

          genericObject => $genericObject

          integerObject => $integerObject

          floatObject => $floatObject

          userNoOverride => $userNoOverride

          userOverride => $userOverride

          非常清楚,除了$前綴外,關鍵字和引用名稱是一樣的,但他們還是有區別的(這個關系不是不致的。)在變量引用的情況下,我們之前聲明的關于在關鍵字和引用名稱之間關系是完全正確的。更確切地說,變量引用名稱就是上下文關鍵字加上$前綴(或$!:用于quiet notation<靜態符號>的情況下,隨后將進行討論)。

          正好,用Velocity的行話講,通過變量引用的有效上下文關鍵字名稱必須遵照VTL標識符語法。正確的VTL標識符是一個由英文字母開始,后跟英文字母、數據字符、連字號(-)或下劃線(_)的字符串組成(英文字母可以是小寫的az或大寫的A-Z,數字可以為0-9)。Velocity變量引用就是在VTL標識符前加前綴$(或$!)。

          方法

          和變量引用一樣,Velocity方法引用名稱包含了一個具有$前綴的VTL標識符。然而,在方法引用的情況下,它還需要一個VTL方法體。VTL方法體由一個VTL標識符、一對圓括號和可選參數(多個參數間用逗號分隔)組成。VTL標識符和VTL方法體之間用點(.)連接,示例如下:

          $date.changeTo( 2003, "March", 2 )

          $car.newColor("Blue" )

          $document.print()

          引用名稱的前半部分(在點[.]之前)和那些變量引用的語法是相同的。也就是說,引用名稱(包含VTL標識符)的上半部分對應上下文對象的上下文關鍵字。Velocity方法引用的剩余部分提供所引用JAVA對象方法實現的名稱和參數列表。為了讓Velocity訪問引用方法,這個方法必須聲明為public,同時必須是public類的成員。

          Velocity的方法引用和許多Velocity的變量引用是同樣的。方法引用被放置在一個模板動作被調用的地方。直覺判斷,在那些較早出現在模板里的引用之后以及在那些較遲出現在模板里的引用之前,Velocity引擎將處理任何一個已經給予的Velocity引用。同樣地,Velocity引用的賦值應該被考慮為一個連續的處理過程,隨著動作被較早的引用調用,它將會影響其隨后的引用的行為。

          當方法引用相應的JAVA方法返回一個值時,模板處理收益(proceed)從某種意義上和變量引用處理相似。當JAVA方法執行完成后,通過調用對象的toString()方法返回Velocity字符串化(stringifies)值,該返回值比JAVA對象返回的原始值要好,Velocity首先把值轉換為適當的JAVA封裝類(比如:整形值轉換為Integer,布爾值轉換為Boolean等等)。在任何情況下,在最終模板輸出時結果字符串將替換方法引用。

          為了對Velocity方法引用的用法有更好的體驗,讓我們來看一個示例。Listing 7.6提供了一個Java類,它展示的是一個汽車的主要技術規范。這個技術規范包括制造、模型、顏色和生產年份。方法用于定義這些規范的值。另外,方法還提供了顯示這些定義值的方法。

          public class Auto

          {

          public void defineType( String make, String model )

          {

          this.make = make;

          this.model = model;

          }

          public void defineColor( String color )

          {

          this.color = color;

          }

          public void defineYear( Integer year )

          {

          this.year = year;

          }

          public String printSpecs()

          {

          return (color + " " + year + " " + make + " " + model);

          }

          private String make;

          private String model;

          private String color;

          private Integer year;

          }

          Listing 7.6 An automobile specification class.

          下面是組裝一個上下文必須要的代碼,它包含一個Auto類的實例:

          context.put( "car", new Auto() );

          Auto的實例可以被模板(Listing 7.7)訪問和操作。這個模板使用Velocity方法引用通過對象的defineType()define-Color() defineYear()方法來定義汽車的技術規范。然后,對象的printSpecs()方法又一次通過方法引用被調用,目的是為了獲取一個包含汽車技術規范定義的字符串。這個字符串被增加到模板輸出,詳見Listing 7.8

          ## Define the make and model of the automobile

          Defining automobile type...$car.defineType( "Chevrolet", "Cavalier")

          ## Define the color of the automobile

          Defining automobile color...$car.defineColor( "Blue" )

          ## Define the year of the automobile

          Defining automobile year...$car.defineYear( 1997 )

          ## Display the automobile specifications

          $car.printSpecs()

          Listing 7.7 汽車技術規范模板

          Defining automobile type...

          Defining automobile color...

          Defining automobile year...

          Blue 1997 Chevrolet Cavalier

          Listing 7.8 汽車技術規范模板處理結果

          一個Velocity方法引用的重要方面就是到目前為止,我們已經巧妙地避開了參數類型。任何一個插入到模板里面或從模板里提取(extract)的值都會當成字符串來處理。我們先前曾經提及,任何一個插入到模板的非字符串值(通過變量引用或方法引用返回的值),都是使用其相應對象的toString()方法來字符串化(stringified)。然而,事情并非這樣簡單,當提及從模板里提取(extract)值時(當Velocity處理方法引用的參數時便會發生這種情況)就不同了。

          作為模板語言,和高級編程語言不同,Velocity模板語法不提供數據類型機制。同樣地,Velocity模板引擎期望所有的方法引用參數都為字符串。字符串型值通過引用字符串(用單引號如‘stringValue’,或雙引號如“stringValue”)在模板里被明確指定。另外,Velocity也支持隱式(implicit)字符串規范,那就是如果整形值在JAVA Integer類型支持的值域范圍內時,就不必引用這樣的值。但這種支持不能擴展到除Integer類型以外的范圍(比如long類型)或其他數字類型(比如float, double),如果需要正確處理這些參數值,則需要提供能接受字符串值并進行自定義類型轉換的Java方法。未來的Velocity版本可能會增強數字類型的支持。

          屬性

          Velocity屬性引用本質上講是一個Velocity方法引用的擴展。利用反射(introspection《自省/反省》),Velocity提供了一個交替接口,它是一個以setget開始命名的公開Java方法。這個交替接口允許模板象訪問普通Java對象屬性一樣訪問這種方法,目的是讓模板代碼更整潔更易讀。Velocity方法引用可能需要一個模板設計者使用一些像$obj.getValue()的方法訪問部分數據,而屬性引用只需使用$obj.Value的方法就可以訪問同樣的數據。

          Velocity屬性機制的功能比我們說的要更進一步。它除了提供交替接口功能外,還提供了一個擴展功能(功能為:it does so in a case-insensitive manner.)。如果在模板里遇到$obj.ValueVelocity首先會查找名叫getValue()的方法,如果沒有找到,Velocity會繼續查找名叫getvalue()的方法。換句話說,屬性引用最初將被當作方法引用$obj.getValue()等同對待,如果Velocity不能匹配引用到適當的Java方法,它將考慮把屬性引用當作方法引用$obj.getvalue()等同對待,并且再次嘗試查找相應的Java方法。同樣地,屬性引用$obj.value將第一個被當作$obj.getvalue()$obj.getValue()方法對待。

          除上面這種情況外,屬性機制支持對象的get()方法實現交替接口(In addition to eliminating issues of case, the property mechanism supports the alternate interface for objects implementing get() methods),比如下面這些原型定義:

          Object get( Object key );

          String get( String key );

          第一個原型和JavaMap類定義是一樣的,它明確指示Velocity的屬性引用適用于任何實現了Map接口的類的對象,假設那些對象用真實的實體字符串關鍵字來進行操作。第二個原型很可能提供了更好的、適用于用戶自定義實現的原型,來自模板和返回到模板的東西要不是明確的,要不就是已經暗中處理成字符串了的。

          正如我們做過的Velocity變量或Velocity方法引用,我們現在介紹一個簡單的示例來解釋如何使用屬性引用。在最后一段,我們將再次使用Auto類來介紹;然而,printSpecs()方法現在被三個新的方法替換,每一個方法都返回printSpecs()的一部分。新方法的名字叫getType(), get-Color(), getYear(),他們將返回汽車制造廠、型號、顏色和出廠年份。

          public class Auto

          {

          public void defineType( String make, String model )

          {

          this.make = make;

          this.model = model;

          }

          public void defineColor( String color )

          {

          this.color = color;

          }

          public void defineYear( Integer year )

          {

          this.year = year;

          }

          public String getType()

          {

          return (make + " " + model);

          }

          public String getColor()

          {

          return (color);

          }

          public Integer getYear()

          {

          return (year);

          }

          private String make;

          private String model;

          private String color;

          private Integer year;

          }

          Listing 7.9 Our revised Auto class with support for the property reference interface.

          屬性引用示例的模板實現見Listing 7.10。模板的上半部分定義了汽車技術規范的值,它和Listing 7.7的方法引用示例是相同的。模板的下半部分示范了三種訪問Auto對象屬性的技術。第一種:采用大寫字母開頭的屬性名稱;第二種:采用小寫字母開頭的屬性名稱;第三種:屬性值是通過等價的方法引用而獲得。不管采用哪種技術,其輸出都是相同,見Listing 7.11Velocity的屬性引用簡單提供了一個交替接口給模板設計者,在幕后,同樣的Java方法以同樣的方式被調用。

          ## Define the make and model of the automobile

          Defining automobile type...$car.defineType( "Chevrolet", "Cavalier")

          ## Define the color of the automobile

          Defining automobile color...$car.defineColor( "Blue" )

          ## Define the year of the automobile

          Defining automobile year...$car.defineYear( 1997 )

          ## Display the automobile specifications (upper case properties)

          $car.Color $car.Year $car.Type

          ## Display the automobile specifications (lower case properties)

          $car.color $car.year $car.type

          ## Display the automobile specifications (method references)

          $car.getColor() $car.getYear() $car.getType()

          Listing 7.10 A template demonstrating the use of property references.

          Defining automobile type...

          Defining automobile color...

          Defining automobile year...

          Blue 1997 Chevrolet Cavalier

          Blue 1997 Chevrolet Cavalier

          Blue 1997 Chevrolet Cavalier

          Listing 7.11 Results from processing the automobile specification template.

          為了替代上面的分離的屬性訪問方法,現在我們假定Auto類實現了一個key-based 的、接近于屬性訪問的方法。如果實現在某種意義上和Listing 7.12的代碼相似,Velocity的反射(introspection反省、自省)機制將為屬性引用(在上一個示例里定義的)提供后續支持。在$car.Type的處理過程中,Velocity將檢索一個有能力來get( “Type” )Java方法。如果找到這樣的一個方法,(僅有在Velocity的反射不能找到getType()gettype()時)該方法將被調用。$car.Color $car.Year將有同樣的方法來實現。在get()實現里的字符串比較將通過equalsIgnoreCase()方法來實現,屬性引用$car.type $car.color $car.year也將保持有效。

          public String get( String item )

          {

          if ( item.equalsIgnoreCase( "type" ) )

          {

          return (make + " " + model);

          }

          else

          if ( item.equalsIgnoreCase( "color" ) )

          {

          return (color);

          }

          else

          if ( item.equalsIgnoreCase( "year" ) )

          {

          return (year.toString());

          }

          else

          {

          return ("");

          }

          }

          Listing 7.12 A key-based implementation of property access for the Auto class.

          正式引用符號(Formal Reference Notation

          迄今為止,在我們的示例和討論中,我們一直限制使用Velocity的簡化的或正式的引用符號(notation)。Velocity也提供了一個正式的標記符(notation),主要是為了改善模板易讀性。不管你偏愛什么,理解正式標記符(notation)很重要,因為為了避免模板不易讀、含糊不清,它有時是必須的。比如,假使你需要從http://www.my.site/pageN.html產生一連串的URLspageN.html里的N代表動態產生的頁面數(如: page2.html, page99.html),可以嘗試使用簡化標記符(shorthand notation)的Velocity變量引用來產生頁面數,模板代碼和下面這段相似http://www.my.site/page$number.html。這段模板代碼在“$number.html”上有問題,它看起來和Velocity屬性引用(一個具有$number 對象的HTML屬性)相象。Velocity僅僅假定了這么一個引用,難道就沒有別的出路來實現這個意圖嗎?如果引用是不正確的假設,那么引用有可能正確解決,也可能不能解決。在任意一種情況下,最后結果或許可能是不需要的輸出。

          如何我們使用Velocity方法引用代替上面的方法來生成URL的頁面數,運行的時候也會出現相似的問題,其模板代碼看起來象http://www.my.site/page$number.getNext().html這個一樣。在這里,有一個使用$number.getNext()方法引用返回對象的HTML屬性請求,其最后結果或許還是不需要的輸出。如果Velocity屬性引用被用在方法引用的地方,則模板代碼變成了http://www.my.site/page$number.next.html,既然$number.next$number.get-Next()相當,模板處理的結果將和方法引用一樣,遭遇再次失敗。

          輕松解決這個問題的方法是使用Velocity的正式引用符號代替Velocity的簡化符號(shorthand notation),正式符號非常適用于解決上面提到的這種含糊不清的模板處理問題。正式標記符清楚地界定了引用,給Velocity提供了足夠的信息去實現你的意圖,在代碼不明確的情況下(比如上面介紹的)也能正確執行。引用用一對大括號({})和一個放在大括號前面的$前綴進行界定,其余部分和引用語法相同。我們所討論的這個URL模板代碼將用正式符號進行重寫,如下所示:

          http://www.my.site/page${number}.html

          http://www.my.site/page${number.getNext()}.html

          http://www.my.site/page${number.next}.html

          安靜記號符(Quiet Notation

          除了標準的$前綴外,Velocity引用可以使用前綴“$!”。$!提供了Velocity想要當作quiet notation(安靜符號)進行引用的東西。安靜記號符(Quiet notation)影響了模板引擎在處理引用找不到對應上下文對象時的處理方式(manner)。在很多情況下,如果不能在上下文里定位適當的對象或方法,Velocity會把引用當作標準文本對待,直接以靜態內容的方式進行輸出。這表面在Listing 7.14里的前三行,模板的處理結果(使用了一個空的上下文)見Listing 7.13。和這個相反,在Listing 7.14里的最后三行文本使用了安靜記號符(quiet notation)。Velocity的安靜記號符(quiet notation)使用空白字符串(比如“”)有效替換未解決的引用,否則他們會被當成靜態內容直接輸出。

          ## Standard variable reference notation

          This variable reference is loud...$object.

          ## Standard method reference notation

          This method reference is loud...$object.getValue().

          ## Standard property reference notation

          This property reference is loud...$object.Value.

          ## Quiet variable reference notation

          This variable reference is quiet...$!object.

          ## Quiet method reference notation

          This method reference is quiet...$!object.getValue().

          ## Quiet property reference notation

          This property reference is quiet...$!object.Value.

          Listing 7.13 A template illustrating the use of both standard and quiet reference notation.

          This variable reference is loud...$object.

          This method reference is loud...$object.getValue().

          This property reference is loud...$object.Value.

          This variable reference is quiet....

          This method reference is quiet....

          This property reference is quiet....

          Listing 7.14 The template output demonstrating the difference between standard and quiet reference notation.

          雖然示例使用的是簡化引用符號。當與Velocity的正式引用符(formal reference notation)結合時,安靜記號符(quiet notation)和正式引用符一樣是相等的、有效的。利用正式引用符實現,在Listing 7.13的模板應該調整為Listing 7.15所示的模板代碼。假定在缺乏有效上下文實體的情況下,這兩個模板的輸出結果是相同的。需要注意的一點是:當結合安靜(quiet)和正式(formal)記號符(notation)時,“!”字符應該放在大括號(curly braces)的外面。

          ## Standard variable reference notation

          This variable reference is loud...${object}.

          ## Standard method reference notation

          This method reference is loud...${object.getValue()}.

          ## Standard property reference notation

          This property reference is loud...${object.Value}.

          ## Quiet variable reference notation

          This variable reference is quiet...$!{object}.

          ## Quiet method reference notation

          This method reference is quiet...$!{object.getValue()}.

          ## Quiet property reference notation

          This property reference is quiet...$!{object.Value}.

          Listing 7.15 The template from Listing 7.13 implemented using formal reference notation.

          忽略(Escape轉義)引用

          當我們在之前的章節里討論安靜記號符(quiet notation)時,示范了一個模板內容雖然看起來象是Velocity引用,但不與上下文的對象或方法綁定,在未使用(employ雇用)安靜記號符(quiet notation)的地方僅被當作靜態上下文處理。

          當模板本身需要看起來和變量引用相同的靜態內容時,就會經常用到這個方法。

          比如,許多腳本語言的變量定義也是在變量前加上前綴$,如果任務是使用這樣的語言來書寫模板代碼。了解這門語言的變量可能會減少大量的單調工作。

          然而,需要注意的是,這個技術沒有保證。萬一Velocity不顧上下文的內容,強制對一個具有$前綴的實體當作引用進行處理,一旦在VTL定義語法中不允許使用冒號,解析結果就是錯誤的。

          因此,或許一些特殊情況,比如不想讓${foo:bar}Velocity處理,原樣輸出。也就是說,你如何明確阻止Velocity把某些看起來象引用的廣本當作引用來處理?最簡單的解決方法就是忽略(轉義)這個引用。這通過在引用的前綴($)之前插入一個反斜線(")來完成。

          為了更進一步闡明本身的問題,讓我們對Listing 7.16的模板進行仔細考慮。模板的第一部分對Velocity的變量引用命名進行了簡要描述。包含在$email$name里的靜態內容將照原樣顯示在最終輸出里。如果上下文缺乏相應的對象來對應這些字符串引用,Velocity將產生你想要的輸出。然而,模板的第二部分提供了一個需要產生動態內容的聯系信息,而且,這個動態部分也使用了$name$email,但在這種情況下,他們將被真實的Velocity引用替換,而不是靜態內容。

          ## Description of names used for standard, shorthand variable references Velocity variable references are built upon the VTL identifiers used to key the associated objects in the context. For example, an object keyed with the string 'email' would be referenced from the template with $email. Likewise, an object keyed with the string ‘name’ would be referenced with $name.

          ## Contact information For more on this topic, contact $name at $email.

          Listing 7.16 A template that illustrates the need to escape references.

          如果上下文包含了姓名和email關鍵字,那么Velocity將用相應的對象值替換所有的$name$email。另一方面,如果上下文不包含姓名和email關鍵字,那么Velocity不替換任何一個$name$email。非常清楚,兩個動作都不能提供想要得到的結果。解決方法是忽略(轉義)$name$email,無論什么情況下,Velocity將把他們當作簡單靜態內容對待。模板代碼見Listing 7.17

          假定上下文包含字符串“John”(對應關鍵字為“name”)和doe@my.site(對應關鍵字“email”),模板處理結果見Listing 7.18

          ## Description of names used for standard, shorthand variable references Velocity variable references are built upon the VTL identifiers used to key the associated objects in the context. For example, an object keyed with the string 'email' would be referenced from the template with "$email. Likewise, an object keyed with the string 'name' would be referenced with "$name.

          ## Contact information For more on this topic, contact $name at $email.

          Listing 7.17 A template using escaped references.

          Velocity variable references are built upon the VTL identifiers used to key the associated objects in the context. For example, an object keyed with the string ‘email’ would be referenced from the template with $email. Likewise, an object keyed with the string 'name' would be referenced with $name. For more on this topic, contact John at doe@my.site.

          Listing 7.18 Output produced by the template in Listing 7.17.

          事實上,反斜線提供了Velocity引用的轉義。當你在引用之前,實際上想要一個文本的反斜線該如何做?答案仍然是增加更多的反斜線。反斜線的數量決定于需要多少文本性的反斜線和是否忽略引用本身。Velocity按從左向右的順序對反斜線進行處理,每一對反斜線減少成一個反斜線字符。如果在處理結束后,剩下了奇數數量的反斜線,則引用被忽略;否則,將對引用進行處理。也就是說,如果是一個奇數數量的反斜線,那么結果是引用被忽略;如果是一個偶數數量的反斜線,那么結果是引用被它定義在上下文里的值替換。Listing 7.19提供了一個模板,在進里面的引用前增加了不同數量的反斜線,isting 7.20顯示了Listing 7.19處理后的結果。

          ##有相應上下文對象情況下的引用轉義

          $object.getValue()

          "$object.getValue()

          ""$object.getValue()

          """$object.getValue()

          """"$object.getValue()

          """""$object.getValue()

          """"""$object.getValue()

          Listing 7.19 A template showing the use of varying numbers of backslash reference escapes.

          formal

          $object.getValue()

          "formal

          "$object.getValue()

          ""formal

          ""$object.getValue()

          """formal

          Listing 7.20 Listing 7.19模板的輸出結果

          你需要明白的是使用反斜線將會使Velocity變得更復雜。當你的模板在使用一個引用時,如果存在反斜線,那么你要非常小心,一不小心就會出錯,結果找不到對應的上下文對象,有一些僅僅看起來象引用,但它只被用作文字輸出。1.3.1版的行為依賴于是否存在一個偶數或奇數數量的反斜線。當反斜線數量為偶數時,所有的反斜線都當作文字處理,不進行任何轉義。相反,如果反斜線數量為奇數時,每一對(從左邊開始)反斜線被當作轉義處理,結果是輸出一個反斜線。最后的反斜線被當成文本處理。詳見Listings 7.21 7.22

          ##在沒有相關上下文對象情況下的引用轉義

          $noobject.getValue()

          "$noobject.getValue()

          ""$noobject.getValue()

          """$noobject.getValue()

          """"$noobject.getValue()

          """""$noobject.getValue()

          """"""$noobject.getValue()

          Listing 7.21使用了反斜線數量不斷增加的模板

          沒有使用上下文組合對象。

          $noobject.getValue()

          "$noobject.getValue()

          ""$noobject.getValue()

          ""$noobject.getValue()

          """"$noobject.getValue()

          """$noobject.getValue()

          """"""$noobject.getValue()

          Listing 7.22 Listing 7.21模板的輸出結果

          本章小節和下章介紹

          在本章里,我們深入研究了Velocity的引用,包括變量、方法和屬性引用。我們也測試了Velocity的正式和靜態標記法(formal and quiet notations)以及引用轉義(escaping)。在這一點上,你應該已經掌握了足夠的知識,足以讓你正確使用Velocity引用進行開發工作。在下一章里,在已經掌握Velocity引用的基礎上,我們將通過學習指令,并使用指令進一步擴展模板的功能。Velocity的指令把模板設計帶到另外一個水平,它允許模板設計者訪問那些在許多編程語言里才具有的控制結構集。

          posted on 2008-10-17 10:12 KINGWEE 閱讀(974) 評論(1)  編輯  收藏 所屬分類: Velocity

          評論

          # re: CHAPTER 7 References引用探索  回復  更多評論   

          有一些錯別字,并且翻譯生硬的地方~
          2015-03-15 11:17 | 江南煙雨
          主站蜘蛛池模板: 阳东县| 禄丰县| 含山县| 革吉县| 松滋市| 大宁县| 宜阳县| 阿鲁科尔沁旗| 托里县| 武宣县| 清水河县| 青岛市| 平南县| 三穗县| 托里县| 万山特区| 日喀则市| 绥江县| 平南县| 嘉善县| 吉安县| 秦皇岛市| 绥化市| 喀喇| 曲麻莱县| 金华市| 专栏| 会泽县| 七台河市| 合江县| 安义县| 青铜峡市| 祁东县| 右玉县| 龙门县| 张家口市| 林口县| 中山市| 清新县| 江安县| 长海县|