本人用过,感觉不错,向各位推荐一下,核心功能包括如下:

1,通用的组织机构管理和权限控制;

组织机构支持历史组织变更记录,满足各类组织要求;
权限控制采用国际通用的RBAC标准开发实现,支持权限报表;

2,动态菜单;

动态操纵菜单,配置起来十分方便;

3,灵活的元数据;

从数据库表,字段级控制数据,功能十分强大;

4,功能强大的工作流;

方便的流程控制,管理;

5,报表打印;

对各类报表数据提供打印支持;

6,系统性能监控。

监视系统运行状况,获得稳定性保证。
posted @ 2006-05-10 23:19 小马歌 阅读(1634) | 评论 (3)编辑 收藏
 
        不管你此刻的心情,感觉如何。请看以下最感动我的话,来之陆幼青。看后请闭上你的眼睛,反复的默念。记住是用你的意念,用心。

“在你去过的一座遥远的山里,向阳的山坡,

在一段久没有人走过的田埂,草丛中,

在枯涩昏暗的台灯光圈外,冷落的花盆中,

在为典礼而忙碌的皇家园林中,精致的圣坛,

有一些小小的,名叫做向日葵的植物在生长,

笑脸为形,真金如色,且懂得寻找阳光。

让我们入静,

意念春光,静享人生。。。。。。”

我想不管我们在人生的旅途中有怎么样的挫折和悲伤。我们都要记得我们还有最珍贵的生命。有什么样的挫折和悲伤不可逾越呢?重要的是我们曾经经历过,勇敢的站起来面对生活和自己。坚持到底,累了闭上眼睛,用意念用心默念以上陆幼青留给我们的话!
posted @ 2005-06-19 11:32 小马歌 阅读(503) | 评论 (0)编辑 收藏
 
     摘要: 首先,要写出自己的Ant Task是一件非常简单的事情,有了心里的这层藐视之后,做起事来就容易多了!说说我做这个Ant Task的背景,随着部门框架的推广,支持国际化是一个严肃的问题,我们选择了utf-8作为UNICODE字符集的编码形式,因此现有项目必须经过一些转换的处理,自然,Ant是首选工具。可以看一个完整的build.xml: <?xml version="1.0"...  阅读全文
posted @ 2005-06-16 11:01 小马歌 阅读(689) | 评论 (0)编辑 收藏
 
设置header为下面的就行了,这样就可以实现弹出下载提示框的效果。   
response.setHeader(
    "Content-Disposition",
    "inline; filename=url");
posted @ 2005-06-15 21:39 小马歌 阅读(1839) | 评论 (1)编辑 收藏
 
1你可以不拥有任何东西,除了对生活的激情。 
2然后是钱。 
3努力赚钱。 
4有了钱,可以拥有很多女人的身体。 
5没有钱,要拥有很多女人的心。 
6如果身体和心你都无法得到,那只能说明你的无能。 
7英雄和浪子,取长补短。 
8该英雄时要英雄,该浪子时得浪子。 
9喝酒,抽烟。一个都不能上瘾。 
10赌,女人,权力。追求,但不能沉沦。
11热爱体育。如果你不热爱你就不是男人。 
12即使你爱体育爱得发疯。也不能抱着体育生活一辈子。 
13善待你的家人。 
14网络游戏,浅尝辄止。 
15有分寸,懂得控制自己。 
16厨艺精湛,但不轻易下厨。 
17如果厨艺不佳,刀功一定要好。 
18得到女人的心,先满足她的胃。 
19再给她可以倚靠的肩膀。 
20依赖。女人的致命处。 
21想让女人嫁给你,给她安全感。经济上和精神上的双重安全。 
22不要以为每个女人都很傻。 
23如果不打算骗女人一生一世。就不要轻易骗她。 
24如果是善意的谎言,要设法让她明白你的良苦用心。 
25如果不爱她,就不要娶她。除非你能保证对她好。 
26如果背叛了她,就尽量补偿她。 
27女人的寿命比男人长,她会恨男人一直恨到死。 
28最好不要得罪女人。 
29补偿最好的方式是钱。 
30连钱都不要的女人,要小心。 
31追到一个女人很容易,可是摆脱掉却很难。追求之前请三思。 
32不要跟玩不起的人玩。 
33就算是尝试一夜情,也不要选择去嫖娼。 
34对象的选择和客户一样,慎重。 
35不要轻易给女人承诺。说者无心,听者有意。 
36尊重女人的最好方式就是坦诚对她。 
37即使你是个**,也要**得坦坦荡荡。 
38没有一个女人,能比你的母亲重要。 
39小时糊涂,大事不糊涂。 
40身材魁梧,动作温柔。 
41找一个理解你的人做妻子。 
42找一个了解你的女人做知已。 
43作为成熟男人,应该清楚得不到的才是最好的。 
所以,该舍时要舍得。 
44不要打女人。有这种冲动前先看看《妇女权益保障法》。 
45不要谈太多次恋爱。否则你自己都会厌倦不堪。 
46不要见一个爱一个,爱得太多,你的爱就要贬值。 
47“我爱你”这三个字不必挂在嘴边,用行动来证明吧。 
48“我爱你”堵住所有废话的最后一击。话要用在刀刃上。 
49拥抱或者吻。肢体语言永远比语言更有力度。 
50对上司,可以服从,可以抗议。就是不能卑躬屈膝。
51买一栋房子。即使是按揭。只要你不打算当无根浪子。 
52再买一栋。即使是借钱。用于投资。 
53炒股。不为赚钱,只为证明自己的判断力。 
54即使是输掉一栋房子,也要笑着自嘲:我不是一个输不起的人。 
55买车。先买二手车。如果你技术很好或者有很多钱则另当别论。 
56哪儿摔倒,哪儿站起来再摔几次。 
57没有才华,也要有气魄。 
58不要西装革履,也不必着装休闲。把衬衫扣子解掉三颗,就是一种随意。 
59神采飞扬,不修边幅。 
60穿西装时记着把商标撕掉。 
61笑,在任何人面前。 
62让你周围的人因为你的存在而感到快乐。 
63怕硬可以,欺软不行。 
64选择婚姻,而不是婚姻选择你。 
65着装整洁,不必非得把皮鞋擦得锃亮。 
66随意。不必往头发上喷发胶或者定型水。 
67看一个女人虚荣不虚荣,就剃上光头衣冠不整地跟她一起走在大街上。注意她的表情。 
68一支玫瑰,或者一句甜言蜜语。关键时候,派上用场。女人是很容易满足的。 
69因为需要才喜欢,还是因为喜欢才需要。分清楚。 
70想跟女人分手时,设法让她先提出来。
71大智若愚。傻与不傻,先看你会不会装傻。 
72做一个出色的男人,先学会哄。 
73哄上司,哄同事,哄老人,哄女人,哄孩子。 
74如果以上你通通都能哄到,那么恭喜你,你的人生一定值得你炫耀。 
75魅力源于实力。 
76能让别人跟着你走,是你的魅力所在。 
77脾气温和,性格好斗。 
78内敛。该出手时再出手。 
79同流,但不合污。 
80异想天开。没有异想,何来天开? 
81沉稳。不乏可爱。 
82如果实在长相严肃,至少可以带点儿冷幽默。 
83有自己的立场和观点。不一定要表明出来。 
84说到做到。做到再说。 
85旅游。不必期待艳遇。 
86沉默。有些话是不必说出来的。 
87在女人面前,永远不要解释,只有认错。 
88邀请不熟的女士吃饭,要找些天时地利的借口。 
89像个君子,即使你不是。 
90先赚钱,再谈爱。 
91同居。如果你享受这种习惯。 
92享受眼前的同时,想想以后。 
93冷静和超然,即使是在危难时刻。装也要装出来。 
94得之淡然,失之泰然。一切皆顺其自然。 
95顺然自然,并不代表不去争取。 
96不要跟一般人一般见识,即使是特殊人也一样。 
97不要骂脏话。 
98侮辱一个人最好的方式就是置之不理。侮辱,而不是责骂。 
99认真。但不顽固。 
100好好生活。你的生命是一次性的。
posted @ 2005-06-15 10:04 小马歌 阅读(515) | 评论 (1)编辑 收藏
 

英文源文件:http://jakarta.apache.org/velocity/user-guide.html

