久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

CHAPTER 8 使用指令 - Velocity空間 - BlogJava

 木木的陽(yáng)光 2011-03-23

在前面的章節(jié)里,,我們明確了引用在Velocity模板里的角色,。除了討論如何直接通過(guò)變量和屬性引用獲取值之外,我們也介紹了方法引用,,方法引用允許模板設(shè)計(jì)者通過(guò)定制的Java方法引用上下文對(duì)象操作和訪問(wèn)數(shù)據(jù),。方法引用提供在窗體里返回字符串的能力。雖然這些功能能夠充分支持任何模板處理需要做的事情,,但Velocity仍然為大家?guī)?lái)了模板語(yǔ)言,,模板語(yǔ)言為許多通用任務(wù)提供了捷徑,。這就是Velocity指令表演的舞臺(tái)。

指令(Directives控制模板處理流程,、插入和操作上下文值,、包含解析、停止解析文本,、模板代碼再使用(通過(guò)宏)提供了支持,。Velocity指令是通過(guò)一個(gè)特定的前綴字符(#)后跟一個(gè)文本來(lái)定義的。Velocity目前支持總共10個(gè)指令,,其中有一些是指令需要和其他指令結(jié)合才有意義,。在這一章里,我們將詳細(xì)介紹每一個(gè)指令,。

 #stop

第一個(gè)指令是#stop,,主要用于程序調(diào)試。當(dāng)模板引擎碰到這個(gè)指令時(shí),,引擎將終止執(zhí)行并將控制返回到調(diào)用程序,。特別的,合并上下文處理和模板的處理將停止在#stop指令處,。這個(gè)處理將調(diào)用stopTemplate的合并方法(見(jiàn)Listing 8.1),。除(一些命名改變和許多附加的打印聲明)以外,驅(qū)動(dòng)代碼(Listing 8.1)和在前面章節(jié)里的是同樣的,。

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 Stop

{

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 stopTemplate = null;

try

{

stopTemplate = Velocity.getTemplate( "Stop.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( "before", "before the stop directive" );

context.put( "after", "after the stop directive" );

// Merge template and context

StringWriter writer = new StringWriter();

try

{

System.out.println( "***** Starting merge *****" );

stopTemplate.merge( context, writer );

System.out.println( "***** Returning from merge *****" );

}

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 8.1 The driver program used for the #stop directive example.

Listing 8.1代碼(使用的模板見(jiàn)Listing 8.2)的執(zhí)行結(jié)果見(jiàn)Listing 8.3,,它示范了Velocity#stop指令的結(jié)果。從中你可以看到#stop指令導(dǎo)致調(diào)用合并在模板完全處理完之前返回,。在#stop指令之前的模板內(nèi)容被正常處理,,其中包括適當(dāng)?shù)囊锰幚怼T?/span>#stop指令之后的模板內(nèi)容根本不進(jìn)行處理,。程序的非模板描述輸出證明了#stop不能傳入任何錯(cuò)誤條件,但它可以讓合并處理提前終止并正常返回,,以便于程序調(diào)試,。

## Start processing

=== Start of template ===

The portion of the template preceding the stop directive is

processed normally.

This is $before.

## Stop processing

#stop

The portion of the template following the stop directive is

not processed.

This is $after.

Listing 8.2 A template using the #stop directive.

***** Starting merge *****

***** Returning from merge *****

=== Start of template ===

The portion of the template preceding the stop directive is

processed normally.

This is before the stop directive.

Listing 8.3 Results from processing the template in Listing 8.2.

#include

#include指令和它的名字一樣,其任務(wù)就是完成文件包含處理,。它允許模板設(shè)計(jì)者包含模板外的文件,。特別的,它允許包含來(lái)自一個(gè)或多個(gè)外來(lái)源的靜態(tài)內(nèi)容,。這些內(nèi)容將被放置在#include指令出現(xiàn)的地方,,并進(jìn)行輸出。讓我們來(lái)看一下Listing 8.4的示例,,除了三條#include指令以外,,模板僅僅由靜態(tài)內(nèi)容組成,。假定#include所包含的“specials”內(nèi)容因某些原因而改變,并假定“specials”僅僅是一個(gè)簡(jiǎn)單的文本文件,,現(xiàn)在計(jì)劃通過(guò)#include指令來(lái)重新得到這些文件的內(nèi)容,。如果這些文件的定義和Listing 8.5一樣,模板處理后的輸出結(jié)果應(yīng)該是和Listing 8.6一樣,。

## Generic welcome

Welcome to Gem's Bar and Grill!

We are conveniently located at the corner of 5th and Ives in beautiful lower downtown.

Our three specials of the day are as follows:

## Present today's specials

#include( "special-1.txt" )

#include( "special-2.txt" )

#include( "special-3.txt" )

## Generic info

We are open from 4:00 P.M. to 2:00 A.M. daily.

Call 555-1234 for more information.

Listing 8.4 A template using #include directives.

special-1.txt: Quesadilla Pie — $7.95

special-2.txt: Gem's Famous Cheeseburger — $5.95

special-3.txt: Soup and Salad — $4.95

Listing 8.5 File definitions used for the #include examples.

Welcome to Gem's Bar and Grill!

We are conveniently located at the corner of 5th and Ives

in beautiful lower downtown.

Our three specials of the day are as follows:

Quesadilla Pie — $7.95

Gem's Famous Cheeseburger — $5.95

Soup and Salad — $4.95

We are open from 4:00 P.M. to 2:00 A.M. daily.

Call 555-1234 for more information.

Listing 8.6 Results from processing the template in Listing 8.4.

對(duì)于Velocity#include指令提供的服務(wù)沒(méi)有更多好說(shuō)的,。在上面這個(gè)示例里,每一個(gè)#include指令通過(guò)相應(yīng)的文件名字符串指定了一個(gè)單一文件,。#include指令允許你在兩個(gè)方面進(jìn)行擴(kuò)展,。首先,你可以用一個(gè)Velocity引用來(lái)代替#include里的參數(shù),。下面的示例將演示這種情況,,示例需要用的上下文封裝代碼見(jiàn)Listing 8.7Listing 8.4模板代碼需要重新書(shū)寫(xiě),,修改后的結(jié)果見(jiàn)Listing 8.8,。最終處理結(jié)果沒(méi)有任何改變。

// Populate context with file names used by #include

context.put( "special-1", "special-1.txt" );

context.put( "special-2", "special-2.txt" );

context.put( "special-3", "special-3.txt" );

Listing 8.7 Java code that populates the context with filenames used by the #include directive.

## Generic welcome

Welcome to Gem's Bar and Grill!

We are conveniently located at the corner of 5th and Ives

in beautiful lower downtown.

Our three specials of the day are as follows:

## Present today's specials

#include( $special-1 )

#include( $special-2 )

#include( $special-3 )

## Generic info

We are open from 4:00 P.M. to 2:00 A.M. daily.

Call 555-1234 for more information.

Listing 8.8 A template demonstrating the use of Velocity references with the #include directive.

第二種方式是#include指令允許你對(duì)指令的語(yǔ)法進(jìn)行擴(kuò)展,。在第一個(gè)示例里是,,需要包含的文件名是直接提供的。現(xiàn)在用字符串式的引用代替他們,,這樣,,你就可以在一個(gè)#include指令包含多更多的文件。比如,,在Listings 8.48.8示例里的#include三個(gè)指令就可以換成如下的方式:

#include( “special-1.txt” “special-2.txt” “special-3.txt” )

#include( $special-1 $special-2 $special-3 )

迄今為止,,我們忽視了一個(gè)重要的部分,是關(guān)于如何使用Velocity#include指令,,既Velocity查找指定文件的方式,。雖然文件的名稱已經(jīng)直接提供給了指令,但并沒(méi)有提及如何獲得相對(duì)于根目錄的文件相對(duì)位置,。Velocity是通過(guò)假定所有文件名都指定為相對(duì)于模板根目錄來(lái)解決這個(gè)不明確的問(wèn)題的,。默認(rèn)路徑是應(yīng)用程序開(kāi)始運(yùn)行的目錄,但默認(rèn)模板根路徑位置可能被Velocity的運(yùn)行時(shí)配置屬性覆蓋,。具體情況將在Chapter 10(獲得Velocity的控制Taking Control of Velocity)進(jìn)行討論,。

#parse

#parse指令與#include指令相當(dāng)相似,雙方都用于從模板根路徑位置的外部文件包含內(nèi)容,。它們的主要主要區(qū)別是:#include包含的內(nèi)容將當(dāng)成靜態(tài)內(nèi)容處理,,#parse包含的內(nèi)容將當(dāng)成另外一個(gè)模板來(lái)處理。也就是說(shuō),,#parse指令允許你嵌套模板,。下面我們將用一個(gè)修改過(guò)的daily special示例(前面章節(jié)提及過(guò))來(lái)說(shuō)明#parse指令如何使用的,。在這里,我們假定管理者想通過(guò)數(shù)據(jù)庫(kù)來(lái)獲取所有價(jià)格,,而不是在包含文件里進(jìn)行硬編碼來(lái)獲取價(jià)格,。

第一步是修改上下文組合代碼,以便能夠獲取當(dāng)前價(jià)格和把當(dāng)前價(jià)格插入到上下文中,,具體代碼見(jiàn)Listing 8.9,,變量qPiePrice cBurgerPricesSaladPrice將從數(shù)據(jù)庫(kù)是獲取價(jià)格值,,每一個(gè)值將通過(guò)和各自變量名稱相匹配的字符串鍵入,。

// Populate context

context.put( "qPiePrice", qPiePrice );

context.put( "cBurgerPrice", cBurgerPrice );

context.put( "sSaladPrice", sSaladPrice );

Listing 8.9 Our modified application code that inserts the daily special prices into the context.

下一步,我們將創(chuàng)建一些新文件來(lái)呈現(xiàn)daily specials,。這些文件的定義是基于Listing 8.5的內(nèi)容進(jìn)行修改的,。這些新文件被重新改名,價(jià)格被替換成Velocity變量引用,。最后修改的結(jié)果見(jiàn)Listing 8.10,。

special-1.vm: Quesadilla Pie — $qPiePrice

special-2.vm: Gem's Famous Cheeseburger — $cBurgerPrice

special-3.vm: Soup and Salad — $sSaladPrice

Listing 8.10 Files definitions used for #parse examples.

最后我們對(duì)Listing 8.4的模板進(jìn)行更新,用#parse指令替換#include指令,,用適當(dāng)?shù)奈募苯痈奈募?。更新后的模板?jiàn)Listing 8.11,輸出結(jié)果和Listing 8.6顯示的是一樣的,。

## Generic welcome

Welcome to Gem's Bar and Grill!

We are conveniently located at the corner of 5th and Ives

in beautiful lower downtown.

Our three specials of the day are as follows:

## Present today's specials

#parse( "special-1.vm" )

#parse( "special-2.vm" )

#parse( "special-3.vm" )

## Generic info

We are open from 4:00 P.M. to 2:00 A.M. daily.

Call 555-1234 for more information.

Listing 8.11 A template using #parse directives.

在使用#include指令時(shí),,文件名或許可以通過(guò)Velocity引用提供。然而,,和#include指令不同,,#parse指令不支持多參數(shù)。因此,,當(dāng)我們按普通方式用下面的語(yǔ)句替換Listing 8.11#parse行時(shí)

#parse( $special-1 )

#parse( $special-2 )

#parse( $special-3 )

使用單個(gè)#parse,,比如

#parse( $special-1 $special-2 $special-3 )

將不能得到正確的輸出結(jié)果。

在進(jìn)行嵌套和遞歸時(shí),,#parse指令也和#include指令不同,,neither of which makes sense in the context of an #include(?,?未譯出)。嵌套(Nesting引用了一個(gè)放置了#parse指令,,并通過(guò)該#parse指令進(jìn)行自包含的文件,。遞歸(Recursion)引用了一種特定情況的嵌套,這種情況是#parse指令引用它自身的文件,。默認(rèn)情況下,,Velocity限制#parse指令最多有10層的嵌套,;然而,這個(gè)默認(rèn)可能被Velocity的運(yùn)行時(shí)配置屬性重寫(xiě)(你將在Chapter 10里進(jìn)行學(xué)習(xí)),。

下面展示了用#parse指令進(jìn)行嵌套和遞歸的示例,,它包含了下面的一個(gè)命名為Myself.vm的模板:

Before parse directive.

#parse( “Myself.vm” )

After parse directive.

假定最大的解析深度被設(shè)置成3,則模板的輸出結(jié)果為:

Before parse directive.

Before parse directive.

Before parse directive.

After parse directive.

After parse directive.

After parse directive.

每一次這個(gè)文件被處理,,其第一行都將被輸出,。然后,#parse指令將致使模板引擎啟動(dòng)處理這個(gè)文件的一個(gè)新拷貝,。這樣一直重復(fù),,直到最后一個(gè)#parse指令被處理或達(dá)到最大解析深度;在遞歸的情況下,,位于其后的語(yǔ)句只有等到遞歸全部返回后才開(kāi)始處理,。最后,隨著模板引擎從每一個(gè)#parse指令的返回,,它將開(kāi)始處理剩余的語(yǔ)句,,直到輸出這個(gè)簡(jiǎn)單模板的最后一行。

#set

Velocity其他的指令不同,,#set指令將影響上下文和模板的合并,。你可以使用#set指令去更新一個(gè)已經(jīng)存在的上下文實(shí)體,也可用于創(chuàng)建一個(gè)新的實(shí)體,。這個(gè)實(shí)體,,無(wú)論是更新還是新建,都是模板的可以立即(直接)使用的,;然而,,他們只能在模板和上下文合并完成之后才能使用。為了說(shuō)明#set指令的基本原理,,讓我們進(jìn)入一個(gè)簡(jiǎn)單的示例進(jìn)行研究,。假定我們已經(jīng)有一個(gè)存在的用于存儲(chǔ)字符串值“oldValue”(對(duì)應(yīng)關(guān)鍵字為“existing”)的上下文實(shí)體。這時(shí),,我們想把模板里的實(shí)體值“oldValue”改成“newValue”,,并增加一個(gè)新的具有字符串值為“newEntry”(對(duì)應(yīng)關(guān)鍵字為“new”)的上下文。Listing 8.12的模板滿足了這些需要,,其輸出結(jié)果見(jiàn)Listing 8.13,。

## Before set directives

The initial value keyed by "existing" is $existing.

The initial value keyed by "new" is $!new.

#set( $existing = "newValue" )

#set( $new = "newEntry" )

## After set directives

The final value keyed by "existing" is $existing.

The final value keyed by "new" is $!new.

Listing 8.12 A template that uses the #set directive to update one entry and add another.

The initial value keyed by "existing" is oldValue.

The initial value keyed by "new" is .

The final value keyed by "existing" is newValue.

The final value keyed by "new" is newEntry.

Listing 8.13 Results from processing the template in Listing 8.12.

注意,模板表面上好象已經(jīng)立即訪問(wèn)了這些更新后的和新增加的值,,下面的應(yīng)用程序并不是這種情況,。事實(shí)上,所有上下文的模板初始化和改變都發(fā)生在合并處理期間,。一旦這些指令以他們?cè)谀0謇锏捻樞蜻M(jìn)行上下文合并和變更操作完成以后,,模板里的引用就可以接收適當(dāng)?shù)母聰?shù)據(jù),。然而,直到這些處理過(guò)程完成,,其下面的應(yīng)用程序?qū)@些改變一無(wú)所知,。示例的Java代碼見(jiàn)Listing 8.14,這些代碼打印了“existing”“new”上下文實(shí)體的值,,在調(diào)用合并之前和在調(diào)用合并之后,。當(dāng)下面的應(yīng)用程序開(kāi)始運(yùn)行時(shí),這此代碼將產(chǎn)生如下輸出:

Before merge: oldValue/null

After merge: newValue/newEntry

System.out.println( "Before merge: " + context.get( "existing" ) + "/" + context.get( "new" ) );

setTemplate.merge( context, writer );

System.out.println( "After merge: " + context.get( "existing" ) + "/" + context.get( "new" ) );

Listing 8.14 Code querying the context before and after the merge of a template using #set directives.

在前面的示例里介紹#set指令時(shí),,為了使程序更加簡(jiǎn)單,,我們僅僅為變量引用指定了一個(gè)簡(jiǎn)單的字符串值。雖然在第一個(gè)示例里介紹的,,我們使用的是#set指令的普通語(yǔ)法(引用=值),,但#set指令允許使用多種類型的引用類型和值類型,這就提高#set指令的能力和使用范圍,。從等號(hào)(=)左側(cè)開(kāi)始,,為#set指令提供的引用可以是一個(gè)變更引用,也可以是一個(gè)屬性引用,。我們已經(jīng)看到了#set指令使用變量引用的例子,,下面讓我們來(lái)一個(gè)使用屬性引用的示例。

我們?cè)?jīng)在Chapter 7里討論過(guò)屬性引用依賴于反射機(jī)制(introspection),。在那些章節(jié)里,,我們提供了一些使用反射的示例,在示例里,,反射揭開(kāi)了通過(guò)屬性引用讀取對(duì)象屬性值的get方法原理,。(In that chapter, we provided examples where introspection uncovered get methods that allowed object property values to be read through property references)。同樣的,,Velocity也允許通過(guò)窗體setValue(value)set方法,,使用屬性引用修改對(duì)象屬性值。下面讓我們考慮一下Listing 8.15里的SetObj類,,它提供了setValue() getValue()方法來(lái)訪問(wèn)它的值屬性,。假定這個(gè)類的實(shí)例被存儲(chǔ)在上下文中(和關(guān)鍵字setObj對(duì)應(yīng)),屬性引用setObj.value可以和#set指令結(jié)合來(lái)更新這個(gè)值屬性,。模板代碼如下:

#set( $setObj.value = “some value” )

public class SetObj

{

public void setValue( String value )

{

this.value = value;

}

public String getValue()

{

return (value);

}

private String value;

}

Listing 8.15 A simple class providing a set and get method for access to its single property.

現(xiàn)在把視線轉(zhuǎn)移到#set指令等號(hào)“=”的右邊,,我們發(fā)現(xiàn)這個(gè)值可以是多種類型的值也可以含有運(yùn)算符。值類型包括文本字符串,、integer,、引用、數(shù)組、值域操作和布爾值,。注意,#set指令不允許把值指定為null,,如果一個(gè)碰巧返回的值為null(比如一個(gè)方法引用),,引用的值(在等號(hào)左邊)將保持原樣。#set指令支持的操作符包括簡(jiǎn)單的算術(shù)運(yùn)算和布爾運(yùn)算,。我們已經(jīng)看到了使用字符串值的示例,,那么就讓我們來(lái)看一個(gè)使用引用的示例。

#set指令支持三種類型的Velocity引用值:變量,、屬性和方法,。在Listing 8.16里示范了這些引用的用法(假定上下文包含了兩個(gè)SetObj<見(jiàn)Listing 8.15>的實(shí)例)。模板一開(kāi)始就創(chuàng)建了一個(gè)變量引用來(lái)保存值“A value”,。然而用變量引用聯(lián)合setObjA上下文對(duì)象來(lái)設(shè)置屬性的值,。之后,setObjA上下文對(duì)象被用于設(shè)置setObjB上下文對(duì)象的屬性值,,首先是屬性引用,,其次是方法引用。模板每一步都將輸出值“A value”,。

