posts - 14, comments - 0, trackbacks - 0, articles - 0

2007年1月10日

1、快速入门

(1)模板 + 数据模型 = 输出
FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念。他们是分工劳动的:设计者专注于表示——创建HTML文件、图片、Web页面的其它可视化方面;程序员创建系统,生成设计页面要显示的数据。经常会遇到的问题是:在Web页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的。在这里,你可以在HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会在输出页面给最终用户时,用适当的数据替代这些代码。
下面是一个例子:

<html>
<head>
 <title>Welcome!</title>
</head>

<body>
 <h1>Welcome ${user}!</h1>
 <p>Our latest product:
 <a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>

</html>

这个例子是在简单的HTML中加入了一些由${…}包围的特定代码,这些特定代码是FreeMarker的指令,而包含FreeMarker的指令的文件就称为模板(Template)。至于user、latestProduct.url和latestProduct.name来自于数据模型(data model)。数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成。模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型
下面是一个可能的数据模型:

(root)
 |
 +- user = "Big Joe"
 |
 +- latestProduct
     |
     +- url = "products/greenmouse.html"
     |
     +- name = "green mouse"
数据模型类似于计算机的文件系统,latestProduct可以看作是目录,而user、url和name看作是文件,url和name文件位于latestProduct目录中(这只是一个比喻,实际并不存在)。当FreeMarker将上面的数据模型合并到模板中,就创建了下面的输出:

<html>
<head>
 <title>Welcome!</title>
</head>

<body>
 <h1>Welcome Big Joe!</h1>
 <p>Our latest product:
 <a href="products/greenmouse.html">green mouse</a>!
</body>

</html> 

(2)数据模型
典型的数据模型是树型结构,可以任意复杂和深层次,如下面的例子:

(root)
 |
 +- animals
 |   |
 |   +- mouse
 |   |   |  
 |   |   +- size = "small"
 |   |   |  
 |   |   +- price = 50
 |   |
 |   +- elephant
 |   |   |  
 |   |   +- size = "large"
 |   |   |  
 |   |   +- price = 5000
 |   |
 |   +- python
 |       |  
 |       +- size = "medium"
 |       |  
 |       +- price = 4999
 |
 +- test = "It is a test"
 |
 +- whatnot
     |
     +- because = "don't know"
类似于目录的变量称为hashes,包含保存下级变量的唯一的查询名字。类似于文件的变量称为scalars,保存单值scalars保存的值有两种类型:字符串(用引号括起,可以是单引号或双引号)和数字(不要用引号将数字括起,这会作为字符串处理)。对scalars的访问从root开始,各部分用“.”分隔,如animals.mouse.price。另外一种变量是sequences,和hashes类似,只是不使用变量名字,而使用数字索引,如下面的例子:

(root)
 |
 +- animals
 |   |
 |   +- (1st)
 |   |   |
 |   |   +- name = "mouse"
 |   |   |
 |   |   +- size = "small"
 |   |   |
 |   |   +- price = 50
 |   |
 |   +- (2nd)
 |   |   |
 |   |   +- name = "elephant"
 |   |   |
 |   |   +- size = "large"
 |   |   |
 |   |   +- price = 5000
 |   |
 |   +- (3rd)
 |       |
 |       +- name = "python"
 |       |
 |       +- size = "medium"
 |       |
 |       +- price = 4999
 |
 +- whatnot
     |
     +- fruits
         |
         +- (1st) = "orange"
         |
         +- (2nd) = "banana"
这种对scalars的访问使用索引,如animals[0].name

(3)模板
在FreeMarker模板中可以包括下面三种特定部分:

${…}:称为interpolations,FreeMarker会在输出时用实际值进行替代

FTL标记(FreeMarker模板语言标记):类似于HTML标记,为了与HTML标记区分,用#开始(有些以@开始,在后面叙述)

注释:包含在<#--和-->(而不是<!--和-->)之间
下面是一些使用指令的例子:

if指令

<#if animals.python.price < animals.elephant.price>
 Pythons are cheaper than elephants today.

<#else>
 Pythons are not cheaper than elephants today.

</#if> 

list指令

<p>We have these animals:

<table border=1>
 <tr><th>Name<th>Price
 <#list animals as being>
 <tr><td>${being.name}<td>${being.price} Euros
 </#list>

</table> 

输出为:

<p>We have these animals:

<table border=1>
 <tr><th>Name<th>Price
 <tr><td>mouse<td>50 Euros
 <tr><td>elephant<td>5000 Euros
 <tr><td>python<td>4999 Euros

</table> 

include指令

<html>

<head>
 <title>Test page</title>

</head>

<body>
 <h1>Test page</h1>
 <p>Blah blah...

<#include "/copyright_footer.html">

</body>

</html> 

一起使用指令

<p>We have these animals:

<table border=1>
 <tr><th>Name<th>Price
 <#list animals as being>
 <tr>
   <td>
     <#if being.size = "large"><b></#if>
     ${being.name}
     <#if being.size = "large"></b></#if>
   <td>${being.price} Euros
 </#list>

</table>

2、数据模型

(1)基础
在快速入门中介绍了在模板中使用的三种基本对象类型:scalars、hashes 和sequences,其实还可以有其它更多的能力:

scalars:存储单值

hashes:充当其它对象的容器,每个都关联一个唯一的查询名字

sequences:充当其它对象的容器,按次序访问

方法:通过传递的参数进行计算,以新对象返回结果

用户自定义FTL标记:宏和变换器
通常每个变量只具有上述的一种能力,但一个变量可以具有多个上述能力,如下面的例子:

(root)
|
+- mouse = "Yerri"
    |
    +- age = 12
    |
    +- color = "brown"> 
mouse既是scalars又是hashes,将上面的数据模型合并到下面的模板:

${mouse}       <#-- use mouse as scalar -->

${mouse.age}   <#-- use mouse as hash -->

${mouse.color} <#-- use mouse as hash --> 
输出结果是:

Yerri

12

brown 

(2)Scalar变量
Scalar变量存储单值,可以是:

字符串:简单文本,在模板中使用引号(单引号或双引号)括起

数字:在模板中直接使用数字值

日期:存储日期/时间相关的数据,可以是日期、时间或日期-时间(Timestamp);通常情况,日期值由程序员加到数据模型中,设计者只需要显示它们

