??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品无码av人在线观看,亚洲精品成人图区,国产精品久久亚洲不卡动漫http://www.tkk7.com/kingwell/category/8831.htmlAspire to Professionalismzh-cnWed, 28 Feb 2007 07:48:18 GMTWed, 28 Feb 2007 07:48:18 GMT60velocity?/title><link>http://www.tkk7.com/kingwell/articles/50307.html</link><dc:creator>KingWell</dc:creator><author>KingWell</author><pubDate>Sun, 04 Jun 2006 10:51:00 GMT</pubDate><guid>http://www.tkk7.com/kingwell/articles/50307.html</guid><wfw:comment>http://www.tkk7.com/kingwell/comments/50307.html</wfw:comment><comments>http://www.tkk7.com/kingwell/articles/50307.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/kingwell/comments/commentRss/50307.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/kingwell/services/trackbacks/50307.html</trackback:ping><description><![CDATA[Velocity是什么?<br />Velocity是一个基于java的模板引擎(template engineQ。它允许MZ仅简单的使用模板语言Qtemplate languageQ来引用由java代码定义的对象?br />当Velocity应用于web开发时Q界面设计h员可以和javaE序开发h员同步开发一个遵循MVC架构的web站点Q也是_面设计人员可以只关注页面的昄效果Q而由javaE序开发h员关注业务逻辑~码。Velocityjava代码从web面中分d来,q样为web站点的长期维护提供了便利Q同时也为我们在JSP和PHP之外又提供了一U可选的Ҏ?br />Velocity的能力远不止web站点开发这个领域,例如Q它可以从模板(templateQ生SQL和PostScript、XMLQ它也可以被当作一个独立工h产生源代码和报告Q或者作为其他系l的集成lg使用。Velocity也可以ؓTurbine web开发架构提供模板服务(template serviceQ。Velocity+Turbine提供一个模板服务的方式允许一个web应用以一个真正的MVC模型q行开发?br /><br />Velocity能ؓ我们作什么?<br />The Mud Store Example <br />假设你是一家专门出售Mud的在U商店的面设计人员Q让我们暂且U它为“在UMUD商店”。你们的业务很旺Q客户下了各U类型和数量的mud订单。他们都是通过输入用户名和密码后才登陆C的网站,登陆后就允许他们查看订单q购买更多的mud。现在,一U非常流行的mud正在打折销售。另外有一些客戯律性的购买另外一U也在打折但是不是很行的Bright Red MudQ由于购买的人ƈ不多所以它被安|在面的边~。所有用L信息都是被跟tƈ存放于数据库中的Q所以某天有一个问题可能会冒出来:Z么不使用velocity来用户更好的浏览他们感兴趣的商品呢Q?br />Velocity使得web面的客户化工作非常Ҏ。作Z个web site的设计h员,你希望每个用L陆时都拥有自q面?br />你会见了一些公司内的Y件工E师Q你发现他们每个人都同意客户应该拥有h个性化的信息。那让我们把软g工程师应该作的事情发在一边,看一看你应该作些什么吧?br />你可能在面内嵌套如下的VTL声明Q?br /><html><br /><body><br />Hello $customer.Name!<br /><table><br />#foreach( $mud in $nudsOnSpecial ) <br />#if ( $customer.hasPurchased( $mud ) ) <br /><tr><td>$flogger.getPromo( $mud )</td></tr><br />#end<br />#end<br /></table><br /><br />Velocity Template Language(VTL):AN introduction<br />VTL意味着提供最单、最Ҏq且最整洁的方式合q面动态内宏V?br />VTL使用references来在web site内嵌套动态内容,一个变量就是一U类型的reference。变量是某种cd的refreenceQ它可以指向java代码中的定义Q或者从当前面内定义的VTL statement得到倹{下面是一个VTL statement的例子,它可以被嵌套到HTML代码中:<br />  #set ( $a = “Velocity?)<br />和所有的VTL statement一Pq个statement以#字符开始ƈ且包含一个directiveQset。当一个在U用戯求你的页面时QVelocity Templating Engine查询整个页面以便发现所有#字符Q然后确定哪些是VTL statementQ哪些不需要VTL作Q何事情?br />Q字W后紧跟一个directiveQsetӞq个set directive使用一个表辑ּQ用括号封闭)――一个方E式分配一个值给变量。变量被列在左边Q而它的D列在双Q最后他们之间用=号分剌Ӏ?br />在上面的例子中,变量?aQ而它的值是Velocity。和其他的references一样以$字符开始,而值L以双引号闭。Velocity中仅有String可以被赋值给变量?br />C以下的规则:<br />使用$字符开始的references用于得到什么;使用#字符开始的directives用于作些什么?br />Hello Velocity World!<br />一旦某个变量被分配了一个|那么你就可以在HTML文g的Q何地方引用它。在下面的例子中Q一个D分配l?foo变量Qƈ在其后被引用?br /><html><br /><body><br />#set ( $foo = “Velocity?)<br />Hello $foo World!<br /></body><br /></html><br />上面的实现结果是在页面上打印“Hello Velocity WorldQ?br />Z使包含VTL directives的statement更具有可L,我们鼓励你在新行开始每个VTL statementQ尽你不是必须q么作。Set directive在后面详细描述?br />注释<br />单行注释Q?br />  ## This is a single line comment.<br />多行注释Q?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 />文档格式Q?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中有三种cd的referencesQ变?variables)、属?properties)、方?methods)。作Z个用VTL的页面设计者,你和你的工程师必dreferences的名U达成共识,以便你可以在你的template中用它们?br />Everything coming to and from a reference被作Z个String对象处理。如果有一个对?foo是一个Integer对象Q那么Velocity调用它的toString()Ҏ这个对象{型ؓStringcd?br />  变量 <br />  格式要求同java?br />  属?<br />  例子Q?br />    $customer.Address<br />    $purchase.Total<br />$customer.Address有两U含义。它可以表示Q查找hashtable对象customer中以Address为关键字的|也可以表C用customer对象的getAddress()Ҏ。当你的面被请求时QVelocity确定以上两U方式选用那种Q然后返回适当的倹{?br />Ҏ <br />一个方法就是被定义在java中的一D代码,q且它有完成某些有用工作的能力,例如一个执行计和判断条g是否成立、满等。方法是一个由$开始ƈ跟随VTL标识W组成的ReferencesQ一般还包括一个VTLҎ体。例如:<br />  $customer.getAddress()<br />  $purchase.getTotal()<br />  $page.setTitle( “My Home Page?)<br />  $person.setAttributes( [“Strange? “Weird? “Excited”] )<br />前两个例?customer.getAddress()?purchase.getTotal()看v来挺想上面的属?customer.Address ?$purchase.Total。如果你觉得他们之间有某U联pȝ话,那你是正的?br />VTL属性可以作为VTLҎ的羃写?customer.Address属性和使用$customer.getAddress()Ҏh相同的效果。如果可能的话用属性的方式是比较合理的。属性和Ҏ的不同点在于你能够给一个方法指定一个参数列表?br />正式reference标记<br />reference的正是格式如下:<br />  ${mudSlinger}        变量<br />  ${customer.Address}    属?br />  ${purchase.getTotal()}    Ҏ<br />非正是格式更见常用,但是有时q是使用正是格式比较适合。例如:你希望通过一个变?vice来动态的l织一个字W串?br />  Jack is a $vicemaniac.<br />本来变量?vice现在却变成了$vicemaniacQ这样Veloctiy׃知道您到底要什么了。所以,应该使用正是格式书写<br />  Jack is a ${vice}maniac<br />现在Velocity知道变量?vice而不?vicemaniac?br />Quiet reference notation<br />例如Q?br />  <input type=”text?name=”email?value=?email?/><br />当页面的form被初始加载时Q变?emailq没有|q时你肯定是希望它能够显CZ个blank text来代替输出?email”这L字段。那么用quiet reference notation比较合适?br />  <input type=”text?name=”email?value=?!email?><br />q样文本框的初始值就不会是email而是Ig?br />正式和quiet格式的reference notation也可一同用,像下面这P<br />  <input type=”text?name=”email?value=?!{email}?><br />Getting literal <br />Velocity使用Ҏ字符$?来帮助它工作Q所以如果要在template里用这些特D字W要格外心。本节将讨论$字符?br />  货币字符 <br />在VTL中?2.5q样的货币标识是没有问题得的QVTL不会它错认为是一个referenceQ因为VTL中的referenceL以一个大写或者小写的字母开始?br />Escaping valid VTL reference <br />VTL中用“\”作为逃逸符?br />例如Q?br />  #set( $email = “foo?)<br />  $email<br />  \$email<br />  \\$email<br />  \\\$email<br />render为:<br />  foo<br />  $email<br />  \foo<br />  \\$email<br />如果email变量没有被定义则<br />  $email<br />  \$email<br />  \\$email<br />  \\\$email<br />被render为:<br />  $email<br />  \$email<br />  \\$email<br />  \\\$email<br />注意QVTL中未被定义的变量被认ؓ是一个字W串Q所以以下例子:<br />  #set( $foo = “gibbous?)<br />  $moon = $foo<br />的输出结果是Q?br />$moon = gibbous<br />Case substitution<br />现在你已l对reference比较熟悉了,你可以将他们高效的应用于你的template了。Velocity利用了很多java规范以方便了设计人员的用。例如:<br />  $foo<br />  $foo.getBar()<br />  ## is the same as<br />  $foo.Bar<br /><br />  $data.getUser(“jon?<br />  ## is the same as<br />  $data.User(“jon?<br /><br />  $data.getRequest().getServerName()<br />  # is the same as<br />  $data.Request.ServerName<br />  ## is the same as<br />  ${data.Request.ServerName}<br />但是Q注意VTL中不会将reference解释为对象的实例变量。例如:$foo.Name被解释为Foo对象的getNameQ)ҎQ而不是Foo对象的Name实例变量?br />Directives<br />Reference允许设计者用动态的内容Q而directive使得你可以应用java代码来控制你的显C逻辑Q从而达C所期望的显C效果?br />  #set <br />  #set directive被用于设|一个reference的倹{例如:<br />    #set ( $primate = “monkey?)<br />    #set ( $customer.Behavior = $primate )<br />赋值左侧的QLHSQ必L一个变量或者属性reference。右侧(RHSQ可以是以下cd中一U:<br />l  变量reference<br />l  String literal<br />l  属性reference<br />l  Ҏreference<br />l  number literal<br />l  ArrayList<br />下面是应用各U类型的RHS的例子:<br />  Qset ( $monkey = $bill ) ##变量reference<br />  Qset ( $monkey.Friend = “monica?) ##String literal<br />  Qset ( $monkey.Blame = $whitehouse.Leak )##属性reference<br />  Qset ( $monkey.Plan = $spindoctor.weave($web) )##Ҏreference<br />  Qset ( $monkey.Number = 123 )##Number literal<br />  Qset ( $monkey.Say = [“Not? $my, “fault”] )##ArrayList<br />注意Q最后一个例子的取值方法ؓQ?monkey.Say.get(0)<br />RHS也可以是一个简单的术表达式:<br />  #set ( $value = $foo + 1 )<br />  #set ( $value = $bar -1 )<br />#set ( $value = $foo * $bar )<br />#set ( $value = $foo / $bar )<br />如果你的RHS是一个nullQVTL的处理将比较ҎQ它指向一个已l存在的referenceQ这对初学者来讲可能是比较费解的。例如:<br />  #set ( $resut = $query.criteria(“name? )<br />  The result of the first query is $result<br /><br />  #set ( $resut = $query.criteria(“address? )<br />  The result of the second query is $result<br />如果$query.criteria(“name?q回一个“bill”,?query.criteria(“address?q回的是nullQ则昄的结果如下:<br />  The result of the first query is bill<br />  The result of the first query is bill<br />看看下面的例子:<br />  #set( $criteria = ["name", "address"] )<br />#foreach( $criterion in $criteria )<br />#set( $result = $query.criteria($criterion) )<br />  #if( $result )<br />  Query was successful<br />     #end<br />#end<br />在上面的例子中,E序不能智能的Ҏ$result的值决定查询是否成功。在$result?set后(added to the contextQ,它不能被讄回nullQremoved from the contextQ。打印的l果显CZơ查询结果都成功了,但是实际上有一个查询是p|的?br />Z解决以上问题我们可以通过预先定义的方式:<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 directiveQString literal闭在一对双引号内?br />    #set ( $directoryRoot = “www?)<br />    #set ( $templateName = “index.vm?)<br />    #set ( $template = ?directoryRoot/$tempateName?)<br />    $template<br />  上面q段代码的输出结果ؓQwww/index.vm<br />  但是Q当string literal被封装在单引号内Ӟ它将不被解析Q?br />    #set ( $foo = “bar?)<br />    $foo<br />    #set ( $blargh = ?foo?)<br />  l果Q?br />    bar<br />    $foo<br />  上面q个Ҏ可以通过修改velocity.properties文g的stringliterals.interpolate = false的值来改变上面的特性是否有效?br />条g语句<br />  if/elseif/else <br />当一个web面被生成时使用Velocity?if directriveQ如果条件成立的话可以在面内嵌入文字。例如:<br />  #if ( $foo )<br />    <strong>Velocity!</strong><br />  #end<br />上例中的条g语句在以下两种条g下成立:<br />l  $foo是一个boolean型的变量Q且它的gؓtrue<br />l  $foo变量的g为null<br />q里需要注意一点:Velocity context仅仅能够包含对象Q所以当我们说“boolean”时实际上代表的时一个Boolean对象。即便某个方法返回的是一个boolean|Velocity也会利用内省机制它转换Z个Boolean的相同倹{?br />如果条g成立Q那?if?end之间的内容将被显C?br />#elseif?else元素可以?if一同用。例如:<br />  #if( $foo < 10 )<br />    <strong> Go North </strong><br />  #elseif( $foo == 10 )<br />    <strong> Go East </strong><br />  #elseif( $foo == 6 )<br />    <strong> Go South </strong><br />  #else<br />    <strong> Go West </strong><br />  #end<br />注意q里的Velocity的数字是作ؓInteger来比较的――其他类型的对象得条件ؓfalseQ但是与java不同它用“=Q”来比较两个|而且velocity要求{号两边的值类型相同?br />关系、逻辑q算W?<br />Velocity中用等h作符判断两个变量的关pR例如:<br />#set ( $foo = “deoxyribonucleic acid?)<br />#set ( $bar = “ribonucleic acid?)<br />#if ( $foo == $foo )<br />  In this case it’s clear they aren’t equivalent.So?br />#else<br />  They are not equivalent and this will be the output.<br />#end<br /><br />Velocity有AND、OR和NOT逻辑q算W。下面是一些例子:<br />  ## logical AND<br />  #if( $foo && $bar )<br />    <strong> This AND that </strong><br />  #end<br /><br />  ## logical OR<br />  #if ( $foo || $bar )<br />    <strong>This OR That </strong><br />  #end<br /><br />  ##logical NOT<br />  #if ( !$foo )<br />    <strong> NOT that </strong><br />  #end<br />循环 <br />  Foreach循环 <br />  例子Q?br />    <ul><br />      #foreach ( $product in $allProducts )<br />        <li> $product </li><br />      #end<br />    </ul><br />  每次循环$allProducts中的一个值都会赋l?product变量?br />$allProducts可以是一个Vector、Hashtable或者Array。分配给$product的值是一个java对象Qƈ且可以通过变量被引用。例如:如果$product是一个java的Productc,q且q个产品的名字可以通过调用他的getNameQ)Ҏ得到?br />现在我们假设$allProducts是一个HashtableQ如果你希望得到它的key应该像下面这P<br /><ul><br />#foreach ( $key in $allProducts.keySet() )<br /><li>Key: $key -> Value: $allProducts.get($key) </li><br />#end<br /></ul><br /><br />Velocityq特别提供了得到循环ơ数的方法,以便你可以像下面q样作:<br /><table><br />#foreach ( $customer in $customerList )<br /><tr><td>$velocityCount</td><td>$customer.Name</td></tr><br />#end<br /></table><br />$velocityCount变量的名字是Velocity默认的名字,你也可以通过修改velocity.properties文g来改变它。默认情况下Q计C?”开始,但是你可以在velocity.properties讄它是从?”还是从?”开始。下面就是文件中的配|:<br />  # Default name of loop counter<br />  # variable reference<br />  directive.foreach.counter.name = velocityCount<br /><br />  # Default starting value of the loop<br />  # counter variable reference<br />  directive.foreach.counter.initial.value = 1<br /><br />include<br />#include script element允许模板设计者引入本地文件。被引入文g的内容将不会通过模板引擎被render。ؓ了安全的原因Q被引入的本地文件只能在TEMPLATE_ROOT目录下?br />  #inclued ( “one.txt?)<br />如果您需要引入多个文Ӟ可以用逗号分隔pQ?br />  #include ( “one.gif? “two.txt? “three.htm?)<br />在括号内可以是文件名Q但是更多的时候是使用变量的:<br />  #inclue ( “greetings.txt? $seasonalstock )<br /><br />parse<br />#parse script element允许模板设计者一个包含VTL的本地文件。Velocity解析其中的VTLqrender模板?br />  #parse( “me.vm?)<br />像#includeQ?parse接受一个变量而不是一个模ѝQ何由#parse指向的模杉K必须包含在TEMPLATE_ROOT目录下。与#include不同的是Q?parse只能指定单个对象?br />你可以通过修改velocity.properties文g的parse_direcive.maxdepth的值来控制一个template可以包含的最?parse的个数――默认值是10?parse是可以递归调用的,例如Q如果dofoo.vm包含如下行:<br />  Count down.<br />  #set ( $count = 8 )<br />  #parse ( “parsefoo.vm?)<br />  All done with dofoo.vm!<br />那么在parsefoo.vm模板中,你可以包含如下VTLQ?br />  $count<br />  #set ( $count = $count ?1 )<br />  #if ( $count > 0 )<br />    #parse( “parsefoo.vm?)<br />  #else<br />    All done with parsefoo.vm!<br />  #end<br />的显C结果ؓQ?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允许模板设计者停止执行模板引擎ƈq回。把它应用于debug是很有帮助的?br />  #stop<br /><br />Velocimacros<br />#macro script element允许模板设计者定义一D可重用的VTL template。例如:<br />  #macro ( d )<br />  <tr><td></td></tr><br />  #end<br />在上面的例子中Velocimacro被定义ؓdQ然后你可以在MVTL directive中以如下方式调用它:<br />  #d()<br />当你的template被调用时QVelocity用<tr><td></td></tr>替换?d()?br />每个Velocimacro可以拥有L数量的参数――甚?个参敎ͼ虽然定义时可以随意设|参数数量,但是调用q个Velocimacro时必L定正的参数。下面是一个拥有两个参数的VelocimacroQ一个参数是color另一个参数是arrayQ?br />  #macro ( tablerows $color $somelist )<br />  #foreach ( $something in $somelist )<br />    <tr><td bgcolor=$color>$something</td</tr><br />  #end<br />  #end<br />调用#tablerows VelocimacroQ?br />  #set ( $greatlakes = [ “Superior? “Michigan? “Huron? “Erie? “Ontario?] )<br />  #set ( $color = “blue?)<br />  <table><br />    #tablerows( $color $greatlakes )<br />  </table><br />l过以上的调用将产生如下的显C结果:<br />  <table><br />    <tr><td bgcolor=?blue?gt; Superior </td></tr><br />    <tr><td bgcolor=?blue?gt; Michigan </td></tr><br />    <tr><td bgcolor=?blue?gt; Huron </td></tr><br />    <tr><td bgcolor=?blue?gt; Erie </td></tr><br />    <tr><td bgcolor=?blue?gt; Ontario </td></tr><br />  </table><br />Velocimacros可以在Velocity模板内实现行内定义(inlineQ,也就意味着同一个web site内的其他Velocity模板不可以获得Velocimacros的定义。定义一个可以被所有模板共享的Velocimacro昄是有很多好处的:它减了在一大堆模板中重复定义的数量、节省了工作旉、减了出错的几率、保证了单点修改?br />上面定义?tablerows( $color $list )Velocimacro被定义在一个Velocimacros模板?在velocity.properties中定?里,所以这个macro可以在Q何规范的模板中被调用。它可以被多ơ应用ƈ且可以应用于不同的目的。例如下面的调用Q?br />  #set ( $parts = [ “volva? “stipe? “annulus? “gills? “pileus?] )<br />  #set ( $cellbgcol = ?CC00FF?)<br />  <table><br />    #tablerows( $cellbgcol $parts )<br />  </table><br />上面VTL生如下的输出Q?br />  <table><br />    <tr><td bgcolor=?CC00FF?gt; volva </td</tr><br />    <tr><td bgcolor=?CC00FF?gt; stipe </td</tr><br />    <tr><td bgcolor=?CC00FF?gt; annulus </td</tr><br />    <tr><td bgcolor=?CC00FF?gt; gills </td</tr><br />    <tr><td bgcolor=?CC00FF?gt; pileus </td</tr><br />  </table><br />  Velocimacro arguments <br />  Velocimacro可以使用以下M元素作ؓ参数Q?br />l  ReferenceQQ何以$开头的reference<br />l  String literalQ?br />l  Number literalQ?br />l  IntegerRangeQ[1?3]或者[$foo?$bar]<br />l  对象数组Q[“a?”b?”c”]<br />l  boolean|true、false<br />当将一个reference作ؓ参数传递给VelocimacroӞh意reference作ؓ参数时是以名字的形式传递的。这意味着参数的值在每次Velocimacro内执行时才会被生。这个特性得你可以一个方法调用作为参C递给VelocimacroQ而每ơVelocimacro执行旉是通过q个Ҏ调用产生不同的值来执行的。例如:<br />  #macro ( callme $a )<br />    $a $a $a<br />  #end<br />  #callme( $foo.bar() )<br />执行的结果是Qreference $foo的barQ)Ҏ被执行了三次?br />如果你不需要这LҎ可以通过以下ҎQ?br />  #set ( $myval = $foo.bar() )<br />  #callme ( $myval )<br /><br />Velocimacro properties <br />Velocity.properties文g中的某几行能够Velocimacros的实现更加灵zR注意更多的内容可以看Developer Guide?br />Velocity.properties文g中的velocimacro.libraaryQ一个以逗号分隔的模板库列表。默认情况下Qvelocity查找唯一的一个库QVM_global_library.vm。你可以通过配置q个属性来指定自己的模板库?br />Velocity.properties文g中的velocimacro.permissions.allow.inline属性:有两个可选的值true或者falseQ通过它可以确定Velocimacros是否可以被定义在regular template内。默认值是ture――允许设计者在他们自己的模板中定义Velocimacros?br />Velocity.properties文g中的<br />velocimacro.permissions.allow.inline.replace.global属性有两个可选值true和falseQ这个属性允怋用者确定inline的Velocimacro定义是否可以替代全局Velocimacro定义Q比如在velocimacro.library属性中指定的文件内定义的VelocimacroQ。默认情况下Q此gؓfalse。这样就L本地Velocimacro定义覆盖全局定义?br />Velocity.properties文g中的<br />velocimacro.permissions.allow.inline.local.scale属性也是有true和false两个可选|默认是false。它的作用是用于定你inline定义的Velocimacros是否仅仅在被定义的template内可见。换句话_如果q个属性设|ؓtrueQ一个inline定义的Velocimacros只能在定义它的template内用。你可以使用此设|实C个奇妙的VM敲门Qa 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文g中的velocimacro.context.localscope属性有true和false两个可选|默认gؓfalse。当讄为trueӞM在Velocimacro内通过#set()对context的修改被认ؓ是针Ҏvelocimacro的本地设|,而不会永久的影响内容?br />Velocity.properties文g中的velocimacro.library.autoreload属性控制Velocimacro库的自动加蝲。默认是false。当讄为tureӞ对于一个Velocimacro的调用将自动查原始库是否发生了变化,如果变化重新加载它。这个属性得你可以不用重新启动servlet容器而达到重新加载的效果Q就像你使用regular模板一栗这个属性可以用的前提是resource loader~存是off状态(file.resource.loader.cache = falseQ。注意这个属性实际上是针对开发而非产品的?br />Velocimacro Trivia <br />Velocimacro必须被定义在他们被用之前。也是_你的#macro()声明应该出现在用Velocimacros之前?br />特别要注意的是,如果你试?parse()一个包?macro()的模ѝ因?parse()发生在运行期Q但是解析器在parsetiem军_一个看似VM元素的元素是否是一个VM元素Q这?parse()-ing一lVM声明不按照预期的样子工作。ؓ了得到预期的l果Q只需要你单的使用velocimacro.library使得Velocity在启动时加蝲你的VMs?br />Escaping VTL directives<br />VTL directives can be escaped with “\”号Q用方式跟VTL的reference使用逃逸符的格式差不多?br />  ## #include( “a.txt?) renders as <ontents of a.txt>(注释?<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 \<contents of a.txt><br />  \\#include( “a.txt?)<br />在对在一个directive内包含多个script元素的VTL directives使用逃逸符时要特别心Q比如在一个if-else-end statement内)。下面是VTL的if-statement的典型应用:<br />  #if ( $jazz )<br />    Vyacheslav Ganelin<br />  #end<br />如果$jazz是tureQ输出将是:<br />  Vyacheslav Ganelin<br />如果$jazz是falseQ将没有输出。用逃逸符改变输出。考虑一下下面的情况Q?br />  \#if ( $jazz )<br />    Vyacheslav Ganelin<br />  \#end<br />现在无论$jazz是trueq是falseQ输出结果都是:<br />  #if ( $jazz )<br />    Vyacheslav Ganelin<br />  #end<br />事实上,׃你用了逃逸符Q?jazzҎ没有被解析为boolean型倹{在逃逸符前用逃逸符是合法的Q例如:<br />  \\#if ( $jazz )<br />    Vyacheslav Ganelin<br />  \\#end<br />以上E序的显C结果ؓQ?br />  \ Vyacheslav Ganelin<br />  \<br />但是如果$jazz为falseQ那么将没有输出。(书上说会没有输出Q但是我觉得应该q有有“\”字W被输出。)<br />VTLQFormatting issues<br />管在此用户手册中VTL通常都开始一个新行,如下所C:<br />  #set ( $imperial = [ “Munetaka? “Koreyasu? “Hisakira? “Morikune?] )<br />  #foreach ( $shogun in $imperial )<br />    $shogun<br />  #end<br />但是像下面这U写法也是可以的Q?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 Q?a in $foo Q?a<br />      #end please.<br />q两U的输出l构一栗?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 />  当执行除法时返回一个Integercd的结果。而余C可以使用%来得刎ͼ<br />    #set ( $foo = $bar % 5 )<br />在Velocity内用数学计公式时Q只能用像-n,-2,-1,0,1,2,nq样的整敎ͼ而不能用其它类型数据。当一个非整型的对象被使用时它被loggedq且以null作ؓ输出l果?br />Range Operator<br />Range operator可以被用于与#set?foreach statement联合使用。对于处理一个整型数l它是很有用的,Range operatorh以下构造Ş式:<br />  [n..m]<br />m和n都必L整型Q而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 />上面四个例子的输出结果ؓQ?br />  First exampleQ?br />  1 2 3 4 5<br /><br />  Second exampleQ?br />  2 1 0 -1 -2<br /><br />  Third exampleQ?br />  0 1<br /><br />  Fourth exampleQ?br />  [1..3]<br />注意Qrange operator只在#set?foreach中有效?br />Advanced IssueQEscaping andQ?br />当一个reference被“!”分隔时Qƈ且在它之前有逃逸符Ӟreference以Ҏ的方式处理。注意这U方式与标准的逃逸方式时不同的。对照如下: <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 />  例如Q?center ( #bold( “hello?) )<br />  不可以。一个directive的参C用另外一个directive是不合法的?br />  但是Q还是有些事情你可以作的。最单的方式是使用双引P<br />    #set ( $stuff = ?bold( ‘hello?)?)<br />    #center ( $stuff ) <br />  上面的格式也可以~写Z行:<br />    #center ( ?bold( ‘hello?) )<br />h意在下面的例子中参数被evaluated在Velocimacro内部Q而不是在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 />输出l果为:<br />  outer : inner : outerlala<br />CVeloctiy的特性:参数的传递是By Name的。例如:<br />  #macro ( foo $color )<br />    <tr bgcolor = $color ><td>Hi</td></tr><br />    <tr bgcolor = $color ><td>There</td></tr><br />  #end<br /><br />  #foo ( $bar.rowColor() )<br />以上代码导致rowColor()Ҏ两次调用Q而不是一ơ。ؓ了避免这U现象的出现Q我们可以按照下面的方式执行Q?br />  #set ( $color = $bar.rowColor() )<br />  #foo ( $color )<br />can I register velocimacros via #parse()? <br />目前QVelocimacros必须在第一ơ被模板调用前被定义。这意味着你的#macro()声明应该出现在用Velocimacros之前?br />如果你试?parse()一个包?macro() directive的模板,q一Ҏ需要牢记的。因?parse()发生在运行期Q但是解析器在parsetiem军_一个看似VM元素的元素是否是一个VM元素Q这?parse()-ing一lVM声明不按照预期的样子工作。ؓ了得到预期的l果Q只需要你单的使用velocimacro.library使得Velocity在启动时加蝲你的VMs?br />What is velocimacro autoreloadingQ?<br />velocimacro.library.autoreload是专门ؓ开发而非产品使用的一个属性。此属性的默认值是false?br />String concatenation<br />开发h员最帔R的问题是我如何作字符拼接Q在java中是使用“+”号来完成的?br />在VTL里要惛_现同L功能你只需要将需要联合的reference攑ֈ一起就行了。例如:<br />#set ( $size = “Big?)<br />#set ( $name = “Ben?)<br />The clock is $size$name.<br />输出l果是QThe clock is BigBen.。更有趣的情冉|Q?br />  #set ( $size = “Big?)<br />  #set ( $name = “Ben?)<br />  #set ( $clokc = ?size$name?)<br />  The clock is $clock.<br />上例也会得到同样的结果。最后一个例子,当你希望混合固定字段C的referenceӞ你需要用标准格式:<br />  #set ( $size = “Big?)<br />  #set ( $name = “Ben?)<br />  #set ( $clock = ?{size}Tall$name?)<br />  The clock is $clock.<br />输出l果是:The clock is BigTallBen.。用这U格式主要是Z使得$size不被解释?sizeTall?img src ="http://www.tkk7.com/kingwell/aggbug/50307.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/kingwell/" target="_blank">KingWell</a> 2006-06-04 18:51 <a href="http://www.tkk7.com/kingwell/articles/50307.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>了解 Struts 框架的全新后?Shale不是Strutshttp://www.tkk7.com/kingwell/articles/48623.htmlKingWellKingWellSun, 28 May 2006 12:54:00 GMThttp://www.tkk7.com/kingwell/articles/48623.htmlhttp://www.tkk7.com/kingwell/comments/48623.htmlhttp://www.tkk7.com/kingwell/articles/48623.html#Feedback0http://www.tkk7.com/kingwell/comments/commentRss/48623.htmlhttp://www.tkk7.com/kingwell/services/trackbacks/48623.html  在过?5 q间出现的所?Web 框架中,Jakarta Struts ?Java?开发h员用得最多的一U框Ӟ因此其后代的问世是一件值得注意的事情。虽?Shale q不是最行的框Ӟ也不是最Zh熟悉的框Ӟ但是名门的背景仍lh以深d象。更令h兴奋的是QShale q不仅仅?Struts 的重大升U和新的发行?它彻底更C Struts 中的很多核心原则Qƈ且加入了 Web 开发中最新的思想?/p>

  您将了解刎ͼShale ?Struts 的背L一柄双刃剑。一斚wQShale 是经q精心设计的 Struts 的后代。Shale 的创立者综合考虑?Struts 的优点和不Q提出可与其前辈媲美的下一代框架。另一斚wQ正如您很快可以在q个pd中看到的一PShale ?一U完全不同于 Struts 的框Ӟ其中隐含着很多新的开发工?

  Shale 不仅仅是 Struts 的又一个修正版Q它已扩展到出 Struts 所能达到的高度。它包含 Java Web E序设计中一些最重要的、最q的开发成果,包括 JSP Standard Tag Library(JSTL)?JavaServer Faces(JSF)Qƈ建立在这些开发成果之上。Shale 完全应该被看作是?Struts 不同的一U框Ӟ在这个系列中Q我还 Shale 框架以本来面目。在q个月的文章中,首先对 Shale ?Struts 之间的区别作一个概qͼ然后带您体验安装 Shale q测试安装情늚步骤。最后,我将l出一些思想Qo您能q一步参与到 Shale 目(它是开放源码的)中,q提供一些相关的信息。整个系列的目的是要向您展C如何安?Shale 以及如何使用 Shale 构徏和开发项目,同时很少涉及 Shale 的前辈,?Struts 框架?/p>

  评h Shale

  M新的 Web 开发框架要惛_q个竞争已经很激烈的领域占得一席之圎ͼ最好能够经受住巨大压力下的评测。好消息是,Shale 独力l受住了l致的考察。但是,坏消息是Q由?Shale 完全是对 Struts 重新构徏的物,因此必须重新~写和重新测试您所有基?Struts 的代码,以便实现q些代码。您花同样多的_֊来编写一个新?Shale 应用E序Q或一?Struts 应用E序转换?Shale 应用E序Q就好像 Shale ?Struts 完全无关一栗?/p>

  所以接下来我们忍不住要问,Z么还要采?Shale ?Z得出{案Q我首先解释一?Shale 的伟大之?—?q在很大E度上是׃它的 Struts 血l,但这又不是惟一的原?—?然后讨论 Shale 之所以没?被发布ؓ Struts 框架的重要修正版的两大原因。这P您就会更好地理解?Shale w上可以得到什么,q将有助于评价用这U下一代的框架是否值得?/p>

  Struts 血l?/strong>

  Shale 重用了大量的 Struts 代码基,q声U?Struts 是它?“父?框架Q因此如果您要相?Shale 的h|得怿 Struts 的h倹{首先,Struts 作ؓW一个真正意义上?Web 开发框Ӟ拥有巨大的h倹{据 Shale ?Struts |站报道Q第一批代码是?2000 q?6 月提交给 Struts CVS 存储库的Q而Struts 1.0 是在 2001 q末才发布的。当很多开发h员正在艰隑֜使用 JavaServer Pages(JSP)和不断变化的 servlet 规范ӞStruts 提供了一U易于用的 Model 2 Ҏ来构建基?servlet ?JSP ?Web 应用E序。换句话_Struts ?Web 开发h员可以开发健壮的 Web 应用E序Q而不必精于日志记录、分布式计算、JDBC、Servlet、JSP、JNDI、RMI ?大量其他?API 和技术?/p>

  接下来,Struts 要做的事情就是保持它的强大?从写出第一批代码开始,Struts q箋 6 q一直是最行?Web 开发框架之一。至今它仍然是h们口中的谈资Q笔下的素材Q用得不比M竞争Ҏ。由?Struts 是如此流行,如此长寿Q如今它已经有丰富的功能Q有良好的文档,被广泛地支持Qƈ且易于用,在它上面q行开发和理也很Ҏ。数千名开发h员对 Struts 邮g列表上的问题作出{复Q数万名开发h员试?Struts q报告问题,q得这些问题很Ҏ得到修复?/p>

  最后,Struts 是不断发展的。很多框架一开始比较强大,然后停滞不?商业产品和开放源码项目都存在q样的现?Q?Struts L不断提供新的Ҏ。当您下?Struts Ӟ核心发行版中q包含一个健壮的认引擎(validation engine)Qƈ?Struts 已经?JavaServer Faces 集成Q拥有广泛的标记库和一个不断发展的 Model 2 架构Q其中引入了在分布式 n-层应用程序领域中最新的思想。而且告诉您,Struts q紧跟程序设计中出现的新模式Q例?IoC(Inversion of Control)。Struts ?WebWork ?Spring 框架自然地集成,后两者都是具有最佌l的、ؓ使用 Web 开发中的新Ҏ提供入口的框架?/p>

  而言之,您很隑֏现在 Struts 中有做不?或不支持的事。所以显然我们就要问Qؓ什?Shale 要另L灶呢?Z?Shale 没有成ؓ Struts 的下一个版本呢?q有两个主要原因:一个原因与鲜ؓ人知的新软g发行惯例有关Q另一个原因则与众所周知?Struts 根基中的q有关。让我们分别来考虑q两个原因?/p>

  发行版L?/strong>

  要理?Shale Z么没有成?Struts 的一个新的发行版Q首先需要理解关于新软g发行的一两g事。对于一个新的Y件发行版Q大多数用户首先看的是一l新的特性。版本升U的q度大Q用户对新特性的期待p大。因此,如果软g版本?2.1 升?2.2Q就应该有一些新的特性,但是如果从版?2.2 升到版?3.0Q那么就应该有很?新特性。这是Z么当一些大型?例如 Microsoft Word)或操作系l?例如 Windows ?Mac OS X )Z新版本的时候,用户L对它们很挑剔。对于每一个新的发行版Q用hL期待有更多新的特性?/p>

  ׃大多数用户一呛_注意力攑֜Ҏ上Q他们没有意识到向后兼容?backward compatibility)才是真正最有h值的东西。虽然每个h都希?Excel 中加入新的、很好的选项Q希?Panther ?iTunes 有更好的集成Q希?Gnome 中对 XUL 有更好的支持Q但是如果那些用L有的E序和文件在新版本下H然不能q行的话Q相信他们会叫Q“这是血腥谋杀”。在q种情况下,新特性毫无h倹{?/p>

  对于 Struts 也一栗一般来_Struts 的每个新版本都增加了新的Ҏ,同时保持了与之前版本的向后兼Ҏ。此外,新版本的 Struts q需要支持旧版本?Java q_?Servlet 规范Q因为已安装的旧?Struts 要在q些q_上运行。这两个需?—?向后兼容性和Ҏ版本?Java API 的支?—?对于 Shale 来说已经是一个严重的U束。尤其是Q至就 Java q_而言QJSF API 已经成ؓ Web 的中心组件。虽?Struts 也支?JSFQ但?Shale 却是完全依赖?JSF ?—?q对于需要维持向后兼Ҏ的 Struts 来说直是不可能的?/p>

  最后,zZ个像 Shale q样的新目Q同时l在 Struts q种已有的项目上q行开发活动,q样做具有无与u比的优势。如?Struts 只是单地升?2.0(或?3.0 ?4.0)Qƈ在不考虑向后兼容性的情况下实?ShaleQ那么对于很多h来说Q由此造成的移植工作将是o人痛苦的Q可能有人干脆连 Struts 也不再用了。即使仍然维护更旧的代码基,也难于吸引开发h员花旉来修?bugQ他们也不愿意ؓ一?“遭到废弃?的或?“旧?版本的Y件增加特性?/p>

  ׃q些原因Q让 Shale 成ؓ一个全新的目Q其徏立在一个新的代码基之上Q是很有意义的?br />Shale 的面向服务架?/strong>

  Shale 之所以没有成?Struts 的一个新的发行版Q其最后一个原因与逻辑没有关系:而是与该框架新Ҏ接纳?Web 开发中的能力有关系。Shale 在很多方面与 Struts 存在不同之处Q其中有两点最为突?

  •   Struts ?JSF 集成Q?Shale 则是建立?JSF 之上?
  •   Struts 实质上是一个巨大的、复杂的h处理??Shale 则是一l可以以M方式q行l合的服务?/li>

  Shale ?JSF 的依赖性具有深q的、o人惊讶的意义Q而且大部分情况下是积极的意义。随着q个pd的深入,我将深入研究q些意义。在讨论其他斚w之前Q有必要寚w成 Shale ?Struts 之间差异的第二个斚wq行详细的讨论?/p>

  如果您多ơ用过 StrutsQ那么会意识到它很大E度上可以看作一个请求处理器Q通过它可以接受请求,q指C框架如何处理请求。您可以指出采取哪种动作Q用什么模型,哪U视图显C给用户Q采用什么验证规则,昄哪种表单 ... Struts 是完全可以配|的。然而,所有这些的核心是一个请求处理器Qؓ每个h提供服务。这L处理器是 Struts 中最重要、也是最复杂的部分,因ؓ对于在处理一个请求的q程中涉及的所有工作,它都必须q行处理或托,?Struts 代码Z几乎没有哪一部分与这个请求处理器没有关系或不受它的媄响?/p>

  因此QStruts 基本上难于作出改变。如果想修改处理h的方式,或改变处理请求过E中各部分的序Q那么将面巨大的困难。实际上Q不得不重新~写 Struts 代码基。更改请求处理器的行为倒是E微可行Q但是大部分是不容变动的。这?Shale 试图解决的关键问题之一(如果您需?Web 框架有那U程度的灉|性的??/p>

  Shale 没有?Struts h处理器那L中心lgQ它只是一l数量很多的服务。可以自q合这些服务,每个服务与其他服务之间是松散耦合的。通过一l良好定义的接口(有时候实际上是 Java 接口c,有时候只是组件之间某UŞ式的契约)Q配|?Shale 的行为很Ҏ。这使得 Shale 是可扩展的、灵zȝQ甚x “聪明的”。很Ҏ更改它,不费吹灰之力可以扩展它Qƈ可以使它q速适应新的~程Ҏ。像q样松散地组装组件或服务通常被称作面向服务的架构Q或U?SOA。当Ӟq听h有点儿玄乎,不过您大可不必因此而觉?Shale 不好!

  安装 Shale

  可以从逻辑上和概念上理?Shale ?Struts 的不同之处,但是要想在脑里弄清楚这两种伟大的框架有什么不同,则需要亲自动手去实践一番。很自然Q每一U?Web 框架首先都需要下载和安装。不q幸好,在这个过E中通常可以了解到很多东ѝ那些安装和讄h比较困难的项目和产品Q通常也难于配|,难于在它上面q行部vQƈ?最坏的情况)难于长久q行。虽然安装过E很难作价一?Web 框架好坏的最可靠手段Q但是至肯定应该成个标准的一部分。在q一节中Q您学习手动地安装 ShaleQ对于一些难Ҏ一定的体会Qƈ了解Z?Shale q行Q系l上需要些什么东ѝ?/p>

  注意Q我q提C Shale ?便安?选项Q但是我强烈您至试一试手动安装,了解它提供的较深层的信息?/p>

  先决条g

  Shale 的先x件和需求相当多。和大多C Apache ?Jakarta 相关的项目一PShale 的安装要依赖于一些其他的 Jakarta 目。下面是Z?Shale 得以q行所需的所有东西的完整列表:

  •   Java Runtime Environment(JRE)?Java Development Kit(JDK) 1.4 或更高版?
  •   Java Servlet API 2.4 或更高版?
  •   JSP 2.0 或更高版?
  •   JSF 1.1 或更高版?
  •   JSP Standard Tag Library(JSTL) 1.1 或更高版?
  •   Jakarta Commons BeanUtils 1.7 或更高版?
  •   Jakarta Commons Chain 1.0 或更高版?
  •   Jakarta Commons Digester 1.7 或更高版?
  •   Apache Logging 1.0.4 或更高版?
  •   Apache Ant 1.6.3 或更高版?/li>

  Apache Ant 只是在构?Shale 时要用到Q但是无论如何,如果您要q行较多?Java 开发,那么pȝ上还是需?很可能已l有?一个版本的 Ant。如果想跟踪 Shale 中的 bugQ那么需?FindBugs 0.8.5 或更高版本和 JUnit 3.8.1 或更高版本。由于在W?1 部分中我只是讨论 Shale 的安装和使用Q因此您q不必关?FindBugs ?JUnitQ除非您x点儿装上q两个项目?/p>

  附g和它们的依赖?/strong>

  ?Struts 一PShale q有一些附??Shale 中常被称作可?Shale lg)Q这些附件各自又有其依赖?

  •   Jakarta Commons Validator 1.2 或更高版?
  •   Spring Framework 1.2.2 或更高版?
  •   Struts Tiles Framework(独立版本)

  如果说这份列表显得有些长q且令h生畏的话Q那么没?Shale 使用大量较低U的库、helper cR实用程序组件和来自其他目的类。如果必逐个安装q些lgQ配|?Shale 使用它们Qƈ所有这些组件组装成可以部v的某UŞ式的话,即是最专业的开发h员也会对 Shale 望而生畏。此外,׃ Shale 在它的开发圈子内仍然相当q轻Q对于这些依赖项的获得和配置仍然有些E嫩;然而,Shale 实是非常可行的Q而且不需要花Ҏ惌中那么多的精力?br /> 

  首先Q如果您正在用某U框架从事某U?Web 开发,那么应该已经有了一些作Z赖项的项目。所以这份列表比它初看上去要Ҏ理得多。例如,M Web 开发h员都应该已经?JRE ?JDKQ也应该有一?servlet 引擎Q例?Jakarta Tomcat。如果已l有一?servlet 引擎Q那么也应该?Servlet API ?JSP 引擎。另外,大部?servlet 引擎(臛_当前版本而言)都包括一?JSTLQƈ且很多都附带?JSF。最后,大多数开发h员很可能在他们的机器上已l安装了 Ant。因此,q䆾列表很快只剩下q些?

  •   JSF 1.1 或更高版?(servlet 引擎中可能已l附带了)
  •   JSTL 1.1 或更高版?(servlet 引擎中可能已l附带了)
  •   Jakarta Commons BeanUtils 1.7 或更高版?
  •   Jakarta Commons Chain 1.0 或更高版?
  •   Jakarta Commons Digester 1.7 或更高版?
  •   Apache Logging 1.0.4 或更高版?/li>

  考虑?Tapestry 实际上提供了它的所有依赖项附带下蝲的选项Q因?“太多依赖项?的问题很快就不成为问题了?/p>

  现在您已l知道了大概Q现在我们来看看下蝲、安装和配置 Shale 及其依赖的步骤?/p>

  1. 下蝲 Shale

  要下?ShaleQ可讉K Shale 目主页。您可以看到一?“Shale Download?区域Q其中有 Shale 框架的每晚构建的链接。单击这个链接,便可以进入如?1 所C的一个站?

点击攑֤此图? src=

  ?1. 来自 Shale CVS 存储库的每晚构徏

  Z?Shale q行Q需要下?“framework?文g?“dependencies?文g。例如,在撰写本文时我下载了以下两个文g:

  •   shale-framework-20060204.zip
  •   shale-dependencies-20060204.zip

  当然Q如果您需要或者更愿意下蝲 .tar.gz 版本Q那么可以不选择 .zip 版本Q而选择 .tar.gz 版本。由?Shale 的开发还在进行中Q目前还没有发行的构建,因此您应该尽量下载最q的每晚构徏(h最q的日期)?/p>

  下蝲完这两个文g后,首先解压q两个归档文件。对于核心框Ӟ解压后可以得C个具有Ş?shale-framework-20060204/ 的名U的文g?对于 dependencies 归档文gQ解压后可以得到一个名?lib/ 的文件夹。将核心框架目录 shale-framework-20060204/ 转移到您希望保存 Java 目的地斏V例如,在我的系l上Q我?shale-framework-20060204/ Ud?/usr/local/java 目录中。接下来Q将 lib/ 目录Ud?Shale 目录中,所以最后的目录l构?shale-framework-20060204/lib/ cM?br /> 

  2. d Shale 库到 Web 应用E序?/strong>

  下一步是所?Shale JAR 文g和库d?Web 应用E序可以讉K和用它们的位置。步骤如?

  1. 如果?servlet 引擎中没有包?JSFQ那么将 shale-framework-20060204/lib/jsf-ri/jsf-api.jar ?shale-framework-20060204/lib/jsf-ri/jsf-impl.jar 复制到应用程序的 WEB-INF/lib 目录中?/p>

  2. ?shale-core.jar、shale-clay.jar、shale-tiles.jar ?tiles-core.jar ?shale-framework-20060204/dist/ 目录复制?Web 应用E序?WEB-INF/lib 目录?/p>

  3. 以?Shale 依赖复制到 Web 应用E序?WEB-INF/lib 目录:

  •   o shale-framework-20060204/lib/commons-beanutils/commons-beanutils.jar
  •   o shale-framework-20060204/lib/commons-chain/commons-chain.jar
  •   o shale-framework-20060204/lib/commons-digester/commons-digester.jar
  •   o shale-framework-20060204/lib/commons-logging/commons-logging.jar
  •   o shale-framework-20060204/lib/commons-validator/commons-validator.jar

  4. 如果要?Shale ?Spring 集成Ҏ,那么?shale-spring.jar ?shale-framework-20060204/dist/ 复制?Web 应用E序?WEB-INF/ 目录。要完成q个步骤Q还必须保 Spring 的打?JAR 文g也在 Web 应用E序?WEB-INF/lib 目录中。这?JAR 文g名ؓ spring.jarQ如果您q没有这个文件的话,可以?shale-framework-20060204/lib/shaleframework/ 目录中找到它?/p>

  5. 如果正在使用 Java 5.0Q那么将 shale-tiger.jar ?shale-framework-20060204/dist/ 复制?Web 应用E序 ?WEB-INF/lib 目录中。只有在使用 Java 5.0 的时候才需要执行这一?否则Qservlet 引擎和?Shale ?Web 应用E序׃出问题?/p>

  再往后走开始复杂v?是的Q这些复制操作是较容易的一部分)。接下来的事情未必都要用最隄方式dQ至我应该让您有机会选择 试试Ҏ的方法。 Shale 在系l上q行q个d的确存在捷径;您已l知道手动设|?Shale 的过E比较复杂,接下来有必要看看 “简侎?Ҏ?/p>

  更容易的Ҏ

  重新讉K Shale 下蝲站点Qƈ下蝲名称cM?shale-starter-20060204.zip ?“starter?应用E序。解压这个归档文Ӟ得C个名?shale-starter/ 的目录。这是一个基本上配置好的 Shale Web 应用E序Q用于帮助避免前一节详l介l的复制和配|工作。首先要做的是将 shale-starter/ 目录重新命名成应用程序以后要使用的名Uͼ例如可以它命名?first-shale/。进?first-shale/ 目录Q在q里可以看到一些文件和子目录?/p>

  ?first-shale/ 目录中,创徏一个名?build.properties 的新文g。通过q个文g可以定制如何构徏 Shale starter 应用E序Qƈ保该应用程序适合您的环境讄。清?1 展示了一个基本的 build.properties 文gQ可以根据自q环境对其q行定制?/p>

  清单 1. Shale starter 应用E序的示?build.properties