## Create a variable reference

#set( $varRef = "A value"" )

## Use a variable reference as the value

#set( $setObjA.value = $varRef )

$setObjA.value

## Use a property reference to set the value

#set( $setObjB.value = $setObjA.value )

$setObjB.value

## Use a method reference to set the value

#set( $setObjB.value = $setObjA.getValue() )

$setObjB.value

Listing 8.16 A template demonstrating the use of variable, property, and method references as values for the #set directive.

個(gè)別的,,我們已經(jīng)了解如何在#set指令里使用字符串和引用,但是你知不知道如何用一個(gè)單獨(dú)的#set指令包含這兩者,?沒(méi)問(wèn)題,,只需要把引用用雙引號(hào)(“”)包裹并放入字符串中就行。Velocity將自動(dòng)在內(nèi)容里插入雙引號(hào)里的引用值,,一部分字符串將按照原樣進(jìn)行輸出,,同時(shí)引用將按照普通方式進(jìn)行處理。從另一方面來(lái)講,,如果你需要包含一個(gè)外表看起來(lái)象引用的字符串,,那么,你只需簡(jiǎn)單地用單引號(hào)(‘’)把引用包裹起來(lái)就行,。

下一步,,讓我們考慮由范圍操作符和數(shù)組列表創(chuàng)建的#set指令值。范圍操作符的使用格式為[m..n],,其中的mn都是整數(shù)或存儲(chǔ)有整數(shù)值的引用,。和范圍操作符一樣,一個(gè)數(shù)組列表也是用方括號(hào)([])定義的,。然而,,數(shù)組的內(nèi)容是用逗號(hào)來(lái)分隔的,它允許使用#set指令支持的所有類型的值,包括范圍和任何其他的數(shù)組列表,。范圍和數(shù)組列表的實(shí)現(xiàn)模板見(jiàn)Listing 8.17,,其對(duì)應(yīng)的輸出結(jié)果見(jiàn)Listing 8.18

