﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-辰o(^o^)o的专栏[除非注释原创，其它文章基本来源于网络]-文章分类-Velocity</title><link>http://www.blogjava.net/jackybu/category/2394.html</link><description>&lt;a href="http://www.fastonlineusers.com"&gt;&lt;b&gt;&lt;font color=red&gt;共有&lt;script src=http://fastonlineusers.com/online.php?d=jackybu.blogjava.net&gt;&lt;/script&gt;人在同时阅读此Blog&lt;/font&gt;&lt;/b&gt;&lt;/a&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 20:39:37 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 20:39:37 GMT</pubDate><ttl>60</ttl><item><title>Velocity用户手册---中文版</title><link>http://www.blogjava.net/jackybu/articles/8805.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Sat, 30 Jul 2005 14:32:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/8805.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/8805.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/8805.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/8805.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/8805.html</trackback:ping><description><![CDATA[<DIV class=forumcontent>创建人：王艺<BR>邮 箱：javamail@263.net<BR>QQ号：179985017<BR><BR><B>Velocity是什么？</B><BR>Velocity是一个基于java的模板引擎（template engine）。它允许任何人仅仅简单的使用模板语言（template language）来引用由java代码定义的对象。<BR>当Velocity应用于web开发时，界面设计人员可以和java程序开发人员同步开发一个遵循MVC架构的web站点，也就是说，页面设计人员可以只关注页面的显示效果，而由java程序开发人员关注业务逻辑编码。Velocity将java代码从web页面中分离出来，这样为web站点的长期维护提供了便利，同时也为我们在JSP和PHP之外又提供了一种可选的方案。<BR>Velocity的能力远不止web站点开发这个领域，例如，它可以从模板（template）产生SQL和PostScript、XML，它也可以被当作一个独立工具来产生源代码和报告，或者作为其他系统的集成组件使用。Velocity也可以为Turbine web开发架构提供模板服务（template service）。Velocity+Turbine提供一个模板服务的方式允许一个web应用以一个真正的MVC模型进行开发。<BR><BR><B>Velocity能为我们作什么？</B><BR>The Mud Store Example <BR>假设你是一家专门出售Mud的在线商店的页面设计人员，让我们暂且称它为“在线MUD商店”。你们的业务很旺，客户下了各种类型和数量的mud订单。他们都是通过输入用户名和密码后才登陆到你的网站，登陆后就允许他们查看订单并购买更多的mud。现在，一种非常流行的mud正在打折销售。另外有一些客户规律性的购买另外一种也在打折但是不是很流行的Bright Red Mud，由于购买的人并不多所以它被安置在页面的边缘。所有用户的信息都是被跟踪并存放于数据库中的，所以某天有一个问题可能会冒出来：为什么不使用velocity来使用户更好的浏览他们感兴趣的商品呢？<BR>Velocity使得web页面的客户化工作非常容易。作为一个web site的设计人员，你希望每个用户登陆时都拥有自己的页面。<BR>你会见了一些公司内的软件工程师，你发现他们每个人都同意客户应该拥有具有个性化的信息。那让我们把软件工程师应该作的事情发在一边，看一看你应该作些什么吧。<BR>你可能在页面内嵌套如下的VTL声明：<BR><PRE class=overflow title="pre code">&lt;html&gt;<BR>&lt;body&gt;<BR>Hello $customer.Name!<BR>&lt;table&gt;<BR>#foreach( $mud in $nudsOnSpecial ) <BR>#if ( $customer.hasPurchased( $mud ) ) <BR>&lt;tr&gt;&lt;td&gt;$flogger.getPromo( $mud )&lt;/td&gt;&lt;/tr&gt;<BR>#end<BR>#end<BR>&lt;/table&gt;</PRE><BR><BR>Velocity Template Language(VTL):AN introduction<BR>VTL意味着提供最简单、最容易并且最整洁的方式合并页面动态内容。<BR>VTL使用references来在web site内嵌套动态内容，一个变量就是一种类型的reference。变量是某种类型的refreence，它可以指向java代码中的定义，或者从当前页面内定义的VTL statement得到值。下面是一个VTL statement的例子，它可以被嵌套到HTML代码中：<BR>#set ( $a = “Velocity” )<BR>和所有的VTL statement一样，这个statement以＃字符开始并且包含一个directive：set。当一个在线用户请求你的页面时，Velocity Templating Engine将查询整个页面以便发现所有＃字符，然后确定哪些是VTL statement，哪些不需要VTL作任何事情。<BR>＃字符后紧跟一个directive：set时，这个set directive使用一个表达式（使用括号封闭）――一个方程式分配一个值给变量。变量被列在左边，而它的值被列在右边，最后他们之间使用＝号分割。<BR>在上面的例子中，变量是$a，而它的值是Velocity。和其他的references一样以$字符开始，而值总是以双引号封闭。Velocity中仅有String可以被赋值给变量。<BR>记住以下的规则：<BR>使用$字符开始的references用于得到什么；使用#字符开始的directives用于作些什么。<BR>Hello Velocity World!<BR>一旦某个变量被分配了一个值，那么你就可以在HTML文件的任何地方引用它。在下面的例子中，一个值被分配给$foo变量，并在其后被引用。<BR><PRE class=overflow title="pre code">&lt;html&gt;<BR>&lt;body&gt;<BR>#set ( $foo = “Velocity” )<BR>Hello $foo World!<BR>&lt;/body&gt;<BR>&lt;/html&gt;</PRE><BR>上面的实现结果是在页面上打印“Hello Velocity World！”<BR>为了使包含VTL directives的statement更具有可读性，我们鼓励你在新行开始每个VTL statement，尽管你不是必须这么作。Set directive将在后面详细描述。<BR>注释<BR>单行注释：<BR>## This is a single line comment.<BR>多行注释：<BR>#*<BR>Thus begins a multi-line comment. Online visitors won’t<BR>see this text because the Velocity Templating Engine will<BR>ignore it.<BR>*#<BR>文档格式：<BR>#**<BR>This is a VTL comment block and<BR>may be used to store such information<BR>as the document author and versioning<BR>information:<BR>@version 5<BR>@author<BR>*#<BR><BR>References<BR>在VTL中有三种类型的references：变量(variables)、属性(properties)、方法(methods)。作为一个使用VTL的页面设计者，你和你的工程师必须就references的名称达成共识，以便你可以在你的template中使用它们。<BR>Everything coming to and from a reference被作为一个String对象处理。如果有一个对象$foo是一个Integer对象，那么Velocity将调用它的toString()方法将这个对象转型为String类型。<BR>变量 <BR>格式要求同java。<BR>属性 <BR>例子：<BR>$customer.Address<BR>$purchase.Total<BR>$customer.Address有两种含义。它可以表示：查找hashtable对象customer中以Address为关键字的值；也可以表示调用customer对象的getAddress()方法。当你的页面被请求时，Velocity将确定以上两种方式选用那种，然后返回适当的值。<BR>方法 <BR>一个方法就是被定义在java中的一段代码，并且它有完成某些有用工作的能力，例如一个执行计算和判断条件是否成立、满足等。方法是一个由$开始并跟随VTL标识符组成的References，一般还包括一个VTL方法体。例如：<BR>$customer.getAddress()<BR>$purchase.getTotal()<BR>$page.setTitle( “My Home Page” )<BR>$person.setAttributes( [“Strange”, “Weird”, “Excited”] )<BR>前两个例子$customer.getAddress()和$purchase.getTotal()看起来挺想上面的属性$customer.Address 和 $purchase.Total。如果你觉得他们之间有某种联系的话，那你是正确的。<BR>VTL属性可以作为VTL方法的缩写。$customer.Address属性和使用$customer.getAddress()方法具有相同的效果。如果可能的话使用属性的方式是比较合理的。属性和方法的不同点在于你能够给一个方法指定一个参数列表。<BR>正式reference标记<BR>reference的正是格式如下：<BR>${mudSlinger} 变量<BR>${customer.Address} 属性<BR>${purchase.getTotal()} 方法<BR>非正是格式更见常用，但是有时还是使用正是格式比较适合。例如：你希望通过一个变量$vice来动态的组织一个字符串。<BR>Jack is a $vicemaniac.<BR>本来变量是$vice现在却变成了$vicemaniac，这样Veloctiy就不知道您到底要什么了。所以，应该使用正是格式书写<BR>Jack is a ${vice}maniac<BR>现在Velocity知道变量是$vice而不是$vicemaniac。<BR>Quiet reference notation<BR>例如：<BR>&lt;input type=”text” name=”email” value=”$email” /&gt;<BR>当页面的form被初始加载时，变量$email还没有值，这时你肯定是希望它能够显示一个blank text来代替输出”$email”这样的字段。那么使用quiet reference notation就比较合适。<BR>&lt;input type=”text” name=”email” value=”$!email”/&gt;<BR>这样文本框的初始值就不会是email而是空值了。<BR>正式和quiet格式的reference notation也可一同使用，像下面这样：<BR>&lt;input type=”text” name=”email” value=”$!{email}”/&gt;<BR>Getting literal <BR>Velocity使用特殊字符$和#来帮助它工作，所以如果要在template里使用这些特殊字符要格外小心。本节将讨论$字符。<BR>货币字符 <BR>在VTL中使用$2.5这样的货币标识是没有问题得的，VTL不会将它错认为是一个reference，因为VTL中的reference总是以一个大写或者小写的字母开始。<BR>Escaping valid VTL reference <BR>VTL中使用“\”作为逃逸符。<BR>例如：<BR><PRE class=overflow title="pre code">&nbsp; #set( $email = “foo” )<BR>&nbsp; $email<BR>&nbsp; \$email<BR>&nbsp; \\$email<BR>&nbsp; \\\$email</PRE><BR><BR>将render为：<BR><PRE class=overflow title="pre code">&nbsp; foo<BR>&nbsp; $email<BR>&nbsp; \foo<BR>&nbsp; \\$email</PRE><BR>如果email变量没有被定义则<BR><PRE class=overflow title="pre code">&nbsp; $email<BR>&nbsp; \$email<BR>&nbsp; \\$email<BR>&nbsp; \\\$email</PRE><BR>将被render为：<BR><PRE class=overflow title="pre code">&nbsp; $email<BR>&nbsp; \$email<BR>&nbsp; \\$email<BR>&nbsp; \\\$email</PRE><BR>注意：VTL中未被定义的变量将被认为是一个字符串，所以以下例子：<BR><PRE class=overflow title="pre code">&nbsp; #set( $foo = “gibbous” )<BR>&nbsp; $moon = $foo</PRE><BR>的输出结果是：<BR><PRE class=overflow title="pre code">$moon = gibbous<BR>Case substitution</PRE><BR>现在你已经对reference比较熟悉了，你可以将他们高效的应用于你的template了。Velocity利用了很多java规范以方便了设计人员的使用。例如：<BR><PRE class=overflow title="pre code">&nbsp; $foo<BR>&nbsp; $foo.getBar()<BR>&nbsp; ## is the same as<BR>&nbsp; $foo.Bar<BR><BR>&nbsp; $data.getUser(“jon”)<BR>&nbsp; ## is the same as<BR>&nbsp; $data.User(“jon”)<BR><BR>&nbsp; $data.getRequest().getServerName()<BR>&nbsp; # is the same as<BR>&nbsp; $data.Request.ServerName<BR>&nbsp; ## is the same as<BR>&nbsp; ${data.Request.ServerName}</PRE>但是，注意VTL中不会将reference解释为对象的实例变量。例如：$foo.Name将被解释为Foo对象的getName（）方法，而不是Foo对象的Name实例变量。<BR>Directives<BR>Reference允许设计者使用动态的内容，而directive使得你可以应用java代码来控制你的显示逻辑，从而达到你所期望的显示效果。<BR>#set <BR>#set directive被用于设置一个reference的值。例如：<BR>#set ( $primate = “monkey” )<BR>#set ( $customer.Behavior = $primate )<BR>赋值左侧的（LHS）必须是一个变量或者属性reference。右侧（RHS）可以是以下类型中一种：<BR><PRE class=overflow title="pre code">l&nbsp; 变量reference<BR>l&nbsp; String literal<BR>l&nbsp; 属性reference<BR>l&nbsp; 方法reference<BR>l&nbsp; number literal<BR>l&nbsp; ArrayList</PRE>下面是应用各种类型的RHS的例子：<BR><PRE class=overflow title="pre code">&nbsp; ＃set ( $monkey = $bill ) ##变量reference<BR>&nbsp; ＃set ( $monkey.Friend = “monica” ) ##String literal<BR>&nbsp; ＃set ( $monkey.Blame = $whitehouse.Leak )##属性reference<BR>&nbsp; ＃set ( $monkey.Plan = $spindoctor.weave($web) )##方法reference<BR>&nbsp; ＃set ( $monkey.Number = 123 )##Number literal<BR>&nbsp; ＃set ( $monkey.Say = [“Not”, $my, “fault”] )##ArrayList</PRE>注意：最后一个例子的取值方法为：$monkey.Say.get(0)<BR>RHS也可以是一个简单的算术表达式：<BR><PRE class=overflow title="pre code">&nbsp; #set ( $value = $foo + 1 )<BR>&nbsp; #set ( $value = $bar -1 )<BR>#set ( $value = $foo * $bar )<BR>#set ( $value = $foo / $bar )</PRE><BR>如果你的RHS是一个null，VTL的处理将比较特殊：它将指向一个已经存在的reference，这对初学者来讲可能是比较费解的。例如：<BR><PRE class=overflow title="pre code">#set ( $resut = $query.criteria(“name”) )<BR>&nbsp; The result of the first query is $result<BR><BR>&nbsp; #set ( $resut = $query.criteria(“address”) )<BR>&nbsp; The result of the second query is $result</PRE><BR>如果$query.criteria(“name”)返回一个“bill”，而$query.criteria(“address”)返回的是null，则显示的结果如下：<BR>The result of the first query is bill<BR>The result of the first query is bill<BR>看看下面的例子：<BR><PRE class=overflow title="pre code">#set( $criteria = ["name", "address"] )<BR>#foreach( $criterion in $criteria )<BR>#set( $result = $query.criteria($criterion) )<BR>&nbsp; #if( $result )<BR>&nbsp; Query was successful<BR>&nbsp; &nbsp; &nbsp;#end<BR>#end</PRE><BR>在上面的例子中，程序将不能智能的根据$result的值决定查询是否成功。在$result被#set后（added to the context），它不能被设置回null（removed from the context）。打印的结果将显示两次查询结果都成功了，但是实际上有一个查询是失败的。<BR>为了解决以上问题我们可以通过预先定义的方式：<BR>#set( $criteria = [“name”, “address”] )<BR>#foreach( $criterion in $criteria )<BR>#set( $result = false )<BR>#set( $result = $query.criteria( $criterion ) )<BR>#if( $result )<BR>Query was successful<BR>#end<BR>#end<BR>String Literals <BR>当你使用#set directive，String literal封闭在一对双引号内。<BR>#set ( $directoryRoot = “www” )<BR>#set ( $templateName = “index.vm” )<BR>#set ( $template = “$directoryRoot/$tempateName” )<BR>$template<BR>上面这段代码的输出结果为：www/index.vm<BR>但是，当string literal被封装在单引号内时，它将不被解析：<BR>#set ( $foo = “bar” )<BR>$foo<BR>#set ( $blargh = ‘$foo’ )<BR>结果：<BR>bar<BR>$foo<BR>上面这个特性可以通过修改velocity.properties文件的stringliterals.interpolate = false的值来改变上面的特性是否有效。<BR>条件语句<BR>if/elseif/else <BR>当一个web页面被生成时使用Velocity的#if directrive，如果条件成立的话可以在页面内嵌入文字。例如：<BR>#if ( $foo )<BR>&lt;strong&gt;Velocity!&lt;/strong&gt;<BR>#end<BR>上例中的条件语句将在以下两种条件下成立：<BR>l $foo是一个boolean型的变量，且它的值为true<BR>l $foo变量的值不为null<BR>这里需要注意一点：Velocity context仅仅能够包含对象，所以当我们说“boolean”时实际上代表的时一个Boolean对象。即便某个方法返回的是一个boolean值，Velocity也会利用内省机制将它转换为一个Boolean的相同值。<BR>如果条件成立，那么#if和#end之间的内容将被显示。<BR>#elseif和#else元素可以同#if一同使用。例如：<BR><PRE class=overflow title="pre code">#if( $foo &lt; 10 )<BR>&nbsp; &nbsp; &lt;strong&gt; Go North &lt;/strong&gt;<BR>&nbsp; #elseif( $foo == 10 )<BR>&nbsp; &nbsp; &lt;strong&gt; Go East &lt;/strong&gt;<BR>&nbsp; #elseif( $foo == 6 )<BR>&nbsp; &nbsp; &lt;strong&gt; Go South &lt;/strong&gt;<BR>&nbsp; #else<BR>&nbsp; &nbsp; &lt;strong&gt; Go West &lt;/strong&gt;<BR>&nbsp; #end</PRE><BR>注意这里的Velocity的数字是作为Integer来比较的――其他类型的对象将使得条件为false，但是与java不同它使用“＝＝”来比较两个值，而且velocity要求等号两边的值类型相同。<BR>关系、逻辑运算符 <BR>Velocity中使用等号操作符判断两个变量的关系。例如：<BR><PRE class=overflow title="pre code">#set ( $foo = “deoxyribonucleic acid” )<BR>#set ( $bar = “ribonucleic acid” )<BR>#if ( $foo == $foo )<BR>&nbsp; In this case it’s clear they aren’t equivalent.So…<BR>#else<BR>&nbsp; They are not equivalent and this will be the output.<BR>#end</PRE><BR><BR>Velocity有AND、OR和NOT逻辑运算符。下面是一些例子：<BR>## logical AND<BR>#if( $foo &amp;&amp; $bar )<BR>&lt;strong&gt; This AND that &lt;/strong&gt;<BR>#end<BR><BR>## logical OR<BR>#if ( $foo || $bar )<BR>&lt;strong&gt;This OR That &lt;/strong&gt;<BR>#end<BR><BR>##logical NOT<BR>#if ( !$foo )<BR>&lt;strong&gt; NOT that &lt;/strong&gt;<BR>#end<BR>循环 <BR>Foreach循环 <BR>例子：<BR>&lt;ul&gt;<BR>#foreach ( $product in $allProducts )<BR>&lt;li&gt; $product &lt;/li&gt;<BR>#end<BR>&lt;/ul&gt;<BR>每次循环$allProducts中的一个值都会赋给$product变量。<BR>$allProducts可以是一个Vector、Hashtable或者Array。分配给$product的值是一个java对象，并且可以通过变量被引用。例如：如果$product是一个java的Product类，并且这个产品的名字可以通过调用他的getName（）方法得到。<BR>现在我们假设$allProducts是一个Hashtable，如果你希望得到它的key应该像下面这样：<BR>&lt;ul&gt;<BR>#foreach ( $key in $allProducts.keySet() )<BR>&lt;li&gt;Key: $key -&gt; Value: $allProducts.get($key) &lt;/li&gt;<BR>#end<BR>&lt;/ul&gt;<BR><BR>Velocity还特别提供了得到循环次数的方法，以便你可以像下面这样作：<BR>&lt;table&gt;<BR>#foreach ( $customer in $customerList )<BR>&lt;tr&gt;&lt;td&gt;$velocityCount&lt;/td&gt;&lt;td&gt;$customer.Name&lt;/td&gt;&lt;/tr&gt;<BR>#end<BR>&lt;/table&gt;<BR>$velocityCount变量的名字是Velocity默认的名字，你也可以通过修改velocity.properties文件来改变它。默认情况下，计数从“1”开始，但是你可以在velocity.properties设置它是从“1”还是从“0”开始。下面就是文件中的配置：<BR><PRE class=overflow title="pre code"># Default name of loop counter<BR>&nbsp; # variable reference<BR>&nbsp; directive.foreach.counter.name = velocityCount<BR><BR>&nbsp; # Default starting value of the loop<BR>&nbsp; # counter variable reference<BR>&nbsp; directive.foreach.counter.initial.value = 1</PRE><BR><BR>include<BR>#include script element允许模板设计者引入本地文件。被引入文件的内容将不会通过模板引擎被render。为了安全的原因，被引入的本地文件只能在TEMPLATE_ROOT目录下。<BR>#inclued ( “one.txt” )<BR>如果您需要引入多个文件，可以用逗号分隔就行：<BR>#include ( “one.gif”, “two.txt”, “three.htm” )<BR>在括号内可以是文件名，但是更多的时候是使用变量的：<BR>#inclue ( “greetings.txt”, $seasonalstock )<BR><BR>parse<BR>#parse script element允许模板设计者一个包含VTL的本地文件。Velocity将解析其中的VTL并render模板。<BR>#parse( “me.vm” )<BR>就像#include，#parse接受一个变量而不是一个模板。任何由#parse指向的模板都必须包含在TEMPLATE_ROOT目录下。与#include不同的是，#parse只能指定单个对象。<BR>你可以通过修改velocity.properties文件的parse_direcive.maxdepth的值来控制一个template可以包含的最多#parse的个数――默认值是10。#parse是可以递归调用的，例如：如果dofoo.vm包含如下行：<BR>Count down.<BR>#set ( $count = 8 )<BR>#parse ( “parsefoo.vm” )<BR>All done with dofoo.vm!<BR>那么在parsefoo.vm模板中，你可以包含如下VTL：<BR>$count<BR>#set ( $count = $count – 1 )<BR>#if ( $count &gt; 0 )<BR>#parse( “parsefoo.vm” )<BR>#else<BR>All done with parsefoo.vm!<BR>#end<BR>的显示结果为：<BR>Count down.<BR>8<BR>7<BR>6<BR>5<BR>4<BR>3<BR>2<BR>1<BR>0<BR>All done with parsefoo.vm!<BR>All done with dofoo.vm!<BR><BR>Stop<BR>#stop script element允许模板设计者停止执行模板引擎并返回。把它应用于debug是很有帮助的。<BR>#stop<BR><BR>Velocimacros<BR>#macro script element允许模板设计者定义一段可重用的VTL template。例如：<BR>#macro ( d )<BR>&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;<BR>#end<BR>在上面的例子中Velocimacro被定义为d，然后你就可以在任何VTL directive中以如下方式调用它：<BR>#d()<BR>当你的template被调用时，Velocity将用&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;替换为#d()。<BR>每个Velocimacro可以拥有任意数量的参数――甚至0个参数，虽然定义时可以随意设置参数数量，但是调用这个Velocimacro时必须指定正确的参数。下面是一个拥有两个参数的Velocimacro，一个参数是color另一个参数是array：<BR>#macro ( tablerows $color $somelist )<BR>#foreach ( $something in $somelist )<BR>&lt;tr&gt;&lt;td bgcolor=$color&gt;$something&lt;/td&lt;/tr&gt;<BR>#end<BR>#end<BR><BR>调用#tablerows Velocimacro：<BR>#set ( $greatlakes = [ “Superior”, “Michigan”, “Huron”, “Erie”, “Ontario” ] )<BR>#set ( $color = “blue” )<BR>&lt;table&gt;<BR>#tablerows( $color $greatlakes )<BR>&lt;/table&gt;<BR>经过以上的调用将产生如下的显示结果：<BR>&lt;table&gt;<BR>&lt;tr&gt;&lt;td bgcolor=” blue”&gt; Superior &lt;/td&gt;&lt;/tr&gt;<BR>&lt;tr&gt;&lt;td bgcolor=” blue”&gt; Michigan &lt;/td&gt;&lt;/tr&gt;<BR>&lt;tr&gt;&lt;td bgcolor=” blue”&gt; Huron &lt;/td&gt;&lt;/tr&gt;<BR>&lt;tr&gt;&lt;td bgcolor=” blue”&gt; Erie &lt;/td&gt;&lt;/tr&gt;<BR>&lt;tr&gt;&lt;td bgcolor=” blue”&gt; Ontario &lt;/td&gt;&lt;/tr&gt;<BR>&lt;/table&gt;<BR>Velocimacros可以在Velocity模板内实现行内定义（inline），也就意味着同一个web site内的其他Velocity模板不可以获得Velocimacros的定义。定义一个可以被所有模板共享的Velocimacro显然是有很多好处的：它减少了在一大堆模板中重复定义的数量、节省了工作时间、减少了出错的几率、保证了单点修改。<BR>上面定义的#tablerows( $color $list )Velocimacro被定义在一个Velocimacros模板库(在velocity.properties中定义)里，所以这个macro可以在任何规范的模板中被调用。它可以被多次应用并且可以应用于不同的目的。例如下面的调用：<BR>#set ( $parts = [ “volva”, “stipe”, “annulus”, “gills”, “pileus” ] )<BR>#set ( $cellbgcol = “#CC00FF” )<BR>&lt;table&gt;<BR>#tablerows( $cellbgcol $parts )<BR>&lt;/table&gt;<BR>上面VTL将产生如下的输出：<BR>&lt;table&gt;<BR>&lt;tr&gt;&lt;td bgcolor=”#CC00FF”&gt; volva &lt;/td&lt;/tr&gt;<BR>&lt;tr&gt;&lt;td bgcolor=”#CC00FF”&gt; stipe &lt;/td&lt;/tr&gt;<BR>&lt;tr&gt;&lt;td bgcolor=”#CC00FF”&gt; annulus &lt;/td&lt;/tr&gt;<BR>&lt;tr&gt;&lt;td bgcolor=”#CC00FF”&gt; gills &lt;/td&lt;/tr&gt;<BR>&lt;tr&gt;&lt;td bgcolor=”#CC00FF”&gt; pileus &lt;/td&lt;/tr&gt;<BR>&lt;/table&gt;<BR><BR>Velocimacro arguments <BR>Velocimacro可以使用以下任何元素作为参数：<BR>l Reference：任何以$开头的reference<BR>l String literal：<BR>l Number literal：<BR>l IntegerRange：[1….3]或者[$foo….$bar]<BR>l 对象数组：[“a”,”b”,”c”]<BR>l boolean值：true、false<BR>当将一个reference作为参数传递给Velocimacro时，请注意reference作为参数时是以名字的形式传递的。这就意味着参数的值在每次Velocimacro内执行时才会被产生。这个特性使得你可以将一个方法调用作为参数传递给Velocimacro，而每次Velocimacro执行时都是通过这个方法调用产生不同的值来执行的。例如：<BR>#macro ( callme $a )<BR>$a $a $a<BR>#end<BR>#callme( $foo.bar() )<BR>执行的结果是：reference $foo的bar（）方法被执行了三次。<BR>如果你不需要这样的特性可以通过以下方法：<BR>#set ( $myval = $foo.bar() )<BR>#callme ( $myval )<BR><BR>Velocimacro properties <BR>Velocity.properties文件中的某几行能够使Velocimacros的实现更加灵活。注意更多的内容可以看Developer Guide。<BR>Velocity.properties文件中的velocimacro.libraary：一个以逗号分隔的模板库列表。默认情况下，velocity查找唯一的一个库：VM_global_library.vm。你可以通过配置这个属性来指定自己的模板库。<BR>Velocity.properties文件中的velocimacro.permissions.allow.inline属性：有两个可选的值true或者false，通过它可以确定Velocimacros是否可以被定义在regular template内。默认值是ture――允许设计者在他们自己的模板中定义Velocimacros。<BR>Velocity.properties文件中的<BR>velocimacro.permissions.allow.inline.replace.global属性有两个可选值true和false，这个属性允许使用者确定inline的Velocimacro定义是否可以替代全局Velocimacro定义（比如在velocimacro.library属性中指定的文件内定义的Velocimacro）。默认情况下，此值为false。这样就阻止本地Velocimacro定义覆盖全局定义。<BR>Velocity.properties文件中的<BR>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。<BR>Velocity.properties文件中的velocimacro.context.localscope属性有true和false两个可选值，默认值为false。当设置为true时，任何在Velocimacro内通过#set()对context的修改被认为是针对此velocimacro的本地设置，而不会永久的影响内容。<BR>Velocity.properties文件中的velocimacro.library.autoreload属性控制Velocimacro库的自动加载。默认是false。当设置为ture时，对于一个Velocimacro的调用将自动检查原始库是否发生了变化，如果变化将重新加载它。这个属性使得你可以不用重新启动servlet容器而达到重新加载的效果，就像你使用regular模板一样。这个属性可以使用的前提就是resource loader缓存是off状态（file.resource.loader.cache = false）。注意这个属性实际上是针对开发而非产品的。<BR><BR>Velocimacro Trivia <BR>Velocimacro必须被定义在他们被使用之前。也就是说，你的#macro()声明应该出现在使用Velocimacros之前。<BR>特别要注意的是，如果你试图#parse()一个包含#macro()的模板。因为#parse()发生在运行期，但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素，这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果，只需要你简单的使用velocimacro.library使得Velocity在启动时加载你的VMs。<BR>Escaping VTL directives<BR>VTL directives can be escaped with “\”号，使用方式跟VTL的reference使用逃逸符的格式差不多。<BR>## #include( “a.txt” ) renders as &lt;ontents of a.txt&gt;(注释行)<BR>#include( “a.txt” )<BR><BR>## \#include( “a.txt” ) renders as \#include( “a.txt” )<BR>\#include( “a.txt” )<BR><BR>## \\#include ( “a.txt” ) renders as \&lt;contents of a.txt&gt;<BR>\\#include( “a.txt” )<BR>在对在一个directive内包含多个script元素的VTL directives使用逃逸符时要特别小心（比如在一个if-else-end statement内）。下面是VTL的if-statement的典型应用：<BR>#if ( $jazz )<BR>Vyacheslav Ganelin<BR>#end<BR>如果$jazz是ture，输出将是：<BR>Vyacheslav Ganelin<BR>如果$jazz是false，将没有输出。使用逃逸符将改变输出。考虑一下下面的情况：<BR>\#if ( $jazz )<BR>Vyacheslav Ganelin<BR>\#end<BR>现在无论$jazz是true还是false，输出结果都是：<BR>#if ( $jazz )<BR>Vyacheslav Ganelin<BR>#end<BR>事实上，由于你使用了逃逸符，$jazz根本就没有被解析为boolean型值。在逃逸符前使用逃逸符是合法的，例如：<BR>\\#if ( $jazz )<BR>Vyacheslav Ganelin<BR>\\#end<BR>以上程序的显示结果为：<BR>\ Vyacheslav Ganelin<BR>但是如果$jazz为false，那么将没有输出。（书上说会没有输出，但是我觉得应该还有有“\”字符被输出。）<BR>VTL：Formatting issues<BR>尽管在此用户手册中VTL通常都开始一个新行，如下所示：<BR>#set ( $imperial = [ “Munetaka”, “Koreyasu”, “Hisakira”, “Morikune” ] )<BR>#foreach ( $shogun in $imperial )<BR>$shogun<BR>#end<BR>但是像下面这种写法也是可以的：<BR>Send me #set($foo = [“$10 and”,”a cake”])#foreach($a in $foo)$a #end please.<BR>上面的代码可以被改写为：<BR>Send me<BR>#set ( $foo = [“$10 and “,”a cake”] )<BR>#foreach ( $a in $foo )<BR>$a<BR>#end<BR>please.<BR>或者<BR>Send me<BR>#set($foo = [“$10 and “,”a cake”])<BR>#foreach （$a in $foo ）$a<BR>#end please.<BR>这两种的输出结构将一样。<BR>其他特性和杂项<BR>math 在模板中可以使用Velocity内建的算术函数，如：加、减、乘、除<BR>#set ( $foo = $bar + 3 )<BR>#set ( $foo = $bar - 4 )<BR>#set ( $foo = $bar * 6 )<BR>#set ( $foo = $bar / 2 )<BR>当执行除法时将返回一个Integer类型的结果。而余数你可以使用%来得到：<BR>#set ( $foo = $bar % 5 )<BR>在Velocity内使用数学计算公式时，只能使用像-n,-2,-1,0,1,2,n这样的整数，而不能使用其它类型数据。当一个非整型的对象被使用时它将被logged并且将以null作为输出结果。<BR>Range Operator<BR>Range operator可以被用于与#set和#foreach statement联合使用。对于处理一个整型数组它是很有用的，Range operator具有以下构造形式：<BR>[n..m]<BR>m和n都必须是整型，而m是否大于n则无关紧要。例子：<BR>First example:<BR>#foreach ( $foo in [1..5] )<BR>$foo<BR>#end<BR><BR>Second example:<BR>#foreach ( $bar in [2..-2] )<BR>$bar<BR>#end<BR><BR>Third example:<BR>#set ( $arr = [0..1] )<BR>#foreach ( $i in $arr )<BR>$i<BR>#end<BR><BR>Fourth example:<BR>[1..3]<BR>上面四个例子的输出结果为：<BR>First example：<BR>1 2 3 4 5<BR><BR>Second example：<BR>2 1 0 -1 -2<BR><BR>Third example：<BR>0 1<BR><BR>Fourth example：<BR>[1..3]<BR>注意：range operator只在#set和#foreach中有效。<BR>Advanced Issue：Escaping and！<BR>当一个reference被“！”分隔时，并且在它之前有逃逸符时，reference将以特殊的方式处理。注意这种方式与标准的逃逸方式时不同的。对照如下： <BR>#set ( $foo = “bar” )<BR>特殊形式 标准格式<BR>Render前 Render后 Render前 Render后<BR>$\!foo $!foo \$foo \$foo<BR>$\!{foo} $!{foo} \$!foo \$!foo<BR>$\\!foo $\!foo \$!{foo} \$!{foo}<BR>$\\\!foo $\\!foo \\$!{foo} \bar<BR>Velocimacro杂记<BR>Can I user a directive or another VM as an argument to a VM? <BR>例如：#center ( #bold( “hello” ) )<BR>不可以。一个directive的参数使用另外一个directive是不合法的。<BR>但是，还是有些事情你可以作的。最简单的方式就是使用双引号：<BR>#set ( $stuff = “#bold( ‘hello’ )” )<BR>#center ( $stuff ) <BR>上面的格式也可以缩写为一行：<BR>#center ( “#bold( ‘hello’ ) )<BR>请注意在下面的例子中参数被evaluated在Velocimacro内部，而不是在calling level。例子：<BR>#macro ( inner $foo )<BR>inner : $foo<BR>#end<BR><BR>#macro ( outer $foo )<BR>#set ( $bar = “outerlala” )<BR>outer : $foo<BR>#end<BR><BR>#set ( $bar = ‘calltimelala’ )<BR>#outer( “#inner($bar)” )<BR>输出结果为：<BR>outer : inner : outerlala<BR>记住Veloctiy的特性：参数的传递是By Name的。例如：<BR>#macro ( foo $color )<BR>&lt;tr bgcolor = $color &gt;&lt;td&gt;Hi&lt;/td&gt;&lt;/tr&gt;<BR>&lt;tr bgcolor = $color &gt;&lt;td&gt;There&lt;/td&gt;&lt;/tr&gt;<BR>#end<BR><BR>#foo ( $bar.rowColor() )<BR>以上代码将导致rowColor()方法两次调用，而不是一次。为了避免这种现象的出现，我们可以按照下面的方式执行：<BR>#set ( $color = $bar.rowColor() )<BR>#foo ( $color )<BR>can I register velocimacros via #parse()? <BR>目前，Velocimacros必须在第一次被模板调用前被定义。这就意味着你的#macro()声明应该出现在使用Velocimacros之前。<BR>如果你试图#parse()一个包含#macro() directive的模板，这一点是需要牢记的。因为#parse()发生在运行期，但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素，这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果，只需要你简单的使用velocimacro.library使得Velocity在启动时加载你的VMs。<BR>What is velocimacro autoreloading？ <BR>velocimacro.library.autoreload是专门为开发而非产品使用的一个属性。此属性的默认值是false。<BR>String concatenation<BR>开发人员最常问的问题是我如何作字符拼接？在java中是使用“＋”号来完成的。<BR>在VTL里要想实现同样的功能你只需要将需要联合的reference放到一起就行了。例如：<BR><PRE class=overflow title="pre code">#set ( $size = “Big” )<BR>#set ( $name = “Ben” )<BR>The clock is $size$name.</PRE><BR>输出结果将是：The clock is BigBen.。更有趣的情况是：<BR><PRE class=overflow title="pre code">#set ( $size = “Big” )<BR>&nbsp; #set ( $name = “Ben” )<BR>&nbsp; #set ( $clokc = “$size$name” )<BR>&nbsp; The clock is $clock.</PRE><BR>上例也会得到同样的结果。最后一个例子，当你希望混合固定字段到你的reference时，你需要使用标准格式：<BR><PRE class=overflow title="pre code">#set ( $size = “Big” )<BR>&nbsp; #set ( $name = “Ben” )<BR>&nbsp; #set ( $clock = “${size}Tall$name” )<BR>&nbsp; The clock is $clock.</PRE><BR>输出结果是：The clock is BigTallBen.。使用这种格式主要是为了使得$size不被解释为$sizeTall。</DIV><img src ="http://www.blogjava.net/jackybu/aggbug/8805.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-07-30 22:32 <a href="http://www.blogjava.net/jackybu/articles/8805.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Velocity简介 ---- from matrix</title><link>http://www.blogjava.net/jackybu/articles/8804.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Sat, 30 Jul 2005 14:31:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/8804.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/8804.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/8804.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/8804.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/8804.html</trackback:ping><description><![CDATA[<DIV class=forumcontent>1.Velocity 的使用 <BR><BR>Velocity是一个开放源吗的模版引擎，由apache.org小组负责开发，现在最新的版本是Velocity1.3.1，http://jakarta.apache.org/velocity/index.html 可以了解Velocity的最新信息。 <BR>Velocity允许我们在模版中设定变量，然后在运行时，动态的将数据插入到模版中，替换这些变量。 <BR>例如： <BR><PRE class=overflow title="pre code">&lt;html&gt; <BR>&lt;body&gt;HELLO $CUSTOMERNAME&lt;/body&gt; <BR>&lt;/html&gt; </PRE>我们可以在运行时得到客户的名字，然后把它插入到这个模版中替换变量$CUSTOMERNAME，整个替换过程是由Velocity进行控制的，而且java的调用代码也非常简单，如我们可以在java代码中这样调用 <BR><PRE class=overflow title="pre code">/***********************************************************/ <BR>//这个文件中设定了Velocity使用的log4j的配置和Velocity的模版文件所在的目录 <BR>Velocity.init("D:\\Template\\resource\\jt.properties"); <BR>//模版文件名，模版文件所在的路径在上一条语句中已经设置了 <BR>Template template = Velocity.getTemplate("hello.vm", "gb2312"); <BR>//实例化一个Context <BR>VelocityContext context = new VelocityContext(); <BR>//把模版变量的值设置到context中 <BR>context.put("CUSTOMERNAME", "My First Template Engine ---- Velocity."); <BR>//开始模版的替换 <BR>template.merge(context, writer); <BR>//写到文件中 <BR>PrintWriter filewriter = new PrintWriter(new FileOutputStream(outpath),true); <BR>filewriter.println(writer.toString()); <BR>filewriter.close(); <BR>/***********************************************************/ </PRE><BR><BR>这就是整个java的代码，非常的简单。如果我们有多个模版变量，我们仅需要把这些模版变量的值设置到context中。 <BR>下面我们简单的分析一下，Velocity引擎读取模板文件时，它直接输出文件中所有的文本，但以$字符开头的除外，$符号标识着一个模版变量位置， <BR>context.put("CUSTOMERNAME", "My First Template Engine ---- Velocity."); <BR>当 Velocity 模板引擎解析并输出模板的结果时，模板中所有出现$CUSTOMERNAME的地方都将插入客户的名字，即被加入到VelocityContext的对象的toString()方法返回值将替代Velocity变量（模板中以$开头的变量）。 <BR>模板引擎中最强大、使用最频繁的功能之一是它通过内建的映像（Reflection）引擎查找对象信息的能力。这个映像引擎允许用一种方便的Java“.”类似的操作符，提取任意加入到VelocityContext的对象的任何公用方法的值，或对象的任意数据成员。 <BR>映像引擎还带来了另外一个改进：快速引用JavaBean的属性。使用JavaBean属性的时候，我们可以忽略get方法和括号。请看下面这个模板的例子。 <BR><PRE class=overflow title="pre code">&lt;html&gt; <BR>&lt;body&gt; <BR>Name:$Customer.Name() <BR>Address:$Customer.Address() <BR>Age:$Customer.Age() <BR>&lt;/body&gt; <BR>&lt;/html&gt; </PRE><BR><BR>java的代码： <BR><PRE class=overflow title="pre code">/***********************************************************/ <BR>//设置客户信息 <BR>Customer mycustomer = new Customer(); <BR>mycustomer.setName("Velocity"); <BR>mycustomer.setAddress("jakarta.apache.org/velocity/index.html"); <BR>mycustomer.setAge(2); <BR>//这个文件中设定了 Velocity 使用的 Log4j 的配置和Velocity的模版文件所在的目录Velocity.init("D:\\Template\\resource\\jt.properties"); <BR>//模版文件名，模版文件所在的路径在上一条语句中已经设置了 <BR>Template template = Velocity.getTemplate("hello.vm", "gb2312"); <BR>//实例化一个Context <BR>VelocityContext context = new VelocityContext(); <BR>//把模版变量的值设置到context中 <BR>context.put("Customer", mycustomer); <BR>//开始模版的替换 <BR>template.merge(context, writer); <BR>//写到文件中 <BR>PrintWriter filewriter = new PrintWriter(new FileOutputStream(outpath),true); <BR>filewriter.println(writer.toString()); <BR>filewriter.close(); </PRE>输出结果： <BR><PRE class=overflow title="pre code">&lt;html&gt; <BR>&lt;body&gt; <BR>Name:Velocity <BR>Address:jakarta.apache.org/velocity/index.html <BR>Age:2 <BR>&lt;/body&gt; <BR>&lt;/html&gt; </PRE><BR>除了替换变量之外，象Velocity高级引擎还能做其他许多事情，它们有用来比较和迭代的内建指令，通过这些指令我们可以完成程序语言中的条件判断语句和循环语句等。 <BR>例如，我们想要输出年龄等于2的所有客户的信息，我们可以这样定义我们的模版 <BR>模版： <BR><PRE class=overflow title="pre code">&lt;html&gt; <BR>&lt;body&gt; <BR>&lt;table&gt; <BR>&lt;tr&gt; <BR>&lt;td&gt;名称&lt;/td&gt; <BR>&lt;td&gt;地址&lt;/td&gt; <BR>&lt;td&gt;年龄&lt;/td&gt; <BR>&lt;/tr&gt; <BR>#foreach ($Customer in $allCustomer) <BR>#if($Customer.Age()=="2") <BR>&lt;tr&gt; <BR>&lt;td&gt;$Customer.Name()&lt;/td&gt; <BR>&lt;td&gt;$Customer.Address()&lt;/td&gt; <BR>&lt;td&gt;$Customer.Age()&lt;/td&gt; <BR>&lt;/tr&gt; <BR>#end <BR>#end <BR>&lt;/table&gt; <BR>&lt;/body&gt; <BR>&lt;/html&gt; </PRE><BR><BR>java的代码： <BR><PRE class=overflow title="pre code">/******************************************************/ <BR>//设置客户信息 <BR>ArrayList allMyCustomer = new ArrayList(); <BR>//客户1 <BR>Customer mycustomer1 = new Customer(); <BR>mycustomer1.setName("Velocity"); <BR>mycustomer1.setAddress("jakarta.apache.org/velocity/index.html"); <BR>mycustomer1.setAge(2); <BR>//客户2 <BR>Customer mycustomer2 = new Customer(); <BR>mycustomer2.setName("Tomcat"); <BR>mycustomer2.setAddress("jakarta.apache.org/tomcat/index.html"); <BR>mycustomer2.setAge(3); <BR>//客户3 <BR>Customer mycustomer3 = new Customer(); <BR>mycustomer3.setName("Log4J"); <BR>mycustomer3.setAddress("jakarta.apache.org/log4j/docs/index.html"); <BR>mycustomer3.setAge(2); <BR>//添加到allMyCustomer(ArrayList)中. <BR>allMyCustomer.add(mycustomer1); <BR>allMyCustomer.add(mycustomer2); <BR>allMyCustomer.add(mycustomer3); <BR>//这个文件中设定了Velocity使用的log4j的配置和Velocity的模版文件所在的目 <BR>Velocity.init("D:\\Template\\resource\\jt.properties"); <BR>//模版文件名，模版文件所在的路径在上一条语句中已经设置了 <BR>Template template =Velocity.getTemplate("hello.vm", "gb2312"); <BR>//实例化一个Context <BR>VelocityContext context = new VelocityContext(); <BR>/** 注意这里我们仅仅需要给一个模版变量负值 */ <BR>context.put("allCustomer", allMyCustomer); <BR>//开始模版的替换 <BR>template.merge(context, writer); <BR>//写到文件中 <BR>PrintWriter filewriter = new PrintWriter(new FileOutputStream(outpath),true); <BR>filewriter.println(writer.toString()); <BR>filewriter.close(); <BR>/******************************************************/ </PRE>结果： <BR><PRE class=overflow title="pre code">&lt;html&gt; <BR>&lt;body&gt; <BR>&lt;table&gt; <BR>&lt;tr&gt; <BR>&lt;td&gt;名称&lt;/td&gt; <BR>&lt;td&gt;地址&lt;/td&gt; <BR>&lt;td&gt;年龄&lt;/td&gt; <BR>&lt;/tr&gt; <BR>&lt;tr&gt; <BR>&lt;td&gt;Velocity&lt;/td&gt; <BR>&lt;td&gt;jakarta.apache.org/velocity/index.html&lt;/td&gt; <BR>&lt;td&gt;2&lt;/td&gt; <BR>&lt;/tr&gt; <BR>&lt;tr&gt; <BR>&lt;td&gt;Log4J&lt;/td&gt; <BR>&lt;td&gt;jakarta.apache.org/log4j/docs/index.html&lt;/td&gt; <BR>&lt;td&gt;2&lt;/td&gt; <BR>&lt;/tr&gt; <BR>&lt;/table&gt; <BR>&lt;/body&gt; <BR>&lt;/html&gt; </PRE><BR><BR>#if 语句完成逻辑判断，这个我想不用多说了。 <BR>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块的内容”。 <BR><BR>2.MVC设计模型 <BR><BR>使用模板引擎最大的好处在于，它分离了代码（或程序逻辑）和表现（输出）。由于这种分离，你可以修改程序逻辑而不必担心邮件消息本身；类似地，你（或公关部门的职员）可以在不重新编译程序的情况下，重新编写客户列表。实际上，我们分离了系统的数据模式（Data Model，即提供数据的类）、控制器（Controller，即客户列表程序）以及视图（View，即模板）。这种三层体系称为Model-View-Controller模型（MVC）。 <BR>如果遵从MVC模型，代码分成三个截然不同的层，简化了软件开发过程中所有相关人员的工作。 <BR>结合模板引擎使用的数据模式可以是任何Java对象，最好是使用Java Collection Framework的对象。控制器只要了解模板的环境（如VelocityContext），一般这种环境都很容易使用。 <BR>一些关系数据库的“对象-关系”映射工具能够和模板引擎很好地协同，简化JDBC操作；对于EJB，情形也类似。 模板引擎与MVC中视图这一部分的关系更为密切。模板语言的功能很丰富、强大，足以处理所有必需的视图功能，同时它往往很简单，不熟悉编程的人也可以使用它。模板语言不仅使得设计者从过于复杂的编程环境中解脱出来，而且它保护了系统，避免了有意或无意带来危险的代码。例如，模板的编写者不可能编写出导致无限循环的代码，或侵占大量内存的代码。不要轻估这些安全机制的价值；大多数模板编写者不懂得编程，从长远来看，避免他们接触复杂的编程环境相当于节省了你自己的时间。 许多模板引擎的用户相信，在采用模板引擎的方案中，控制器部分和视图部分的明确分离，再加上模板引擎固有的安全机制，使得模板引擎足以成为其他内容发布系统（比如JSP）的替代方案。因此，Java模板引擎最常见的用途是替代JSP也就不足为奇了。 <BR><BR>3.HTML处理 <BR><BR>由于人们总是看重模板引擎用来替换JSP的作用，有时他们会忘记模板还有更广泛的用途。到目前为止，模板引擎最常见的用途是处理HTML Web内容。但我还用模板引擎生成过SQL、email、XML甚至Java源代码。</DIV><img src ="http://www.blogjava.net/jackybu/aggbug/8804.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-07-30 22:31 <a href="http://www.blogjava.net/jackybu/articles/8804.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Velocity 的工作原理---from matrix</title><link>http://www.blogjava.net/jackybu/articles/8803.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Sat, 30 Jul 2005 14:28:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/8803.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/8803.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/8803.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/8803.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/8803.html</trackback:ping><description><![CDATA[<DIV class=forumcontent>这个程序很简单，但是它能让你清楚的了解 Velocity 的基本工作原理。程序中其他部分基本上很固定，最主要的部分在以下代码<BR><BR>　　这里 Velocity 获取模板文件，得到模板引用<BR><BR>/* next, get the Template */<BR>Template t = ve.getTemplate( "hellosite.vm" );<BR><BR>　　这里，初始化环境，并将数据放入环境<BR><BR>/* create a context and add data */<BR><BR>VelocityContext context = new VelocityContext();<BR><BR>context.put("name", "Eiffel Qiu");<BR><BR>context.put("site", "http://www.eiffelqiu.com");<BR><BR>　　其他代码比较固定，但是也非常重要，但是对于每个应用来说写法都很相同：<BR>这是初始化 Velocity 模板引擎<BR><BR>/* first, get and initialize an engine */<BR><BR>VelocityEngine ve = new VelocityEngine();<BR>ve.init();<BR><BR>　　这是用来将环境变量和输出部分结合。<BR><BR>StringWriter writer = new StringWriter();<BR>t.merge( context, writer );<BR>/* show the World */<BR>System.out.println( writer.toString() ); <BR><BR>　　记住，这在将来的 servlet 应用中会有所区别，因为网页输出并不和命令行输出相同，如果用于网页输出，将并不通过 System.out 输出。这会在以后的教程中给大家解释的。<BR><BR>那让我来总结一下 Velocity 真正的工作原理：<BR>　　Velocity 解决了如何在 Servlet 和网页之间传递数据的问题，当然这种传输数据的机制是在 MVC 模式上进行的，也就是View 和 Modle , Controller 之间相互独立工作，一方的修改不影响其他方变动，他们之间是通过环境变量（Context）来实现的，当然双方网页制作一方和后台程序一方要相互约定好对所传递变量的命名约定，比如上个程序例子中的 site, name 变量，它们在网页上就是 $name ,$site 。这样只要双方约定好了变量名字，那么双方就可以独立工作了。无论页面如何变化，只要变量名不变，那么后台程序就无需改动，前台网页也可以任意由网页制作人员修改。这就是 Velocity 的工作原理。<BR><BR>　　你会发现简单变量名通常无法满足网页制作显示数据的需要，比如我们经常会循环显示一些数据集，或者是根据一些数据的值来决定如何显示下一步的数据， Velocity 同样提供了循环，判断的简单语法以满足网页制作的需要。Velocity 提供了一个简单的模板语言以供前端网页制作人员使用，这个模板语言足够简单（大部分懂得 javascript 的人就可以很快掌握，其实它比 javascript 要简单的多），当然这种简单是刻意的，因为它不需要它什么都能做， View 层其实不应该包含更多的逻辑，Velocity 的简单模板语法可以满足你所有对页面显示逻辑的需要，这通常已经足够了，这里不会发生象 jsp 那样因为一个无限循环语句而毁掉系统的情况，jsp 能做很多事情，Sun 在制定 Jsp 1.0 标准的时候，没有及时的限定程序员在 jsp 插入代码逻辑，使得早期的jsp 代码更象是 php 代码，它虽然强大，但是对显示层逻辑来说，并不必要，而且会使 MVC 三层的逻辑结构发生混淆。<BR><BR>我的网站： http://www.eiffelqiu.com<BR>Email： eiffelqiu@163.com<BR>希望和大家交流<BR><BR>出处：牧羊人手记</DIV><img src ="http://www.blogjava.net/jackybu/aggbug/8803.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-07-30 22:28 <a href="http://www.blogjava.net/jackybu/articles/8803.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>velocity 的介绍-------from matrix jdyao</title><link>http://www.blogjava.net/jackybu/articles/8802.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Sat, 30 Jul 2005 14:26:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/8802.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/8802.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/8802.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/8802.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/8802.html</trackback:ping><description><![CDATA[<DIV class=forumcontent>Velocity 是如何工作的呢？ 虽然大多 Velocity 的应用都是基于 Servlet 的网页制作。但是为了说明 Velocity 的使用，我决定采用更通用的 Java application 来说明它的工作原理。<BR><BR>　　似乎所有语言教学的开头都是采用 HelloWorld 来作为第一个程序的示例。这里也不例外。<BR><BR>　　任何 Velocity 的应用都包括两个方面:<BR>　　第一是： 模板制作，在我们这个例子中就是 hellosite.vm:<BR>　　它的内容如下（虽然不是以 HTML 为主，但是这很容易改成一个 html 的页面）<BR><BR>Hello $name! Welcome to $site world!<BR><BR>　　第二是 Java 程序部分：<BR>　　下面是 Java 代码<BR><BR>import java.io.StringWriter;<BR>import org.apache.velocity.app.VelocityEngine;<BR>import org.apache.velocity.Template;<BR>import org.apache.velocity.VelocityContext;<BR><BR>public class HelloWorld<BR>{<BR>public static void main( String[] args )<BR>throws Exception<BR>{<BR>/* first, get and initialize an engine */<BR><BR>VelocityEngine ve = new VelocityEngine();<BR>ve.init();<BR><BR>/* next, get the Template */<BR><BR>Template t = ve.getTemplate( "hellosite.vm" );<BR><BR>/* create a context and add data */<BR><BR>VelocityContext context = new VelocityContext();<BR><BR>context.put("name", "Eiffel Qiu");<BR><BR>context.put("site", "http://www.eiffelqiu.com");<BR><BR>/* now render the template into a StringWriter */<BR><BR>StringWriter writer = new StringWriter();<BR><BR>t.merge( context, writer );<BR><BR>/* show the World */<BR><BR>System.out.println( writer.toString() );<BR>}<BR>}<BR><BR>将两个文件放在同一个目录下，编译运行，结果是：<BR><BR>Hello Eiffel Qiu! Welcome to http://www.eiffelqiu.com world<BR><BR>　　为了保证运行顺利，请从 Velocity 的网站 http://jakarta.apache.org/velocity/ 上下载 Velocity 的运行包，将其中的 Velocity Jar 包的路径放在系统的 Classpath 中，这样就可以编译和运行以上的程序了。<BR><BR>出处：牧羊人手记</DIV><img src ="http://www.blogjava.net/jackybu/aggbug/8802.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-07-30 22:26 <a href="http://www.blogjava.net/jackybu/articles/8802.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>