布尔值:true或false,通常在<#if …>标记中使用

(3)hashes 、sequences和集合
有些变量不包含任何可显示的内容,而是作为容器包含其它变量,者有两种类型:

hashes:具有一个唯一的查询名字和它包含的每个变量相关联

sequences:使用数字和它包含的每个变量相关联,索引值从0开始
集合变量通常类似sequences,除非无法访问它的大小和不能使用索引来获得它的子变量;集合可以看作只能由<#list …>指令使用的受限sequences

(4)方法
方法变量通常是基于给出的参数计算值
下面的例子假设程序员已经将方法变量avg放到数据模型中,用来计算数字平均值:

The average of 3 and 5 is: ${avg(3, 5)}

The average of 6 and 10 and 20 is: ${avg(6, 10, 20)}

The average of the price of python and elephant is: ${avg(animals.python.price, animals.elephant.price)}

(5)宏和变换器
宏和变换器变量是用户自定义指令(自定义FTL标记),会在后面讲述这些高级特性

(6)节点
节点变量表示为树型结构中的一个节点,通常在XML处理中使用,会在后面的专门章节中讲述


3、模板

(1)整体结构
模板使用FTL(FreeMarker模板语言)编写,是下面各部分的一个组合:

文本:直接输出

Interpolation:由${和},或#{和}来限定,计算值替代输出

FTL标记:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出

注释:由<#--和-->限定,不会输出
下面是以一个具体模板例子:

<html>[BR]

<head>[BR]
 <title>Welcome!</title>[BR]

</head>[BR]

<body>[BR]
 <#-- Greet the user with his/her name -->[BR]
 <h1>Welcome ${user}!</h1>[BR]
 <p>We have these animals:[BR]
 <ul>[BR]
 <#list animals as being>[BR]
   <li>${being.name} for ${being.price} Euros[BR]
 </#list>[BR]
 </ul>[BR]

</body>[BR]

</html> 
[BR]是用于换行的特殊字符序列
注意事项:

FTL区分大小写,所以list是正确的FTL指令,而List不是;${name}和${NAME}是不同的

Interpolation只能在文本中使用

FTL标记不能位于另一个FTL标记内部,例如:

<#if <#include 'foo'>='bar'>...</if>

注释可以位于FTL标记和Interpolation内部,如下面的例子:

<h1>Welcome ${user <#-- The name of user -->}!</h1>[BR]

<p>We have these animals:[BR]

<ul>[BR]

<#list <#-- some comment... --> animals as <#-- again... --> being>[BR]

... 

多余的空白字符会在模板输出时移除

(2)指令
在FreeMarker中,使用FTL标记引用指令
有三种FTL标记,这和HTML标记是类似的:

开始标记:<#directivename parameters>

结束标记:</#directivename>

空内容指令标记:<#directivename parameters/>
有两种类型的指令:预定义指令和用户定义指令
用户定义指令要使用@替换#,如<@mydirective>...</@mydirective>(会在后面讲述)
FTL标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的:

<ul>

<#list animals as being>
 <li>${being.name} for ${being.price} Euros
 <#if use = "Big Joe">
    (except for you)

</#list>

</#if> <#-- WRONG! -->

</ul> 
如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息
FreeMarker会忽略FTL标记中的空白字符,如下面的例子:

<#list[BR]
 animals       as[BR]
    being[BR]

>[BR]

${being.name} for ${being.price} Euros[BR]

</#list    > 
但是,<、</和指令之间不允许有空白字符

(3)表达式
直接指定值

字符串

使用单引号或双引号限定

如果包含特殊字符需要转义,如下面的例子:

${"It's \"quoted\" and

this is a backslash: \\"}


${'It\'s "quoted" and

this is a backslash: \\'}

输出结果是:

It's "quoted" and

this is a backslash: \


It's "quoted" and

this is a backslash: \

下面是支持的转义序列:

转义序列
 

含义

\"
 

双引号(u0022)

\'
 

单引号(u0027)

\\
 

反斜杠(u005C)

\n
 

换行(u000A)

\r
 

Return (u000D)

\t
 

Tab (u0009)

\b
 

Backspace (u0008)

\f
 

Form feed (u000C)

\l
 

<

\g
 

>

\a
 

&

\{
 

{

\xCode
 

4位16进制Unicode代码

有一类特殊的字符串称为raw字符串,被认为是纯文本,其中的\和{等不具有特殊含义,该类字符串在引号前面加r,下面是一个例子:

${r"${foo}"}

${r"C:\foo\bar"} 

输出的结果是:

${foo}

C:\foo\bar 

数字

直接输入,不需要引号

精度数字使用“.”分隔,不能使用分组符号

目前版本不支持科学计数法,所以“1E3”是错误的

不能省略小数点前面的0,所以“.5”是错误的

数字8、+8、08和8.00都是相同的

布尔值

true和false,不使用引号

序列

由逗号分隔的子变量列表,由方括号限定,下面是一个例子:

<#list ["winter", "spring", "summer", "autumn"] as x>

${x}

</#list>

输出的结果是:

winter

spring

summer

autumn

列表的项目是表达式,所以可以有下面的例子:

[2 + 2, [1, 2, 3, 4], "whatnot"]

可以使用数字范围定义数字序列,例如2..5等同于[2, 3, 4, 5],但是更有效率,注意数字范围没有方括号

可以定义反递增的数字范围,如5..2

散列(hash)

由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔,下面是一个例子:

{"name":"green mouse", "price":150}

键和值都是表达式,但是键必须是字符串
获取变量

顶层变量: ${variable},变量名只能是字母、数字、下划线、$、@和#的组合,且不能以数字开头

从散列中获取数据

可以使用点语法或方括号语法,假设有下面的数据模型:

(root)
|
+- book
|   |
|   +- title = "Breeding green mouses"
|   |
|   +- author
|       |
|       +- name = "Julia Smith"
|       |
|       +- info = "Biologist, 1923-1985, Canada"
|
+- test = "title"

下面都是等价的:

book.author.name

book["author"].name

book.author.["name"]

book["author"]["name"]

使用点语法,变量名字有顶层变量一样的限制,但方括号语法没有该限制,因为名字是任意表达式的结果

从序列获得数据:和散列的方括号语法语法一样,只是方括号中的表达式值必须是数字;注意:第一个项目的索引是0

序列片断:使用[startIndex..endIndex]语法,从序列中获得序列片断(也是序列);startIndex和endIndex是结果为数字的表达式

特殊变量:FreeMarker内定义变量,使用.variablename语法访问


字符串操作

Interpolation(或连接操作)

可以使用${..}(或#{..})在文本部分插入表达式的值,例如:

${"Hello ${user}!"}

${"${user}${user}${user}${user}"} 

可以使用+操作符获得同样的结果

${"Hello " + user + "!"}

${user + user + user + user}

${..}只能用于文本部分,下面的代码是错误的:

<#if ${isBig}>Wow!</#if>

<#if "${isBig}">Wow!</#if>

应该写成:

<#if isBig>Wow!</#if>

子串

例子(假设user的值为“Big Joe”):

${user[0]}${user[4]}

${user[1..4]}

结果是(注意第一个字符的索引是0):

BJ

ig J
序列操作

连接操作:和字符串一样,使用+,下面是一个例子:

<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>

- ${user}

</#list>

输出结果是:

- Joe

- Fred

- Julia

- Kate
散列操作

连接操作:和字符串一样,使用+,如果具有相同的key,右边的值替代左边的值,例如:

<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>

- Joe is ${ages.Joe}

- Fred is ${ages.Fred}

- Julia is ${ages.Julia} 

输出结果是:

- Joe is 30

- Fred is 25

- Julia is 18 
算术运算

+、-、×、/、%,下面是一个例子:

${x * x - 100}

${x / 2}

${12 % 10}

输出结果是(假设x为5):

-75

2.5

操作符两边必须是数字,因此下面的代码是错误的:

${3 * "5"} <#-- WRONG! --> 

使用+操作符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串,例如:

${3 + "5"} 

输出结果是:

35

使用内建的int(后面讲述)获得整数部分,例如:

${(x/2)?int}

${1.1?int}

${1.999?int}

${-1.1?int}

${-1.999?int}

输出结果是(假设x为5):

2

1

1

-1

-1
比较操作符

使用=(或==,完全相等)测试两个值是否相等,使用!= 测试两个值是否不相等

=和!=两边必须是相同类型的值,否则会产生错误,例如<#if 1 = "1">会引起错误

Freemarker是精确比较,所以对"x"、"x  "和"X"是不相等的

对数字和日期可以使用<、<=、>和>=,但不能用于字符串

由于Freemarker会将>解释成FTL标记的结束字符,所以对于>和>=可以使用括号来避免这种情况,例如<#if (x > y)>

另一种替代的方法是,使用lt、lte、gt和gte来替代<、<=、>和>=
逻辑操作符

&&(and)、||(or)、!(not),只能用于布尔值,否则会产生错误

例子:

<#if x < 12 && color = "green">
 We have less than 12 things, and they are green.

</#if>

<#if !hot> <#-- here hot must be a boolean -->
 It's not hot.

</#if> 
内建函数

内建函数的用法类似访问散列的子变量,只是使用“?”替代“.”,下面列出常用的一些函数

字符串使用的:

html:对字符串进行HTML编码

cap_first:使字符串第一个字母大写

lower_case:将字符串转换成小写

upper_case:将字符串转换成大写

trim:去掉字符串前后的空白字符

序列使用的:

size:获得序列中元素的数目

数字使用的:

int:取得数字的整数部分(如-1.9?int的结果是-1)

例子(假设test保存字符串"Tom & Jerry"):

${test?html}

${test?upper_case?html}

输出结果是:

Tom &amp; Jerry

TOM &amp; JERRY 
操作符优先顺序

操作符组
 

操作符

后缀
 

[subvarName] [subStringRange] . (methodParams)

一元
 

+expr、-expr、!

内建
 

?

乘法
 

*、 / 、%

加法
 

+、-

关系
 

<、>、<=、>=(lt、lte、gt、gte)

相等
 

==(=)、!=

逻辑and
 

&&

逻辑or
 

||

数字范围
 

..

(4)Interpolation
Interpolation有两种类型:

通用Interpolation:${expr}

数字Interpolation:#{expr}或#{expr; format}
注意:Interpolation只能用于文本部分
通用Interpolation

插入字符串值:直接输出表达式结果

插入数字值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子:

<#setting number_format="currency"/>

<#assign answer=42/>

${answer}

${answer?string}  <#-- the same as ${answer} -->

${answer?string.number}

${answer?string.currency}

${answer?string.percent}

输出结果是:

$42.00

$42.00

42

$42.00

4,200%

插入日期值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个使用格式模式的例子:

${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}

${lastUpdated?string("EEE, MMM d, ''yy")}

${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")} 

输出的结果类似下面的格式:

2003-04-08 21:24:44 Pacific Daylight Time

Tue, Apr 8, '03

Tuesday, April 08, 2003, 09:24:44 PM (PDT)

插入布尔值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子:

<#assign foo=true/>

${foo?string("yes", "no")}

输出结果是:

yes
数字Interpolation的#{expr; format}形式可以用来格式化数字,format可以是:

mX:小数部分最小X位

MX:小数部分最大X位

例子:
          <#-- If the language is US English the output is: -->

<#assign x=2.582/>

<#assign y=4/>

#{x; M2}   <#-- 2.58 -->

#{y; M2}   <#-- 4    -->

#{x; m1}   <#-- 2.6 -->

#{y; m1}   <#-- 4.0 -->

#{x; m1M2} <#-- 2.58 -->

#{y; m1M2} <#-- 4.0  --> 


4、杂项

(1)用户定义指令
宏和变换器变量是两种不同类型的用户定义指令,它们之间的区别是宏是在模板中使用macro指令定义,而变换器是在模板外由程序定义,这里只介绍宏
基本用法

宏是和某个变量关联的模板片断,以便在模板中通过用户定义指令使用该变量,下面是一个例子:

<#macro greet>
 <font size="+2">Hello Joe!</font>

</#macro> 

作为用户定义指令使用宏变量时,使用@替代FTL标记中的#

<@greet></@greet>

如果没有体内容,也可以使用:

<@greet/>
参数

在macro指令中可以在宏变量之后定义参数,如:

<#macro greet person>
 <font size="+2">Hello ${person}!</font>

</#macro>

可以这样使用这个宏变量:

<@greet person="Fred"/> and <@greet person="Batman"/>

输出结果是:
 <font size="+2">Hello Fred!</font>
and   <font size="+2">Hello Batman!</font>
 

宏的参数是FTL表达式,所以下面的代码具有不同的意思:

<@greet person=Fred/>

这意味着将Fred变量的值传给person参数,该值不仅是字符串,还可以是其它类型,甚至是复杂的表达式

宏可以有多参数,下面是一个例子:

<#macro greet person color>
 <font size="+2" color="${color}">Hello ${person}!</font>

</#macro>

可以这样使用该宏变量:

<@greet person="Fred" color="black"/>

其中参数的次序是无关的,因此下面是等价的:

<@greet color="black" person="Fred"/>

只能使用在macro指令中定义的参数,并且对所有参数赋值,所以下面的代码是错误的:

<@greet person="Fred" color="black" background="green"/>

<@greet person="Fred"/>

可以在定义参数时指定缺省值,如:

<#macro greet person color="black">
 <font size="+2" color="${color}">Hello ${person}!</font>

</#macro> 

这样<@greet person="Fred"/>就正确了

宏的参数是局部变量,只能在宏定义中有效
嵌套内容

用户定义指令可以有嵌套内容,使用<#nested>指令执行指令开始和结束标记之间的模板片断

例子:

<#macro border>
 <table border=4 cellspacing=0 cellpadding=4><tr><td>
   <#nested>
 </tr></td></table>

</#macro> 

这样使用该宏变量:

<@border>The bordered text</@border>

输出结果:
 <table border=4 cellspacing=0 cellpadding=4><tr><td>
   The bordered text
 </tr></td></table>
 

<#nested>指令可以被多次调用,例如:

<#macro do_thrice>
 <#nested>
 <#nested>
 <#nested>

</#macro>

<@do_thrice>
 Anything.

</@do_thrice

输出结果:
 Anything.
 Anything.
 Anything.

嵌套内容可以是有效的FTL,下面是一个有些复杂的例子:

<@border>
 <ul>
 <@do_thrice>
   <li><@greet person="Joe"/>
 </@do_thrice>
 </ul>

</@border>

输出结果:
 <table border=4 cellspacing=0 cellpadding=4><tr><td>
     <ul>
   <li><font size="+2">Hello Joe!</font>

   <li><font size="+2">Hello Joe!</font>

   <li><font size="+2">Hello Joe!</font>

 </ul>

 </tr></td></table> 

宏定义中的局部变量对嵌套内容是不可见的,例如:

<#macro repeat count>
 <#local y = "test">
 <#list 1..count as x>
   ${y} ${count}/${x}: <#nested>
 </#list>

</#macro>

<@repeat count=3>${y?default("?")} ${x?default("?")} ${count?default("?")}</@repeat>

输出结果:
   test 3/1: ? ? ?
   test 3/2: ? ? ?
   test 3/3: ? ? ?

在宏定义中使用循环变量

用户定义指令可以有循环变量,通常用于重复嵌套内容,基本用法是:作为nested指令的参数传递循环变量的实际值,而在调用用户定义指令时,在<@…>开始标记的参数后面指定循环变量的名字

例子:

<#macro repeat count>
 <#list 1..count as x>
   <#nested x, x/2, x==count>
 </#list>

</#macro>

<@repeat count=4 ; c, halfc, last>
 ${c}. ${halfc}<#if last> Last!</#if>

</@repeat

输出结果:
 1. 0.5
 2. 1
 3. 1.5
 4. 2 Last!
 

指定的循环变量的数目和用户定义指令开始标记指定的不同不会有问题

调用时少指定循环变量,则多指定的值不可见

调用时多指定循环变量,多余的循环变量不会被创建

(2)在模板中定义变量
在模板中定义的变量有三种类型:

plain变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换

局部变量:在宏定义体中有效,使用local指令创建和替换

循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建;宏的参数是局部变量,而不是循环变量
局部变量隐藏(而不是覆盖)同名的plain变量;循环变量隐藏同名的局部变量和plain变量,下面是一个例子:

<#assign x = "plain">

1. ${x}  <#-- we see the plain var. here -->

<@test/>

6. ${x}  <#-- the value of plain var. was not changed -->

<#list ["loop"] as x>
   7. ${x}  <#-- now the loop var. hides the plain var. -->
   <#assign x = "plain2"> <#-- replace the plain var, hiding does not mater here -->
   8. ${x}  <#-- it still hides the plain var. -->

</#list>

9. ${x}  <#-- the new value of plain var. -->


<#macro test>
 2. ${x}  <#-- we still see the plain var. here -->
 <#local x = "local">
 3. ${x}  <#-- now the local var. hides it -->
 <#list ["loop"] as x>
   4. ${x}  <#-- now the loop var. hides the local var. -->
 </#list>
 5. ${x}  <#-- now we see the local var. again -->

</#macro> 

输出结果:

1. plain
 2. plain
 3. local
   4. loop
 5. local

6. plain
   7. loop
   8. loop

9. plain2

内部循环变量隐藏同名的外部循环变量,如:

<#list ["loop 1"] as x>
 ${x}
 <#list ["loop 2"] as x>
   ${x}
   <#list ["loop 3"] as x>
     ${x}
   </#list>
   ${x}
 </#list>
 ${x}

</#list>

输出结果:
 loop 1
   loop 2
     loop 3
   loop 2
 loop 1
模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用特殊变量global,下面的例子假设数据模型中的user的值是Big Joe:

<#assign user = "Joe Hider">

${user}          <#-- prints: Joe Hider -->

${.globals.user} <#-- prints: Big Joe --> 

(3)名字空间
通常情况,只使用一个名字空间,称为主名字空间
为了创建可重用的宏、变换器或其它变量的集合(通常称库),必须使用多名字空间,其目的是防止同名冲突
创建库

下面是一个创建库的例子(假设保存在lib/my_test.ftl中):

<#macro copyright date>
 <p>Copyright (C) ${date} Julia Smith. All rights reserved.
 <br>Email: ${mail}</p>

</#macro> 

<#assign mail = "jsmith@acme.com">

使用import指令导入库到模板中,Freemarker会为导入的库创建新的名字空间,并可以通过import指令中指定的散列变量访问库中的变量:

<#import "/lib/my_test.ftl" as my>

<#assign mail="fred@acme.com">

<@my.copyright date="1999-2002"/>

${my.mail}

${mail} 

输出结果:
 <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
 <br>Email: jsmith@acme.com</p>

jsmith@acme.com

fred@acme.com 

可以看到例子中使用的两个同名变量并没有冲突,因为它们位于不同的名字空间
可以使用assign指令在导入的名字空间中创建或替代变量,下面是一个例子:

<#import "/lib/my_test.ftl" as my>

${my.mail}

<#assign mail="jsmith@other.com" in my>

${my.mail} 
输出结果:

jsmith@acme.com

jsmith@other.com 
数据模型中的变量任何地方都可见,也包括不同的名字空间,下面是修改的库:

<#macro copyright date>
 <p>Copyright (C) ${date} ${user}. All rights reserved.</p>

</#macro>

<#assign mail = "${user}@acme.com">  
假设数据模型中的user变量的值是Fred,则下面的代码:

<#import "/lib/my_test.ftl" as my>

<@my.copyright date="1999-2002"/>

${my.mail}  
输出结果:
 <p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>

posted @ 2007-01-11 00:33 忆了又忆| 编辑 收藏

你想使用FreeMarker做的最后一件事是将表单域绑定到命令属性中。在第8章中,你使用JSP的 <spring:bind> 标签,而在第9.1.6节中,你是使用#springBind Velocity宏来实现这一点的。类似地,Spring提供了一组FreeMarker宏来进行这种绑定。

等价的FreeMarker宏是< @spring.bind>和<@spring.bindEscaped>。例如,程序清单9.4节选了 registerStudent.ftl中的一段,演示了如何使用<@spring.bind>指令将status信息绑定到表单中。

 程序清单9.4  在FreeMarker模板中使用<@spring.bind>
<@spring.bind "command.phone" />

  phone: <input type="text"

      name="${spring.status.expression}"

      value="${spring.status.value}">

  <font color="#FF0000">${spring.status.errorMessage}</font><br>

<@spring.bind "command.email" />

      email: <input type="text"

      name="${spring.status.expression}"

      value="${spring.status.value}">

  <font color="#FF0000">${spring.status.errorMessage}</font><br>

你可能已经注意到程序清单9.4和程序清单9.2非常相像。但这里有两个不同。首先,FreeMarker版中不是使用Velocity的#springBind宏,而是使用< @spring.bind>指令。其次,<@spring.bind>将状态信息绑定到${spring.status}而不是$ {status}。

正如Sping的Velocity宏,为了使用这些宏,必须设置FreeMarkerViewResolver的exposeMacroHelpers属性为true:

 

  <bean id="viewResolver" class="org.springframework.

          ➥web.servlet.view.freemarker.FreeMarkerViewResolver">

  …

    <property name="exposeSpringMacroHelpers">

      <value>true</value>

    </property>

  </bean>

 

最后,你还需要做一件事才能使用FreeMarker宏。在所有需要使用<@spring.bind>和<@spring.bindEscaped>的FreeMarker模板的顶部增加以下一行:

 

  <#import "/spring.ftl" as spring />

 

这一行会在模板中导入Spring的FreeMarker宏。

posted @ 2007-01-11 00:04 忆了又忆| 编辑 收藏

This is an attempt to put together a comprehensive reference for using Cascading Style Sheets with the Google Web Toolkit. I’ve assembled this document by first starting with the official documentation and then reviewing the source code. Where the source disagreed with the documentation I’ve sided with the source. I then did a runtime analysis of the sample applications that ship with the SDK to verify the results.

I feel there is a need for this because the documentation that comes with the SDK is rather unhelpful. The SDK says, basically, that widget styles are conventionally named [project]-[widget], e.g., gwt-Button, and style names correspond to CSS class names, so in order to style your button you would include something like

.gwt-Button { font-size: 150%; }
				

in your stylesheet. And that’s all it says. Really.

I believe this documentation to be inadequate for a number of reasons.

  1. The style is almost never as simple as the button example. Many GWT widgets correspond to messy nested tables, divs, and spans so it can be hard to know what it is you’re actually styling and what options are available to you in that context.
  2. The naming rule is not applied consistently within the SDK. The DialogBox class, for one, does not follow the rule.
  3. In some situations similarly named styles (*-selected*) are used in different or even contradictory manners making it hard to generalize your experience from one widget to another.
  4. In many cases the documentation is incorrect; the documented style simply is not implemented. The ListBox class should, according to both the general rule above and the specific class documentation, implement a style named gwt-ListBox. Nope, not there. Grep the source directory if you don’t believe me.

If I’ve left out a class below, it’s probably because it doesn’t participate in styling in any way. (I hope.) If you’re trying to read this straight through instead of just jumping to an item of interest, more power to you. If you find yourself yawning you might want to skip around a bit.

With that said…

AbsolutePanel

Implemented as a DIV and by default sets overflow to hidden. Contents are positioned absolutely according to given x, y values unless x == -1 and y == -1 in which case the widget is positioned statically.

<div style="overflow: hidden;"></div>
				

Button

Implemented as HTML BUTTON. Default style name is gwt-Button and is used. No default attributes. Can contain text or HTML.

<button class="gwt-Button" />
				

CellPanel

Implemented as a TABLE. No default styles. Can set border and cell-spacing attributes.

<table>
</table>
				

CheckBox

Implemented as HTML CHECKBOX. Default style name is gwt-CheckBox and is used. Automatically generates unique id of the form checkN where N is an integer. Uses checked, defaultChecked, and disabled attributes. No default styles.

<checkbox class="gwt-CheckBox" />
				

DeckPanel

Implemented using a DIV containing any number of children. The visibility of the individual children are controlled using the display attribute. The DeckPanel sets display to 'none' or '' as appropriate.

<div style="width: 100%; height: 100%"></div>
				

DialogBox

Default style names are gwt-DialogBox and Caption and are both used. Implemented as a DIV and the caption is also a DIV. (Technically, the caption is an HTML, which is a Label, which is implemented using a DIV.)

<div class="gwt-DialogBox">
  <table cell-spacing="0" cell-padding="0">
    <tbody>
      <tr>
      <td><div class="Caption">caption</div></td> </tr> <tr> <td> content </td> </tr> </tbody> </table> </div>

DockPanel

Implemented using TABLE. cell-spacing and cell-padding attributes both default to 0. Nesting of TR and TD elements can get quite complicated in order to achieve desired layout.

<table cell-spacing="0" cell-padding="0">
  <tbody>
  </tbody>
</table>
				

FlexTable

Just a TABLE, there’s nothing funky going on here.

<table>
  <tbody>
  </tbody>
</table>
				

FlowPanel

Implemented as a DIV with display set to inline.

<div style="display: inline;">content</div>
				

FocusPanel

A DIV. FocusPanel is only important in that it publishes a number of events (FOCUSEVENTS, KEYEVENTS, ONCLICK, and MOUSEEVENTS) and is very useful for containing widgets that don’t publish their own events. See Drag-and-Drop with the Google Web Toolkit.

<div>
  content
</div>
				

FocusWidget

Can be anything because it is implemented using whatever element is passed to it in the constructor. Interesting because it generates FOCUSEVENTS and KEYEVENTS.

Frame

Implemented as an IFRAME. Documented style name of gwt-Frame is not implemented.

<iframe>
</iframe>
				

Grid

Is just a table.

<table>
  <tbody>
  </tbody>
</table>
				

HTML

Implemented as a DIV with default style name of gwt-HTML. Can also set attribute white-space to normal or nowrap.

<div class="gwt-HTML">html</div>
				

HTMLPanel

Is a DIV that can either contain HTML exactly as HTMLor a collection of widgets. Does not use the gwt-HTML style. The most useful attribute of an HTMLPanel is that it contains the method createUniqueId that returns an id of the form HTMLPanel_N that can be used to apply styles to specific elements, as opposed to classes.

Contrast this with CheckBox which generates ids of the form checkN without either the capitalization or the underscore. Not a bug, just another minor inconsistency.

<div>
  content
</div>
				

HTMLTable

Unsurprisingly this class is implemented as a TABLE. The most important things to know about HTMLTable are (a) that it is the superclass for both FlexTable and Grid and (b) that it provides methods for setting the styles of individual rows or cells.

It is also worth noting that HTMLTable does not include a THEAD. The 0th row therefore must be used as something of a pseudo-header by applying any necessary styles.

<table>
  <tbody>
    <tr>Row 0 -- if you want a header you have to fake it here.</tr>
  </tbody>
</table>
				
// Style the first row to fake a header.
table.getRowFormatter(0).setStyleName("something-interesting");
				

HorizontalPanel

Implemented using a TABLE with all elements laid out as TDs in a single TR.

<table cell-spacing="0" cell-padding="0">
  <tbody>
    <tr>
      <td style="display: static; vertical-align: top;" align="left">Item 1</td>
      <td style="display: static; vertical-align: top;" align="left">Item 2</td>
    </tr>
  </tbody>
</table>
				

HyperLink

A DIV containing an anchor. Documented style name gwt-HyperLink is not implemented.

<div></div>
				

Image

Implemented as IMG. Documented style of gwt-Image is not implemented.

<img src="..." />
				

Label

Label is implemented as a DIV with a default style name of gwt-Label. Labels do not interpret their content as HTML and by default allow word-wrap. If you want to use HTML content in your label then you should use an instance of HTML. Both classes provide MOUSEEVENTS.

You can change the default word-wrap by calling the setWordWrap method.

<div class="gwt-Label">your text here</div>
				

ListBox

Implemented using SELECT with OPTION for elements. Documented style name gwt-ListBox is not implemented. Uses attributes selected, size, and multiple as part of implementation.

MenuBar

Implemented as a DIV containing a TABLE with menu items contained in TD elements. A horizontal MenuBar contains all menu items as children of a single TR and a vertical MenuBar uses a separate TR for each item. Simple enough. The documented style name of gwt-MenuBar is used and applied to the outer DIV.

<div class="gwt-MenuBar">
  <table>
    <tbody>
      
      <tr>
        <td class="gwt-MenuItem">text or html</td>
        <td class="gwt-MenuItem">text or html</td>
      </tr>
      <!-- example of a vertical menu
        <tr><td class="gwt-MenuItem">text or html</td></tr>
        <tr><td class="gwt-MenuItem">text or html</td></tr>
      -->
    </tbody>
  </table>
</div>
				

MenuItem

A MenuItem is a TD that can be inserted into a MenuBar. The default style name is gwt-MenuItem. A selected MenuItem has the additional style name of gwt-MenuItem-selected. I want to emphasize that the selected style is added to the default style, so that class="gwt-MenuItem" becomes class="gwt-MenuItem gwt-MenuItem-selected". This is not the case with all widgets and is another minor inconsistency in the GWT style design. See StackPanel for an example of the opposite behavior.

PasswordTextBox

Implemented as PASSWORD. Uses gwt-PasswordTextBox.

PopupPanel

Just a DIV.

RadioButton

Implemented as an instance of INPUT. Uses gwt-RadioButton.

RootPanel

A RootPanel can be attached to any element, but it will discard all children previously belonging to that element. If you stop to think about it, this can be useful in contexts outside of your application init.

ScrollPanel

A DIV with overflow set to scroll or auto. Defaults to auto.

<div style="overflow: auto;">
  content
</div>
				

SimplePanel

Just a DIV.

StackPanel

Implemented as a TABLE with 2 rows per item. In each pair of rows the first contains the caption and the second contains the corresponding widget. By default the TABLE is styled with gwt-StackPanel. The captions are styled with gwt-StackPanelItem and gwt-StackPanelItem-selected. When an item is selected the caption’s unselected style gwt-StackPanelItem is replaced with gwt-StackPanelItem-selected. Not all widgets behave this way. See MenuItem for an example of the opposite behavior.

<table class="gwt-StackPanel" cell-spacing="0" cell-padding="0">
  <tbody>
    
    <tr>
      <td class="gwt-StackPanelItem" height="1px">text/html</td>
    </tr>
    <tr>
      <td height="100%" valign="top">
        content -- a widget
      </td>
    </tr>
  </tbody>
</table>
				

TabBar

A TabBar is implemented using a HorizontalPanel so it is effectively a TABLE. The style name gwt-TabBar applies to the TABLE — that is, to the actual tabs. The style gwt-TabBarFirst applies to the first (effectively empty) HTML widget and is only useful for creating some sort of left border effect. The style gwt-TabBarRest applies to that part of the TabBar following the tabs.

When a tab is selected the style gwt-TabBarItem-selected gets added to the existing style. This behavior is like that of MenuItem but opposite that of StackPanel.

<table class="gwt-TabBar" cell-spacing="0" cell-padding="0">
  <tbody>
    <tr>
      <td class="gwt-TabBarFirst" style="height: 100%;"><div class="gwt-HTML" style="height: 100%;">&amp;nbsp;</div></td>
      <td>Tab #1</td>
      <td>Tab #2</td>
      <td class="gwt-TabBarRest" style="width: 100%;"><div class="gwt-HTML" style="height: 100%;">&amp;nbsp;</div></td>
    </tr>
  </tbody>
</table>
				

TabPanel

Implemented as a VerticalPanel containing a TabBar and a DeckPanel. In other words, it’s a bunch of nested tables. The style gwt-TabPanel applies to the top-level TABLE, gwt-TabBar still applies to the contained TABLE implementing the TabBar, and gwt-TabPanelBottom styles the DIV containing the actual content.

Note that the TabBar gets the added default style of width: 100%. This ensures that the TabBar is as wide as the content panel and is the reason the gwt-TabBarRest style is important. It’s all about how you want that empty space to look.

<table class="gwt-TabPanel" cell-spacing="0" cell-padding="0">
  <tbody>
    <tr>
      <td>
        
        <table class="gwt-TabBar" style="width: 100%;" cell-spacing="0" cell-padding="0">
          <tbody>
            <tr>
              <td class="gwt-TabBarFirst" style="height: 100%;"><div class="gwt-HTML" style="height: 100%;">&amp;nbsp;</div></td>
	      
              <td class="gwt-TabBarRest" style="width: 100%;"><div class="gwt-HTML" style="height: 100%;">&amp;nbsp;</div></td>
            </tr>
          </tbody>
        </table>
      </td>
    </tr>
    <tr>
      <td>
        <div class="gwt-TabPanelBottom">
	  
	</div>
      </td>
    </tr>
  </tbody>
</table>
				

TextArea

Implemented as a TEXTAREA with a default style of gwt-TextArea.

TextBox

<input type="text" class="gwt-TextBox" />
				

Tree

Implemented as a DIV containing nested TreeItems. The style name gwt-Tree applies to the DIV and the style overflow defaults to auto.

<div class="gwt-Tree" style="overflow: auto;">
  
  <div style="position: relative; margin-left: 16;" (handle)>
    <table>
      <tr>
        <td></td>
        <td></td>
      </tr>
    </table>
    
  </div>
</div>
				

TreeItem

Implemented as a TABLE nested within a DIV. The styles gwt-TreeItem and gwt-TreeItem-selected apply to the nested content element, a SPAN. The selected state gwt-TreeItem-selectedreplaces the unselected state gwt-TreeItem, like StackPanel but unlike MenuItem or TabBar.

<div style="position: relative; margin-left: 16; white-space: nowrap" (handle)>
  <table style="white-space: nowrap;">
    <tr>
      <td style="vertical-align: middle;"><img src="tree_white.gif" /></td>
      <td style="vertical-align: middle;">content</td>
    </tr>
  </table>
  children
</div>
				

VerticalPanel

Implemented using a TABLE with all elements laid out as TRs.

<table cell-spacing="0" cell-padding="0">
  <tbody>
    <tr><td style="display: static; vertical-align: top;" align="left">Item 1</td></tr>
    <tr><td style="display: static; vertical-align: top;" align="left">Item 2</td></tr>
  </tbody>
</table>
				

posted @ 2007-01-10 17:08 忆了又忆| 编辑 收藏

在Oracle9i Rlease2中,Oracle的全文检索技术被称为:Oracle Text,功能十分强大。Oracle Text是Oracle9i采用的新名称,在Oracle8/8i中它被称作Oracle interMedia Text,在Oracle8以前它的名称是Oracle ConText Cartridge。
Oracle Text组件可以在安装数据库的时候选择,缺省是安装的,如果没有安装,那么可以按照以下方式手动安装Oracle Text。
1.创建存储表空间

$ sqlplus "/ as sysdba"

SQL*Plus: Release 9.2.0.4.0 - Production on Sun May 15 19:54:48 2005

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

SQL> select name from v$datafile;

NAME
--------------------------------------------------------------------------------
/h2love/oracle/system01.dbf
/h2love/oracle/undotbs01.dbf
/h2love/oracle/users01.dbf
...

9 rows selected.

SQL> create tablespace oratext
  2  datafile '/h2love/oracle/oratext01.dbf' size 100m
  3  extent management local uniform size 128k
  4  ;     

Tablespace created.


2.创建相关对象
SQL> spool text.log
SQL> connect sys/oracleHURRAY as sysdba
Connected.
SQL> start ?/ctx/admin/dr0csys password oratext temp
...creating user CTXSYS
...creating role CTXAPP
SQL> connect ctxsys/password
Connected.
SQL> start ?/ctx/admin/dr0inst ?/ctx/lib/libctxx9.so
==============  ConText Database Objects Installation ==============

This script must be run as CTXSYS.  This script will exit
below if run as any other user.

User is CTXSYS
... creating tables and Oracle object types
... creating table dr$parameter
... creating table dr$class
... creating table dr$object
... creating table dr$object_attribute
... creating table dr$object_attribute_lov
... creating table dr$preference
... creating table dr$preference_value
... creating table dr$index
... creating table dr$index_partition
... creating table dr$index_value
... creating table dr$policy_tab
... creating table dr$sqe
... creating table dr$ths
... creating table dr$ths_phrase
... creating table dr$ths_fphrase
... creating table dr$ths_bt
... creating table dr$section_group
... creating table dr$section
... creating table dr$stoplist
... creating table dr$stopword
... creating table dr$sub_lexer
... creating table dr$index_set
... creating table dr$index_set_index
... creating table dr$server
... creating table dr$pending
... creating table dr$waiting
... creating table dr$online_pending
... creating table dr$delete
... creating table dr$unindexed
... creating table dr$index_error
... creating table dr$parallel
... creating table dr$stats
... creating table dr$part_stats
... creating named data type ctx_feedback_item_type
... creating named data type ctx_feedback_type
... creating safe callout library
... creating CONTEXT interface
drop public synonym contains


这样就完成了手工安装全文检索工具。

posted @ 2007-01-10 13:54 忆了又忆| 编辑 收藏

查询文本不同于查询数据,因为有同义词、近义词和反义词。你可能希望搜索互相接近的词或搜索相关联的词。如果仅使用标准的关系操作符,要进行这些查询是非常困难的。通过SQL进行扩充,使其包含文本索引,则ORACLE TEXT允许用户就文本提出非常复杂的问题。
文本索引主要有两种CONTEXT和CTXCAT

用如下方式建立索引
CREATE INDEX REVIEW_CONTEXT_INDEX ON BOOK_REVIEW_CONTEXT(REVIEW_TEXT) INDEXTYPE IS CTXSYS.CONTEXT;

CREATE INDEX REVIEW_CTXCAT_INDEX ON BOOK_REVIEW_CTXCAT(REVIEW_TEXT) INDEXTYPE IS CTXSYS.CTXCAT;

建立好索引后就可以进行文本查询
select title from book_review_context where contains(review_text,'property')>0
CONTAINS函数有两个参数即列名和搜索串,它检查review_text列的文本索引。如果在review_text列的文本索引中找到单词'property'则数据库返回的得分大于0,并返回匹配的TITLE值。

如果建立的是CTXCAT索引就用CATSEARCH函数
select title from book_review_ctxcat where catsearch(review_text,'property',null)>0;

可使用的文本查询表达式有以下几种:
1。单词的精确匹配搜索
select title from book_review_context where contains(review_text,'property')>0
2。多个单词精确匹配的搜索
可以使用AND连接多个单词
select title from book_review_context where contains(review_text,'property and harvests')>0
还可以使用&但是在SQLPLUS里必须执行set define off否则&将被视作变量
set define off
select title from book_review_context where contains(review_text,'property & harvests')>0
对于CTXCAT索引AND完全可以省略
select title from book_review_ctxcat where catsearch(review_text,'property harvests',null)>0;
除AND外还可以使用OR运算符在ORACLE TEXT中OR是一根竖线(|)
因此下面的两个查询是等同的
select title from book_review_context where contains(review_text,'property or harvests')>0

select title from book_review_context where contains(review_text,'property | harvests')>0
但是要注意CATSEARCH函数不支持OR只支持‘|’符号;
ACCUM(累加)提供了另一种组合搜索的方法。等价于逗号,所以下面的两个查询是等价的
select title from book_review_context where contains(review_text,'property accum harvests')>0
select title from book_review_context where contains(review_text,'property , harvests')>0
但是CATSEARCH函数调用支持ACCUM语法但不应该使用,因为CATSEARCH不计算用来与阀值进行比较的得分;
MINUS运算符从第一项搜索的得分中减去第二项搜索的得分等价于减号,所以下面的两个查询是等价的
select title from book_review_context where contains(review_text,'property minus harvests')>0
select title from book_review_context where contains(review_text,'property - harvests')>0
可以用圆括号来阐明搜索条件内的逻辑
select title from book_review_context where contains(review_text,'house or (workers and harvests')>0
3。短语精确匹配的搜索
在进行短语搜索的时候应将整个短语作为搜索串的一部分
select title from book_review_context where contains(review_text,'doctor visits')>0
若搜索的短语中包含ORACLE TEXT内的保留字,则必须使用花括号括住相应的保留字
select title from book_review_context where contains(review_text,'taengdmg {and} dfdng)>0
4。搜索互相接近的词
select title from book_review_context where contains(review_text,'property near harvests')>0
可以使用关键词NEAR也可以用;代替NEAR
5。在搜索中使用通配符
select title from book_review_context where contains(review_text,'worker%')>0
select title from book_review_context where contains(review_text,'work___)>0
6。搜索具有相同词根的词
select title from book_review_context where contains(review_text,'$worker')>0
7。模糊匹配搜索
select title from book_review_context where contains(review_text,'?worker')>0
8。搜索发音相似的词
select title from book_review_context where contains(review_text,'!worker')>0
9。使用ABOUT运算符
在ORACLE TEXT中可以搜索文档的主题
select review_text from book_review_context where contains(review_text,'about(mdgd)')>0
10。索引集
为了建立一个名为reviews的索引集可使用CREATE_INDEX_SET过程
execute ctx_ddl.create_index_set('reviews)
可以通过add_index过程添加索引到索引集中了
execute ctx_ddl.add_index('reviewers','reviewer');

posted @ 2007-01-10 13:50 忆了又忆| 编辑 收藏

Field Name Mandatory? Allowed Values Allowed Special Characters
Seconds YES 0-59 , - * /
Minutes YES 0-59 , - * /
Hours YES 0-23 , - * /
Day of month YES 1-31 , - * ? / L W C
Month YES 1-12 or JAN-DEC , - * /
Day of week YES 1-7 or SUN-SAT , - * ? / L C #
Year NO empty, 1970-2099 , - * /
 
项目实例:
              second  minute  hours  dayOfMonth  month  dayOfWeek  year
每月         0            0           6              ?                    *                6#3            ?
每周        59           59         18            ?                    *                1                ?
自定义    28          47          9             30                 7                ?             2006
 
每月:每个月的第三个星期五的上午6:00:00 触发
每周:每周的星期日的下午18:59:59 触发
自定义:2006年7月30日上午9:47:28 触发
 

所有星号对应的段位置,都可以出现后面的符号(, - * /)
(? / L C)这些符号可以出现在"一月哪天"和"星期"段位置
(w)只能出现在"一月哪天"段位置
(#)只能出现在"星期"段位置

解释符号代表的意思:
* 代表任意合法的字段
0 * 17 * * ? :表示在每天的5 PM 到 5:59之间的每一分钟启动scheduler

? 表示没值被指定
如果同时指定"一月哪天"和"星期",可能两者对应不起来
0 0,15,30,45 * * * ? :表示每刻钟启动scheduler
所以推荐用法是其中一个指定值,另一个用?指定

/ 表示时间的增量
0 0/15 * * * ? :表示每刻钟启动scheduler

- 表示值的范围
0 45 3-8 ? * *

L 如果用在"一月哪天"段上,表示一个月的最后一天;如果用在"星期"段上。表示一个星期的最后一天(星期六)
0 0 8 L * ? :表示每个月最后一天的8点启动scheduler

W 表示最靠近给定时间的一天,(必须是星期一到星期五)

# 例如 6#3表示一个月的第三个星期五

posted @ 2007-01-10 13:45 忆了又忆| 编辑 收藏