模板首先使用#set指令來(lái)創(chuàng)建一個(gè)整數(shù)范圍和一個(gè)保存有整數(shù)值的變量引用范圍,。接著使用#set指令來(lái)創(chuàng)建一個(gè)字符串?dāng)?shù)組列表,、一個(gè)整數(shù)、一個(gè)值域范圍,、一個(gè)布爾值和一個(gè)變量引用,。在模板中的不同位置上,將查詢這些新創(chuàng)建的引用的內(nèi)容和屬性信息,。The referenced objects behave as instances of Java’s ArrayList class, and thus we adhere to the ArrayList interface when working with the new range and list references(涉及的對(duì)象行為作為Java ArrayList類的實(shí)例,,并且當(dāng)和新范圍、新列表引用一起工作時(shí),,我們從此附加了ArrayList接口,??,?,?)。

## Set range with literals

#set( $range1 = [0..9] )

#set( $m = 1 )

#set( $n = 10 )

## Set range with references

#set( $range2 = [$m..$n] )

## Use ArrayList interface to access first and last

First value of range2: $range2.get( 0 )

Last value of range2 : $range2.get( 9 )

## Build list with a string literal, numeric literal,

## boolean value, and variable reference

#set( $list = ["string", 2, [2..-5], false, $m] )

## Use ArrayList interface to access index of some value

Index of $m : $list.indexOf( 1 )

Index of false : $list.indexOf( false )

Index of 2 : $list.indexOf( 2 )

Index of string: $list.indexOf( "string" )

## Get the size and fourth element of the nested range

Size of nested range: $list.get( 2 ).size()

Fourth element of nested range: $list.get( 2 ).get( 3 )

Listing 8.17 A template that uses range operators and array lists with the #set directive.

First value of range2: 1

Last value of range2 : 10

Index of 1 : 4

Index of false : 3

Index of 2 : 1

Index of string: 0

Size of nested range: 8

Fourth element of nested range: -1

Listing 8.18 Results from processing the template in Listing 8.17.

下一步,,#set指令支持的值類型列表是布爾類型,。正如你預(yù)料的一樣,布爾類型的值僅限于truefalse,。If the values were all that Velocity provided, the type wouldn’t buy much for the template designer since it is easy enough to store a Boolean value with a string or number.(如果Velocity提供了所有的值,,雖然可以很容易地使用字符串和數(shù)字來(lái)充當(dāng)布爾值,但模板設(shè)計(jì)者并不能使用太多的類型),。然而,,Velocity也支持布爾操作符ANDORNOT,。和許多編程語(yǔ)言一樣,,Velocity使用短路比較法進(jìn)行布爾運(yùn)算,意思是在表達(dá)式里,,Velocity只考慮必須的運(yùn)算來(lái)決定最終結(jié)果,。比如,如果第一個(gè)元素是布爾AND,,且第一個(gè)運(yùn)算值是false時(shí),,那么在其之后的就不再進(jìn)行運(yùn)算。同樣地,,如果第一個(gè)元素是布爾OR,,且第一個(gè)運(yùn)算值是true時(shí),那么在其之后的也同樣不再進(jìn)行運(yùn)算,。

Velocity模板里,布爾操作符AND,、OR NOT都是用符號(hào)&&||!表示的,。分別地,,布爾值通過(guò)truefalse表示。在布爾表達(dá)式里允許使用圓括號(hào)用于分組,,也可以在任何地主用引用來(lái)表示布爾值。我們展示了一個(gè)模板(Listing 8.19),,用于示范不同的布爾操作,,輸出結(jié)果見(jiàn)Listing 8.20

## Initialize some references with boolean values

#set( $bValA = true )

#set( $bValB = false )

#set( $bValC = false )

## Perform some boolean operations

#set( $taf = $bValA && $bValB )

true AND false = $taf

#set( $tanf = $bValA && !$bValB )

true AND NOT false = $tanf

#set( $tof = $bValA || $bValC )

true OR false = $tof

#set( $ntof = !$bValA || $bValC )

NOT true OR false = $ntof

#set( $paoa = ($bValA && $bValB) || (!$bValC && !$bValB) )

(true AND false) OR (NOT false AND NOT false) = $paoa

Listing 8.19 A template demonstrating the use of Boolean values and operations in #set directives.

true AND false = false

true AND NOT false = true

true OR false = true

NOT true OR false = false

(true AND false) OR (NOT false AND NOT false) = true

Listing 8.20 Results from processing the template in Listing 8.19.

最后,,我們來(lái)到最后一個(gè)被Velocity #set指令支持的值類型:integer,。integer支持的值域和JavaInteger類支持的值域相同,從–21474836482147483647之間的整數(shù),。在這個(gè)范圍以外的值將導(dǎo)致integer溢出,。而且只有標(biāo)準(zhǔn)10進(jìn)制的整形符號(hào)允許用作integer值。10進(jìn)制小數(shù),、科學(xué)計(jì)數(shù)法和其他進(jìn)制將導(dǎo)致模板解析錯(cuò)誤,。引用表示的數(shù)字值可以和數(shù)字一起在算術(shù)表達(dá)式里交替使用。

除了允許模板設(shè)計(jì)者存儲(chǔ)integer值外,,#set指令還支持簡(jiǎn)單的算術(shù)運(yùn)算,。運(yùn)算包括加、減,、乘,,整數(shù)除和取模,Velocity模板代碼分別用符號(hào)+,、-,、*/%表示,。圓括號(hào)可以用于表達(dá)式,,并且優(yōu)先級(jí)最高。Listing 8.21的模板示范了#set指令使用integer整形數(shù)字和整形操作符的例子,,其中包括整數(shù)溢出的示例,。輸出結(jié)果見(jiàn)Listing 8.22

