Turbine Training
(一)
Turbine
简介
1.
概述
Turbine
是
Apache Jakarta
项目中的一个开源的服务器端
Java
框架。任何支持
Servlet2.2
或以上规范的容器都可以运行
Turbine
应用程序。
当然,
Turbine
的最大优势是免费,并且向开发人员提供全部的源代码。
Turbine
技术概述:
- 表示层 - Velocity or JSP
- 数据库层(持久层) - Turbine 使用 Torque, 但是也支持其他的持久层工具,如OJB或者 Hibernate。.
- HTML 表单数据验证使用 "Intake"-Service.
- 日志(Logging) - Turbine 使用 Commons Logging并且支持众多的日志输出工具,如Log4J。(注:Scarab使用Log4j,不过有些问题。), jdk14 or simple file logging
- 基于服务的框架,在Turbine2.4及以后版本中使用和Avalon框架兼容的组件。
Turibne
促使基于它的应用程序遵循
MVC
架构。在
MVC
设计模式中,模型层(
Model
)包含了业务逻辑和存储的数据;表示层是用户接口;控制层负责控制应用程序的流程并且管理模型层和表示层。
Turbine
有
2
个版本,各有优劣:
- 当你从旧的版本迁移到新的版本,或者基于Turbine框架的一个已发布版本进行项目开发的时候,应该使用Turbine2.3.2。
- Turbine2.4是将要发布的下一个版本。Turbine2.4使用了下一代技术,比如基于avalon的容器和从Turbine的姊妹项目Fulcrum中分离出来的组件。如果你不介意自己从Subversion中取出代码打成jar包,并且可以忍受框架开发过程中所做出的偶尔的修改,那么你应该使用这个版本。
2.
关于
Turbine3.0
(
Scarab
用的
Turbine
版本)
Turbine3.0是Turbine的一个试验版本。从内部来说,它和Turbine2.x有很多不同。它使用了一个Catalina式的Pipeline(通过这个Pipeline可以很容易地对处理流程进行细类度[fine-grained]的控制),并且做了许多提高和简化。
虽然这个版本叫做3.0,但是不应当把它看作是Turbine的下一个或者未来的版本。
开发这个版本的最初目的确实是把它作为下一个主要版本,不过,开发已经停止。这个版本中超前于当前
Turbine
版本的不同设计之处正在逐渐迁移回来。
Turbine3.0
不再进行开发,开发重点已经转移到
Turbine2.4
。目前针对
Turbine3.0
的各种各样的改动是为了使人们更容易的迁移到
Turbine2.4
,重点是把
Scarab
迁移到
Turbine2.4
。
这当中涉及到把使用
commons-xo
的
pipeline
改为使用
XStream
;添加
Yaafi
,一个
Avalon
组件服务;迁移到许多发布的
Fulcrum Avalon
组件等等。
3.
Turbine
服务简介(
Turbine
是基于服务的框架)
服务
(Services)
在
Turbine
框架中都是单例的
(singleton)
,并且是可插入式的实现,能够在
Turbine
启动和关闭的时候进行初始化和关闭。
①
服务的特征:
Ø
单例(singleton) – 在系统中只有一个实例。内存和连接都只分配一次,内部状态对于所有的客户端来说是共同的。
Ø
插入式实现 – 需要的话可以使用自己的实现,只要改变配置文件TurbineResources.properties中的相关记录就可以了。
Ø
能够在系统启动的时候访问ServletConfig,处理相对路径以及诸如此类的操作。
Ø
能够在第一次执行doGet方法的时候访问RunData,取得当前的URL以及诸如此类的信息。
Ø
能够在客户端第一次请求该项服务之前初始化自己(分配内存,建立连接)。应用程序从来没有用到的服务不会分配资源。
Ø
能够在系统关闭的时候执行某些动作,比如关闭打开的连接。
②
服务的生命周期:
服务的生命周期开始于服务的构造器。一项服务不应当在构造器中做很多事情,尤其是许多耗费系统资源的事情,比如分配很大的内存,建立
DB
或者网络连接等等。服务可能存在于
properties
配置文件中,但是除非一个客户端用到了某个服务,否则没有必要起动这项服务。
Early initialization
和构造器类似。用来传递一些服务可能会用到的信息。
Early initialization
方法应当处理配置信息,存储一些值,但是不应当分配资源。因为仍然有可能这项服务不会被用到。如果服务可以使用了
(
不再需要传给它任何对象
)
,也不需要在
late initialization
过程中分配资源,那么可以更改内部状态以便使
getInit
方法返回
true
。
当系统第一次请求某项服务时,该服务才进行
Late initialization
,分配需要的资源,然后更改内部状态以便使
getInit
方法返回
true
。如果初始化之后,
getInit
方法仍然返回
false
,那么这项服务就出问题了。
Late initialization
之后,服务就做好干活的准备了。
当不再需要某项服务的时候
(
通常是系统关闭的时候
)
,调用
shutdown
方法,释放所有资源。如果发生错误,那么这些错误会被忽略。
Turbine
服务相关类一般放在
org.apache.turbine.services
包中。
注:
Turbine
包结构对比
Turbine2.4
中提供了许多默认服务,
services
包下有
20
多个子包;
Turbine3.0
中就少多了,
services
包下只有
pull/rundata/yaaficomponent 3
个子包。不过在
org.apache.fulcrum
有
4
个子包,也是提供服务的,应该是使用了
fulcrum
项目的东西。
补充:
Fulcrum
项目
简介
i.
Fulcrum
概述
Fulcrum最初是作为Turbine3的一部份进行开发的,目的是把服务从Turbine2中分离(decouple)出来,使它们在2个项目中都可以使用。
Fulcrum现在逐渐演化为一个基于Avalon框架的组件库。每个服务都正在被转化为一个独立的组件,各自独立发布。这使得Turbine项目可以在某个组件更改后单独发布它,而不必一次发布整个框架。同时,其它的项目可以也利用这些组件。
ii.
容器兼容性
所有的组件兼容于Avalon的ECM容器。任何对于其他组件,系统属性,或者上下文元素的依赖都记录在每个组件各自的文档里。
而且,
Fulcrum
提供了
Yaafi
组件。
Yaafi (Yet Another Avalon Framework Implementation)
是一个简易容器,用于和单例组件
(singleton components)
一起使用。
Yaafi
非常适合用于对你的组件进行单元测试。通过之后,你的组件就可以运行在任何
Avalon
容器中,如
ECM
,
Phoenix
,
Excaliber
,等等。
iii.
Fulcrum
组件列表
(
红色
组件在
Scarab
中有应用
)
Released Components
- BSF
- Cache
- Crypto
- DVSL
- Factory
- Localization
- Mimetype
- Pool
- Naming
- OSWorkflow
- Quartz
- Security
- Test Container
- Upload
- XMLRPC
- XSLT
- YAAFI
Sandbox Components
- Script
- CommonsEmail
- PBE
- Groovy
- ResourceManager
- Configuration
- HsqlDB
- Intake
- Parser
- Template
Howtos (old)
- JSP Service
- Template Service
- Velocity Service
4.
Turbine
配置简介(作为控制器)
①
web.xml
文件的配置
正常配置,只有一点需要注意一下,即
Servlet
的初始化参数可以指定
2
种文件:
a)
使用参数名为
"configuration"
的配置文件:
//
// <init-param>
// <param-name>configuration</param-name>
// <param-value>/WEB-INF/conf/turbine.xml</param-value>
// </init-param>
//
//
加载
XML
配置文件。
//
b)
使用一个名为
"properties"
的配置文件:
//
// <init-param>
// <param-name>properties</param-name>
// <param-value>/WEB-INF/conf/TurbineResources.properties</param-value>
// </init-param>
//
//
加载属性(
.properties
)文件。
//
//
如果未使用
a
或者
b
的方式设置的话,
Turbine
默认加载相对于应用程序根目录下的
/WEB-INF/conf/TurbineResources.properties
文件。
注:
Scarab
中使用
XML
配置文件。其中可以指定多个
properties
文件。
②
TurbineResources.properties
顾名思义,这个文件中配置了关于
Turibne
框架的配置信息。从目前掌握的情况来看,以下几项是必须的配置:
a.
M O D E
只有一项设置:
turbine.mode = standalone
可选的值为:
standalone, integrated
指定
Turbine
是作为控制器,还是集成组件。
b.
R E S O L V E R
指定使用什么
Resolver
来找到
modules
和
templates
。
c.
R E S O L V E R C A C H I N G
指定
modules
和
templates
是否缓存。
d.
M O D U L E P A C K A G E S
这是
Turbine
的“
classpath”
。如果自定义
modules
的话,需要在这里指明路径。
有两点需要特别指出:
Ø
一是
Turbine
的
pipeline
配置文件在此处指定。
pipeline.default.descriptor = WEB-INF/conf/scarab-pipeline.xml
这个描述文件中指出了
pipeline
中含有哪些
Values
。
Ø
二是默认框架页面也应该是在这里指出的:
template.default = /Default
template.default.extension = vm
e.
F R A M E W O R K S E T T I N G S
这部分是关于控制框架行为的设置,比如默认
templates
和
screens
,
session
管理,等等。
f.
S E R V I C E S
定义为
Turbine
提供服务的类。(注:我认为可以理解为注册服务)
格式:
services.[name].classname=[implementing class]
e.g.
:
services.IntakeService.classname=org.apache.fulcrum.intake.TurbineIntakeService
指定一项服务的属性使用如下的与法:
service.[name].[property]=[value]
另外,服务在这里的注册顺序就是服务的初始化顺序,不可以随意改动,因为有的服务需要依赖于其他的服务。
g.
具体
Services
配置
配置某个服务自己的配置。
注:配置文件中有关于配置的简单说明。
警告:上述配置未全部经过严格验证。
5.
Scarab Services
浅析
在
Scarab
使用的
Turbine
配置文件
TurbineResource.properties
中配置了下述服务:
Ø
services.YaafiComponentService.classname=org.apache.turbine.services.yaaficomponent.TurbineYaafiComponentService
Ø
services.SecurityService.classname=org.tigris.scarab.services.security.ScarabDBSecurityService
Ø
services.TemplateService.classname=org.apache.fulcrum.template.TurbineTemplateService
Ø
services.RunDataService.classname=org.apache.turbine.services.rundata.TurbineRunDataService
Ø
services.PullService.classname=org.apache.turbine.services.pull.TurbinePullService
Ø
services.IntakeService.classname=org.apache.fulcrum.intake.TurbineIntakeService
# Turn on the appropriate template service.
Ø
services.VelocityService.classname=org.apache.fulcrum.velocity.TurbineVelocityService
Ø
services.EmailService.classname=org.tigris.scarab.services.email.VelocityEmailService
配置为
org.apache.turbine.*
的,使用的是
Turbine3.0
提供的默认服务;
配置为
org.tigris.scarab.*
的,应该是
Scarab
自行实现的服务;
配置为
org.apache.fulcrum.*
的,原意应该是使用已经分离到
Fulcrum
中的组件。
前面提到过,
Fulcrum
最初是作为
Turbine3
的一部份进行开发的,目的是把服务从
Turbine2
中分离
(decouple)
出来,形成单独的组件,以便对每个组件进行版本升级和复用。从
Turbine3.0
框架的结构来看,显然是取消了大部分
Turbine
框架提供的默认服务,代之以
Fulcrum
中的组件。不过,显然开发组在按照这个想法进行开发的时候,因某种变故改变了计划,取消了
Turbine3.0
的开发。
根据
Scarab
的配置文件以及
Fulcrum
的文档可以确认,
TemplateService
和
VelocityService
使用的是旧的
Fulcrum
配置,可能是早期
Fulcrum
项目的成果。其中,
TemplateService
已经在
Fulcrum
中有新的组件,但是在
Scarab
中没有采用(
Turbine2.4
中采用了);而
Velocity
是
Apache Jakarta
的子项目,也就是和
Turbine
项目平级。根据
Velocity
的文档来看,
Velocity
在开发
Turbine
的时候就已经作为
Turbine
的主要页面语言,而且很多
Velocity
的开发者参与了
Turbine
框架的开发。因此,
Velocity
在
Turbine
框架中的使用方法不同于其它框架。
IntakeService
在
Scarab
中的使用也有一点特殊。这里,
IntakeService
是作为一项独立的服务在
TurbineResources.properties
中配置;而在
Turbine2.4
中,
IntakeService
是作为一个
Avalon Component
进行配置的。
(二)
Velocity
1.
简介
Velocity
是基于
Java
的模版引擎(
template engine
)。它允许任何人使用简单但是功能强大的模版语言引用在
Java
代码中定义的对象。
当使用
Velocity
进行
Web
开发的时候,通过
MVC
模式,网页开发者和
Java
程序员可以平行工作开发
web
网站,这意味着网页设计者可以完全将注意力集中于网站的视觉效果,而程序员完全将注意力集中于后台程序开发。
Velocity
将
Java
代码和网页分离开,增强了网站在其生命周期内的可维护性,提供了一种除了
JSP
或者
PHP
之外的可行选择。
Velocity
的用途不仅局限于
web
领域;比如说,它能够用来从模版中生成
SQL
,
PostScript
和
XML
。它既可以作为独立的工具用来生成源代码和报告,也可以作为其他系统的集成组件。举个例子,
Velocity
为
Turbine
应用程序框架提供模版服务(
template service
),并且一起构成了一个视图引擎,通过真正的
MVC
模型简化了
web
应用程序的开发。
2.
VTL
(
Velocity Template Language
)语法简介:
1) 概述
VTL
提供了一种在页面中和动态内容交互的最容易,最简洁的方法。即使一个没有编程经验的页面开发人员也可以很快地学会在页面中使用
VTL
和动态内容交互。
VTL使用“
引用
(references)
”来把动态内容嵌入到页面中,一个变量(variable)就是引用的一种。变量能够引用在Java代码中定义的东西,或者在页面的VTL语句(statement)中赋值。下面是一个可以嵌入到HTML文档中的VTL语句的例子:
#set( $a = "Velocity" )
和所有的
VTL
语句一样,这个
VTL
语句以“
#
”开头,包含了一个标识符
(directive)
:
set
。当客户端请求一个页面的时候,
Velocity Templating Engine
会搜索整个页面,找到所有的“
#
”,然后决定哪些“
#
”标志着
VTL
语句的开始,哪些“
#
”与
VTL
无关。
“
#
”后面跟着一个标识符,
set
。这个
set
标识符使用了一个表达式
(
包含在括号中
)
——一个给变量赋值的等式。这个变量位于左边,值位于右边;中间由一个等号分隔。
在上面的例子中,变量是
$a
,其值是“
Velocity
”。和所有的引用一样,这个变量以“
$
”开头。值总是位于括号中;
Velocity
中关于数据类型不会有任何混乱,因为只有
strings(
文本信息
)
可以赋给变量。下面的经验之谈可能更有助于理解
Velocity
是如何工作的:引用以“
$
”开头,用来取得值;标识符以“
#
”开头,用来做某些事情。
(
References begin with
$
and are used to get something. Directives begin with
#
and are used to do something.
)
。
在上面的例子中,
#set
用来给变量赋值。然后,就可以在页面中使用变量
$a
输出“
Velocity
”了。
2) 基本语法
①
引用标识符“
$
”用来引用变量,属性,方法。
变量:
· Normal notation: $mud-Slinger_9
· Silent notation: $!mud-Slinger_9
· Formal notation: ${mud-Slinger_9}
属性:
· Regular Notation: $customer.Address
· Formal Notation: ${purchase.Total}
方法:
· Regular Notation: $customer.getAddress()
· Formal Notation: ${purchase.getTotal()}
· Regular Notation with Parameter List: $page.setTitle( "My Home Page" )
②
指示标识符“
#
”用来标识控制语句
A)
#set标识符用来给引用赋值。可以把值赋给一个变量,也可以赋给一个属性。赋值过程位于括号中,如下所示:
#set( $primate = "monkey" )
#set( $customer.Behavior = $primate )
表达式左侧(left hand side [LHS])是一个变量或者属性;
右侧(RHS)是下述类型中的一种:
¨ Variable reference
¨ String literal
¨ Property reference
¨ Method reference
¨ Number literal
¨ ArrayList
下面是上述每种类型的例子:
#set( $monkey = $bill ) ## variable reference
#set( $monkey.Friend = "monica" ) ## string literal
#set( $monkey.Blame = $whitehouse.Leak ) ## property reference
#set( $monkey.Plan = $spindoctor.weave($web) ) ## method reference
#set( $monkey.Number = 123 ) ##number literal
#set( $monkey.Say = ["Not", $my, "fault"] ) ## ArrayList
注意:在最后一个例子中,在[ ]中定义的元素可以使用ArrayList类的方法进行访问。所以,举例来说,你可以使用$monkey.Say.get(0) 来取得其中的第一个元素。
B)
Conditionals
n
If / ElseIf / Else
#if
用来进行条件判断,比如:
#if( $foo )
<strong>Velocity!</strong>
#end
根据变量
$foo
的值来决定条件是否为真,有下述两种判断方式:
(i) $foo
是布尔型,其值为
true
;
(ii) $foo
的值不为
null
。记住,
Velocity
上下文中只含有对象,所以当我们说“
boolean
”的时候,意味着一个
Boolean
对象。即使对于返回值为
true
的方法也是这样——内部机制会决定返回值是一个对应的
Boolean
对象。
#elseif
或者
#else
元素可以和
#if
元素一起使用。注意,
Velocity Templating Engine
会在第一个条件为真的地方停止执行。在下面的这个例子中,假设
$foo
的值为
15
,
$bar
等于
6
:
#if( $foo < 10 )
<strong>Go North</strong>
#elseif( $foo == 10 )
<strong>Go East</strong>
#elseif( $bar == 6 )
<strong>Go South</strong>
#else
<strong>Go West</strong>
#end
$foo
大于
10
,所以前两个条件为
false
。下一步比较
$bar
的值是否为
6
,返回
true
,所以输出结果为
Go South
.
请注意,现在,
Velocity
的数字比较仅限于
Integers –
任何其它的类型都会返回
false
。唯一的例外是“
==
”,
Velocity
要求“
==
”两边的对象必须是同一种类型。
n
关系和逻辑运算符
Velocity
使用等号运算符决定变量之间的关系。请看下面的例子:
#set ($foo = "deoxyribonucleic acid")
#set ($bar = "ribonucleic acid")
#if ($foo == $bar)
In this case it's clear they aren't equivalent. So...
#else
They are not equivalent and this will be the output.
#end
Velocity
也有逻辑
AND, OR and NOT
运算符。下面是使用方法示例:
## logical AND
#if( $foo && $bar )
<strong> This AND that</strong>
#end
## logical OR
#if( $foo || $bar )
<strong>This OR That</strong>
#end
##logical NOT
#if( !$foo )
<strong>NOT that</strong>
#end
需要注意的一点是,不要把( !$foo )和($!foo )搞混了。
C)
Loops
n
Foreach Loop
示例:
<ul>
#foreach( $product in $allProducts )
<li>$product</li>
#end
</ul>
这个
loop
循环遍历了
List
对象
$allProducts
。
每次循环,取出
$allProducts
中一个对象,赋给变量
$product
。
变量
$allProducts
是一个
Vector
,
Hashtable
或者
Array
。赋给变量
$product
的是一个
Java
对象,可以使用
$product
来引用这个对象。比如说,如果
$product
是一个
Product
对象,可以通过
$product.Name
(
或者
$Product.getName()
)
方法取得这个
Product
的名称。
假设
$allProducts
是一个
Hashtable
。如果想要取得这个
Hashtable
中的所有的
key
和
value
,可以这样:
<ul>
#foreach( $key in $allProducts.keySet() )
<li>Key: $key -> Value: $allProducts.get($key)</li>
#end
</ul>
Velocity提供了一种简便方法取得循环计数值以便做点什么,比如:
<table>
#foreach( $customer in $customerList )
<tr><td>$velocityCount</td><td>$customer.Name</td></tr>
#end
</table>
循环计数变量的默认名称为
$velocityCount
,是在配置文件
velocity.properties
中指定的。默认情况下,其值从
1
开始,可以在配置文件中重新指定起始值。
下面是循环计数属性的配置方法:
# Default name of the loop counter
# variable reference.
directive.foreach.counter.name = velocityCount
# Default starting value of the loop
# counter variable reference.
directive.foreach.counter.initial.value = 1
D)
Velocimacros
#macro
脚本元素使模版设计者
(template designers)
能够定义一段重复的段落
(segment)
。
Velocimacros
用途很广泛。下面这个
Velocimacro
简要表现了其概念:
#macro( d )
<tr><td></td></tr>
#end
这个Velocimacro叫做d ,可以象使用其它VTL标识符那样来使用Velocimacro:
#d()
当这个模版被请求的时候,Velocity会用包含单个空数据单元的行替代
#d() 。
一个
Velocimacro
可以带有任意个参数
–
也可以如上例所示没有参数
–
但是当调用
Velocimacro
的时候,参数个数必须和定义的一致。下面这个
Velocimacro
有
2
个参数,一个
color
和一个
array
:
#macro( tablerows $color $somelist )
#foreach( $something in $somelist )
<tr><td bgcolor=$color>$something</td></tr>
#end
#end
上例中的Velocimacro名为tablerows,有2个参数:$color和$somelist。
任何可以放入
VTL
模版中的语句都可以放入
Velocimacro
中。
Velocimacro tablerows
是一个
foreach
语句。在这个
Velocimacro
的定义中有
2
个
#end
语句:第一个和
#foreach
对应;第二个表示
Velocimacro
定义的结束。
#set( $greatlakes = ["Superior","Michigan","Huron","Erie","Ontario"] )
#set( $color = "blue" )
<table>
#tablerows( $color $greatlakes )
</table>
注意,当调用Velocimacro#tablerows的时候,第二个参数为$greatlakes,输出结果如下:
<table>
<tr><td bgcolor="blue">Superior</td></tr>
<tr><td bgcolor="blue">Michigan</td></tr>
<tr><td bgcolor="blue">Huron</td></tr>
<tr><td bgcolor="blue">Erie</td></tr>
<tr><td bgcolor="blue">Ontario</td></tr>
</table>
Velocimacros的参数可以是如下类型的VTL元素:
· Reference : anything that starts with '$'
· String literal : something like "$foo" or 'hello'
· Number literal : 1, 2 etc
· IntegerRange : [ 1..2] or [$foo .. $bar]
· ObjectArray : [ "a", "b", "c"]
· boolean value true
· boolean value false
当把引用作为参数传给Velocimacros的时候,请注意是引用传递。这意味着其值是在Velocimacro中每次使用到的时候才产生的。这个特点允许你传进去一个带有方法的引用,每次使用的时候才调用该方法。如下所示:
#macro( callme $a )
$a $a $a
#end
#callme( $foo.bar() )
执行结果,引用$foo的方法bar()被调用了3次。
如果你需要回避这个特点的话,可以每次先取出方法的执行结果,然后把它传进去:
#set( $myval = $foo.bar() )
#callme( $myval )
③
注释标识符
Ø
单行注释:
## This is a comment.
Ø
多行注释:
#*
This is a multiline comment.
This is the second line
*#
This is a multiline comment.
This is the second line
*#
④
字符串连接示例:
例1:
#set( $size = "Big" )
#set( $name = "Ben" )
The clock is $size$name.
输出结果:
The clock is BigBen.
例2:
#set( $size = "Big" )
#set( $name = "Ben" )
#set($clock = "$size$name" )
The clock is $clock.
输出结果:
同上例。
例
3
:
最后一个例子,如果想把“静态”字符串和引用混合输出,必须使用
'formal references'
:
#set( $size = "Big" )
#set( $name = "Ben" )
#set($clock = "${size}Tall$name" )
The clock is $clock.
输出结果:
The clock is BigTallBen.
(三)
Intake Service
1.
简介
Intake
使用
XML
规范验证
form
提交的数据,并且把这些数据映射到
bean
属性中。换句话说,
Intake
允许
web
应用程序获得
form
提交的数据,验证数据,然后把这些数据映射到一个对象中。类似
Torque
的工具在对象和数据库之间建立映射,而
Intake
则在对象和
form
数据之间建立映射。
Intake
可以在一个支持
Avalon
组件的应用程序中单独使用。不过,
Intake
最适用于
Turbine
框架。
使用
Intake
有若干优势。首先,
Intake
提供了一个处理表单数据的集中管理系统。所有
Intake
的配置都在一个专门的
XML
文件(
Intake.xml
)中完成。其次,
Intake
便于验证表单数据。
Intake
能够进行表达式匹配以便保证表单域中包含合法的数据。比如说,如果某人应当在一个表单域中填入数字,填入内容可以用一个合格的表达式进行验证。最后,
Intake
能够把错误信息集中到一起。如果验证失败,定义在
XML
文件中的错误信息将被显示给用户。
2.
概念
示例
Intake.xml
文件
:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
<input-data basePackage="com.neusoft.">
<group name="Login" key="Login" mapToObject="beans.TurbineUser">
<field name="Name" key="name" type="String" mapToProperty="Name">
<rule name="required" value="true">Name is required.</rule>
</field>
<field name="Password" key="pwd" type="String" mapToProperty="Pwd" >
<rule name="required" value="true">Password is required.</rule>
</field>
</group>
</input-data>
Group
是已经赋值的一组域,他们形成了一个逻辑单元。
示例中
Login
这个
group
包含了一些域,它们和数据对象
bean.TurbineUser
中的成员变量相对应。同时,数据对象中的成员变量需要有相应的
setter/getter
方法。注:
Group
中的域必须有相应的数据对象中的成员变量与其对应;而数据对象中的成员变量可以多于
group
中的域。
每个
Group
有一个
name
属性,在页面代码和
servlet
代码中就是通过这个值来引用相应的
group
对象。每个
Group
还有一个
key
属性,这个属性不会在代码中用到,只要保证它在整个配置文件中是唯一的就可以了。
Group
的域所映射的数据对象也可以指定。这里有一个默认值,而一个
group
中单个的域可以映射到不同的对象。
Field
s
也有
name
和
key
属性,功能和
group
的类似。属性
mapToObject
和
mapToPropertiy
用来映射
group
对象和数据对象
(JavaBean)
,并且在成功验证之后,把字段数据赋到
bean
中。每个字段必须有一个类型,可以是诸如
String
和
Integer
的简单类型。
Field
可以定义
rule
元素。可以定义的
rule
包括最大
/
小值,长度,值的范围等等。
<field name="TypeId" key="typeid" type="int">
<rule name="mask" value="[0-9]+">intake_BadIdMessage</rule>
</field>
<rule name="minLength" value="1">intake_AttributeNameNotAllowedEmpty</rule>
<rule name="maxLength" value="255">MustBeLessThan255Characters</rule>
(四)
Torque
1.
简介
Torque是一个持久层框架,原来包括在Turbine框架中,从Turbine2.2开始Torque被分离出来作为DB项目下的一个单独的子项目。目前最高版本是3.2。
Torque是面向Java的对象-关系转换器。换句话说,Torque使你能够使用Java对象来访问和操纵关系型数据库中的数据。和大多数对象-关系转化器不同的是,Torque不是使用反射来访问用户提供的类,而是根据描述数据库层次的XML Schema(可以是手写的,也可以是根据已存在的数据库生成的)生成必须的类(包括数据对象)。XML Schema也可以用来生成和执行创建数据库中的所有表的sql语句。
转载:
对持久层以及持久层框架的理解
所谓持久层就是在整个系统中与持久存储介质如
Database,LDAP Server,XML等打交道的部分。持久层框架的作用就是使持久层访问持久介质更加方便。如果是为了访问Database而建立的持久层框架那么就又有一个O/R Mapping的概念。O/R Mapping就是建立对象(Object)与关系数据库(R)中的表(不一定是一对一)的映射。Torque就是这样一种起到O/R Mapping作用的持久层框架。他使java程序员可以方便地通过操作普通java对象的方式来访问数据库,甚至不用了解数据库的相关知识(最好是了解),另一个好处是屏蔽数据库类型即可任意更换持久层框架支持的Database。
Torque的工作原理
一般在利用
O/R Mapping框架进行开发的时候,有三个基本的单元即关系数据库中的表(Table),Java中的持久对象(PO),定义PO到Table映射的xml文件(Schema)。
首先,
Torque包含一个generator用来根据由开发者配置好的Schema来自动生成PO和Table,这就意味着开发者只要定义好Schema,PO和Table就可以自动生成了。
在生成好的PO和Table以后,开发者就可以利用PO来进行对Table的访问了。为了达到这个目的Torque提供了一个运行时环境来保证代码的正确运行。在工程中引入了torque相关的.jar就可以拥有这个运行环境了。
2.
Torque
的元素
Torque
由多个部分构成:
Ø
runtime
Torque runtime 包含了在应用程序中操作数据库所需的一切。这是应用程序中需要的唯一的Torque组件,可以单独使用。
Ø
generator
Generator含有一些ant task,供Maven插件使用。如果使用Maven的话,不需要直接操作generator。不过,也可以直接使用ant调用generator。
Ø
maven-plugin
Maven plugin 创建了用来访问和存储数据库信息的O/R peer和object类。它也可以生成已存在数据库的XML描述文件,或者反过来,生成SQL脚本来创建数据库中的表。从内部来说,Maven plugin使用generator来实现这些任务。
Ø
templates
模版含有构建块(building blocks),供generator使用来创建O/R peer 和 object类,SQL 脚本以及诸如此类的东西。如果你想改变generator的输出结果的话,可以通过改变模版来实现(只有在其特殊的情况下才需要这样做)。3.1.x及以前版本,模版都是generator的一部分。从Torque3.2开始,模版已经被分离到了自己的jar包中。
3.
主要
Runtime classes
介绍:
Peers
①
Peers
中的一切都转换到了
Peer
类中。一个
Peer
类和一个数据表对应。你可以使用和某个数据表相对应的
Peer
类来操作这个表。
Peer
类都是自动生成的。
②
Peer
类只含有静态方法,所以不必创建任何
Peer
类对象。由于和表的关系是一一对应的,所以在这个层次上没有必要创建对象。
③
Peer
类都是自动生成的。每个表生成
2
个
Peer
类:“
Base
表名
Peer
”类和“表名
Peer
”类。“
Base
表名
Peer
”类包含了所有功能,并且不应该进行任何改动;“表名
Peer
”类是“
Base
表名
Peer
”类的子类,初始时是空的,可以添加或者更改方法以提供需要的功能。如果使用
Torque
重新生成
Peer
类,只有“
Base
表名
Peer
”类中的代码发生改变,已有的存在于“表名
Peer
”类中的代码仍然可以使用。
Data Objects
①
一个数据对象保存了一个表中的一行数据。数据对象是自动生成的。它以
Bean
属性的形式保存了表中的每个字段。
②
数据对象类也是自动生成的。每个表对应生成
2
个数据对象类:“
Base<table-name>
”和“
<table-name>
”。功能和使用方法与
Peer
类相似。
③
数据对象是由和其相关联的
Peer
类以几乎独占的方式使用的。
Peer
类把表包装了起来,而数据对象把表中的单行数据包装了起来。二者往往联合使用。
④
数据对象有2种使用方式。最常用的方式是在调用一个Peer类的doSelect方法之后使用数据对象抽取数据。doSelect方法返回一个含有数据对象的List,其中包含了查询结果集(Resultset)中的数据。第二种方式是创建数据对象,然后调用该对象的save方法来把相关的行插入或者更新到数据库中。
Criteria
①
Criteria是对一个sql查询条件的抽象。我们使用criteria对象来指定一个sql语句的查询条件。数据库调节器类(adaptor classes)包含了如何转换criteria对象以便适应不同的数据库的信息。
②
Criteria
从作用上来说是构成一个查询条件的字段名称和值的映射。默认的运算符是“
=
”,但是也可以自己定义运算符
(<, >, <=, > =, IN, etc.)
。
③
Creteria也能用来做其它的查询,如ORDER BY或者DISTINCT。如果Criteria不能满足你的要求的话(这种情况不应经常发生),你仍旧可以使用原始的sql语句进行查询。
4.
使用方法简介:
主要涉及到
Runtime classes
中的
Peers
,
Data Objects
和
Criteria
。
①
Peer类都是自动生成的。每个表生成2个Peer类:“Base表名Peer”类和“表名Peer”类。
需要重写,或者添加新的方法的时候,都在“表名Peer”类中进行,不要修改Base表名Peer”类。“
②
Peer类只含有静态方法,所以
不必创建Peer类对象。任何
③
每个表对应生成2个数据对象类:“Base<table-name>”和“<table-name>”。功能和使用方法与Peer类相似。
④
一个数据对象保存了一个表中的一行数据。数据对象是自动生成的。它以Bean属性的形式保存了表中的每个字段。
可以作为bean来使用。
⑤
数据对象有2种使用方式:
1)
最常用的方式是在调用一个Peer类的doSelect方法之后使用数据对象抽取数据。doSelect方法返回一个含有数据对象的List,其中包含了查询结果集(Resultset)中的数据。
2)
第二种方式是创建数据对象,然后调用该对象的save方法来把相关的行插入或者更新到数据库中。
⑥
Criteria中包装了sql语句。在进行数据库操作的时候需要传递一个Criteria对象给相关Peer类中方法。
比如:
Criteria criteria = new Criteria();
List authors = AuthorPeer.doSelect(critieria);
上述语句取出Author表中的所有数据,相当于sql语句:
Select * from Author
关于Criteria的详细使用方法,参见:
http://db.apache.org/torque/releases/torque-3.2/runtime/reference/read-from-db.html
http://db.apache.org/torque/releases/torque-3.2/runtime/reference/write-to-db.html
操作数据库的详细例子,参见:
http://db.apache.org/torque/releases/torque-3.2/tutorial/step5.html
(五)
Turbine Sample
1.
Login页面主要代码注解:
①
指定处理页面的
Action
:
<input type="hidden" name="action" value="Login" />
②
指定
action
中处理页面的具体方法:
<input type="submit" value="submit" name="eventSubmit_doLogin" tabindex="2" />
此处,提交按钮
name
属性的命名方式是固定的,即必须有一个前缀
eventSubmit
,加上一个下划线“
_
”,然后是具体的方法名称。在对应的
action
中,方法的命名也是
doXXX
。其中,
do
后面的第一个字母大写,其余的均小写。
③
指定跳转的目标页面:
<input type="hidden" name="nextTemplate" value="success.vm" />
④
取得对应的
Intake group
对象:
#set ($login = $intake.Login.default )
其中,
$intake
是内置的
Intake
对象,可以直接在页面中使用;
Login
是在
intake.xml
中配置的
group
名称。通过该语句得到了一个
group
对象
$login
。
⑤
把表单中的字段映射到相应的
group
域中
<input name= "$login.Name.Key" value="$!login.Name" size="25" type="text"/>
<input name= "$login.Password.Key" value="$!login.Password" size="25" type="text"/>
⑥
Intake
根据配置文件中每个
field
定义的
rule
进行入力数据校验。如果验证未通过,则显示
rule
指定的错误信息。
#if ( !$login.Name.isValid() )
$login.Name.Message<br>
#end
<br>
#if ( !$login.Password.isValid() )
$login.Password.Message<br>
#end
⑦
指定提交的页面名称,如果验证未通过,返回
setPage
方法指定的页面:
<form action="$link.setPage("Login.vm")" method="post" name="login">
此处仍存在问题,需要进一步调查。
2.
Login.java主要代码注解:
①
处理页面请求的方法一般都有
2
个参数,
RunData
和
TemplateContext
。
RunData
是
Turbine
的一个接口,储存了一些运行时的数据。
TemplateContext
提供了对
Context
的操作
②
在
Servlet
中取得
Intake
对象:
IntakeTool intake = (IntakeTool) getTool(context,ScarabConstants.INTAKE_TOOL);
IntakeTool
是
Intake
的子类,一般使用的
Intake
对象都是
IntakeTool
对象。
③
校验输入的数据:
intake.isAllValid()
④
取得页面中指定的下一页面:
String nextTemplate = data.getParameters().getString(ScarabConstants.NEXT_TEMPLATE);
⑤
设置跳转的目标页面:
setTarget(data, nextTemplate);
通过
setTarget
方法来指定下一页面;可以根据不同情况指定不同的目标页面。
⑥
取得表单对应的
group
对象
Group login = intake.get("Login", IntakeTool.DEFAULT_KEY);
⑦
取得某个表单字段:
String username = login.get("Name").toString();
⑧
把表单中的数据映射到对应的对象中:
login.setProperties(user);
⑨
特别说明:
context.put("loginuser",user);
此处仅做示例用
。
为了方便使用,把一个
bean
对象放在了
context
中,以便目标页面可以直接从
context
中取得这个对象,验证程序的正确性。
3.
目标页面success.vm主要代码注解:
①
显示登陆用户的信息:
$loginuser.Name
参考资料:
Apache
网站:
http://www.apache.org/
Turbine
主页:
http://jakarta.apache.org/turbine/
Intake Service使用说明:
http://jakarta.apache.org/turbine/fulcrum/fulcrum-intake/howto.html
velocity主页:
http://jakarta.apache.org/velocity/
torque主页:
http://db.apache.org/torque/
附:
web.xml文件:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<display-name>Scarab Bug Tracker</display-name>
<description>Scarab Bug Tracker</description>
<servlet>
<servlet-name>turbine</servlet-name>
<servlet-class>org.apache.turbine.Turbine</servlet-class>
<init-param>
<param-name>properties</param-name>
<param-value>
/WEB-INF/conf/TurbineResources.properties
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>turbine</servlet-name>
<url-pattern>/issues/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1358991