# Basic project information
project.copyright=My project, Copyright ? 2006
project.name=My First Shale Application
project.vendor=IBM DeveloperWorks
project.vendor.id=com.ibm.dw

# Java package and context path for servlet engine
project.package=com.ibm.dw.firstShale
project.path=first-shale

# Directory for Shale distribution - change this for your system
shale.dir=/usr/local/java/shale-framework-20060204

# Directory for all your libraries - change this for your system
lib.dir=/usr/local/java/shale-framework-20060204/lib

  Ҏpȝ讄好这些属性后Q便可以q行 ant。Shale starter 应用E序开始构?q?假设已经正确地设|了路径)创徏一个示例应用程序。如果有问题Q则构徏脚本输出错误消息;q些错误消息都描q得很清楚,所以您应该可以更正M错误?/p>

  构徏q程的最后将生成一个名?target/ 的新目录。进入这个目录,可以看到一个名?first-app(x?build.properties 中ؓ目指定的名U?的子目录。大多数 servlet 引擎都允许将q个目录整个地复制到 servlet 引擎?webapps/ 目录。例如,我用的?TomcatQ于是我构本创建的整个 first-shale 目录复制?/usr/local/java/tomcat/webapps?br /> 

  构徏 WAR 文g

  如果使用?servlet 引擎要求提供 WAR 文gQ那么可以用相同的 Shale starter 应用E序的构建文Ӟ只需略微修改一下。由于还没有?Shale 应用E序~写M Java 文gQ当您请求一?WAR 文gӞ构徏脚本出现错??build.xml 中有查找文g?JavaScript 命oQ但是没有找CQ何文?。ؓ了修复这个问题,打开 build.xml 文gQ找C “javadoc?开头且如下所C的代码:

<!-- ===================== Generate Documentation ======================== -->
  <target         name="javadocs" depends="compile"
           description="Create JavaDocs">

    <mkdir         dir="${build.docs.dir}"/>

    <javadoc
            sourcepath="${src.java.dir}"
               destdir="${build.docs.dir}"
                author="false"
               private="true"
               version="true"
                source="${project.source}"
          packagenames="${project.package}.*"
           windowtitle="${project.name} (Version ${project.version})"
              doctitle="${project.name} (Version ${project.version})"
                bottom="${project.copyright}">
      <classpath refid="compile.classpath"/>
    </javadoc>

    <copy        todir="${build.docs.dir}">
      <fileset     dir="${src.java.dir}"
              includes="**/*.gif"/>
    </copy>

  </target>

  现在Q注释掉 javadoc dQ如下所C?

  <!-- ===================== Generate Documentation ======================== -->
  <target         name="javadocs" depends="compile"
           description="Create JavaDocs">

    <mkdir         dir="${build.docs.dir}"/>
<
    <javadoc
            sourcepath="${src.java.dir}"
               destdir="${build.docs.dir}"
                author="false"
               private="true"
               version="true"
                source="${project.source}"
          packagenames="${project.package}.*"
           windowtitle="${project.name} (Version ${project.version})"
              doctitle="${project.name} (Version ${project.version})"
                bottom="${project.copyright}">
      <classpath refid="compile.classpath"/>
    </javadoc>
-->
    <copy        todir="${build.docs.dir}">
      <fileset     dir="${src.java.dir}"
              includes="**/*.gif"/>
    </copy>

  </target>

  一旦开始ؓ Shale 应用E序开?Java 代码Q便不必q样做。不q对于现在,q样做可以解决上q问题。保存修改后?build.xml q运?ant dist。Ant ~译和装?starter 应用E序Qƈ?dist/ 目录中创Z个新?WAR 文g。例如,我运?ant dist 后得C?dist/first-shale-0.1.war 文g。现在可以将q个 WAR 文g复制?servlet 引擎?webapps/ 目录?/p>

  试安装情况

  如果完成了以上步骤,不管选择的安装\径是什么,都应该可以启?servlet 引擎q过地址 http://your.host.name/first-shale 讉K Shale 应用E序。例如,如果在本地机器上q行 TomcatQ那么最l可以访问的地址?http://localhost:8080/first-shale。如果一切正常,那么应该可以看到如图 2 所C的单页?

点击攑֤此图? src=

  ?2. Shale starter 应用E序证明一切没问题

  看v来似乎做了这么多工作却所得甚,但是要考虑刎ͼ通过打开q编辑一个简单的 build.properties 文gQ可以避免大量繁杂的复制和配|工作。您发玎ͼ从空白的 Shale starter 应用E序开始L开发新?Shale 应用E序最Ҏ的方式。实际上Q当在下一文章中开始开?Shale 应用E序的时候,用空白的 starter 应用E序作ؓ开始的基础?/p>

  Shale 用例

  关于 Shale 的下载和安装׃l到q里Q不q我们还是再q儿时间从 Shale M载站点下?Shale 的用?WAR 应用E序。找C个文件名形如 shale-usecases-20060204.war 的文件。下载该文gQƈ它攑օ servlet 引擎?webapps/ 目录Q然后进入到q个 WAR。在我的pȝ上,讉K http://localhost:8080/shale-usecases-20060204/ q得到如?3 所C的屏幕:

  ?3. Shale 用例应用E序

  您应该花些时间来看看q个用例应用E序。它有关?Shale ?Validator 和远E报告等Ҏ的很好的演C,q有一个简单的 Ajax 应用E序。通过览q些用例Q您可以了解到即使是单的 Shale 应用E序也可以做许多事情?/p>

  不过q里要提一个忠?有些用例仍在开发中Q取决于您何时下载每晚构建,可能发现有些用例不能正常工作。不qL可以晚些时候再下蝲q些用例应用E序Q看看有些问题是否已l被修复。虽然存在这些小问题Q但是用例应用程序仍然是取得?Shale 的基本印象的一U好途径?/p>

       深入研究 ShaleQ?/strong>

  大多?Web 开发h员向来只是用已有的框架(例如 Shale、Struts ?Spring)来开发他们的 Web 应用E序Q而没有做别的事情。当然这没有什么错Q但是如果想理解一U框架以及它所涉及的技术,那么只能Ҏ架本w做深入的研I?/p>

  对于 Shale(当然也包?Struts)Q通过查看框架的内部,您可以学到大量关?servlet ?Web 开发的知识。如果想在自q目中用一?Shale 依赖,q样做还可以获得难以|信的帮助。如果您寚w过 Java 应用E序q行日志理感兴,那么通过 Shale 来熟?Apache Logging 目比阅MQ何文章都要有效得多。对?Jakarta Commons BeanUtils、Chain ?Digester 目也是一栗这些都是很好的工具Q对于开发h员很有用Q所以花几个星期或几个月的时间探索一?Shale 对于q些领域是一个很好的学习l历?/p>

  ׃本文是对 Shale q行深入探讨的系列中的第一期,因此如果我不对几个对?Shale 目入门来说臛_重要的方面进行讨论的话,是不负责Q了?/p>

  亲密接触源代?/strong>

  不幸的是Q关?Shale 中涉及的开发过E的文档q不多,所以如果您想直接?Shale 源代码的话,需要用点儿技巧。一般来_我这里给出的关于下蝲 Shale q将它作为框架用的说明也适用于下?Shale 的源代码。每晚构建包?Shale 的所有源代码Qƈ且代码的每个目录中都有一?build.xml 文g?/p>

  需要将下蝲?Shale 的根目录下的 build.properties.sample 文g复制C个名?build.properties 的文件中(L原始文g名尾部的 ?sample?。清?2 展示了这个文件的一个示例,Zzv见,q里省略了其中一些注?

  清单 2. CZ Shale 构徏文g

# This file contains example property settings that you would use to customize
# your build environment to build the Struts Shale Library from
# source code.  To use this file, make a copy of it in "build.properties" and
# customize the values as required.

# Root directory into which you have unpacked the Shale Framework release.
root.dir=${basedir}

# Fully qualified pathname of the directory into which you have unpacked
# a binary distribution of the JavaServer Faces Reference Implementation
jsfri.dir=/usr/local/jsf-1_1_01

findbugs.outputFile=${root.dir}/find-bugs.html
lib.dir=${root.dir}/lib
jsf.home = ${lib.dir}/myfaces
jsf-api.jar = ${jsf.home}/myfaces-api.jar
jsf-impl.jar = ${jsf.home}/myfaces-impl.jar

# The absolute or relative pathname of the Apache Struts
# distribution
struts.home = /usr/local/jakarta-struts

spring.home=${lib.dir}/springframework
findbugs.home = /usr/local/findbugs-0.8.6

  Z与您的系l相匚wQ需要更改这个构建文件中大部分的路径。默认情况下Q?{basedir} 指向q行 Ant 时所在的目录Q因此如果是从下载的 Shale 的根目录下运?AntQ那么就刚好不用改\径了。但是对于其他\径,应该改ؓ适当的与pȝ相匹配的路径。例如,如果您的 JSF 参考实现在 c:/java/jsf-1_1_02 中,那么使用 jsfri.dir 目录所在的路径。大多数默认路径都适合于?MyFaces(请参?“MyFaces q是 JavaServer Faces?Q但是当然也可以使用 Sun ?JSF 实现Qƈ对这些\径作相应的更攏V另外还需要设|?Struts、Spring(q是可选的Q对于核?Shale 框架来说不必??FindBugs 目的\径?/p>

  Ant d

  讄好这些文件的路径后,可以在 Shale 的根目录中运?Ant。但是,首先应该q行 ant download-dependencies。您当然也已l注意到QShale 有很?依赖,而通过使用 Ant 自动下蝲q些依赖可以ؓ您节省很多时_也o您轻松不。Ant 脚本q负责设|\径,以便?Shale 与那些依赖项q接h。还应该q行 ant copy-jsf-ri 来处理一些特定于 JSF 的Q?具体l节不必兛_Q因?Ant 会ؓ您打点一??/p>

  在构Z Shale 发行版之前,应该q行 ant clean 删除之前已有的构建后的代码。虽然这意味着整个构徏旉会更长,但是可以保所有代码将一致地构徏。最后,q行 ant releaseQ以便从头开始构?Shale。当q个 Ant 脚本q行完成?q要׃点儿旉)Q就可以得到一个完整的、从源代码构建的 Shale 发行版?/p>

  关于邮g列表的只a片语

  开发源码项目几乎完全是通过电子邮g(再加?Apache bug 跟踪数据库,?参考资?节中有q方面的内容)来运作的。Shale 在这斚w也是一LQ不q它仍然使用 Struts 的邮件列表。如果在使用 Shale 时有什么疑问,可以发送电子邮件到 user@struts.apache.org。但是当您开始开发真正的 Shale 内部lgӞ应该电子邮件发送到 dev@struts.apache.org。不将电子邮g发送到哪里Q都应该?“[shale]?开_q样别h一下子明白您是要问关?Shale 的问题,而不是关?Struts 的问题。预期在几个月后Q当 Shale 开始成为独立的目Ӟ它也会有它自q邮g列表?/p>

  q里E微提醒一下,其是在发送电子邮件到开发列表的时?做好自己的工作,问题要有的放矢。那些飘忽不定、模׃可或~Z思想的邮件很可能不会收到回复。如果您到处发?“我惛_?ShaleQ请l我发送一些例子应用程序?之类的邮Ӟ甚至q可能得到粗鲁的回答。虽然这U提醒看上去有些傻,但事实就是这栗开发列表中L充斥着q一cȝ问题Q这些问题都是不受欢q?的。通常Q花点儿旉认真地斟酌您的问题,解释一下您使用的^台和软g的版本,q说明您已经试过了一些常用的步骤。这样一来,您的h才会得到重q受到欢q,也就更容易得到答案。开发h员的列表q不是o人生畏的Q但最Lq样做显得您重别h?/p>

  l束?/strong>

  q个关于 Shale 的系列中的第一期文章说明,Shale q不适合每一个h。Shale 没有提供一个打包好的、有~制好的文档q经q良好测试的产品Q也没有附带自动安装E序和优雅的理界面Q这些都是很?Web 开发h员期?Tapestry 时代能提供的东西。虽然在以后版本的框架中会体现这些东?除了完全打包)Q但目前 Shale(?2006 q初?仍在开发过E中Qƈ?Shale 站点也基本上它UCؓ处于 “alpha?状态的目。Shale 中用的很多lg是稳定和成熟的,?Shale 本n仍然很年轅R如果您不能接受一些麻烦和困惑Q那么可能会惌一q左叛_开始用它?/p>

  另一斚wQ如果您是一名对 Web 开发的前沿技术感兴趣?Java 开发h员,那么真应该看?Shale 目。虽然安?Shale q之工作要p更多的精力,但是它完全有条g成ؓ特别行?Web 开发框架。Shale l承?StrutsQ同时也提供了一些全新的东西Q这本n值得作一番调查。对于有兴趣成ؓ开放源码项目中的一员的开发h员,Shale 也是值得投入_֊的一个项目?/p>归于此类Q因为shale与jsf有千丝万~的联系

KingWell 2006-05-28 20:54 发表评论
]]>
Web应用E序中的可重用?/title><link>http://www.tkk7.com/kingwell/articles/45457.html</link><dc:creator>KingWell</dc:creator><author>KingWell</author><pubDate>Wed, 10 May 2006 06:53:00 GMT</pubDate><guid>http://www.tkk7.com/kingwell/articles/45457.html</guid><wfw:comment>http://www.tkk7.com/kingwell/comments/45457.html</wfw:comment><comments>http://www.tkk7.com/kingwell/articles/45457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/kingwell/comments/commentRss/45457.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/kingwell/services/trackbacks/45457.html</trackback:ping><description><![CDATA[ <span id="ggamayy" class="italicbodycopy">作者:Andrei Cioroianu<br />转自QOracle Technology Network <a >http://www.oracle.com/technology/global/cn/pub/articles/andrei_reuse.html</a><br /><br /></span> <p> <span id="gimyaqg" class="boldbodycopy">了解如何利用 JSP 标记文g、JSF ?Oracle ADF Faces 重用 Web 内容?Java 代码?/span> </p> <p> </p> <table cellspacing="0" cellpadding="1" width="42%" bgcolor="#cccccc" border="0"> <tbody> <tr> <td> <table cellspacing="0" cellpadding="2" width="100%" bgcolor="#ffffff" border="0"> <tbody> <tr> <td> <span id="gkwgkak" class="boldbodycopy">本文相关下蝲Q?/span> <br /> <img height="5" src="http://oracleimg.com/admin/images/ocom/bullet_5x5.gif" width="5" align="bottom" border="0" /> <a class="bodylink" >CZ代码</a> <br /> <img height="5" src="http://oracleimg.com/admin/images/ocom/bullet_5x5.gif" width="5" align="bottom" border="0" /> <a class="bodylink" >Oracle JDeveloper 10<em>g</em> (10.1.3)</a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <p> <span id="imkgsgg" class="legalese">2005 q?10 月发?/span> </p> <p> <span id="oyuoaqe" class="bodycopy">代码重用是提高开发h员生产效率和应用E序可维护性的一U非常好的方式。您应当LL设计良好的框架和可自定义的组Ӟ而不是从头重来。应用程序特有的代码也可以在模块甚至相关目间重用。后一U可重用性可使您快速修改,整体利用新特性,q减测试和调试的时间?/span> </p> <p> </p> <span id="ukgkwmc" class="bodycopy">虽然q些听v来像是针对程序员的不错徏议,?Web 开发h员也应当注意q些事情。许?Web 开发h员已l在使用诸如 Java Server Faces (JSF)、Oracle ADF Faces ?Apache MyFaces 之类的框Ӟq些框架提供了许多内|组件ƈ支持创徏其他可重用组件。然而,很多时候是许?HTML ?JSP 标记从一?Web 面复制_脓到其他页面中Q这意味着?Web 内容改变时将不得不修改这些页面中的重复标记。此外,如果没有更新某些面Q那么应用程序的外观会不一致。如果跨面重用 UI lg׃会发生这U情况了Q这是因为发生变化时只需在一个地方进行编辑就可以了?/span> <p> </p> <span id="ecicwme" class="bodycopy">在本文中Q我提供一些在Z JSF ?ADF Faces ?Web 应用E序中重?UI lg的最佛_c您了解到如何创徏定义 Web 面布局的模板,以及如何重用表单、菜单和按钮栏。您q将了解到如何{换现有的 JSP 面以它们更易于维护,以及如何由 JSF ?Oracle ADF Faces 提供的组件与 JSTL 和现?JSP Ҏ(例如标记文gQ一起用?/span> <p> </p> <span id="eysuowu" class="parahead1">Java Web 可重用特?/span> <p> </p> <span id="wgkeoou" class="bodycopy">自从W一个版本vQJSP 已l提供了一些鼓励可重用的基本机Ӟ例如 JavaBeans 支持、基?Servlets API RequestDispatcher ?<tt><%@include%></tt> 指o?<jsp:include> 标记。JSTL 增加?<c:import> 标记Q它使您能够包含某个资源的内容,该资源可以位于同一个应用程序、服务器中,甚至也可以在q程服务器上。Struts Tiles 围绕着q种内容包含Ҏ构Z一个完整的框架。JSF 也支持这一Ҏ,允许您构Z?<tt><f:subview></tt> 标记的子表单。JSP 2.0 增加了一个称为“隐式包含”的新特性。这些特性?<tt><include-prelude></tt> ?<tt><include-coda></tt> ?web.xml 文g中声明。正如您所能看到的Q虽焉?片断包含U类各异Q但每一U都有其自己的用途和上下文?</span> <p> </p> <span id="iuoqmsa" class="bodycopy">对自定义标记的支持从 JSP 1.1 有了,它ؓ构徏标记库提供了一?API。JSP 1.2 对该 API q行了增强,但很多h认ؓ它太复杂了。因此,JSP 2.0 定义了一个具有相同功能的全新 API。这个ؓ标记库提供的?API UCؓ单标?APIQ旧 API 现在UCؓ标准标记 API。许?Web 框架Q如 Struts、JSF ?JSTLQ仍使用标准标记 APIQ以便可以与 JSP 1.2 以及 JSP 2.0 一起用。简单标?API 是另一U?JSP 2.0 Ҏ??标记文g ?的基Q该Ҏ您能够?JSP 语法构徏标记库。除了简单标记和标记文g之外QJSP 2.0 规范q定义了 EL 函数Q后者您能够?EL 语法?JSP 面中调用静?Java Ҏ?/span> <p> </p> <span id="seqsomm" class="bodycopy">JSF 标准组件定义ؓ它的可重用单元。这些组件比自定义标记更强大Q但也更难设计和实施。因为有几个公司和开放源代码机构正在制作可供使用?JSF lg库,所以您可能不需要构q JSF lg。本文的CZ使用?Oracle ADF FacesQ它是基?JSF 标准的最先进的框架?/span> <p> </p> <span id="qauqcss" class="bodycopy"> <strong>创徏面模板?/strong>典型 Web 应用E序的所有页面共享一个公共布局Q该布局可以定义在一个地方,?JSP 标记文g中。该模板可以生成标题和正文标记、应用程序的菜单以及在所有页面中出现的其他部分。此外,它可以包含用于加载资源绑定、设|?JSP 变量{的讄标记。在应用E序的每?Web 面中重复该标记是没有意义的。在q一部分中,您将了解如何使用 Oracle JDeveloper 10<em>g</em> (10.1.3)Q撰写此文时为早期试用版Q基?JSF ?Oracle ADF Faces 构徏自定义模ѝ?</span> <p> </p> <span id="wqugiai" class="bodycopy">JDeveloper 提供了一个创?JSF 面模板的向对{从 File 菜单中选择 New ,打开 New Gallery H口。然后,转至 Web Tier 中的 JSF cdQ在右侧面板中选择 JSF JSP Template q单?OKQ?/span> <p> </p> <center> <img alt="?1" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f1.jpg" /> </center> <p> </p> <span id="coicccs" class="bodycopy">单击 Next 跌 Welcome 面Q然后选择您用的 J2EE 版本Qƈ再次单击 NextQ?/span> <p> </p> <center> <img alt="?2" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f2.jpg" /> </center> <p> </p> <span id="yueauuk" class="bodycopy">为模板提供一个文件名Q?/span> <p> </p> <center> <img alt="?3" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f3.jpg" /> </center> <p> </p> <span id="wiugkaq" class="bodycopy">选择lgl定样式Q?/span> <p> </p> <center> <img alt="?4" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f4.jpg" /> </center> <p> </p> <span id="suikoem" class="bodycopy">指定是否要用错误页面:</span> <p> </p> <center> <img alt="?5" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f5.jpg" /> </center> <p> </p> <span id="qamqusi" class="bodycopy">选择要用的标记库:</span> <p> </p> <center> <img alt="?6" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f6.jpg" /> </center> <p> </p> <span id="wykoqqo" class="bodycopy">提供面标题和其他页面属性:</span> <p> </p> <center> <img alt="?7" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f7.jpg" /> </center> <p> </p> <span id="eyiuyoe" class="bodycopy">单击 Finish。JDeveloper 创模板q在可视化编辑器中将其打开。您可以使用 Component Palette ?JSF ?Oracle ADF Faces lgd到该模板中。然后,您可以在 New Gallery H口中从 Template 中选择 JSF JSPQ基于您刚创建的模板创徏 JSF 面。这是从模板构徏面的一U非常简单的Ҏ。另一U方法是该q?JSF 标记Ud一个可重用的标记文件中。以下段落用了W二U方法?</span> <p> </p> <span id="gcwowas" class="bodycopy"> <strong>创徏标记文g?/strong>?File 菜单中选择 New ,打开 New Gallery H口。然后,转至 Web Tier 中的 JSP cdQ在右侧面板中选择 JSP Tag File q单?OKQ?</span> <p> </p> <center> <img alt="?8" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f8.jpg" /> </center> <p> </p> <span id="woakees" class="bodycopy">JDeveloper 打开一个创?JSP 标记文g的向导窗口。单?Next 跌 Welcome 面Q在 File Name 域中输入 pageTemplate.tag q单?NextQ?/span> <p> </p> <center> <img alt="?9" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f9.jpg" /> </center> <p> </p> <span id="yceiccs" class="bodycopy">现在您就可以定义模板标记的属性了。假定您正在构徏一个基?Web 的向|您希望每个页面都有一个步?ID 和一个标题。标记文仉要该信息来ؓ每个面自定义模板标记。单?Add 按钮Q输?step 属性名Qƈ?Required 设ؓ true。对另一个名UCؓ title 的属性执行同L操作Q?/span> <p> </p> <center> <img alt="?10" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f10.jpg" /> </center> <p> </p> <span id="ocmquks" class="bodycopy">单击 Next ?Finish。JDeveloper 在 WEB-INF 目录?tags 子目录下创徏 pageTemplate.tag 文g。用 <%@attribute%> 指o定义q两个标记属性: </span> <pre><%@ attribute name="step" required="true" %> <%@ attribute name="title" required="true" %> </pre> <span id="ueykeou" class="bodycopy">在创建标记文件之后,JDeveloper 打开它进行编辑。以下段落介l了本文通篇用到的示例应用程序的模板代码?/span> <p> </p> <span id="isoigmm" class="bodycopy"> <strong>在标记文件中使用 JSF ?Oracle ADF Faces?/strong>无论您是否想在普通页面的标记文g内用这些框Ӟ您都必须?<tt><%@taglib%></tt> 指o来对其进行声明。在 Component Palette 中选择 JSPQ然后单?Taglib。您需要在一个对话框中输入要使用的标记库?URI 和前~Q?</span> <p> </p> <center> <img alt="?11" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f11.jpg" /> </center> <p> </p> <span id="wyamqgm" class="bodycopy">您还可以使用 Component Palette 来将M标记拖放?JSP 面上,如果它的 <tt><%@taglib%></tt> 指o不在面中,那么 JDeveloper 自动添加它。pageTemplate.tag CZ使用了四个标记库QJSTL Core、JSF Core、Oracle ADF Faces Core ?Oracle ADF Faces HTMLQ?/span> <pre><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <%@ taglib prefix="afh" uri="http://xmlns.oracle.com/adf/faces/html" %> </pre> <span id="ewskomu" class="bodycopy">在同时?JSF ?JSTL Ӟ或者在标记文g中?JSF 时有一仉帔R要的事情您必dl牢讎ͼJSF 框架不支持页面范_后者是 JSTL 标记的默?JSP 范围。因此,您应当显式指定与 JSTL、JSF ?Oracle ADF Faces 的标记结合用的 JSP 变量的请求范围。此外,标记文g的所有属性都可以通过保存在页面范围内?JSP 变量来访问。您必须复制h范围内的属性,以便它们可以?JSF ?Oracle ADF Faces 标记一起用:</span> <pre><c:set var="pageTitle" scope="request" value="${pageScope.title}"/> </pre> <span id="emquwec" class="bodycopy">您还可以属性的值存储在?JSF 理?Bean 内。假定您有一个名UCؓ WizardBean 的类Q该cd faces-config.xml 中被配置为受?BeanQ?/span> <pre><faces-config> ... <managed-bean> <managed-bean-name>wizard</managed-bean-name> <managed-bean-class>webreuse.WizardBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> ... </faces-config> </pre> <span id="gqmgeuc" class="bodycopy">CZ Bean 有一?currentStep 属性,您可以在该属性中存储 step 属性的倹{该操作可以利用 JSTL ?<tt><c:set></tt> 标记来完成,但您必须保?Bean 存在于会话范围中Q如 faces-config.xml 文g中所声明的那P。只有在 JSF EL 表达式中首次引用受管 Bean 实例ӞJSF 才会创徏该实例。如果在讉K受管 Bean ?JSF ?Oracle ADF Faces 标记之前执行 JSTL 标记Q那么,您应当?<tt><jsp:useBean></tt>以确保该 Bean 实例存在于会话范围中。如此,您就可以安全C?<tt><c:set></tt> 标记了:</span> <pre><jsp:useBean class="webreuse.WizardBean" id="wizard" scope="session"/> <c:set target="${wizard}" property="currentStep" value="${pageScope.step}"/> </pre> <span id="mmosmek" class="bodycopy">以上代码可以手动输入Q或者可以?JDeveloper ?Component Palette。选择 JSPQ然后单?UseBeanQ添?<tt><jsp:useBean></tt> 标记。JDeveloper 打开一个对话框Q您必须在其中提供该标记的属性: </span> <p> </p> <center> <img alt="?12" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f12.jpg" /> </center> <p> </p> <span id="weiegou" class="bodycopy">最后,您可以在 pageTemplate.tag 文g中添加模板代码:</span> <pre><f:view> <afh:html> <afh:head title="#{pageTitle}"/> <afh:body> <af:panelPage title="#{pageTitle}"> <jsp:doBody/> </af:panelPage> </afh:body> </afh:html> </f:view> </pre> <span id="oqamyem" class="bodycopy">所有的 JSF ?Oracle ADF Faces lg都必ȝ?<f:view> 内部?tt><afh:html></tt>?tt><afh:head></tt> ?<tt><afh:body></tt> lg生成具有相同名U的 HTML 标记?lt;af:panelPage> lg昄面标题。然后,<tt><jsp:doBody></tt> 调用您攑֜使用模板标记?JSP 面中的 <tt><tags:pageTemplate></tt> ?<tt></tags:pageTemplate></tt> 之间?JSP 内容。这U?JSP 面类gQ?/span> <pre><%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> <tags:pageTemplate step="..." title="..."> ... JSP content executed by doBody ... </tags:pageTemplate> </pre> <span id="uuaoqyg" class="bodycopy">当执行该面Ӟ标记文g生?<tt><html></tt>?tt><head></tt> ?<tt><body></tt> 标记以及面标题和其他标题标记。然后,模板标记文g调用包?<tt><tags:pageTemplate></tt> ?<tt></tags:pageTemplate></tt> 之间?JSP 内容。在此之后,标记文g可能会生成一个页脚,q用 <tt></body></tt> ?<tt></html></tt> 来完成页面。下一部分在Z Web 的向导的面中用模板标记?</span> <p> </p> <span id="oiwykmm" class="parahead1">重用表单、菜单和其他 UI lg</span> <p> </p> <span id="scegaqw" class="bodycopy">利用 JSF ?Oracle ADF Faces lg构徏?UI 面板可以使用 "subviews" ?JSP 标记文g在多个页面中重用。前一U解x案与旧的 JSP 1.2 版本兼容Q但标记文g更灵zR这一部分介l如何基?JSF ?Oracle ADF Faces 一?Web 表单分成多个面和标记文件。当用户W一ơ访问应用程序时Q他用包含后退和前q按钮的向导式界面来逐步览q些面。在此以后,他可能想更新最初提供的信息。在q种情况下,用户需要用基于菜单的界面直接讉K应用E序的页面?</span> <p> </p> <span id="gwicwks" class="bodycopy">可以在上q的两种情况下用同一U?Web 表单。此外,所有的表单可以l合在一个确认页面中Q该面可以让用户以只读模式查看信息。当用户必须修改其中一个表单时Q可以编辑单个文件。每一个修攚w显C在向导风格的界面(用于从用户那获取信息Q、确认页面(用于查看信息Q和Z菜单的界面(qL于更C息)中。如果不重用表单Q您必d三个不同的地方进行相同的修改?/span> <p> </p> <span id="umauoek" class="bodycopy"> <strong>开?Backing Bean?/strong>您在前一部分中已l发玎ͼCZ应用E序使用了一个名UCؓ WizardBean ?Backing Bean。pageTemplate.tag 文g讄?currentStep 属性,该属性保存用户在览器中看到的当前表单的步骤 ID。示例应用程序在认面Q第四步Q之前用了三个表单Q确认页面的 ID ?<tt>MAX_STEP</tt> 帔R来定义。将该常量公开为名?maxStep ?bean 属性,以便可以?Web 面中?JSF EL 来访问它Q?/span> <pre>package webreuse; public class WizardBean implements java.io.Serializable { public final static int MAX_STEP = 4; private int currentStep; private String connName, connType; private String userName, password, role; private String driver, hostName, sid; private int jdbcPort; public int getMaxStep() { return MAX_STEP; } public int getCurrentStep() { return currentStep; } public void setCurrentStep(int currentStep) { this.currentStep = currentStep; } ... } </pre> <span id="iscyaiy" class="bodycopy">?<tt>currentStep</tt> ?<tt>maxStep</tt> 之外QWizardBean c还有几个其他的属性可用于保存用户提供的向导参敎ͼ<tt>connName</tt>?tt>connType</tt>?tt>userName</tt>?tt>password</tt>?tt>role</tt>?tt>driver</tt>?tt>hostName</tt>?tt>sid</tt> ?<tt>jdbcPort</tt>。该CZ应用E序与用h据无养I但在实际情况中,向导用它来配置数据库连接。WizardBean q实施了几个在用户单d导的按钮时将执行 JSF 操作。这些方法稍后将在本部分中进行介l?/span> <p> </p> <span id="kaoyuca" class="bodycopy">要创建您自己?BeanQ您可以?File 菜单中选择 New 来打开 New Gallery H口。然后,转至 General 中的 Simple Files cdQ在右侧面板中选择 Java ClassQƈ单击 OKQ?/span> <p> </p> <center> <img alt="?13" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f13.jpg" /> </center> <p> </p> <span id="kcmosqi" class="bodycopy">提供cd和程序包名称。然后单?OKQ创c:</span> <p> </p> <center> <img alt="?14" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f14.jpg" /> </center> <p> </p> <span id="mmiogyo" class="bodycopy">在声明一个字D之后(例如 <tt>private int currentStep</tt>Q,右键单击其名Uƈ选择 Generate Accessors。单?OKQ生?get ?set ҎQ?/span> <p> </p> <center> <img alt="?15" src="http://www.oracle.com/technology/pub/images/andrei_reuse_f15.jpg" /> </center> <p> </p> <span id="aikgyoo" class="bodycopy"> <strong>创徏可重用表单?/strong>向导的主表单编写ؓ可重用标记文件。第一个表?(form1.tag) 包含一个文本域和一个下拉列表:</span> <pre><!-- form1.tag --> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <af:inputText id="connName" required="true" columns="40" label="Connection Name:" value="#{wizard.connName}" readOnly="#{wizard.currentStep == wizard.maxStep}"/> <af:selectOneChoice id="connType" required="true" label="Connection Type:" value="#{wizard.connType}" readOnly="#{wizard.currentStep == wizard.maxStep}"> <af:selectItem label="Oracle (JDBC)" value="Oracle_JDBC"/> </af:selectOneChoice> </pre> <span id="mcugqiy" class="bodycopy">W二个表?(form2.tag) 包含三个文本域:</span> <pre><!-- form2.tag --> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <af:inputText id="userName" required="true" columns="40" label="User Name:" value="#{wizard.userName}" readOnly="#{wizard.currentStep == wizard.maxStep}"/> <af:inputText id="password" required="true" columns="40" label="Password:" value="#{wizard.password}" secret="true" readOnly="#{wizard.currentStep == wizard.maxStep}"/> <af:inputText id="role" required="false" columns="40" label="Role:" value="#{wizard.role}" readOnly="#{wizard.currentStep == wizard.maxStep}"/> </pre> <span id="mmwikks" class="bodycopy">W三个表?(form3.tag) 与其他两个表单类|</span> <pre><!-- form3.tag --> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <af:selectOneChoice id="driver" required="true" label="Driver:" value="#{wizard.driver}" readOnly="#{wizard.currentStep == wizard.maxStep}"> <af:selectItem label="thin" value="thin"/> <af:selectItem label="oci8" value="oci8"/> </af:selectOneChoice> <af:inputText id="hostName" required="true" columns="40" label="Host Name:" value="#{wizard.hostName}" readOnly="#{wizard.currentStep == wizard.maxStep}"/> <af:inputText id="sid" required="true" columns="40" label="SID:" value="#{wizard.sid}" readOnly="#{wizard.currentStep == wizard.maxStep}"/> <af:inputText id="jdbcPort" required="true" columns="40" label="JDBC Port:" value="#{wizard.jdbcPort}" readOnly="#{wizard.currentStep == wizard.maxStep}"/> </pre> <span id="euqkmkc" class="bodycopy">正如您可能已l注意到的那P三个标记文g中没有一个包含了用于排列 Oracle ADF Faces lg的标记。不含Q何布局标记使得您可以独立地使用表单标记Q或在确认页面中l合它们。Oracle ADF Faces 提供了一个名UCؓ <af:panelForm> 的强大组Ӟ它将自动执行布局。除了主要的lg之外Q表单通常包含有其他的标记Q例?<tt><h:messages globalOnly="true"/></tt> ?<tt><af:objectLegend name="required"/></tt>。所有这些标记都可以集中在一个名?formTemplate.tag 的标记文件中Q?/span> <pre><!-- formTemplate.tag --> <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <h:panelGrid columns="1" border="0" cellspacing="5"> <h:messages globalOnly="true"/> <af:objectLegend name="required"/> <af:panelForm> <jsp:doBody/> </af:panelForm> </h:panelGrid> </pre> <span id="ckwausq" class="bodycopy">使用 pageTemplate.tag ?formTemplate.tag ?JSF 面类gQ?/span> <pre><%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> <tags:pageTemplate step="..." title="..."> <af:form id="..."> ... <tags:formTemplate> <tags:form123/> </tags:formTemplate> ... </af:form> </tags:pageTemplate> </pre> <span id="yakoaio" class="bodycopy">在前面的代码D中Q?tt><tags:form123/></tt> 代表向导的三个主表单中的L一个(&<tt>lt;tags:form1/></tt>?tt><tags:form2/></tt> ?<tt><tags:form3/></tt>Q。除了这些表单的lg之外Q?tt><af:form></tt> 可能包含其他?JSF ?Oracle ADF Faces lgQ例如按钮)。下一D介l了使用 <tt><tags:pageTemplate></tt>?tt><tags:formTemplate></tt>?tt><tags:form1></tt>?tt><tags:form2></tt> ?<tt><tags:form3></tt> 的应用程序页面。这些具体的例子充分说明了利用可重用标记文g构徏 JSF 用户界面的实际好处?</span> <p> </p> <span id="iaeqkay" class="bodycopy"> <strong>向导风格的界面?/strong>Z Web 的向导的面包含标Cؓ Back、Next ?Finish 的按钮。可以在一个名?stepButtons.tag 的标记文件中定义q些按钮Q?/span> <pre><!-- stepButtons.tag --> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <af:panelButtonBar> <af:singleStepButtonBar selectedStep="#{wizard.currentStep}" maxStep="#{wizard.maxStep}" previousAction="#{wizard.previousAction}" nextAction="#{wizard.nextAction}"/> <c:if test="${wizard.currentStep == wizard.maxStep}"> <af:commandButton text="Finish" action="#{wizard.finishAction}"/> </c:if> </af:panelButtonBar> </pre> <span id="cwikock" class="bodycopy">WizardBean cd含当用户单击按钮时将执行的操作方法:</span> <pre>package webreuse; public class WizardBean implements java.io.Serializable { ... public String previousAction() { if (currentStep <= 1) return null; else { currentStep--; return "step" + currentStep; } } public String nextAction() { if (currentStep >= getMaxStep()) return null; else { currentStep++; return "step" + currentStep; } } public String finishAction() { currentStep = 0; return "finished"; } ... } </pre> <span id="ckyskaa" class="bodycopy">操作Ҏq回的结果将?faces-config.xml 文g的导航规则中使用Q?/span> <pre><faces-config> ... <navigation-rule> <from-view-id>*</from-view-id> <navigation-case> <from-outcome>step1</from-outcome> <to-view-id>/step1.jsp</to-view-id> </navigation-case> </navigation-rule> ... <navigation-rule> <from-view-id>*</from-view-id> <navigation-case> <from-outcome>step4</from-outcome> <to-view-id>/confirm.jsp</to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>*</from-view-id> <navigation-case> <from-outcome>finished</from-outcome> <to-view-id>/index.jsp</to-view-id> </navigation-case> </navigation-rule> ... </faces-config> </pre> <span id="ouqkecu" class="bodycopy">除了所有可见的lg之外Q向导页面还包含一个与 WizardBean ?currentStep 属性绑定的隐藏字段。您已经看到?pageTemplate.tag 在每一ơ执行页面时讄该属性。然而,用户可能单击览器的后退按钮。作操作的结果,在浏览器中看到的当前步骤与 currentStep 属性的gW,因ؓ览器将从其~存中检索到面Q而不是请求执?JSF 面?/span> <p> </p> <span id="ikwgkis" class="bodycopy">如果每一ơ用户单L钮时 currentStep 值都与表单数据一h交,则不会导致Q何问题。hiddenData.tag 文g?<tt>currentStep</tt> 作ؓ一个隐藏字D包含在内。此外,如果 <tt>currentStep</tt> {于 <tt>maxStep</tt>Q这意味着标记在确认页面中使用Q,那么该标记文件将为所?Bean 属性生成隐藏字D:</span> <pre><!-- hiddenData.tag --> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %> <h:inputHidden id="currentStep" value="#{wizard.currentStep}"/> <c:if test="${wizard.currentStep == wizard.maxStep}"> <h:inputHidden id="h_connName" value="#{wizard.connName}"/> <h:inputHidden id="h_connType" value="#{wizard.connType}"/> <h:inputHidden id="h_userName" value="#{wizard.userName}"/> <h:inputHidden id="h_password" value="#{wizard.password}"/> <h:inputHidden id="h_role" value="#{wizard.role}"/> <h:inputHidden id="h_driver" value="#{wizard.driver}"/> <h:inputHidden id="h_hostName" value="#{wizard.hostName}"/> <h:inputHidden id="h_sid" value="#{wizard.sid}"/> <h:inputHidden id="h_jdbcPort" value="#{wizard.jdbcPort}"/> </c:if> </pre> <span id="akgkwmu" class="bodycopy">所有的向导部分都可以在 JSF 面中组装,?step1.jspQ?/span> <pre><!-- step1.jsp --> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> <tags:pageTemplate step="1" title="Create Database Connection - Step 1"> <af:form id="form1"> <tags:formTemplate> <tags:form1/> </tags:formTemplate> <tags:stepButtons/> <tags:hiddenData/> </af:form> </tags:pageTemplate> </pre> <span id="mugamcc" class="bodycopy">step2.jsp ?step3.jsp 面?step1.jsp 非常cM。作为练习,您可以尝试ؓq些面构徏一个模板,从而将q些面都减ؓ四行代码。confirm.jsp 面一hC所有三个表单,但组件在只读模式下工作,从而占用的屏幕I间更少q且无需用户交互Q?/span> <pre><!-- confirm.jsp --> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> <tags:pageTemplate step="4" title="Confirm Connection Parameters"> <af:form id="form4"> <tags:formTemplate> <tags:form1/> <tags:form2/> <tags:form3/> </tags:formTemplate> <tags:stepButtons/> <tags:hiddenData/> </af:form> </tags:pageTemplate> </pre> <span id="cugicmu" class="bodycopy"> <strong>Z菜单的界面?/strong>假定用户逐步览向导的页面,提供所有需要的信息。如果用户需要在以后修改某些地方Q那么他应当不需要再ơ浏览所有的向导面。相反,用户界面让用户直接转至必须修改信息的表单。menuTabs.tag 文g使用相同名称?Oracle ADF Faces lg来构单:</span> <pre><!-- menuTabs.tag --> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <af:menuTabs> <af:commandMenuItem text="Name and Type" action="tab1" selected="#{wizard.currentStep == 1}"/> <af:commandMenuItem text="Authentication" action="tab2" selected="#{wizard.currentStep == 2}"/> <af:commandMenuItem text="Connection" action="tab3" selected="#{wizard.currentStep == 3}"/> </af:menuTabs> </pre> <span id="kquyqge" class="bodycopy">菜单的导航规则在 faces-config.xml 中定义:</span> <pre><faces-config> ... <navigation-rule> <from-view-id>*</from-view-id> <navigation-case> <from-outcome>tab1</from-outcome> <to-view-id>/tab1.jsp</to-view-id> </navigation-case> </navigation-rule> ... <navigation-rule> <from-view-id>*</from-view-id> <navigation-case> <from-outcome>tab3</from-outcome> <to-view-id>/tab3.jsp</to-view-id> </navigation-case> </navigation-rule> ... </faces-config> </pre> <span id="ygceiyw" class="bodycopy">当用户单击菜单的标签Ӟ表单数据被提交l?Web 服务器,在该服务器上 JSF 框架更?Backing Bean。如果用h更新表单而不改变当前的标{,那么需要用提交按钮。submitButton.tag 文g提供了提交按钮:</span> <pre><!-- submitButton.tag --> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <af:commandButton id="command" text="Submit" action="submitAction"/> </pre> <span id="kqkwsqq" class="bodycopy">tab1.jsp、tab2.jsp ?tab3.jsp 文g把菜单附加到向导的表单上。下面是 tab1.jspQ?/span> <pre><!-- tab1.jsp --> <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> <tags:pageTemplate step="1" title="Edit Database Connection"> <af:form id="form1"> <tags:menuTabs/> <tags:formTemplate> <tags:form1/> </tags:formTemplate> <tags:submitButton/> <tags:hiddenData/> </af:form> </tags:pageTemplate> </pre> <span id="muoaeks" class="parahead1">使显C逻辑可重?/span> <p> <span id="qqcesii" class="bodycopy">如果您必M?JSF ?Oracle ADF Faces 从头开始构建新的页面,那么一切都没什么问题。但是,对于包含了以 Java 代码形式存在的显C逻辑的旧 JSP 面Q该如何处理呢?l护q些面困难重重Qƈ且,若不显CZ码从 JSP 面中分d来,则无法对其进行重用。此外,Java 代码?HTML 标记不应混合在同一个页面中Q因 Java 开发h员和 Web 设计人员无法L地展开q行工作?/span> </p> <p> </p> <span id="ouokucs" class="bodycopy">JSF ?Oracle ADF Faces lg解决了多数情况下的此U问题,因ؓ Web 面用这两个框架提供的标记来构徏Q同时将 Java 代码攑ֈ?Backing Bean 中。JSTL 和其他的标记库也非常有用Q但有时您必d能?Java 代码来动态生成内宏V?/span> <p> </p> <span id="cawkygg" class="bodycopy">一U好的解x案是使用 JSP 2.0 提供?Simple Tags API 来构建标记库。该 API 使您能够开发标记处理器c,但您必须l护一个单独的 XML 文gQ称为标记库描述W?(TLD)Q,该文件定义标记名U、它们的属性等。如果这听v来太复杂Q那么您可以单地?Java 代码Ud使用 JSP 语法的标记文件中Q让应用服务器生成标记处理器cd TLD 文g。让我们看一下名?oldCode.jsp ?JSP 面Q它混合?Java ?HTML。该面读取一个文本文Ӟ其\径将作ؓ一个请求参数提供)q显C文件的内容Q包括行P。当您构建演C应用程序ƈxCZ码时Q这非常有用?/span> <p> </p> <span id="ckmyukk" class="bodycopy">重要注意事项Q请勿在生环境中用本部分的示例(oldCode.jsp ?newCode.jspQ,因ؓ它们可能会泄漏应用程序的源代码?/span> <p> </p> <span id="yyuysqg" class="bodycopy">oldCode.jsp 面使用 java.io API 来读取文本文件。它在 JSP 面范围中ؓ每一行文本创Z个名?<tt>lineText</tt> ?<tt>lineNo</tt> 的变量。行号将?JSTL ?<tt><fmt:formatNumber></tt> 标记来进行格式化Q文本将通过 <tt><c:out></tt> 标记q行昄Q?/span> <pre><!-- oldCode.jsp --> <%@ page import="java.io.*" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <HTML> <HEAD> <TITLE>${param.path}</TITLE> </HEAD> <BODY> <c:if test="${empty param.path}"> <P>The <CODE>path</CODE> parameter wasn't specified. </c:if> <c:if test="${!empty param.path}"> <P><B><CODE>${param.path}</CODE></B> <% String path = application.getRealPath( request.getParameter("path")); BufferedReader in = new BufferedReader(new FileReader(path)); try { int lineNo = 0; String lineText; while ((lineText = in.readLine()) != null) { lineNo++; pageContext.setAttribute("lineText", lineText); pageContext.setAttribute("lineNo", new Integer(lineNo)); %> <fmt:formatNumber var="fmtLineNo" value="${lineNo}" minIntegerDigits="3"/> <PRE>${fmtLineNo} <c:out value="${lineText}"/></PRE> <% } } finally { in.close(); } %> </c:if> </BODY> </HTML> </pre> <span id="mugacyw" class="bodycopy">来自前一个页面示例的全部 Java 代码都可以移C个名?readTextFile.tag 的标记文件中。只需q行许修改Q您必须使用 <tt><%@tag%></tt> 指o?jspContext 隐式对象Q而不?<tt><%@page%></tt> ?pageContext。您q必M?JSP 指o来声明属性和变量Q?/span> <pre><!-- readTextFile.tag --> <%@ tag import="java.io.*" %> <%@ attribute name="path" required="true" %> <%@ variable name-given="lineText" scope="NESTED" %> <%@ variable name-given="lineNo" scope="NESTED" %> <% String path = application.getRealPath( (String) jspContext.getAttribute("path")); BufferedReader in = new BufferedReader(new FileReader(path)); try { int lineNo = 0; String lineText; while ((lineText = in.readLine()) != null) { lineNo++; jspContext.setAttribute("lineText", lineText); jspContext.setAttribute("lineNo", new Integer(lineNo)); %> <jsp:doBody/> <% } } finally { in.close(); } %> </pre> <span id="iikgkqq" class="bodycopy">您可以在M需要逐行处理文本文g?JSP 面中?readTextFile.tag 文g。每一个页面都可以Ҏ本行执行M需要的操作Q因标记文g使用?<tt><jsp:doBody/></tt>Q从而允?JSP 面处理当前行的代码放?<tt><tags:readTextFile></tt> ?<tt></tags:readTextFile></tt> 之间。newCode.jsp 面的功能与旧样式的CZ相同Q但它没有؜?Java ?HTMLQ?/span> <pre><!-- newCode.jsp --> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> <HTML> <HEAD> <TITLE>${param.path}</TITLE> </HEAD> <BODY> <c:if test="${empty param.path}"> <P>The <CODE>path</CODE> parameter wasn't specified. </c:if> <c:if test="${!empty param.path}"> <P><B><CODE>${param.path}</CODE></B> <tags:readTextFile path="${param.path}"> <fmt:formatNumber var="fmtLineNo" value="${lineNo}" minIntegerDigits="3"/> <PRE>${fmtLineNo} <c:out value="${lineText}"/></PRE> </tags:readTextFile> </c:if> </BODY> </HTML> </pre> <span id="sikoagy" class="bodycopy">正如您所见,修改旧的 JSP 面以便可以重用代码q不是很难。维护也变得更加Ҏ?/span> <p> <span id="gqcgqqo" class="parahead1">随意重用</span> </p> <p> </p> <span id="gamokck" class="bodycopy">重复的代码或内容是最令h头疼的事情。有时它可能是一U容易的解决ҎQ但修改应用E序变得更加困难Q这意味着从长q来看,您将不能适应新的用户需求或快速地修复问题。在理想情况下,应用E序不应包含相同代码的多个版本,Web 内容不应被复制和_脓?/span> <img src ="http://www.tkk7.com/kingwell/aggbug/45457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/kingwell/" target="_blank">KingWell</a> 2006-05-10 14:53 <a href="http://www.tkk7.com/kingwell/articles/45457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> վ֩ģ壺 <a href="http://szq18888.com" target="_blank">wwwѸƵ</a>| <a href="http://sx97zc.com" target="_blank">޳a޳av </a>| <a href="http://cqkalai.com" target="_blank">Ƭ߹ۿ</a>| <a href="http://928348.com" target="_blank">Ƶ</a>| <a href="http://jufandev.com" target="_blank">޾ƷþëƬ</a>| <a href="http://www-3499.com" target="_blank">һ˿wwwƵ߹ۿ</a>| <a href="http://6789311.com" target="_blank">ѻ߹ۿ</a>| <a href="http://yes5555.com" target="_blank">޳a߹ۿ</a>| <a href="http://bovch.com" target="_blank">Ļվ</a>| <a href="http://3344by.com" target="_blank">߲ŹƵ</a>| <a href="http://szwangzhongwang.com" target="_blank">޾ƷձƷ</a>| <a href="http://shiliuvip.com" target="_blank">ĻƬa</a>| <a href="http://czshenyue.com" target="_blank">þþ޹</a>| <a href="http://lyaa17.com" target="_blank">þŮվ</a>| <a href="http://yixinbanks.com" target="_blank">þþƷһԡ</a>| <a href="http://922eee.com" target="_blank">߹ۿƵԴ</a>| <a href="http://gnebs.com" target="_blank">91ۺ</a>| <a href="http://922eee.com" target="_blank">㽶Ƶ߹ۿѹ</a>| <a href="http://selaohu.com" target="_blank">AVһ</a>| <a href="http://www-33758.com" target="_blank">Ʒպһ</a>| <a href="http://czdlglass.com" target="_blank">ձĻ</a>| <a href="http://hbwhgd.com" target="_blank">˳ɵӰ߹ۿ</a>| <a href="http://lh726.com" target="_blank">Ʒҹѹۿ</a>| <a href="http://4eeyy.com" target="_blank">ڵɫƵѹۿɫ </a>| <a href="http://kt4444.com" target="_blank">ëƬպëƬ </a>| <a href="http://dajiaody.com" target="_blank">޹뾫ƷŮ˾þþò </a>| <a href="http://www52a.com" target="_blank">лиëƬѿ</a>| <a href="http://www132126.com" target="_blank">պŷAVҹҹ</a>| <a href="http://783944.com" target="_blank">AëƬר</a>| <a href="http://www-282555.com" target="_blank">йchina[ձ</a>| <a href="http://800141.com" target="_blank">һƵ</a>| <a href="http://apguangyu.com" target="_blank">ðѾƷƵ</a>| <a href="http://yulongfilm.com" target="_blank">޹Ʒþþ</a>| <a href="http://fenglufzjx.com" target="_blank">ĻmvƵ7</a>| <a href="http://lshwork.com" target="_blank">Ѿþþþþþ</a>| <a href="http://199044.com" target="_blank">ɫʮʮɫ</a>| <a href="http://dbyssw.com" target="_blank">Ƶѹۿ</a>| <a href="http://js-jiarui.com" target="_blank">aձѿ</a>| <a href="http://331927.com" target="_blank">tsվ</a>| <a href="http://612662.com" target="_blank">޾Ʒ鶼</a>| <a href="http://zz1220.com" target="_blank">պav</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>