## Set maximum and minimum Integer values

#set( $max = 2147483647 )

#set( $min = -2147483648 )

## Demonstrate overflow

#set( $maxo = $max + 1 )

$max + 1 = $maxo

#set( $mino = $min - 1 )

$min - 1 = $mino

## Addition

#set( $add = 1 + 1 )

1 + 1 = $add

## Subtraciton

#set( $sub = 1 - 2 )

1 - 2 = $sub

## Multiplication

#set( $mult = 2 * 2 )

2 * 2 = $mult

## Integer division

#set( $div = 10 / 6 )

10 / 6 = $div

## Modulus

#set( $mod = 10 % 6 )

10 % 6 = $mod

## Compound expression

#set( $comp = ((7 / 3) * 3) + (7 % 3) )

((7 / 3) * 3) + (7 % 3) = $comp

Listing 8.21 A template demonstrating the use of integer literals and operations in #set directives.

2147483647 + 1 = -2147483648

-2147483648 - 1 = 2147483647

1 + 1 = 2

1 - 2 = -1

2 * 2 = 4

10 / 6 = 1

10 % 6 = 4

((7 / 3) * 3) + (7 % 3) = 7

Listing 8.22 Results from processing the template in Listing 8.21.

#end

#end指令用于標(biāo)識(shí)模板代碼塊的結(jié)束,,它只有和Velocity的某幾個(gè)指令結(jié)合才有意義,,這些指令是#if,、#foreach#macro。當(dāng)模板引擎碰到#end指令時(shí),,它就會(huì)認(rèn)為該指令之前的#if,、#foreach#macro指令所標(biāo)識(shí)的代碼塊到止結(jié)束。我們?cè)谟懻?/span>#if,、#foreach#macro這些指令的示例時(shí),,就會(huì)看到,他們必須依賴#end指令來(lái)結(jié)束代碼塊,。

#if

正如其名字暗示的一樣,,Velocity#if指令為模板代碼的條件處理提供了支持。最簡(jiǎn)單的說(shuō)法就是,,#if放置在一個(gè)有條件的模板代碼塊之前,,并用#end指令結(jié)束這個(gè)代碼塊。如果條件運(yùn)算的結(jié)果為true,,這個(gè)代碼塊就會(huì)被處理,,其處理結(jié)果將會(huì)插入到輸出中。與此相反,,如果條件運(yùn)算的結(jié)果為false,,這個(gè)代碼塊就會(huì)被忽略,并不會(huì)產(chǎn)生輸出,。如果布爾表達(dá)式或引用的結(jié)果為非null值或?yàn)椴紶?/span>true時(shí),,就認(rèn)為條件運(yùn)算的結(jié)果為true。否則,,會(huì)被認(rèn)為是false,。Listing 8.23的示例示范了一個(gè)使用#if指令的模板,其輸出結(jié)果見(jiàn)Listing 8.24,。

## Trivial example with boolean literal

#if ( true )

The condition literal is true!

#end

## Examples using boolean conditions

#set( $condition = true )

#if( $condition )

The condition reference is true!

#end

#set( $condition = false )

#if( $condition )

This test is never output! The condition reference is false.

#end

## Example using non-boolean condition

#set( $refValue = "A string" )

#if( $refValue )

A string is true!

#end

## Example using non-existent (null) condition

#if ( $nullValue )

This text is never output! Reference is null.

#end

Listing 8.23 A template demonstrating simple uses of the #if directive.

The condition literal is true!

The condition reference is true!

A string is true!

Listing 8.24 Results from processing the template in Listing 8.23.

在前面的示例里,,我們限制條件表達(dá)式僅由簡(jiǎn)單的引用和布爾值組成。然而,,#if指令也支持布爾表達(dá)式,。布爾表達(dá)式由引用、布爾值,、布爾操作符和關(guān)系運(yùn)算符等組成,。在此這前,我們討論了布爾操作符AND (&&),、OR (||)NOT (!),。關(guān)系運(yùn)算符包括小于、大于,、小于等于,、大于等于,、不等于和等于,在Velocity模板中分別用<,、>,、<=>=,、!===表示,。這些關(guān)系運(yùn)算符只允許在整數(shù)和具有(符合Velocity整形值標(biāo)準(zhǔn)的)整形值的引用之間運(yùn)算。一般的,,你可以在表達(dá)式中使用圓括號(hào)來(lái)明確優(yōu)先運(yùn)算權(quán),。Listing 8.25中的模板示范了如何在#if指令里使用布爾運(yùn)算、關(guān)系運(yùn)算和混合表達(dá)式的例子,。

## Example using boolean operators

#if ( ($bValA && !$bValB) || $bValB )

Boolean expression evaluates to true.

#end

## Examples using relational operators

#if ( $iVal < 1 ) less-than #end

#if ( $iVal > 1 ) greater-than #end

#if ( $iVal <= 1 ) less-than-equal #end

#if ( $iVal >= 1 ) greater-than-equal #end

#if ( $iVal != 1 ) not-equal #end

#if ( $iVal == 1 ) equal #end

## Example mixing boolean and relational operators

#if ( ($iVal >= 1) && (!($iVal == 1) || $bValB) )

The expression evaluates to true.

#end

Listing 8.25 A template demonstrating Boolean and relational expressions used for #if directive conditions.

讓我們看一下Listing 8.26的例子,。第一個(gè)#if指令包含四個(gè)獨(dú)立的條件運(yùn)算。當(dāng)混合條件全部有效時(shí),,理解并不困難。同樣,,由于它自身的復(fù)雜性,,在代碼維護(hù)期間,更容易發(fā)生錯(cuò)誤,。

第二個(gè)#if指令采用的是#if指令嵌套塊,,由四個(gè)簡(jiǎn)單的條件組成,功能和第一個(gè)完全一樣,,但它更易讀,,也更易維護(hù)。給$x,、$y,、$allow$sleeping設(shè)置任何一個(gè)值,其運(yùn)算結(jié)果都是一樣,。

雖然關(guān)系操作符和布爾操作符為條件表達(dá)式提供了有力的工具,,但是這樣的表達(dá)式卻損害了程序的易讀性和可維護(hù)性。在許多情況下,,使用#if指令嵌套可以讓一些較為復(fù)雜的條件表達(dá)式變得更明朗,、更易讀。讓我們看一下Listing 8.26的示例,。

## Single complex condition

#if ( ($x < 5) && ($y < 3 || $y >= 9) && $allow && !$sleeping )

Take action

#end

## Complex condition rewritten as four simple nested conditions

#if ( $x < 5 )

#if ( $y < 3 || $y >= 9 )

#if ( $allow )

#if ( !$sleeping )

Take action

#end

#end

#end

#end