目录
1. About this Guide
2. What is Velocity?
3. What can Velocity do for me?
1. The Mud Store example
4. Velocity Template Language (VTL): An Introduction
5. Hello Velocity World!
6. Comments
7. References
1. Variables
2. Properties
3. Methods
8. Formal Reference Notation
9. Quiet Reference Notation
10. Getting literal
1. Currency
2. Escaping Valid VTL References
11. Case Substitution
12. Directives
1. Set
2. String Literals
3. If-Else Statements
1. Relational and Logical Operators
4. Foreach Loops
5. Include
6. Parse
7. Stop
8. Velocimacros
2. Escaping VTL Directives
3. VTL: Formatting Issues
4. Other Features and Miscellany
1. Math
2. Range Operator
3. Advanced Issues: Escaping and !
4. Velocimacro Miscellany
5. String Concatenation
5. Feedback
Velocity是什么?
Velocity是一个基于java的模板引擎(template engine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。
当Velocity应用于web开发时,界面设计人员可以和java程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员可以只关注页面的显示效果,而由java程序开发人员关注业务逻辑编码。Velocity将java代码从web页面中分离出来,这样为web站点的长期维护提供了便利,同时也为我们在JSP和PHP之外又提供了一种可选的方案。
Velocity的能力远不止web站点开发这个领域,例如,它可以从模板(template)产生SQL和PostScript、XML,它也可以被当作一个独立工具来产生源代码和报告,或者作为其他系统的集成组件使用。Velocity也可以为Turbine web开发架构提供模板服务(template service)。Velocity+Turbine提供一个模板服务的方式允许一个web应用以一个真正的MVC模型进行开发。
Velocity能为我们作什么?
The Mud Store Example                                                  
假设你是一家专门出售Mud的在线商店的页面设计人员,让我们暂且称它为"在线MUD商店"。你们的业务很旺,客户下了各种类型和数量的mud订单。他们都是通过输入用户名和密码后才登陆到你的网站,登陆后就允许他们查看订单并购买更多的mud。现在,一种非常流行的mud正在打折销售。另外有一些客户规律性的购买另外一种也在打折但是不是很流行的Bright Red Mud,由于购买的人并不多所以它被安置在页面的边缘。所有用户的信息都是被跟踪并存放于数据库中的,所以某天有一个问题可能会冒出来:为什么不使用velocity来使用户更好的浏览他们感兴趣的商品呢?
Velocity使得web页面的客户化工作非常容易。作为一个web site的设计人员,你希望每个用户登陆时都拥有自己的页面。
你会见了一些公司内的软件工程师,你发现他们每个人都同意客户应该拥有具有个性化的信息。那让我们把软件工程师应该作的事情发在一边,看一看你应该作些什么吧。
你可能在页面内嵌套如下的VTL声明:
<html>
<body>
Hello  $customer.Name!
<table>
#foreach( $mud  in  $nudsOnSpecial )
    #if ( $customer.hasPurchased( $mud )  )
        <tr>
            <td>
                $flogger.getPromo( $mud )
            <td>
        <tr>
    #end
#end
</table>
Velocity Template Language(VTL):AN introduction
VTL意味着提供最简单、最容易并且最整洁的方式合并页面动态内容。
VTL使用references来在web site内嵌套动态内容,一个变量就是一种类型的reference。变量是某种类型的refreence,它可以指向java代码中的定义,或者从当前页面内定义的VTL statement得到值。下面是一个VTL statement的例子,它可以被嵌套到HTML代码中:
 #set ( $a = "Velocity" )
和所有的VTL statement一样,这个statement以#字符开始并且包含一个directive:set。当一个在线用户请求你的页面时,Velocity Templating Engine将查询整个页面以便发现所有#字符,然后确定哪些是VTL statement,哪些不需要VTL作任何事情。
#字符后紧跟一个directive:set时,这个set directive使用一个表达式(使用括号封闭)――一个方程式分配一个值给变量。变量被列在左边,而它的值被列在右边,最后他们之间使用=号分割。
在上面的例子中,变量是$a,而它的值是Velocity。和其他的references一样以$字符开始,而值总是以双引号封闭。Velocity中仅有String可以被赋值给变量。
记住以下的规则:
使用$字符开始的references用于得到什么;使用#字符开始的directives用于作些什么。
Hello Velocity World!
一旦某个变量被分配了一个值,那么你就可以在HTML文件的任何地方引用它。在下面的例子中,一个值被分配给$foo变量,并在其后被引用。
 <html>
 <body>
  #set ( $foo = "Velocity" )
  Hello $foo World!
 </body>
 </html>
上面的实现结果是在页面上打印"Hello Velocity World!"
为了使包含VTL directives的statement更具有可读性,我们鼓励你在新行开始每个VTL statement,尽管你不是必须这么作。Set directive将在后面详细描述。
注释
单行注释:
 ## This is a single line comment.
多行注释:
 #*
   Thus begins a multi-line comment. Online visitors won't
   see this text because the Velocity Templating Engine will
      ignore it.
 *#
文档格式:
 #**
   This is a VTL comment block and
   may be used to store such information
      as the document author and versioning
   information:
   @version 5
   @author
 *#
References
在VTL中有三种类型的references:变量(variables)、属性(properties)、方法(methods)。作为一个使用VTL的页面设计者,你和你的工程师必须就references的名称达成共识,以便你可以在你的template中使用它们。
Everything coming to and from a reference被作为一个String对象处理。如果有一个对象$foo是一个Integer对象,那么Velocity将调用它的toString()方法将这个对象转型为String类型。
 变量                                                                      
 格式要求同java。
 属性                                                                      
 例子:
  $customer.Address
  $purchase.Total
$customer.Address有两种含义。它可以表示:查找hashtable对象customer中以Address为关键字的值;也可以表示调用customer对象的getAddress()方法。当你的页面被请求时,Velocity将确定以上两种方式选用那种,然后返回适当的值。
方法                                                                      
一个方法就是被定义在java中的一段代码,并且它有完成某些有用工作的能力,例如一个执行计算和判断条件是否成立、满足等。方法是一个由$开始并跟随VTL标识符组成的References,一般还包括一个VTL方法体。例如:
 $customer.getAddress()
 $purchase.getTotal()
 $page.setTitle( "My Home Page" )
 $person.setAttributes( ["Strange", "Weird", "Excited"] )
前两个例子$customer.getAddress()和$purchase.getTotal()看起来挺想上面的属性$customer.Address 和 $purchase.Total。如果你觉得他们之间有某种联系的话,那你是正确的。
VTL属性可以作为VTL方法的缩写。$customer.Address属性和使用$customer.getAddress()方法具有相同的效果。如果可能的话使用属性的方式是比较合理的。属性和方法的不同点在于你能够给一个方法指定一个参数列表。
正式reference标记
reference的正是格式如下:
 ${mudSlinger}    变量
 ${customer.Address}  属性
 ${purchase.getTotal()}  方法
非正是格式更见常用,但是有时还是使用正是格式比较适合。例如:你希望通过一个变量$vice来动态的组织一个字符串。
 Jack is a $vicemaniac.
本来变量是$vice现在却变成了$vicemaniac,这样Veloctiy就不知道您到底要什么了。所以,应该使用正是格式书写
 Jack is a ${vice}maniac
现在Velocity知道变量是$vice而不是$vicemaniac。
Quiet reference notation
例如:
 <input  type="text"  name="email"  value="$email" />
当页面的form被初始加载时,变量$email还没有值,这时你肯定是希望它能够显示一个blank text来代替输出"$email"这样的字段。那么使用quiet reference notation就比较合适。
 <input  type="text"  name="email"  value="$!email"/>
这样文本框的初始值就不会是email而是空值了。
正式和quiet格式的reference notation也可一同使用,像下面这样:
 <input  type="text"  name="email"  value="$!{email}"/>
Getting literal                                                             
Velocity使用特殊字符$和#来帮助它工作,所以如果要在template里使用这些特殊字符要格外小心。本节将讨论$字符。
 货币字符                                                                  
在VTL中使用$2.5这样的货币标识是没有问题得的,VTL不会将它错认为是一个reference,因为VTL中的reference总是以一个大写或者小写的字母开始。
Escaping valid VTL reference                                             
VTL中使用"\"作为逃逸符。
例如:
 #set( $email = "foo" )
 $email
 \$email
 
\\$email
 \\\$email
将render为:
 foo
 $email
 \foo
 
\\$email
如果email变量没有被定义则
 $email
 \$email
 
\\$email
 \\\$email
将被render为:
 $email
 \$email
 
\\$email
 \\\$email
注意:VTL中未被定义的变量将被认为是一个字符串,所以以下例子:
 #set( $foo = "gibbous" )
 $moon = $foo
的输出结果是:
$moon = gibbous
Case substitution
现在你已经对reference比较熟悉了,你可以将他们高效的应用于你的template了。Velocity利用了很多java规范以方便了设计人员的使用。例如:
 $foo
 $foo.getBar()
 ## is the same as
 $foo.Bar

 $data.getUser("jon")
 ## is the same as
 $data.User("jon")

 $data.getRequest().getServerName()
 # is the same as
 $data.Request.ServerName
 ## is the same as
 ${data.Request.ServerName}
但是,注意VTL中不会将reference解释为对象的实例变量。例如:$foo.Name将被解释为Foo对象的getName()方法,而不是Foo对象的Name实例变量。
Directives
Reference允许设计者使用动态的内容,而directive使得你可以应用java代码来控制你的显示逻辑,从而达到你所期望的显示效果。
 #set                                                                      
 #set directive被用于设置一个reference的值。例如:
  #set ( $primate = "monkey" )
  #set ( $customer.Behavior = $primate )
赋值左侧的(LHS)必须是一个变量或者属性reference。右侧(RHS)可以是以下类型中一种:
  变量reference
  String literal
  属性reference
  方法reference
  number literal
  ArrayList
下面是应用各种类型的RHS的例子:
 #set ( $monkey = $bill ) ##变量reference
 #set ( $monkey.Friend = "monica" ) ##String literal
 #set ( $monkey.Blame = $whitehouse.Leak )##属性reference
 #set ( $monkey.Plan = $spindoctor.weave($web) )##方法reference
 #set ( $monkey.Number = 123 )##Number literal
 #set ( $monkey.Say = ["Not", $my, "fault"] )##ArrayList
注意:最后一个例子的取值方法为:$monkey.Say.get(0)
RHS也可以是一个简单的算术表达式:
 #set ( $value = $foo + 1 )
 #set ( $value = $bar -1 )
#set ( $value = $foo * $bar )
#set ( $value = $foo / $bar )
如果你的RHS是一个null,VTL的处理将比较特殊:它将指向一个已经存在的reference,这对初学者来讲可能是比较费解的。例如:
 #set ( $resut = $query.criteria("name") )
 The result of the first query is $result

 #set ( $resut = $query.criteria("address") )
 The result of the second query is $result
如果$query.criteria("name")返回一个"bill",而$query.criteria("address")返回的是null,则显示的结果如下:
 The result of the first query is bill
 The result of the first query is bill
看看下面的例子:
 #set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
    #set( $result = $query.criteria($criterion) )
     #if( $result )
         Query was successful
      #end
#end
在上面的例子中,程序将不能智能的根据$result的值决定查询是否成功。在$result被#set后(added to the context),它不能被设置回null(removed from the context)。打印的结果将显示两次查询结果都成功了,但是实际上有一个查询是失败的。
为了解决以上问题我们可以通过预先定义的方式:
 #set( $criteria = ["name", "address"] )
 #foreach( $criterion in $criteria )
  #set( $result = false )
  #set( $result = $query.criteria( $criterion ) )
  #if( $result )
   Query was successful
  #end
 #end
 String Literals                                                        
 当你使用#set directive,String literal封闭在一对双引号内。
  #set ( $directoryRoot = "www" )
  #set ( $templateName = "index.vm" )
  #set ( $template = "$directoryRoot/$tempateName" )
  $template
 上面这段代码的输出结果为:www/index.vm
 但是,当string literal被封装在单引号内时,它将不被解析:
  #set ( $foo = "bar" )
  $foo
  #set ( $blargh = '$foo' )
 结果:
  bar
  $foo
 上面这个特性可以通过修改velocity.properties文件的stringliterals.interpolate = false的值来改变上面的特性是否有效。
条件语句
 if/elseif/else                                                              
当一个web页面被生成时使用Velocity的#if directrive,如果条件成立的话可以在页面内嵌入文字。例如:
 #if ( $foo )
  <strong>Velocity!</strong>
 #end
上例中的条件语句将在以下两种条件下成立:
  $foo是一个boolean型的变量,且它的值为true
  $foo变量的值不为null
这里需要注意一点:Velocity context仅仅能够包含对象,所以当我们说"boolean"时实际上代表的时一个Boolean对象。即便某个方法返回的是一个boolean值,Velocity也会利用内省机制将它转换为一个Boolean的相同值。
如果条件成立,那么#if和#end之间的内容将被显示。
#elseif和#else元素可以同#if一同使用。例如:
 #if( $foo < 10 )
  <strong> Go North </strong>
 #elseif( $foo == 10 )
  <strong> Go East </strong>
 #elseif( $foo == 6 )
  <strong> Go South </strong>
 #else
  <strong> Go West </strong>
 #end
注意这里的Velocity的数字是作为Integer来比较的――其他类型的对象将使得条件为false,但是与java不同它使用"=="来比较两个值,而且velocity要求等号两边的值类型相同。
关系、逻辑运算符                                                          
Velocity中使用等号操作符判断两个变量的关系。例如:
 #set ( $foo = "deoxyribonucleic acid" )
 #set ( $bar = "ribonucleic acid" )
 #if ( $foo == $foo )
  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和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
循环                                                                      
 Foreach循环                                                              
 例子:
  <ul>
   #foreach ( $product in $allProducts )
    <li> $product </li>
   #end
  </ul>
 每次循环$allProducts中的一个值都会赋给$product变量。
$allProducts可以是一个Vector、Hashtable或者Array。分配给$product的值是一个java对象,并且可以通过变量被引用。例如:如果$product是一个java的Product类,并且这个产品的名字可以通过调用他的getName()方法得到。
现在我们假设$allProducts是一个Hashtable,如果你希望得到它的key应该像下面这样:
 <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默认的名字,你也可以通过修改velocity.properties文件来改变它。默认情况下,计数从"1"开始,但是你可以在velocity.properties设置它是从"1"还是从"0"开始。下面就是文件中的配置:
 # Default name of loop counter
 # variable reference
 directive.foreach.counter.name = velocityCount

 # Default starting value of the loop
 # counter variable reference
 directive.foreach.counter.initial.value = 1
include
#include script element允许模板设计者引入本地文件。被引入文件的内容将不会通过模板引擎被render。为了安全的原因,被引入的本地文件只能在TEMPLATE_ROOT目录下。
 #inclued ( "one.txt" )
如果您需要引入多个文件,可以用逗号分隔就行:
 #include ( "one.gif", "two.txt", "three.htm" )
在括号内可以是文件名,但是更多的时候是使用变量的:
 #inclue ( "greetings.txt", $seasonalstock )
parse
#parse script element允许模板设计者一个包含VTL的本地文件。Velocity将解析其中的VTL并render模板。
 #parse( "me.vm" )
就像#include,#parse接受一个变量而不是一个模板。任何由#parse指向的模板都必须包含在TEMPLATE_ROOT目录下。与#include不同的是,#parse只能指定单个对象。
你可以通过修改velocity.properties文件的parse_direcive.maxdepth的值来控制一个template可以包含的最多#parse的个数――默认值是10。#parse是可以递归调用的,例如:如果dofoo.vm包含如下行:
 Count down.
 #set ( $count = 8 )
 #parse ( "parsefoo.vm" )
 All done with dofoo.vm!
那么在parsefoo.vm模板中,你可以包含如下VTL:
 $count
 #set ( $count = $count - 1 )
 #if ( $count > 0 )
  #parse( "parsefoo.vm" )
 #else
  All done with parsefoo.vm!
 #end
的显示结果为:
 Count down.
 8
 7
 6
 5
 4
 3
 2
 1
 0
 All done with parsefoo.vm!
All done with dofoo.vm!
Stop
#stop script element允许模板设计者停止执行模板引擎并返回。把它应用于debug是很有帮助的。
 #stop
Velocimacros
#macro script element允许模板设计者定义一段可重用的VTL template。例如:
 #macro ( d )
 <tr><td></td></tr>
 #end
在上面的例子中Velocimacro被定义为d,然后你就可以在任何VTL directive中以如下方式调用它:
 #d()
当你的template被调用时,Velocity将用<tr><td></td></tr>替换为#d()。
每个Velocimacro可以拥有任意数量的参数――甚至0个参数,虽然定义时可以随意设置参数数量,但是调用这个Velocimacro时必须指定正确的参数。下面是一个拥有两个参数的Velocimacro,一个参数是color另一个参数是array:
 #macro ( tablerows $color $somelist )
 #foreach ( $something in $somelist )
  <tr><td bgcolor=$color>$something</td</tr>
 #end
 #end
调用#tablerows Velocimacro:
 #set ( $greatlakes = [ "Superior", "Michigan", "Huron", "Erie", "Ontario" ] )
 #set ( $color = "blue" )
 <table>
  #tablerows( $color $greatlakes )
 </table>
经过以上的调用将产生如下的显示结果:
 <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可以在Velocity模板内实现行内定义(inline),也就意味着同一个web site内的其他Velocity模板不可以获得Velocimacros的定义。定义一个可以被所有模板共享的Velocimacro显然是有很多好处的:它减少了在一大堆模板中重复定义的数量、节省了工作时间、减少了出错的几率、保证了单点修改。
上面定义的#tablerows( $color $list )Velocimacro被定义在一个Velocimacros模板库(在velocity.properties中定义)里,所以这个macro可以在任何规范的模板中被调用。它可以被多次应用并且可以应用于不同的目的。例如下面的调用:
 #set ( $parts = [ "volva", "stipe", "annulus", "gills", "pileus" ] )
 #set ( $cellbgcol = "#CC00FF" )
 <table>
  #tablerows( $cellbgcol $parts )
 </table>
上面VTL将产生如下的输出:
 <table>
  <tr><td bgcolor="#CC00FF"> volva </td</tr>
  <tr><td bgcolor="#CC00FF"> stipe </td</tr>
  <tr><td bgcolor="#CC00FF"> annulus </td</tr>
  <tr><td bgcolor="#CC00FF"> gills </td</tr>
  <tr><td bgcolor="#CC00FF"> pileus </td</tr>
 </table>
 Velocimacro arguments                                                  
 Velocimacro可以使用以下任何元素作为参数:
  Reference:任何以$开头的reference
  String literal:
  Number literal:
  IntegerRange:[1….3]或者[$foo….$bar]
  对象数组:["a","b","c"]
  boolean值:true、false
当将一个reference作为参数传递给Velocimacro时,请注意reference作为参数时是以名字的形式传递的。这就意味着参数的值在每次Velocimacro内执行时才会被产生。这个特性使得你可以将一个方法调用作为参数传递给Velocimacro,而每次Velocimacro执行时都是通过这个方法调用产生不同的值来执行的。例如:
 #macro ( callme $a )
  $a $a $a
 #end
 #callme( $foo.bar() )
执行的结果是:reference $foo的bar()方法被执行了三次。
如果你不需要这样的特性可以通过以下方法:
 #set ( $myval = $foo.bar() )
 #callme ( $myval )
Velocimacro properties                                                  
Velocity.properties文件中的某几行能够使Velocimacros的实现更加灵活。注意更多的内容可以看Developer Guide。
Velocity.properties文件中的velocimacro.libraary:一个以逗号分隔的模板库列表。默认情况下,velocity查找唯一的一个库:VM_global_library.vm。你可以通过配置这个属性来指定自己的模板库。
Velocity.properties文件中的velocimacro.permissions.allow.inline属性:有两个可选的值true或者false,通过它可以确定Velocimacros是否可以被定义在regular template内。默认值是ture――允许设计者在他们自己的模板中定义Velocimacros。
Velocity.properties文件中的
velocimacro.permissions.allow.inline.replace.global属性有两个可选值true和false,这个属性允许使用者确定inline的Velocimacro定义是否可以替代全局Velocimacro定义(比如在velocimacro.library属性中指定的文件内定义的Velocimacro)。默认情况下,此值为false。这样就阻止本地Velocimacro定义覆盖全局定义。
Velocity.properties文件中的
velocimacro.permissions.allow.inline.local.scale属性也是有true和false两个可选值,默认是false。它的作用是用于确定你inline定义的Velocimacros是否仅仅在被定义的template内可见。换句话说,如果这个属性设置为true,一个inline定义的Velocimacros只能在定义它的template内使用。你可以使用此设置实现一个奇妙的VM敲门:a template can define a private implementation of the second VM that will be called by the first VM when invoked by that template. All other templates are unaffected。
Velocity.properties文件中的velocimacro.context.localscope属性有true和false两个可选值,默认值为false。当设置为true时,任何在Velocimacro内通过#set()对context的修改被认为是针对此velocimacro的本地设置,而不会永久的影响内容。
Velocity.properties文件中的velocimacro.library.autoreload属性控制Velocimacro库的自动加载。默认是false。当设置为ture时,对于一个Velocimacro的调用将自动检查原始库是否发生了变化,如果变化将重新加载它。这个属性使得你可以不用重新启动servlet容器而达到重新加载的效果,就像你使用regular模板一样。这个属性可以使用的前提就是resource loader缓存是off状态(file.resource.loader.cache = false)。注意这个属性实际上是针对开发而非产品的。
Velocimacro Trivia                                                        
Velocimacro必须被定义在他们被使用之前。也就是说,你的#macro()声明应该出现在使用Velocimacros之前。
特别要注意的是,如果你试图#parse()一个包含#macro()的模板。因为#parse()发生在运行期,但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素,这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果,只需要你简单的使用velocimacro.library使得Velocity在启动时加载你的VMs。
Escaping VTL directives
VTL directives can be escaped with "\"号,使用方式跟VTL的reference使用逃逸符的格式差不多。
 ## #include( "a.txt" ) renders as <ontents of a.txt>(注释行)
 #include( "a.txt" )

 ## \#include( "a.txt" ) renders as \#include( "a.txt" )
 \#include( "a.txt" )

 ## \\#include ( "a.txt" ) renders as \<contents of a.txt>
 
\\#include( "a.txt" )
在对在一个directive内包含多个script元素的VTL directives使用逃逸符时要特别小心(比如在一个if-else-end statement内)。下面是VTL的if-statement的典型应用:
 #if ( $jazz )
  Vyacheslav Ganelin
 #end
如果$jazz是ture,输出将是:
 Vyacheslav Ganelin
如果$jazz是false,将没有输出。使用逃逸符将改变输出。考虑一下下面的情况:
 \#if ( $jazz )
  Vyacheslav Ganelin
 \#end
现在无论$jazz是true还是false,输出结果都是:
 #if ( $jazz )
  Vyacheslav Ganelin
 #end
事实上,由于你使用了逃逸符,$jazz根本就没有被解析为boolean型值。在逃逸符前使用逃逸符是合法的,例如:
 
\\#if ( $jazz )
  Vyacheslav Ganelin
 
\\#end
以上程序的显示结果为:
 \ Vyacheslav Ganelin
 \
但是如果$jazz为false,那么将没有输出。(书上说会没有输出,但是我觉得应该还有有"\"字符被输出。)
VTL:Formatting issues
尽管在此用户手册中VTL通常都开始一个新行,如下所示:
 #set ( $imperial = [ "Munetaka", "Koreyasu", "Hisakira", "Morikune" ] )
 #foreach ( $shogun in $imperial )
  $shogun
 #end
但是像下面这种写法也是可以的:
 Send me #set($foo = ["$10 and","a cake"])#foreach($a in $foo)$a #end please.
上面的代码可以被改写为:
 Send me
 #set ( $foo = ["$10 and ","a cake"] )
 #foreach ( $a in $foo )
  $a
 #end
 please.
或者
 Send me
 #set($foo      = ["$10 and ","a cake"])
    #foreach         ($a in $foo )$a
   #end please.
这两种的输出结构将一样。
其他特性和杂项
 math                                                                       在模板中可以使用Velocity内建的算术函数,如:加、减、乘、除
  #set ( $foo = $bar + 3 )
  #set ( $foo = $bar - 4 )
  #set ( $foo = $bar * 6 )
  #set ( $foo = $bar / 2 )
 当执行除法时将返回一个Integer类型的结果。而余数你可以使用%来得到:
  #set ( $foo = $bar % 5 )
在Velocity内使用数学计算公式时,只能使用像-n,-2,-1,0,1,2,n这样的整数,而不能使用其它类型数据。当一个非整型的对象被使用时它将被logged并且将以null作为输出结果。
Range Operator
Range operator可以被用于与#set和#foreach statement联合使用。对于处理一个整型数组它是很有用的,Range operator具有以下构造形式:
 [n..m]
m和n都必须是整型,而m是否大于n则无关紧要。例子:
 First example:
 #foreach ( $foo in [1..5] )
  $foo
 #end

 Second example:
 #foreach ( $bar in [2..-2] )
  $bar
 #end

 Third example:
 #set ( $arr = [0..1] )
 #foreach ( $i in $arr )
  $i
 #end

 Fourth example:
 [1..3]
上面四个例子的输出结果为:
 First example:
 1 2 3 4 5

 Second example:
 2 1 0 -1 -2

 Third example:
 0 1

 Fourth example:
 [1..3]
注意:range operator只在#set和#foreach中有效。
Advanced Issue:Escaping and!
当一个reference被"!"分隔时,并且在它之前有逃逸符时,reference将以特殊的方式处理。注意这种方式与标准的逃逸方式时不同的。对照如下:
#set ( $foo = "bar" )
特殊形式 标准格式
Render前 Render后 Render前 Render后
$\!foo $!foo \$foo \$foo
$\!{foo} $!{foo} \$!foo \$!foo
$\\!foo $\!foo \$!{foo} \$!{foo}
$\\\!foo $\\!foo 
\\$!{foo} \bar
Velocimacro杂记
 Can I user a directive or another VM as an argument to a VM?     
 例如:#center ( #bold( "hello" ) )
 不可以。一个directive的参数使用另外一个directive是不合法的。
 但是,还是有些事情你可以作的。最简单的方式就是使用双引号:
  #set ( $stuff = "#bold( 'hello' )" )
  #center ( $stuff )
 上面的格式也可以缩写为一行:
  #center ( "#bold( 'hello' ) )
请注意在下面的例子中参数被evaluated在Velocimacro内部,而不是在calling level。例子:
 #macro ( inner $foo )
  inner : $foo
 #end

 #macro ( outer $foo )
  #set ( $bar = "outerlala" )
  outer : $foo
 #end
 
 #set ( $bar = 'calltimelala' )
 #outer( "#inner($bar)" )
输出结果为:
 outer : inner : outerlala
记住Veloctiy的特性:参数的传递是By Name的。例如:
 #macro ( foo $color )
  <tr bgcolor = $color ><td>Hi</td></tr>
  <tr bgcolor = $color ><td>There</td></tr>
 #end

 #foo ( $bar.rowColor() )
以上代码将导致rowColor()方法两次调用,而不是一次。为了避免这种现象的出现,我们可以按照下面的方式执行:
 #set ( $color = $bar.rowColor() )
 #foo ( $color )
can I register velocimacros via #parse()?                                
目前,Velocimacros必须在第一次被模板调用前被定义。这就意味着你的#macro()声明应该出现在使用Velocimacros之前。
如果你试图#parse()一个包含#macro() directive的模板,这一点是需要牢记的。因为#parse()发生在运行期,但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素,这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果,只需要你简单的使用velocimacro.library使得Velocity在启动时加载你的VMs。
What is velocimacro autoreloading?                                      
velocimacro.library.autoreload是专门为开发而非产品使用的一个属性。此属性的默认值是false。
String concatenation
开发人员最常问的问题是我如何作字符拼接?在java中是使用"+"号来完成的。
在VTL里要想实现同样的功能你只需要将需要联合的reference放到一起就行了。例如:
#set ( $size = "Big" )
#set ( $name = "Ben" )
The clock is $size$name.
输出结果将是:The clock is BigBen.。更有趣的情况是:
 #set ( $size = "Big" )
 #set ( $name = "Ben" )
 #set ( $clokc = "$size$name" )
 The clock is $clock.
上例也会得到同样的结果。最后一个例子,当你希望混合固定字段到你的reference时,你需要使用标准格式:
 #set ( $size = "Big" )
 #set ( $name = "Ben" )
 #set ( $clock = "${size}Tall$name" )
 The clock is $clock.
输出结果是:The clock is BigTallBen.。使用这种格式主要是为了使得$size不被解释为$sizeTall。
反馈

 

posted @ 2005-06-14 22:50 小马歌 阅读(446) | 评论 (0)编辑 收藏
 
     摘要:   第一章 XML的发展背景     XML是W3C在1996年底提出的标准,是从SGML衍生出来的简化格式,也是一种元语言(meta-language),可以用来定义任何一种新的标示语言。XML的制定是为了补HTML的不足,使得在Web上能够传输、处理各类复杂的文件,它舍去了SGML复杂不常用及不利于在Web传送的选项功能,让使用者可以很容易地定义属于...  阅读全文
posted @ 2005-06-14 22:39 小马歌 阅读(2714) | 评论 (1)编辑 收藏
 

1.Velocity 的使用

Velocity是一个开放源码的模版引擎,由apache.org小组负责开发,现在最新的版本是Velocity1.4,
http://jakarta.apache.org/velocity/index.html 可以了解Velocity的最新信息。
Velocity允许我们在模版中设定变量,然后在运行时,动态的将数据插入到模版中,替换这些变量。
例如:
<html>
<body>HELLO $CUSTOMERNAME</body>
</html>
我们可以在运行时得到客户的名字,然后把它插入到这个模版中替换变量$CUSTOMERNAME,整个替换过程是由Velocity进行控制的,而且java的调用代码也非常简单,如我们可以在java代码中这样调用

/***********************************************************/ 
//这个文件中设定了Velocity使用的log4j的配置和Velocity的模版文件所在的目录 
Velocity.init("D:\\Template\\resource\\jt.properties"); 
//模版文件名,模版文件所在的路径在上一条语句中已经设置了 
Template template = Velocity.getTemplate("hello.vm""gb2312"); 
//实例化一个Context 
VelocityContext context = new VelocityContext(); 
//把模版变量的值设置到context中 
context.put("CUSTOMERNAME""My First Template Engine ---- Velocity."); 
//开始模版的替换 
template.merge(context, writer); 
//写到文件中 
PrintWriter filewriter = new PrintWriter(new FileOutputStream(outpath),true); 
filewriter.println(writer.toString()); 
filewriter.close(); 
/***********************************************************/ 


这就是整个java的代码,非常的简单。如果我们有多个模版变量,我们仅需要把这些模版变量的值设置到context中。
下面我们简单的分析一下,Velocity引擎读取模板文件时,它直接输出文件中所有的文本,但以$字符开头的除外,$符号标识着一个模版变量位置,
context.put("CUSTOMERNAME", "My First Template Engine ---- Velocity.");
当 Velocity 模板引擎解析并输出模板的结果时,模板中所有出现$CUSTOMERNAME的地方都将插入客户的名字,即被加入到VelocityContext的对象的toString()方法返回值将替代Velocity变量(模板中以$开头的变量)。
模板引擎中最强大、使用最频繁的功能之一是它通过内建的映像(Reflection)引擎查找对象信息的能力。这个映像引擎允许用一种方便的Java“.”类似的操作符,提取任意加入到VelocityContext的对象的任何公用方法的值,或对象的任意数据成员。
映像引擎还带来了另外一个改进:快速引用JavaBean的属性。使用JavaBean属性的时候,我们可以忽略get方法和括号。请看下面这个模板的例子。
<html>
<body>
Name:$Customer.Name()
Address:$Customer.Address()
Age:$Customer.Age()
</body>
</html>

java的代码:

/***********************************************************/ 
//设置客户信息 
Customer mycustomer = new Customer(); 
mycustomer.setName(
"Velocity"); 
mycustomer.setAddress(
"jakarta.apache.org/velocity/index.html"); 
mycustomer.setAge(
2); 
//这个文件中设定了 Velocity 使用的 Log4j 的配置和Velocity的模版文件所在的目录Velocity.init("D:\\Template\\resource\\jt.properties"); 
//模版文件名,模版文件所在的路径在上一条语句中已经设置了 
Template template = Velocity.getTemplate("hello.vm""gb2312"); 
//实例化一个Context 
VelocityContext context = new VelocityContext(); 
//把模版变量的值设置到context中 
context.put("Customer", mycustomer); 
//开始模版的替换 
template.merge(context, writer); 
//写到文件中 
PrintWriter filewriter = new PrintWriter(new FileOutputStream(outpath),true); 
filewriter.println(writer.toString()); 
filewriter.close(); 

输出结果:
<html>
<body>
Name:Velocity
Address:jakarta.apache.org/velocity/index.html
Age:2
</body>
</html>
除了替换变量之外,象Velocity高级引擎还能做其他许多事情,它们有用来比较和迭代的内建指令,通过这些指令我们可以完成程序语言中的条件判断语句和循环语句等。
例如,我们想要输出年龄等于2的所有客户的信息,我们可以这样定义我们的模版
模版:
<html>
<body>
<table>
<tr>
<td>名称</td>
<td>地址</td>
<td>年龄</td>
</tr>
#foreach ($Customer in $allCustomer)
#if($Customer.Age()=="2")
<tr>
<td>$Customer.Name()</td>
<td>$Customer.Address()</td>
<td>$Customer.Age()</td>
</tr>
#end
#end
</table>
</body>
</html>

java的代码:
 

/******************************************************/ 
//设置客户信息 
ArrayList allMyCustomer = new ArrayList(); 
//客户1 
Customer mycustomer1 = new Customer(); 
mycustomer1.setName(
"Velocity"); 
mycustomer1.setAddress(
"jakarta.apache.org/velocity/index.html"); 
mycustomer1.setAge(
2); 
//客户2 
Customer mycustomer2 = new Customer(); 
mycustomer2.setName(
"Tomcat"); 
mycustomer2.setAddress(
"jakarta.apache.org/tomcat/index.html"); 
mycustomer2.setAge(
3); 
//客户3 
Customer mycustomer3 = new Customer(); 
mycustomer3.setName(
"Log4J"); 
mycustomer3.setAddress(
"jakarta.apache.org/log4j/docs/index.html"); 
mycustomer3.setAge(
2); 
//添加到allMyCustomer(ArrayList)中. 
allMyCustomer.add(mycustomer1); 
allMyCustomer.add(mycustomer2); 
allMyCustomer.add(mycustomer3); 
//这个文件中设定了Velocity使用的log4j的配置和Velocity的模版文件所在的目 
Velocity.init("D:\\Template\\resource\\jt.properties"); 
//模版文件名,模版文件所在的路径在上一条语句中已经设置了 
Template template =Velocity.getTemplate("hello.vm""gb2312"); 
//实例化一个Context 
VelocityContext context = new VelocityContext(); 
/** 注意这里我们仅仅需要给一个模版变量负值 */ 
context.put(
"allCustomer", allMyCustomer); 
//开始模版的替换 
template.merge(context, writer); 
//写到文件中 
PrintWriter filewriter = new PrintWriter(new FileOutputStream(outpath),true); 
filewriter.println(writer.toString()); 
filewriter.close(); 
/******************************************************/ 

结果:
<html>
<body>
<table>
<tr>
<td>名称</td>
<td>地址</td>
<td>年龄</td>
</tr>
<tr>
<td>Velocity</td>
<td>jakarta.apache.org/velocity/index.html</td>
<td>2</td>
</tr>
<tr>
<td>Log4J</td>
<td>jakarta.apache.org/log4j/docs/index.html</td>
<td>2</td>
</tr>
</table>
</body>
</html>

#if 语句完成逻辑判断,这个我想不用多说了。
allCustomer对象包含零个或者多个Customer对象。由于ArrayList (List, HashMap, HashTable, Iterator, Vector等)属于Java Collections Framework的一部分,我们可以用#foreach指令迭代其内容。我们不用担心如何定型对象的类型——映像引擎会为我们完成这个任务。#foreach指令的一般格式是“#foreach in ”。#foreach指令迭代list,把list中的每个元素放入item参数,然后解析#foreach块内的内容。对于list内的每个元素,#foreach块的内容都会重复解析一次。从效果上看,它相当于告诉模板引擎说:“把list中的每一个元素依次放入item变量,每次放入一个元素,输出一次#foreach块的内容”。

2.MVC设计模型

使用模板引擎最大的好处在于,它分离了代码(或程序逻辑)和表现(输出)。由于这种分离,你可以修改程序逻辑而不必担心邮件消息本身;类似地,你(或公关部门的职员)可以在不重新编译程序的情况下,重新编写客户列表。实际上,我们分离了系统的数据模式(Data Model,即提供数据的类)、控制器(Controller,即客户列表程序)以及视图(View,即模板)。这种三层体系称为Model-View-Controller模型(MVC)。
如果遵从MVC模型,代码分成三个截然不同的层,简化了软件开发过程中所有相关人员的工作。
结合模板引擎使用的数据模式可以是任何Java对象,最好是使用Java Collection Framework的对象。控制器只要了解模板的环境(如VelocityContext),一般这种环境都很容易使用。
一些关系数据库的“对象-关系”映射工具能够和模板引擎很好地协同,简化JDBC操作;对于EJB,情形也类似。 模板引擎与MVC中视图这一部分的关系更为密切。模板语言的功能很丰富、强大,足以处理所有必需的视图功能,同时它往往很简单,不熟悉编程的人也可以使用它。模板语言不仅使得设计者从过于复杂的编程环境中解脱出来,而且它保护了系统,避免了有意或无意带来危险的代码。例如,模板的编写者不可能编写出导致无限循环的代码,或侵占大量内存的代码。不要轻估这些安全机制的价值;大多数模板编写者不懂得编程,从长远来看,避免他们接触复杂的编程环境相当于节省了你自己的时间。 许多模板引擎的用户相信,在采用模板引擎的方案中,控制器部分和视图部分的明确分离,再加上模板引擎固有的安全机制,使得模板引擎足以成为其他内容发布系统(比如JSP)的替代方案。因此,Java模板引擎最常见的用途是替代JSP也就不足为奇了。

3.HTML处理

由于人们总是看重模板引擎用来替换JSP的作用,有时他们会忘记模板还有更广泛的用途。到目前为止,模板引擎最常见的用途是处理HTML Web内容。但我还用模板引擎生成过SQL、email、XML甚至Java源代码。

posted @ 2005-06-13 15:57 小马歌 阅读(474) | 评论 (1)编辑 收藏
 

一般来说,ResourceBundle类通常是用于针对不同的语言来使用的属性文件。

而如果你的应用程序中的属性文件只是一些配置,并不是针对多国语言的目的。那么使用Properties类就可以了。

通常可以把这些属性文件放在某个jar文件中。然后,通过调用class的getResourceAsStream方法,来获得该属性文件的流对象,再用Properties类的load方法来装载。

示例如下:

Class TestLoad {
           
public static void main( String[] argv) {
                     InputStream 
is = TestLoad.class.getResourceAsSteam("myprops.properties");
                     Properties p 
= new Properties();
                     p.load(
is);
                     System.
out.println(p.get("MAIL_SERVER_HOSTNAME"));
           }

}

有时候有些简单的配置文件可以没必要使用xml,其实ResourceBundle类就已经做的很好的。它甚至可以搜索到classpath里的jar文件中一些properties文件。

例如在jar文件中的根目录放置一个文件:test.properties,然后只要这个jar文件在classpath里。就可以使用这样的语句来获得一些属性:

  ResourceBundle rb = ResourceBundle.getBundle("test");
  String s = rb.getString("MQ_Server_Address");
  System.out.println(s);

posted @ 2005-06-08 19:15 小马歌 阅读(6165) | 评论 (0)编辑 收藏
 
##数据库和表空间恢复
#数据库恢复

下面是 RESTORE 命令的语法:


RESTORE DATABASE source-database-alias { restore-options | CONTINUE | ABORT }

restore-options:
  [USER username [USING password]] [{TABLESPACE [ONLINE] |
  TABLESPACE (tblspace-name [ {,tblspace-name} ... ]) [ONLINE] |
  HISTORY FILE [ONLINE]}] [INCREMENTAL [AUTOMATIC | ABORT]]
  [{USE {TSM | XBSA} [OPEN num-sess SESSIONS] |
  FROM dir/dev [ {,dir/dev} ... ] | LOAD shared-lib
  [OPEN num-sess SESSIONS]}] [TAKEN AT date-time] [TO target-directory]
  [INTO target-database-alias] [NEWLOGPATH directory]
  [WITH num-buff BUFFERS] [BUFFER buffer-size]
  [DLREPORT file-name] [REPLACE EXISTING] [REDIRECT] [PARALLELISM n]
  [WITHOUT ROLLING FORWARD] [WITHOUT DATALINK] [WITHOUT PROMPTING]


让我们研究一个示例。要执行 sample 数据库的恢复,请使用以下命令:


(1)RESTORE DATABASE sample
(2)  FROM  C:\DBBACKUP
(3)  TAKEN AT 20030314131259
(4)  WITHOUT ROLLING FORWARD
(5)  WITHOUT PROMPTING


让我们更仔细地研究该命令:

指明要恢复的数据库映像的名称。
指定要从什么位置读取输入备份文件。
如果目录中有多个备份映像,那么该选项将根据时间戳记(它是备份名称的一部分)确定特定的备份。
如果为数据库启用了归档日志记录,那么当恢复该数据库时,它将自动被置于前滚暂挂状态。这行告诉 DB2 不要使数据库处于前滚暂挂状态。
在执行 RESTORE 时,不会提示您。
请注意,语法中没有关键字 OFFLINE,因为这是缺省方式。事实上,对于 RESTORE 实用程序,这是数据库允许的唯一方式。

#表空间恢复

表空间恢复需要相当仔细的规划,因为比较容易犯错,这会使数据处于不一致状态。

下面是表空间 RESTORE 命令的示例:


(1)RESTORE DATABASE sample
(2)  TABLESPACE ( mytblspace1 )
(3)  ONLINE
(4)  FROM /db2tbsp/backup1, /db2tbsp/backup2


让我们更仔细地研究该命令:

指明要恢复的数据库映像的名称。
指出这是表空间 RESTORE,并指定要恢复的一个或多个表空间的名称。
指出这是联机恢复。注:对于用户表空间,既允许联机恢复也允许脱机恢复。正如前面所提到的那样,对于数据库,只允许脱机恢复。
指定输入备份文件所在的位置。
表空间恢复注意事项

恢复表空间之后,它将始终处于前滚暂挂状态。要使表空间可访问并复位该状态,必须至少将表空间前滚到最小的时间点
(point in time,PIT)。该最小的 PIT 确保表空间和日志与系统目录中的内容保持一致。

请考虑下面的示例:

假设在时间 t1 您执行了完全数据库备份,该备份包括了表空间 mytbls1
在时间 t2,您在表空间 mytbls1 中创建了表 myTable。这会将表空间 mytbs1 恢复的最小 PIT 设置为 t2。
在时间 t3,您决定仅从在 t1 进行的完全数据库备份恢复表空间 mytbls1。
恢复完成之后,表空间 mytbls1 将处于前滚暂挂状态。如果允许前滚到最小 PIT 之前的某一点,则表空间 mytbls1 将失去表 myTable;然而,系统目录将显示该表确实存在于 mytbls1 中。因此,为了避免类似的不一致,DB2 会在您恢复表空间时强制您至少前滚到最小 PIT。
当针对表空间或表空间中的表运行 DDL 语句时,会更新最小的 PIT。为了确定表空间恢复的最小 PIT,可以使用下列两种方法之一:

使用 LIST TABLESPACES SHOW DETAIL 命令
通过 GET SNAPSHOT FOR TABLESPACE ON db_name 命令获取表空间快照。
另外,系统目录表空间(SYSCATSPACE)必须前滚到日志的末尾并处于脱机方式。

#重定向恢复
我们前面提到过备份文件包括有关表空间和容器的信息。如果过去存在的容器在进行备份时不再存在时,会发生什么情况?如果 RESTORE 实用程序找不到该容器,那么您将得到一个错误。

如果您不想在这个位置恢复该备份,而想在别的位置进行恢复,但在那个地方又使用了其它配置,该怎么办?同样,在该情况下恢复备份将会产生问题。

重定向恢复解决了这些问题。重定向恢复的恢复备份过程只有四个步骤:

获取记录在输入备份中的、有关容器和表空间的信息。通过将 REDIRECT 关键字包含在 RESTORE 命令中就能完成这一任务。例如:

RESTORE DATABASE DB2CERT FROM C:\DBBACKUP
        INTO NEWDB REDIRECT WITHOUT ROLLING FORWARD

不需要事先产生数据库NEWDB
下面是该命令的输出:


SQL1277N  Restore has detected that one or more table space containers are
inaccessible, or has set their state to 'storage must be defined'.
DB20000I  The RESTORE DATABASE command completed successfully.

注意:此时已经创建了数据库NEWDB。

复查来自(部分)恢复数据库 newdb 的表空间信息:

LIST TABLESPACES SHOW DETAIL
表空间还没有产生。

为每个表空间设置新容器。表空间有一个标识,可以从 LIST TABLESPACES 命令的输出获取这个标识。如下使用该标识:

SET TABLESPACE CONTAINERS FOR 0 USING (FILE "d:\newdb\cat0.dat" 5000)
SET TABLESPACE CONTAINERS FOR 1 USING (FILE "d:\newdb\cat1.dat" 5000)
...
SET TABLESPACE CONTAINERS FOR n USING (PATH "d:\newdb2")

上面命令将产生表空间。

在上面的示例中,n 表示备份中某一个表空间的标识。另外请注意,对于重定向恢复,不能更改表空间的类型;即,如果表空间是 SMS,那么就不能将它更改为 DMS。

通过将关键字 CONTINUE 包含在 RESTORE 命令中,开始将数据本身恢复到新容器中,如下所示:

RESTORE DATABASE DB2CERT CONTINUE
现在,您已经了解了重定向恢复是如何工作的。也可以将它用于为 SMS 表空间添加容器。如果您阅读过本系列的第二篇教程,那么您应该知道在大多数情况下不能对 SMS 表空间进行修改以添加容器。重定向恢复为这一限制提供了一种变通方法。

分区数据库的恢复::

In the following example, the database WSDB is defined on all 4 partitions,
numbered 0 through 3. The path /dev3/backup is accessible from all
partitions. The following offline backup images are available from
/dev3/backup:
wsdb.0.db2inst1.NODE0000.CATN0000.20020331234149.001
wsdb.0.db2inst1.NODE0001.CATN0000.20020331234427.001
wsdb.0.db2inst1.NODE0002.CATN0000.20020331234828.001
wsdb.0.db2inst1.NODE0003.CATN0000.20020331235235.001
To restore the catalog partition first, then all other database partitions of the
WSDB database from the /dev3/backup directory, issue the following
commands from one of the database partitions:

db2_all ’<<+0< db2 RESTORE DATABASE wsdb FROM /dev3/backup
TAKEN AT 20020331234149
INTO wsdb REPLACE EXISTING’
db2_all ’<<+1< db2 RESTORE DATABASE wsdb FROM /dev3/backup
TAKEN AT 20020331234427
INTO wsdb REPLACE EXISTING’
db2_all ’<<+2< db2 RESTORE DATABASE wsdb FROM /dev3/backup
TAKEN AT 20020331234828
INTO wsdb REPLACE EXISTING’
db2_all ’<<+3< db2 RESTORE DATABASE wsdb FROM /dev3/backup
TAKEN AT 20020331235235
INTO wsdb REPLACE EXISTING’


##数据库和表空间前滚
#数据库前滚
在上一章中,我们简要地讨论了 ROLLFORWARD 命令。在本章中,我们将更详细地讨论它。ROLLFORWARD 命令允许恢复到某一时间点;
这意味着该命令将让您遍历 DB2 日志,并重做或撤销记录在日志中的操作直到某个特定的时间点。虽然可以将数据库或表空间前滚到最小
PIT 之后的任何时间点,但不能保证您选择前滚到的结束时间将使所有数据保持一致。

我们将不在本教程中讨论 QUIESCE 命令。然而,值得提一下的是:可以在常规数据库操作期间使用该命令来设置一致性点。通过设置
这些一致性点,您可以始终执行至其中任何一点的时间点恢复,并保证数据同步。

一致性点和许多其它信息一起被记录在 DB2 历史记录文件中,可以使用 LIST HISTORY 命令来查看该文件。

在前滚处理期间,DB2 将:

在当前日志路径中查找必需的日志文件。
如果找到该日志,重新从日志文件应用事务。
如果在当前路径中找不到该日志文件,并且使用了 OVERFLOWLOGPATH 选项,那么 DB2 将在该选项指定的路径中搜索并且将使用该位置中的
日志。
如果在当前路径中找不到该日志文件并且没有使用 OVERFLOWLOGPATH 选项,则调用用户出口来检索归档路径中的日志文件。
仅当前滚完全数据库恢复并且启用了用户出口时,才会调用用户出口来检索日志文件。
一旦日志在当前日志路径或 OVERFLOWLOGPATH 中,就将重新应用事务。
执行 ROLLFORWARD 命令需要 SYSADM、SYSCTRL 或 SYSMAINT 权限。

下面是 ROLLFORWARD 命令的语法:


ROLLFORWARD DATABASE database-alias [USER username [USING password]]
[TO {isotime [ON ALL DBPARTITIONNUMS] [USING LOCAL TIME] | END OF LOGS
[On-DbPartitionNum-Clause]}] [AND {COMPLETE | STOP}] |
{COMPLETE | STOP | CANCEL | QUERY STATUS [USING LOCAL TIME]}
[On-DbPartitionNum-Clause] [TABLESPACE ONLINE | TABLESPACE (tblspace-name
[ {,tblspace-name} ... ]) [ONLINE]] [OVERFLOW LOG PATH (log-directory
[{,log-directory ON DBPARTITIONNUM db-partition-number} ... ])] [NORETRIEVE]
[RECOVER DROPPED TABLE dropped-table-id TO export-directory]

On-DbPartitionNum-Clause:
  ON {{DBPARTITIONNUM | DBPARTITIONNUMS} (db-partition-number
  [TO  db-partition-number] , ... ) | ALL DBPARTITIONNUMS [EXCEPT
  {DBPARTITIONNUM | DBPARTITIONNUMS} (db-partition-number
  [TO db-partition-number] , ...)]}


让我们研究一个示例。要执行样本数据库的前滚,可以使用下列任意一条语句:


(1)ROLLFORWARD DATABASE sample TO END OF LOGS AND COMPLETE
(2)ROLLFORWARD DATABASE sample TO timestamp AND COMPLETE
(3)ROLLFORWARD DATABASE sample TO timestamp USING LOCAL TIME AND COMPLETE


让我们仔细地研究每一条语句:

在该示例中,我们将前滚到日志的结尾,这意味着将遍历所有归档和活动日志。最终它将完成前滚并通过回滚任何未提交的事务来除去
前滚暂挂状态。
对于该示例,DB2 将前滚到指定的时间点。使用的时间戳记形式必须是 CUT(全球标准时间,Coordinated Universal Time),这可以通
过从当前时区减去本地时间来计算。
该示例类似于上一个示例,但可以用本地时间表示时间戳记。
请注意,语法中没有关键字 OFFLINE,因为这是缺省方式。事实上,对于 ROLLFORWARD 命令,这是数据库允许的唯一方式。

#表空间前滚 第 2 页(共4 页)


表空间前滚通常可以联机或脱机。但系统目录表空间(SYSCATSPACE)是例外,它只能进行脱机前滚。

下面是一个表空间前滚示例:

ROLLFORWARD DATABASE sample
  TO END OF LOGS AND COMPLETE
  TABLESPACE ( userspace1 ) ONLINE


上面示例中的选项已经在数据库前滚一章中说明过了。这里唯一的新选项是 TABLESPACE,它指定要前滚的表空间。

表空间前滚考虑事项

如果启用注册表变量 DB2_COLLECT_TS_REC_INFO,则只处理恢复表空间所需的日志文件;ROLLFORWARD 命令将跳过不需要的日志文件,这可以加快恢复时间。
ROLLFORWARD 命令的 QUERY STATUS 选项可用于列出 DB2 已经前滚的日志文件、下一个需要的归档日志文件以及自前滚处理开始以来最后一次提交的事务的时间戳记。例如:
ROLLFORWARD DATABASE sample QUERY STATUS USING LOCAL TIME
在表空间时间点前滚操作完成后,表空间处于备份暂挂状态。必须对表空间或数据库进行备份,因为在表空间恢复到的时间点和当前时间之间对它所做的所有更新都已经丢失。

##索引的重新创建
#重建索引

如果由于一些硬件或操作系统原因而使数据库崩溃,那么在数据库重新启动阶段一些索引可能被标记为无效。配置参数 INDEXREC 确定 DB2 何时将试图重建无效索引。

INDEXREC 在数据库管理器和数据库配置文件中都进行了定义。该参数有三个可能的设置:

SYSTEM:只能在数据库配置文件中指定该值。当将 INDEXREC 设置为该值时,DB2 将查找在数据库管理器配置文件中指定的 INDEXREC 设置,并使用该值。
ACCESS:这意味着在第一次访问索引时重建无效索引。
RESTART:这意味着在数据库重新启动期间重建无效索引。


###管理服务器
get admin cfg
update admin cfg using <p> <v>


备份表空间
BACKUP DATABASE SAMPLE TABLESPACE ( USERSPACE1 ) ONLINE TO "d:\db2\" WITH 1 BUFFERS BUFFER 1024 PARALLELISM 1 WITHOUT PROMPTING;

生成表的DDL
db2look -d SAMPLE -t  MY_EMPLOYEE  -a -e  -l  -x  -c ;
包括表的统计信息的DDL
db2look -d SAMPLE -t  MY_EMPLOYEE  -a -e  -l  -x  -m  -r  -c ;

svmon

5.1 maintrcie 4
db2 fixpak 2

## 数据库空间需求
# 系统目录表的空间需求  3.5MB

# 用户表数据的空间需求
每页面255行 
4KB页面 68字节用于管理开销,4028用于数据,行长度不能超过4005字节,最多500列。
8,16,32KB 页面                                     8101,16293,32677     1012列
       估计大小公式4KB:
          (4028/(AVERAGE ROW SIZE + 10)) = RECORDS_PER_PAGE
          (NUMBER_OF_RECORDS/RECORDS_PER_PAGE)*1.1 = NUMBER_OF_PAGES
  长型字段数据的空间需求
存储在单独的表对象中。数据存储在大小为32KB的区域中。
  大对象数据的空间需求
#索引的空间的需求
(平均索引键大小+9)×行数×2
  创建索引的临时空间需求
         (平均索引键大小+9)×行数×3.2
对每个叶子页的平均键数的粗略估计是
#日志文件的空间需求
(logprimary + logsecond)*(logfilesiz+2)*4096
如果以对数据库启用了无限记录(logsecond 设置为-1),则必须启用userexit配置参数。
#临时空间需求
 
##分区数据库验证
  select distinct dbpartitionnum(empno) from employee;
#分区键
未指定则使用主键的第一列,无主键则使用第一个非长类型列。
选择能否使数据分布均匀及经常使用的列,可以用列的组合但不能超过16列,列越少,性能越好。
分区键不能更改,任何唯一键或主键必须包含分区键列

#表并置
需要经常进行关联的表在指定分区键时,每个分区键中对应列的数据类型必须是分区兼容的,并称为表并置
具有相同值但有不同类型的两个变量会安相同的分区算法映射至同一个分区号。
        如:INTEGER,SMALLINT,BIGINT
    REAL,FLOAT
    CHAR,VARCHAR

#隔离级别
  隔离级确定了在数据被访问时,如何锁定数据或将数据与其它进程隔离。您可以在应用程序预编译或在
  静态 SQL 程序中绑定到数据库时指定隔离级,或者也可以将它指定为连接或语句选项。
  选择的隔离级可同时影响 DB2 选择的锁定策略和 S 行锁定可以由应用程序持有的时间。
  隔离级只应用于被读取的行。对于更改的行,应用程序需要获取一个 X 或 W 锁。无论应用程序的隔离级是什么,
  X 或 W 锁在回滚或提交之前不被释放。
posted @ 2005-06-08 19:11 小马歌 阅读(1470) | 评论 (0)编辑 收藏
仅列出标题
共95页: First 上一页 87 88 89 90 91 92 93 94 95 下一页