(一) Turbine简介
1. 概述
Turbine是Apache Jakarta项目中的一个开源的服务器端Java框架。任何支持Servlet2.2或以上规范的容器都可以运行Turbine应用程序。
当然,Turbine的最大优势是免费,并且向开发人员提供全部的源代码。
Turbine技术概述:
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
- Factory
- Localization
- Mimetype
- Pool
- Naming
- OSWorkflow
- Quartz
- Security
- Test Container
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
*#
④ 字符串连接示例:
例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中单个的域可以映射到不同的对象。
Fields也有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/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