Listing 8.26 A template demonstrating nested #if directives.

#else

#else指令只有和Velocity#if指令一起配合使用時(shí)才有效,。它充當(dāng)?shù)氖且粋€(gè)雙重角色,終止一個(gè)模板代碼塊并初始化另一個(gè)模板代碼塊,。在第一個(gè)角色里,,當(dāng)#if指令的條件運(yùn)算結(jié)果為true時(shí),,它的表現(xiàn)和#if指令的#end指令相似,用作關(guān)閉模板代碼塊的定界符,。在第二個(gè)角色里,,當(dāng)#if指令的條件運(yùn)算結(jié)果為false時(shí),它充當(dāng)一個(gè)模板代碼塊的開(kāi)始定界符,。簡(jiǎn)短點(diǎn)說(shuō),,就是 #else指令為#if指令指定一個(gè)當(dāng)#if的條件運(yùn)算為false時(shí)需要執(zhí)行的模板代碼塊。這個(gè)新指定的代碼塊終止于#end指令,。在Listing 8.27的示例里演示了#else指令的用法,,其對(duì)應(yīng)的輸出見(jiàn)Listing 8.28

## An if/else with a true condition

#set( $condition = true )

#if ( $condition )

With a condition of $condition, we get the 'if' block.

#else

With a condition of $condition, we get the 'else' block.

#end

## Try one with a false condition

#set( $condition = false )

#if ( $condition )

With a condition of $condition, we get the 'if' block.

#else

With a condition of $condition, we get the 'else' block.

#end

Listing 8.27 A template demonstrating the use of #else directives.

With a condition of true, we get the 'if' block.

With a condition of false, we get the 'else' block.

Listing 8.28 Results from processing the template in Listing 8.27.

#elseif

不要感到驚訝,,Velocity#elseif指令只能與#else#if指令配合使用才有效,。#else指令只能為#if指令的模板代碼塊提供無(wú)條件的二選一能力,而#elseif指令則可以提供有條件的二選一能力,。和#else指令相似,,#elseif指令也充當(dāng)了兩個(gè)角色,也就是,,充當(dāng)前面代碼塊的關(guān)閉定界符,,同時(shí)作為交替代碼塊的開(kāi)始定界符。這個(gè)交替代碼塊只有在#elseif指令后面的條件運(yùn)算結(jié)果為true的時(shí)候才進(jìn)行處理,。最簡(jiǎn)單的情況下,,#end指令用于終止這個(gè)交替代碼塊。Listing 8.29示范了一個(gè)使用#elseif指令的模板,。這個(gè)模板從本質(zhì)上講和Listing 8.27的模板是相同的,,但#else指令被替換成#elseif指令,并為#elseif指令指定了條件運(yùn)算,。這個(gè)模板的運(yùn)算結(jié)果與Listing 8.27相同,,詳見(jiàn)Listing 8.30

## An if/elseif with a true condition

#set( $condition = true )

#if ( $condition )

With a condition of $condition, we get the 'if' block.

#elseif ( !$condition )

With a condition of $condition, we get the 'elseif' block.

#end

## Try one with a false condition

#set( $condition = false )

#if ( $condition )

With a condition of $condition, we get the 'if' block.

#elseif (!$condition )

With a condition of $condition, we get the 'elseif' block.

#end

Listing 8.29 A template demonstrating the use of #elseif directives.

With a condition of true, we get the 'if' block.

With a condition of false, we get the 'elseif' block.

Listing 8.30 Results from processing the template in Listing 8.29.

Listing 8.29里的模板清楚地示范了如何使用Velocity#elseif指令,,但這個(gè)示例并不能展示#elseif指令相對(duì)于#else指令的到底有些什么優(yōu)勢(shì),?第一個(gè)優(yōu)勢(shì)是,#elseif指令可以擁有自己的條件判斷,,并不依賴與之對(duì)應(yīng)的#if指令,;與此相反,#else指令不能擁有自己的條件判斷,,其條件判斷必須依賴于與之對(duì)應(yīng)的#if指令,。第二個(gè)優(yōu)勢(shì)是,一個(gè)#if指令可以擁有多個(gè)#elseif指令,,在這種情況下,,#elseif指令的條件判斷的結(jié)果將決定執(zhí)行哪個(gè)交替模板代碼塊,,除此而外的所有其他代碼塊都將被忽略。

當(dāng)在一個(gè)單獨(dú)的#if結(jié)構(gòu)里出現(xiàn)多個(gè)#elseif指令時(shí),,每一個(gè)#elseif用于終止前一個(gè)#elseif的代碼塊,,或作為第一個(gè)#elseif時(shí),用于終止#if的代碼塊,。如果沒(méi)有無(wú)條件二選一的情況,,則用#end指令終止最后一個(gè)#elseif代碼塊。如果必須要使用無(wú)條件二選一(即所有的條件均為false時(shí),,就執(zhí)行無(wú)條件代碼塊),,那么就需要用#else指令來(lái)終止最后一個(gè)#elseif代碼塊,最后用一個(gè)#end指令來(lái)終止該#else代碼塊,。Listing 8.31里的模板演示了這種情況,。

#set( $isDawn = false )

#set( $isNoon = false )

#set( $isDusk = false )

## Multiple #elseif directives

#if ( $isDawn )

The sun is rising.

#elseif ( $isNoon )

The sun is overhead.

#elseif ( $isDusk )

The sun is setting.

#end

## Multiple #elseif directives with closing #else directive

#if ( $isDawn )

The sun is rising.

#elseif ( $isNoon )

The sun is overhead.

#elseif ( $isDusk )

The sun is setting.

#else

What time is it?

#end

Listing 8.31 A template demonstrating the use of multiple #elseif directives, without and with a closing #else directive.

#if指令允許進(jìn)行嵌套。任何一個(gè)#if結(jié)構(gòu)都是由#if開(kāi)始,,用#end指令結(jié)束的,,當(dāng)然,在其中還包括#elseif,、#else和相應(yīng)的模板代碼塊以及可能嵌套的#if結(jié)構(gòu),。Listing 8.32里的模板演示了一個(gè)#if結(jié)構(gòu)的嵌套例子。最外層的#if結(jié)構(gòu)首先檢查$red是否為true,,如果不是,它就轉(zhuǎn)到與其搭配的#elseif,,繼續(xù)檢查$blue是否為true,,如果仍舊不是,則執(zhí)行與其對(duì)應(yīng)的#else代碼塊,。外部的判斷結(jié)果決定了內(nèi)部的結(jié)構(gòu)能否被執(zhí)行,。比如,如果最外層的#if結(jié)構(gòu)檢查$red的結(jié)果為true,,模板引擎將處理嵌套的第一個(gè)#if結(jié)構(gòu),,所有其他的內(nèi)置結(jié)構(gòu)將被忽略。

另外需要注意的是,,Velocity不支持多層嵌套,。

#if ( $red ) ## outer

#if ( $blue ) ## inner

Purple

#elseif ( $yellow ) ## inner

Orange

#else ## inner

Red and What?

#end ## inner

#elseif ( $blue ) ##outer

#if ( $yellow ) ## inner

Green

#else ## inner

Blue and What?

#end ## inner

#else ## outer

#if ( $yellow ) ## inner

We only mix yellow with red or blue

#end ## inner

#end ## outer

Listing 8.32 A template demonstrating the use of nested #if, #elseif, and #else directives.

#foreach

Velocity#foreach指令為模板設(shè)計(jì)者提供了多次重復(fù)處理相同模板代碼塊的能力。更精確一點(diǎn),,它提供了基于一個(gè)列表進(jìn)行反復(fù)處理的能力,,當(dāng)每次從列表里讀取一個(gè)列表成員時(shí)就對(duì)這個(gè)組合代碼塊進(jìn)行一次處理。#foreach指令放置在代碼塊的開(kāi)始處,,and as with the #if related directives,,#end放在代碼塊的末尾,。#foreach指令的語(yǔ)法形式為#foreach (REF in LIST)LIST對(duì)應(yīng)成員的列表,,REF對(duì)應(yīng)Velocity變量引用,,它引用了當(dāng)前的成員列表。模板引擎執(zhí)行#foreach指令聯(lián)合代碼塊的次數(shù)和LIST的大小相等,。每執(zhí)行一次重復(fù)時(shí),,REF成員的值依次從列表的第一成員到最后一個(gè)成員進(jìn)行更新。

在指定#foreach指令的LIST值時(shí),,有一些彈性,。Listing 8.33的模板示范了兩個(gè)比較簡(jiǎn)單的情況。第一種,,通過(guò)操作數(shù)范圍來(lái)提供LIST,,#foreach指令重復(fù)是基于列表1, 2, 3, 4, 5的。第二種,,通過(guò)數(shù)組列表來(lái)提供LIST,,#foreach指令重復(fù)是基于數(shù)組列表“one”, “two”, “three”, “four”, “five”的。其輸出結(jié)果見(jiàn)Listing 8.34,。

Iterating over a range...

#foreach ( $item in [1..5] )

On this iteration, "$item refers to the value $item.

#end

Iterating over an array list...

#foreach ( $item in ["one", "two", "three", "four", "five"] )

On this iteration, "$item refers to the value $item.

#end

Listing 8.33 A template demonstrating the use of #foreach directives.

Iterating over a range...

On this iteration, $item refers to the value 1.

On this iteration, $item refers to the value 2.

On this iteration, $item refers to the value 3.

On this iteration, $item refers to the value 4.

On this iteration, $item refers to the value 5.

Iterating over an array list...

On this iteration, $item refers to the value one.

On this iteration, $item refers to the value two.

On this iteration, $item refers to the value three.

On this iteration, $item refers to the value four.

On this iteration, $item refers to the value five.

Listing 8.34 Results from processing the template in Listing 8.33.

除了使用操作數(shù)范圍和數(shù)組列表為#foreach指令指定固定列表之外,,Velocity還允許你通過(guò)模板上下文來(lái)指定列表。為了使用上下文對(duì)象來(lái)為#foreach指令指定列表,,這個(gè)上下文對(duì)象必須是一個(gè)Java對(duì)象數(shù)組(Object[])或是一個(gè)實(shí)現(xiàn)了許多Java接口的對(duì)象,。這些允許的接口包括CollectionMap,、IteratorEnumeration,。Listing 8.35的模板包含了以上類型的示例,上下文封裝見(jiàn)Listing 8.36,,輸出結(jié)果見(jiàn)Listing 8.37,。

## Object Array

Iterating over Object array...

#foreach ( $elem in $objectArray ) The element is $elem on this iteration.

#end

## Map Interface

Iterating over Hashtable values...

#foreach ( $value in $hashtable ) The value is $value on this iteration.

#end

## Collection Interface

Iterating over Hashtable keys...

#foreach ( $key in $hashtable.keySet() ) The key is $key on this iteration.

#end

## Enumeration Interface

Iterating over Vector elements...

#foreach ( $elem in $vector.elements() ) The element is $elem on this iteration.

#end

## Iterator Interface

Iterating over LinkedList elements...

#foreach ( $elem in $linkedList.listIterator() ) The element is $elem on this iteration.

#end

Listing 8.35 A template demonstrating the use of the #foreach directive with lists taken from the context.

// Create and initialize context objects

Object[] objAr = new Object [3];

objAr[0] = "0";

objAr[1] = new Integer( 1 );

objAr[2] = "2";

Hashtable hash = new Hashtable();

hash.put( "A", new Integer( 65 ) );

hash.put( "B", new Integer( 66 ) );

hash.put( "C", new Integer( 67 ) );

Vector vec = new Vector();

vec.add( "Hickory" );

vec.add( "Dickory" );

vec.add( "Dock" );

LinkedList list = new LinkedList();

list.add( "Red" );

list.add( "Green" );

list.add( "Blue" );

// Populate context

context.put( "objectArray", objAr );

context.put( "hashtable", hash );

context.put( "vector", vec );

context.put( "linkedList", list );

Listing 8.36 Context population code used with the template in Listing 8.35 to generate the output shown in Listing 8.37.

Iterating over Object array...

The element is 0 on this iteration.

The element is 1 on this iteration.

The element is 2 on this iteration.

Iterating over Hashtable values...

The value is 65 on this iteration.

The value is 67 on this iteration.

The value is 66 on this iteration.

Iterating over Hashtable keys...

The key is A on this iteration.

The key is C on this iteration.

The key is B on this iteration.

Iterating over Vector elements...

The element is Hickory on this iteration.

The element is Dickory on this iteration.

The element is Dock on this iteration.

Iterating over LinkedList elements...

The element is Red on this iteration.

The element is Green on this iteration.

The element is Blue on this iteration.

Listing 8.37 Output generated by the template in Listing 8.35 when using the context defined in Listing 8.36.

正如你在Listing 8.37里所看到哈希表一樣,列表成員的次序和它們插入到列表的次序不必相同,。#foreach指令將按列表的次序,,依次從第一成員移動(dòng)到最后一個(gè)成員;然而,,它本身的次序?qū)⒂扇萜鱽?lái)決定,,當(dāng)在Java代碼里直接完成相同反復(fù)的類型時(shí),就是一樣的(just as it is

),。

在之前的示例里,,我們并沒(méi)有嘗試明確的區(qū)別反復(fù)(iteration),我們只讓當(dāng)前列表成員引用它本身(speak for itself)?然而,,了解和掌握反復(fù)(iteration)比較有用,,比如當(dāng)進(jìn)行標(biāo)簽輸出或在已確定反復(fù)的情況執(zhí)行特定行為時(shí)。雖然你可以使用#set指令來(lái)初始化和增加一個(gè)循環(huán)記數(shù)器,,但這樣的處理方式相當(dāng)乏味,。Velocity將忙于(address)處理這個(gè)問(wèn)題(issue)(通過(guò)提供一個(gè)特定的用作#foreach指令循環(huán)計(jì)數(shù)器的變量引用)。默認(rèn)情況下,,這個(gè)變量被命名為$velocityCount,,但是這個(gè)名字可能被Velocity的運(yùn)行時(shí)配置重載。Listing 8.38的模板提供了一個(gè)使用Velocity的內(nèi)置循環(huán)計(jì)數(shù)器的示例,。輸出結(jié)果見(jiàn)Listing 8.39,。

## Track the iteration with Velocity's loop counter

#foreach ( $outer in [-1..1] )

Iteration $velocityCount of outer loop: $outer

#foreach ( $inner in ["one", "two"] )

Iteration $velocityCount of inner loop: $inner

#end

#end

Listing 8.38 A template demonstrating the use of Velocity’s loop counter reference.

Iteration 1 of outer loop: -1

Iteration 1 of inner loop: one

Iteration 2 of inner loop: two

Iteration 2 of outer loop: 0

Iteration 1 of inner loop: one

Iteration 2 of inner loop: two

Iteration 3 of outer loop: 1

Iteration 1 of inner loop: one

Iteration 2 of inner loop: two

Listing 8.39 Results from processing the template in Listing 8.38.

除了進(jìn)行簡(jiǎn)單地示范Velocity的循環(huán)計(jì)數(shù)器之外,Listings 8.38 8.39突出了兩個(gè)#foreach指令的其他重要方面,。第一個(gè)方面是Velocity支持#foreach指令嵌套,;它也支持嵌套其他指令。第二個(gè)方面是循環(huán)計(jì)數(shù)器的作用域范圍是當(dāng)前#foreach指令,。事實(shí)上,,當(dāng)模板引擎從外面的#foreach指令移動(dòng)到一個(gè)內(nèi)部的#foreach指令時(shí),外圍#foreach指令的循環(huán)計(jì)數(shù)器被保存,,同時(shí),,一個(gè)為內(nèi)部#foreach指令計(jì)數(shù)新的計(jì)數(shù)器被初始化。當(dāng)控制返回到外部指令時(shí),,外部指令原來(lái)保存的計(jì)數(shù)器值被還原,。

#macro

Velocity#macro指令提供了一個(gè)模板代碼復(fù)用的機(jī)制。它和#parse指令的功能比較相似,,但#macro提供了更多的彈性和控制能力,。為了導(dǎo)入和處理所有的被任意文件包含的模板代碼,作為代替,,#macro指令提供了一個(gè)語(yǔ)法用一指定和命名一個(gè)模板代碼塊,包括對(duì)參數(shù)輸入的支持,。代碼塊可以在宏庫(kù)里指定,,也可在有秩序的模板文件里(inline in a regular template file)指定。一旦被定義,,這個(gè)代碼塊就可以通過(guò)普通的Velocity指令語(yǔ)法進(jìn)行訪問(wèn),。既然在Chapter 9里會(huì)介紹Velocity的宏(“Introducing Velocimacros”),并詳細(xì)介紹#macro指令,,那么在這里,,我們只作一個(gè)快速嘗試。Listing 8.40展示一個(gè)簡(jiǎn)單的示例,,它內(nèi)置(inline)了#macro指令,。在模板文件里定義了一個(gè)名稱為sayHi的宏,,并且用#sayHi()進(jìn)行調(diào)用。輸出結(jié)果為Hello world,。

## Define inline macro for this template

#macro( sayHi )

Hello world

#end

## Invoke the macro using normal directive syntax

#sayHi()

Listing 8.40 A template demonstrating the use of the #macro directive.

轉(zhuǎn)義/忽略指令(Escaping Directives)

有些時(shí)候,,我們需要阻止模板引擎停止處理一個(gè)指令。很明顯的例子就是我們?cè)谟懻?/span>Velocity模板語(yǔ)法時(shí)有關(guān)動(dòng)態(tài)內(nèi)容的各種情況,。在那種情況下,,需要經(jīng)常把指令當(dāng)作字符串對(duì)待,雖然外表看起來(lái)像Velocity的引用,,但我們只想把它當(dāng)作文本來(lái)處理,。作為Velocity的引用,這是通過(guò)使用反斜線(")換碼符來(lái)完成的,。事實(shí)上,,轉(zhuǎn)義處理指令從本質(zhì)上講同我們?cè)?/span>Chapter 7討論過(guò)的引用一樣,包括忽略換碼符(escape character),、和(放置引用/指令的地方與不需要定義)這兩種情況下的行為差異,。綁定召回(Recall that binding)是從左到右的,每一對(duì)換碼符被壓縮成單個(gè)反斜線,,雖然在指令(或宏)沒(méi)有定義的情況下,,這個(gè)行為稍微有點(diǎn)古怪。Listings 8.418.42提供了一個(gè)模板和相應(yīng)的輸出,。

## Valid directive

Output for valid directive with varying numbers of escapes.

#include( "info.txt" )

"#include( "info.txt" )

""#include( "info.txt" )

"""#include( "info.txt" )

""""#include( "info.txt" )

"""""#include( "info.txt" )

## Undefined directive/macro

Output for undefined directive/macro with varying numbers of escapes.

#xinclude( "info.txt" )

"#xinclude( "info.txt" )

""#xinclude( "info.txt" )

"""#xinclude( "info.txt" )

""""#xinclude( "info.txt" )

"""""#xinclude( "info.txt" )

Listing 8.41 A template demonstrating the use of directive escapes.

Output for valid directive with varying numbers of escapes.

Included information.

#include( "info.txt" )

"Included information.

"#include( "info.txt" )

""Included information.

""#include( "info.txt" )

Output for undefined directive/macro with varying numbers of escapes.

#xinclude( "info.txt" )

"#xinclude( "info.txt" )

""#xinclude( "info.txt" )

"""#xinclude( "info.txt" )

""#xinclude( "info.txt" )

"""""#xinclude( "info.txt" )

Listing 8.42 Results from processing the template in Listing 8.41.

本章小節(jié)和下章介紹

在本章里,,我們?cè)敿?xì)討論了Velocity指令,它極大地賦予模板設(shè)計(jì)者對(duì)模板進(jìn)行處理的能力,。我們提供了眾多的示例來(lái)示范如何使用這些指令來(lái)控制處理流程,、插入內(nèi)容、操作上下文和對(duì)模板代碼進(jìn)行重復(fù)使用,。我們只是暫時(shí)介紹了#macro指令,,我們將在下一章對(duì)這個(gè)指令進(jìn)行詳細(xì)介紹。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多