﻿<?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-jeffy-随笔分类-Web Framwork</title><link>http://www.blogjava.net/jeffy/category/7977.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 08 Mar 2007 11:01:00 GMT</lastBuildDate><pubDate>Thu, 08 Mar 2007 11:01:00 GMT</pubDate><ttl>60</ttl><item><title>FreeMarker设计指南 (转载)</title><link>http://www.blogjava.net/jeffy/archive/2006/03/02/33260.html</link><dc:creator>Live-in Java</dc:creator><author>Live-in Java</author><pubDate>Thu, 02 Mar 2006 09:17:00 GMT</pubDate><guid>http://www.blogjava.net/jeffy/archive/2006/03/02/33260.html</guid><wfw:comment>http://www.blogjava.net/jeffy/comments/33260.html</wfw:comment><comments>http://www.blogjava.net/jeffy/archive/2006/03/02/33260.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jeffy/comments/commentRss/33260.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jeffy/services/trackbacks/33260.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1、快速入门 （1）模板 + 数据模型 = 输出 l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念 l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 他们是分工劳动的：设计者专注于表示——创建HTML文件、图片、W...&nbsp;&nbsp;<a href='http://www.blogjava.net/jeffy/archive/2006/03/02/33260.html'>阅读全文</a><img src ="http://www.blogjava.net/jeffy/aggbug/33260.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jeffy/" target="_blank">Live-in Java</a> 2006-03-02 17:17 <a href="http://www.blogjava.net/jeffy/archive/2006/03/02/33260.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>webwork 相关urls</title><link>http://www.blogjava.net/jeffy/archive/2006/03/02/33237.html</link><dc:creator>Live-in Java</dc:creator><author>Live-in Java</author><pubDate>Thu, 02 Mar 2006 08:21:00 GMT</pubDate><guid>http://www.blogjava.net/jeffy/archive/2006/03/02/33237.html</guid><wfw:comment>http://www.blogjava.net/jeffy/comments/33237.html</wfw:comment><comments>http://www.blogjava.net/jeffy/archive/2006/03/02/33237.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jeffy/comments/commentRss/33237.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jeffy/services/trackbacks/33237.html</trackback:ping><description><![CDATA[扬子江：<A href="http://blog.video.com.cn/andy/subject/177.shtml">http://blog.video.com.cn/andy/subject/177.shtml</A><img src ="http://www.blogjava.net/jeffy/aggbug/33237.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jeffy/" target="_blank">Live-in Java</a> 2006-03-02 16:21 <a href="http://www.blogjava.net/jeffy/archive/2006/03/02/33237.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork的interceptor机制 (转载)</title><link>http://www.blogjava.net/jeffy/archive/2006/03/02/33234.html</link><dc:creator>Live-in Java</dc:creator><author>Live-in Java</author><pubDate>Thu, 02 Mar 2006 08:02:00 GMT</pubDate><guid>http://www.blogjava.net/jeffy/archive/2006/03/02/33234.html</guid><wfw:comment>http://www.blogjava.net/jeffy/comments/33234.html</wfw:comment><comments>http://www.blogjava.net/jeffy/archive/2006/03/02/33234.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jeffy/comments/commentRss/33234.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jeffy/services/trackbacks/33234.html</trackback:ping><description><![CDATA[<FONT size=2>WebWork项目建立在XWork项目上。入口Servlet是WebWork项目中定义的ServletDispatcher，而Action在XWork项目中定义。 <BR>XWork Action接口的execute()方法没有参数，不像Struts Action那样接受request, response参数，所以XWork Action能够脱离Web环境被直接调用，便于单元测试。 <BR>这里引入了一个问题。没有了request参数，那么XWork Action如何获得request parameters作为输入数据？又通过什么桥梁（Struts用request.setAttribute）把结果数据传送到View层？ <BR>在Web Work中，只能通过Action本身的getter, setter属性来传送输入参数和输出结果。 <BR>比如，我们有这样一个实现了XWork Action接口的类，</FONT> <BR><BR>YourAction implements Action{ <BR>int productId = null; <BR>String productName = null; <BR>public void setProductId(int productId){this.productId = productId;} <BR>public String getProductName(){return productName;} <BR>public String execute(){ <BR>productName = findNameById(productId);<BR>return “success”; <BR>} <BR>}<BR><FONT size=2>这个类里面的productId将接受request输入参数，productName是输出到页面显示的结果。 <BR>比如，这样的请求，http://yourhost/yourapp/MyAction.action?productId=1 <BR>Web Work会把1填到YourAction的productId里面，然后执行execute()方法，JSP里的语句&lt;ww:property value=“productName”&gt;会把YourAction的productName显示在页面上。 <BR><BR>如果一个Web Framework采用了这种屏蔽Action的request, response参数的设计方式，一般也同时会采用这种Action和输入输出数据结合成一体的解决方式。类似的情形也存在于Tapestry和Maverick中，后面会讲到。 <BR><BR>当WebWork ServletDispatcher接收到HTTP Request的时候，首先把所有相关的信息（包括request, response, session, servlet config, servelt context, 所有request参数）等存放到AcationContext中，然后根据Interceptor配置信息，生成一个YourAction的动态代理类对象。实际上运行的正是这个代理对象，如同Servlet Filter的工作机制一般，所有注入的Interceptor方法会先于Actio方法运行。 <BR><BR>我们来看一下Action和Interceptor的地位：Action没有参数，无法获得ActionContext；而Interceptor接受的ActionInvoication参数拥有包括ActionContext在内的所有重要信息。 <BR>这种权力分配的不平等，注定了Action的作用非常有限，只限于调用商业逻辑，然后返回一个成功与否标志。所有与外部Web世界打交道、协调内部工作流程的重担，都责无旁贷地落在Interceptor的肩上。 <BR>我们可以设想一个极端的例子。我们声明一批不做任何事情的空Action，我们只是需要它们的空壳类名；我们制作一批对应的Interceptor，所有的转发控制、商业逻辑都在Interceptor上实现，然后把Interceptor都注入到对应的空Action。这在理论上是完全可行的。 <BR>在Web海洋的包围中，Action可少，Interceptor不可少。Action是一个孤岛,如果没有外来盟友Interceptor的协助，只能在自己的小范围内独立作战（比如Unit Test），而对整体大局的作战目标无法产生影响。 <BR>下面我们来看一下Action是如何在Interceptor的全程监管下工作的。 <BR>在WebWork中，我们需要如下配置XWork.xml。 <BR>&lt;xwork&gt; <BR><BR>&lt;!-- Include webwork defaults (from WebWork-2.1 JAR). --&gt; <BR>&lt;include file="webwork-default.xml" /&gt; <BR>&lt;!-- Configuration for the default package. --&gt; <BR>&lt;package name="default" extends="webwork-default"&gt; <BR>&lt;!-- Default interceptor stack. --&gt; <BR>&lt;default-interceptor-ref name=" defaultStack" /&gt; <BR>&lt;!-- Action: YourAction. --&gt; <BR>&lt;action name="youraction" class="yourapp.YourAction"&gt; <BR>&lt;result name="success" type="dispatcher"&gt; <BR>YourAction.jsp <BR>&lt;/result&gt; <BR>&lt;/action&gt; <BR>&lt;/package&gt; <BR>&lt;/xwork&gt; </FONT><BR>webwork-default.xml里面的相关定义如下： <BR>&lt;interceptors&gt; <BR>&lt;interceptor name="validation" class="com.opensymphony.xwork.validator.ValidationInterceptor"/&gt; <BR>&lt;interceptor name="static-params" class="com.opensymphony.xwork.interceptor. <BR>StaticParametersInterceptor"/&gt; <BR>&lt;interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor "/&gt; <BR>&lt;interceptor name="conversionError" class="com.opensymphony.webwork.interceptor. <BR>WebWorkConversionErrorInterceptor"/&gt; <BR>&lt;interceptor-stack name="<STRONG><FONT color=#ff1493>defaultStack</FONT></STRONG>"&gt; <BR>&nbsp; &lt;interceptor-ref name="static-params"/&gt; <BR>&nbsp; &lt;interceptor-ref name="params"/&gt; <BR>&nbsp; &lt;interceptor-ref name="conversionError"/&gt; <BR>&lt;/interceptor-stack&gt; <BR>&lt;/interceptors&gt; <BR><BR><FONT size=2>从上述的配置信息中可以看出，YourAction执行execute()方法的前后，会被 <BR>defaultStack所定义的三个Intercepter截获。这些Interceptor的任务之一就是把输入参数设置到Action的对应属性当中。 <BR>如果我们需要加入对YourAction的属性的验证功能，只要把上述定义中的validation Interceptor加入到defaultStack中就可以了。当然，实际工作还没有这么简单，一般来说，还要为每个进行属性验证的Action的都配置一份validation.xml。 <BR>XWork Interceptor能够在Package和Action级别上，进行截获处理。 <BR>Servlet Filter能够在URL Patten级别上，进行截获处理。虽然实际上，Servlet Filter截获的是Servlet，但某些情况下，可以达到和截获一批Action的同样效果。 <BR>比如，在Web Work中，我们可以为所有admin package的Action，加入一个Interceptor，当检查到当前Session的用户没有admin权限时，统一返回一个警告页面：您没有足够的权限执行这个操作。 <BR>我们看到也可以为所有URL Pattern为“admin/*.action”的URL定义一个Servlet Filter，当检查到当前Session的用户没有admin权限时，统一返回一个警告页面：您没有足够的权限执行这个操作。 <BR>WebWork的Interceptor配置是相当灵活的，相当于对Action实现了AOP。Interceptor相当于Aspect，基类AroundInterceptor的before(), after()方法相当于Advice。 <BR>另外，XWork也提供了从XML配置文件装配Component的机制，相当于实现了对于Component的IoC。</FONT>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG><FONT color=#ff1493>&nbsp;&nbsp;&nbsp; （申明：本文来源于网络，摘录于此，仅为日后方便查看）</FONT></STRONG><img src ="http://www.blogjava.net/jeffy/aggbug/33234.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jeffy/" target="_blank">Live-in Java</a> 2006-03-02 16:02 <a href="http://www.blogjava.net/jeffy/archive/2006/03/02/33234.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Webwork2 的Action Result Type 的定义 (转载)</title><link>http://www.blogjava.net/jeffy/archive/2006/03/02/33227.html</link><dc:creator>Live-in Java</dc:creator><author>Live-in Java</author><pubDate>Thu, 02 Mar 2006 07:45:00 GMT</pubDate><guid>http://www.blogjava.net/jeffy/archive/2006/03/02/33227.html</guid><wfw:comment>http://www.blogjava.net/jeffy/comments/33227.html</wfw:comment><comments>http://www.blogjava.net/jeffy/archive/2006/03/02/33227.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jeffy/comments/commentRss/33227.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jeffy/services/trackbacks/33227.html</trackback:ping><description><![CDATA[<FONT size=2>&nbsp;&nbsp;&nbsp; 和Webwork1.x不同，Webwork2的Action执行完后，其Result对应一个 Result Type，而这个Result Type完全可以根据具体应用或环境自己进行 定义，只需实现com.opensymphony.xwork.Result接口。Result Type使得Action的执行结果表现形式可以灵活多变！下面这会举例说明，这里先看看Webwork2提供的几种Result Type的定义，该定义在webwork-default.xml中，xwork.xml文件包含了该文件，自定义的Result Type可以直接写在 xwork.xml中：<BR>&nbsp; &lt;result-types&gt;<BR>&nbsp; &nbsp; &lt;result-type name="dispatcher" class="com.opensymphony.webwork.dispatcher.ServletDispatcherResult" default="true"/&gt;<BR>&nbsp; &nbsp; &lt;result-type name="redirect" class="com.opensymphony.webwork.dispatcher.ServletRedirectResult"/&gt;<BR>&nbsp; &nbsp; &lt;result-type name="velocity" class="com.opensymphony.webwork.dispatcher.VelocityResult"/&gt;<BR>&nbsp; &nbsp; &lt;result-type name="chain" class="com.opensymphony.xwork.ActionChainResult"/&gt;<BR>&nbsp; &nbsp; &lt;result-type name="xslt" class="com.opensymphony.webwork.views.xslt.XSLTResult"/&gt;<BR>&nbsp; &nbsp; &lt;result-type name="jasper" class="com.opensymphony.webwork.views.jasperreports.JasperReportsResult"/&gt;<BR>&nbsp; &nbsp; &lt;result-type name="freemarker" class="com.opensymphony.webwork.views.freemarker.FreemarkerResult"/&gt;<BR>&nbsp; &lt;/result-types&gt;<BR>&nbsp; 其大多都有location和parse两个参数，location指明action执行后接着去哪里，parse指明是否对location进行OGNL表达式解析。<BR>&nbsp; <BR>&nbsp; 1) dispatcher<BR>&nbsp; &nbsp; action执行完后，请求会导向对应的View，Webwork2幕后其实是用RequestDispatcher来处理的，所以原Request/Response对象会接着传递，原Request中的Atrributes不会丢失，这点与下面的redirect是不同的。<BR>&nbsp; <BR>&nbsp; 2) redirect<BR>&nbsp; &nbsp; 对上次的响应将重定向到指定的位置，redirect是重新产生一个新的Request，原来Request保存的东西将不再有效，比如不能通过requet.getAtrribute 取得原来set的对象，也不能取得action的实例，errors，field errors等，因为Action是建立在Single-thread model上的。<BR><BR>&nbsp; 3) chain<BR>&nbsp; &nbsp; action链，特殊的View调用方式，一个action执行完接着调用另一个action。有个必须的参数actionName，指明紧接着调用的另一action对象。如：<BR>&nbsp; &nbsp; &lt;result name="success" type="chain"&gt;<BR>&nbsp; &nbsp; &nbsp; &nbsp; &lt;param name="actionName"&gt;bar&lt;/param&gt;<BR>&nbsp; &nbsp; &nbsp; &nbsp; &lt;param name="namespace"&gt;/foo&lt;/param&gt;<BR>&nbsp; &nbsp; &lt;/result&gt;<BR>&nbsp; 执行后接着调用下面的action:<BR>&nbsp; &nbsp; &lt;action name="bar" class="myPackage.barAction"&gt;<BR>&nbsp; &nbsp; &nbsp; &nbsp; ...<BR>&nbsp; &nbsp; &lt;/action&gt;<BR><BR>&nbsp; 4) velocity<BR>&nbsp; 5) freemarker<BR>&nbsp; 6) jasperreports<BR>&nbsp; 7) xslt<BR>&nbsp; &nbsp; 以上都是用不同技术的产生不同的View。<BR><BR>&nbsp; 下面我举个自定义Result Type的示例，假如我有个Action testSendmail，根据处理结果将给指用户发送一份email。自定义一个Result Type，实现Result接口。<BR>&nbsp; &nbsp; <BR>&nbsp; &nbsp; com.mycompany.webwork.example.SendmailResult<BR>&nbsp; &nbsp; 有三个必须参数：from ,to, subject,一个可选参数 body。<BR>&nbsp; 在xwork.xml中定义如下：<BR>&nbsp; &lt;result-types&gt;<BR>&nbsp; &nbsp; &lt;result-type name="sendmail" class="com.mycompany.webwork.example.SendmailResult"/&gt;<BR>&nbsp; &lt;/result-types&gt;<BR>&nbsp; <BR>&nbsp; action定义：<BR>&nbsp; &lt;action name="testSendmail" class="com.mycompany.webwork.example.TestSendMailAction"&gt;<BR>&nbsp; &nbsp; &lt;result name="success" type="sendmail"&gt;<BR>&nbsp; &nbsp; &nbsp; &nbsp; &lt;param name="from"&gt;root@sina.com&lt;/param&gt;<BR>&nbsp; &nbsp; &nbsp; &nbsp; &lt;param name="to"&gt;user@sina.com&lt;/param&gt;<BR>&nbsp; &nbsp; &nbsp; &nbsp; &lt;param name="subject"&gt;hello,webwork!&lt;/param&gt;<BR>&nbsp; &nbsp; &lt;/result&gt;<BR>&nbsp; &nbsp; &lt;result name="error" type="dispatcher"&gt;<BR>&nbsp; &nbsp; &nbsp; &nbsp; &lt;param name="location"&gt;error.jsp&lt;/param&gt;<BR>&nbsp; &nbsp; &lt;/result&gt;<BR>&nbsp; &lt;/action&gt;<BR>&nbsp; <BR>&nbsp; SendmailResult.java<BR><BR>&nbsp; package com.opensymphony.webwork.example;<BR><BR>&nbsp; import com.opensymphony.xwork.ActionInvocation;<BR>&nbsp; import com.opensymphony.xwork.Result;<BR><BR>&nbsp; public class SendmailResult implements Result {<BR>&nbsp; &nbsp; private String to;<BR>&nbsp; &nbsp; private String from;<BR>&nbsp; &nbsp; private String subject;<BR>&nbsp; &nbsp; private String body;<BR><BR>&nbsp; &nbsp; public void execute(ActionInvocation invocation) throws Exception {<BR>&nbsp; &nbsp; //TODO 实现Email发送部分<BR>&nbsp; &nbsp; System.out.println("sending mail....");<BR>&nbsp; &nbsp; System.out.println(" &nbsp; To:" + to);<BR>&nbsp; &nbsp; System.out.println(" &nbsp; From:" + from);<BR>&nbsp; &nbsp; System.out.println("Subject:" + subject);<BR>&nbsp; &nbsp; }<BR><BR>&nbsp; &nbsp; public String getBody() {<BR>&nbsp; &nbsp; return body;<BR>&nbsp; &nbsp; }<BR><BR>&nbsp; &nbsp; public void setBody(String body) {<BR>&nbsp; &nbsp; this.body = body;<BR>&nbsp; &nbsp; }<BR><BR>&nbsp; &nbsp; public String getFrom() {<BR>&nbsp; &nbsp; return from;<BR>&nbsp; &nbsp; }<BR><BR>&nbsp; &nbsp; public void setFrom(String from) {<BR>&nbsp; &nbsp; this.from = from;<BR>&nbsp; &nbsp; }<BR><BR>&nbsp; &nbsp; public String getSubject() {<BR>&nbsp; &nbsp; return subject;<BR>&nbsp; &nbsp; }<BR><BR>&nbsp; &nbsp; public void setSubject(String subject) {<BR>&nbsp; &nbsp; this.subject = subject;<BR>&nbsp; &nbsp; }<BR><BR>&nbsp; &nbsp; public String getTo() {<BR>&nbsp; &nbsp; return to;<BR>&nbsp; &nbsp; }<BR><BR>&nbsp; &nbsp; public void setTo(String to) {<BR>&nbsp; &nbsp; this.to = to;<BR>&nbsp; &nbsp; }<BR>&nbsp; }<BR><BR>&nbsp; 写个简单的测试Action：<BR>&nbsp; package com.opensymphony.webwork.example;<BR>&nbsp; <BR>&nbsp; import com.opensymphony.xwork.ActionSupport;<BR><BR>&nbsp; public class TestSendMailAction extends ActionSupport {<BR>&nbsp; &nbsp; public String execute() throws Exception {<BR>&nbsp; &nbsp; &nbsp; return SUCCESS;<BR>&nbsp; &nbsp; }<BR>&nbsp; }<BR><BR>&nbsp; 测试jsp,把它放在webwork-example/下：<BR><BR>&nbsp; testsendmail.jsp<BR><BR>&nbsp; &lt;%@ taglib prefix="ww" uri="webwork" %&gt;<BR>&nbsp; &lt;html&gt;<BR>&nbsp; &lt;head&gt;&lt;title&gt;Test sendmail restul type&lt;/title&gt;&lt;/head&gt;<BR>&nbsp; &lt;body&gt;<BR>&nbsp; <BR>&nbsp; &lt;form action="testSendmail.action"&gt;<BR>&nbsp; &nbsp; &lt;input type="Submit" value="Submit"/&gt;<BR>&nbsp; &lt;/form&gt;<BR>&nbsp; &lt;/body&gt;<BR>&nbsp; &lt;/html&gt;</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG><FONT color=#ff1493>&nbsp;&nbsp;&nbsp; （申明：本文来源于网络，摘录于此，仅为日后方便查看）</FONT></STRONG><BR><img src ="http://www.blogjava.net/jeffy/aggbug/33227.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jeffy/" target="_blank">Live-in Java</a> 2006-03-02 15:45 <a href="http://www.blogjava.net/jeffy/archive/2006/03/02/33227.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tapestry和ognl</title><link>http://www.blogjava.net/jeffy/archive/2006/03/01/32990.html</link><dc:creator>Live-in Java</dc:creator><author>Live-in Java</author><pubDate>Wed, 01 Mar 2006 03:43:00 GMT</pubDate><guid>http://www.blogjava.net/jeffy/archive/2006/03/01/32990.html</guid><wfw:comment>http://www.blogjava.net/jeffy/comments/32990.html</wfw:comment><comments>http://www.blogjava.net/jeffy/archive/2006/03/01/32990.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/jeffy/comments/commentRss/32990.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jeffy/services/trackbacks/32990.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><FONT face="Times New Roman">OGNL(<SPAN lang=EN-US><FONT face="Times New Roman" size=2>Object Graph Navigation Language</FONT></SPAN>)Tapestry</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">OGNL</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">结合的很完美。</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">OGNL</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是一种</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Java</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表达式语言，它被用来读取和更新对象的属性。</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">OGNL</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">比建立在</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">JSP2.0</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">标签库之上的表达式语言更简单功能也更强大。</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">OGNL</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">不仅仅提供属性的访问，它包括了精确的表达式和方法的调用。也能访问类的静态域。也可以创建新的对象，包括</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">List</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">Map</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象。简单的</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">OGNL</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表达式是属性的名字。如：</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">foo</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，这就等同于调用了方法</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">getFoo()</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（或者是</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">setFoo()</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果表达式是用来更新属性的）。当属性的名字是连续的属性名时，导航功能就起作用了。如：</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">foo.bar.baz</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，它就等于</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">getFoo().getBar().getBaz() </FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。不过要注意的是</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">foo</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</SPAN><SPAN lang=EN-US><FONT face="Times New Roman">bar</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这些属性不能为空。</SPAN><SPAN lang=EN-US><FONT face="Times New Roman"><SPAN style="mso-tab-count: 1">&nbsp;</SPAN>OGNL</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">允许两个对象（如页和页所包含的组件）来共享信息。</SPAN></P><img src ="http://www.blogjava.net/jeffy/aggbug/32990.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jeffy/" target="_blank">Live-in Java</a> 2006-03-01 11:43 <a href="http://www.blogjava.net/jeffy/archive/2006/03/01/32990.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tapestry简介－ 转载 (转自java-cn)</title><link>http://www.blogjava.net/jeffy/archive/2006/02/27/32710.html</link><dc:creator>Live-in Java</dc:creator><author>Live-in Java</author><pubDate>Mon, 27 Feb 2006 09:46:00 GMT</pubDate><guid>http://www.blogjava.net/jeffy/archive/2006/02/27/32710.html</guid><wfw:comment>http://www.blogjava.net/jeffy/comments/32710.html</wfw:comment><comments>http://www.blogjava.net/jeffy/archive/2006/02/27/32710.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jeffy/comments/commentRss/32710.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jeffy/services/trackbacks/32710.html</trackback:ping><description><![CDATA[<STRONG><FONT style="BACKGROUND-COLOR: #ff1493">介绍Tapestry的相关中文网址：</FONT></STRONG><A href="http://www.netbei.com/Article/jsp/Tapestry/Index.html"><BR>http://www.netbei.com/Article/jsp/Tapestry/Index.html</A><BR><BR>Tapestry是一个开源的基于servlet的应用程序框架，它使用组件对象模型来创建动态的，交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java&nbsp;Web&nbsp;Component。Tapestry使得java代码与html完全分离，利用这个框架开发大型应用变得轻而易举。并且开发的应用很容易维护和升级。Tapestry支持本地化，其错误报告也很详细。Tapestry主要利用javabean和xml技术进行开发。&nbsp; <BR><BR>第一个应用程序&nbsp; <BR><BR>在介绍第一个应用之前，先介绍一下Tapestry的安装。从sourceforge下载其最新版，解压后，将lib目录下的jar文件放到CLASSPATH中，将其中的war文件放到tomcat的webapp目录下。然后就可以通过http://localhost:8080/tutorial访问其tutorial应用。&nbsp; <BR>在Tapestry中一个应用程序有以下几部分组成，我们以其自身带的HelloWorld程序为例介绍：&nbsp; <BR><BR>Servlet：&nbsp; <BR>这是一个应用的主体部分：servlet类，这个类必须是ApplicationServlet的子类，并且必须实现getApplicationSpecificationPath()方法。示例如下：&nbsp; <BR><BR><BR>import&nbsp;com.primix.tapestry.*;&nbsp; <BR>public&nbsp;class&nbsp;HelloWorldServlet&nbsp;extends&nbsp;ApplicationServlet&nbsp; <BR>{&nbsp; <BR>protected&nbsp;String&nbsp;getApplicationSpecificationPath()&nbsp; <BR>{&nbsp; <BR>return&nbsp;"/tutorial/hello/HelloWorld.application";&nbsp; <BR>}&nbsp; <BR>}&nbsp; <BR><BR><BR>/tutorial/hello/HelloWorld.application是一个应用的说明文件。&nbsp; <BR>Application&nbsp;Specification：&nbsp; <BR>其实就是描述这个应用的一个xml文件，在这个应用中有许多参数需要设置，engine-class将在下面介绍，page中的name属性指定html文件名，specification-path指定对这个页面的说明文件。在一个应用中可以有很多个page，但必须有一个page的name为"Home"，因为当访问你的应用时，首先显示的就是这个page。&nbsp; <BR><BR>&lt;?xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"?&gt;;&nbsp; <BR>&lt;!DOCTYPE&nbsp;application&nbsp;PUBLIC&nbsp;"-//Howard&nbsp;Ship//Tapestry&nbsp;Specification&nbsp;1.1//EN"&nbsp;"http://tapestry.sf.net/dtd/Tapestry_1_1.dtd"&gt;;&nbsp; <BR>&lt;application&nbsp;name="Hello&nbsp;World&nbsp;Tutorial"&nbsp;engine-class="com.primix.tapestry.engine.SimpleEngine"&gt;;&nbsp; <BR>&lt;page&nbsp;name="Home"&nbsp;specification-path="/tutorial/hello/Home.jwc"/&gt;;&nbsp; <BR>&lt;/application&gt;;&nbsp; <BR><BR><BR>Application&nbsp;Engine：&nbsp; <BR><BR>当客户连接到Tapestry应用时，Tapestry将会创建一个Engine对象（类似于session）。通常我们程序中的application&nbsp;engine&nbsp;一般是SimpleEngine类的一个实例，当然这个类的子类也可以。&nbsp; <BR><BR>Page&nbsp;Specification：&nbsp; <BR>跟应用说明相似，页说明也是一个xml描述文件：&nbsp; <BR><BR><BR>&lt;?xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"?&gt;;&nbsp; <BR>&lt;!DOCTYPE&nbsp;specification&nbsp;PUBLIC&nbsp;"-//Howard&nbsp;Ship//Tapestry&nbsp;Specification&nbsp;1.1//EN"&nbsp;"http://tapestry.sf.net/dtd/Tapestry_1_1.dtd"&gt;;&nbsp; <BR>&lt;specification&nbsp;class="com.primix.tapestry.BasePage"/&gt;;&nbsp; <BR><BR><BR>因为这个应用是静态的，所以使用com.primix.tapestry.BasePage即可，如果是动态的应用，则需在这个文件中定义一些component，当然使用BasePage为基类的派生类也可以。&nbsp; <BR>html页面：&nbsp; <BR>这个应用的html页面非常简单：&nbsp; <BR><BR><BR>&lt;html&gt;;&nbsp; <BR>&lt;head&gt;;&nbsp; <BR>&lt;title&gt;;Hello&nbsp;World&lt;/title&gt;;&nbsp; <BR>&lt;/head&gt;;&nbsp; <BR>&lt;body&gt;;&nbsp; <BR>&lt;b&gt;;HelloWorld&lt;/b&gt;;&nbsp; <BR>&lt;/body&gt;;&nbsp; <BR>&lt;/html&gt;;&nbsp; <BR><BR><BR>注意上面所讲到的各种文件都要放到放在WAR的WEB-INF/classes目录下。<BR>一个复杂的应用&nbsp; <BR><BR>在这个应用中我们以一个简单的学生管理系统为例介绍一下Tapestry的常用功能。我们要实现学生的增加和显示，因此我们需要两个html页面。至于StudentServlet类和Student.application我们就不描述了，在Student.application中定义了两个page：Home和EditStudent，具体看附件。学生数据存放在数据库中，我们用Student类表示数据中的一条记录，用StudentFactory类检索学生数据，这两个类用到了一个JDBC包装器，关于这个JDBC包装器可以见我的另外一篇文章&lt;&lt;对一个简单的&nbsp;JDBC&nbsp;包装器的扩展及应用&gt;;&gt;;。&nbsp; <BR>首先看一下Home.html&nbsp; <BR><BR><BR>&lt;html&gt;;&nbsp; <BR>&lt;head&gt;;&nbsp; <BR>&lt;title&gt;;学生管理&lt;/title&gt;;&nbsp; <BR>&lt;meta&nbsp;http-equiv="Content-Type"&nbsp;content="text/html;&nbsp;charset=gb2312"&gt;;&nbsp; <BR>&lt;/head&gt;;&nbsp; <BR>&lt;body&nbsp;bgcolor="#FFFFFF"&gt;;&nbsp; <BR>&lt;p&nbsp;align="center"&gt;;学生列表&lt;/p&gt;;&nbsp; <BR>&lt;table&nbsp;width="100%"&nbsp;border="1"&gt;;&nbsp; <BR>&lt;tr&gt;;&nbsp; <BR>&lt;td&nbsp;&gt;;学号&lt;/td&gt;;&nbsp; <BR>&lt;td&nbsp;&gt;;姓名&lt;/td&gt;;&nbsp; <BR>&lt;td&nbsp;&gt;;性别&lt;/td&gt;;&nbsp; <BR>&lt;td&nbsp;&gt;;班级&lt;/td&gt;;&nbsp; <BR>&lt;/tr&gt;;&nbsp; <BR>&lt;span&nbsp;jwcid="liststudent"&gt;;&nbsp; <BR>&lt;tr&gt;;&nbsp; <BR>&lt;td&gt;;&lt;span&nbsp;jwcid="id"&gt;;20012400&lt;/span&gt;;&lt;/td&gt;;&nbsp; <BR>&lt;td&gt;;&lt;span&nbsp;jwcid="sname"&gt;;宗锋&lt;/span&gt;;&lt;/td&gt;;&nbsp; <BR>&lt;td&gt;;&lt;span&nbsp;jwcid="gender"&gt;;男&lt;/span&gt;;&lt;/td&gt;;&nbsp; <BR>&lt;td&gt;;&lt;span&nbsp;jwcid="department"&gt;;计算机研一&lt;/span&gt;;&lt;/td&gt;;&nbsp; <BR>&lt;/tr&gt;;&nbsp; <BR>&lt;/span&gt;;&nbsp; <BR>&lt;tr&nbsp;jwcid="$remove$"&gt;;&nbsp; <BR>&lt;td&gt;;20011389&lt;/td&gt;;&nbsp; <BR>&lt;td&gt;;桑一珊&lt;/td&gt;;&nbsp; <BR>&lt;td&gt;;男&lt;/td&gt;;&nbsp; <BR>&lt;td&gt;;计算机研一&lt;/td&gt;;&nbsp; <BR>&lt;/tr&gt;;&nbsp; <BR>&lt;/table&gt;;&nbsp; <BR>&lt;a&nbsp;jwcid="add"&gt;;添加学生&lt;/a&gt;;&nbsp; <BR>&lt;/body&gt;;&nbsp; <BR>&lt;/html&gt;;&nbsp; <BR><BR>与前面的简单应用不同，我们在这个页面中定义了七个组件，下面看一下部分Home.jwc文件，我们将详细讲述一下怎样描述这些组件。&nbsp; <BR><BR><BR>&lt;specification&nbsp;class="test.ListStudent"&gt;;&nbsp; <BR>&lt;component&nbsp;id="liststudent"&nbsp;type="Foreach"&gt;;&nbsp; <BR>&lt;binding&nbsp;name="source"&nbsp;property-path="student"/&gt;;&nbsp; <BR>&lt;binding&nbsp;name="value"&nbsp;property-path="eachstudent"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR>&lt;component&nbsp;id="id"&nbsp;type="Insert"&gt;;&nbsp; <BR>&lt;binding&nbsp;name="value"&nbsp;property-path="eachstudent.id"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR>&lt;component&nbsp;id="add"&nbsp;type="Page"&gt;;&nbsp; <BR>&lt;static-binding&nbsp;name="page"&gt;;EditStudent&lt;/static-binding&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR>&lt;/specification&gt;;&nbsp; <BR><BR>在这里，我们的specification的class属性值不再是BasePage，而是其派生类ListStudent。对于每一个组件，id属性指定唯一的标识符，这个值与html文件中的jwcid值相对应，type&nbsp;指定组件名，binding指定组件怎得到数据，property-path是一系列属性的集合，这些属性一般定义在javabean中，例如上面的property-path="student"，则在相应的javabean类ListStudent中应该有个函数getStudent。liststudent是一个Foreach组件，这个组件其实是一个for循环，它从source中读入一个数组，将其一个一个的赋值给value参数指定的属性。id，name，gender，department四个是Insert组件，这个组件用来插入文本数据，参数value指定要插入的值，property-path指定怎样获取这些值，eachstudent.id相当于调用javabean的getEachstudent().getId()。add是一个Page组件，page属性指定页面名（定义在application文件中），static-binding表明要绑定的数据是不可修改的。$remove$组件没有在这个文件中描述，因为Tapestry运行时会自动删除这种组件。&nbsp; <BR>下面看一下ListStudent类：&nbsp; <BR><BR>package&nbsp;test;&nbsp; <BR>import&nbsp;com.primix.tapestry.*;&nbsp; <BR>import&nbsp;sun.jdbc.odbc.JdbcOdbcDriver&nbsp;;&nbsp; <BR><BR><BR>/**&nbsp; <BR>*&nbsp;返回每个学生的数据&nbsp; <BR>*&nbsp; <BR>*/&nbsp; <BR><BR>public&nbsp;class&nbsp;ListStudent&nbsp;extends&nbsp;BasePage&nbsp; <BR>{&nbsp; <BR>private&nbsp;Student&nbsp;eachstudent;&nbsp; <BR>private&nbsp;Student[]&nbsp;student;&nbsp; <BR>public&nbsp;void&nbsp;detach()&nbsp; <BR>{&nbsp; <BR>eachstudent=null;&nbsp; <BR>student=null;&nbsp; <BR>super.detach();&nbsp; <BR>}&nbsp; <BR><BR>public&nbsp;Student&nbsp;getEachstudent()&nbsp; <BR>{&nbsp; <BR>return&nbsp;eachstudent;&nbsp; <BR>}&nbsp; <BR>public&nbsp;void&nbsp;setEachstudent(Student&nbsp;value)&nbsp; <BR>{&nbsp; <BR>eachstudent&nbsp;=&nbsp;value;&nbsp; <BR>}&nbsp; <BR>public&nbsp;Student[]&nbsp;getStudent()&nbsp; <BR>{&nbsp; <BR>try{&nbsp; <BR>Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");&nbsp; <BR>student=StudentFactory.findAllStudents();&nbsp; <BR>}catch(Exception&nbsp;e){&nbsp; <BR>e.printStackTrace();&nbsp; <BR>}&nbsp; <BR>return&nbsp;student;&nbsp; <BR><BR>}&nbsp; <BR><BR>}&nbsp; <BR><BR><BR>这个类有四个函数，其中detach函数是将页面放入缓冲池时执行的操作，getStudent函数返回所有的学生记录，这是给jwc文件中liststudent组件的source参数赋值，getEachstudent给这个组件的value参数赋值，因为source是一个数组，每次循环需要从中取出一条记录赋值给eachstudent,所以还有一个函数为setEachstudent，你会注意到这个函数很简单，其实是Tapestry帮你做了大部分工作。&nbsp; <BR>至此，显示学生的部分已经完成，下面看一下EditStudent.html&nbsp; <BR><BR>&lt;html&gt;;&nbsp; <BR>&lt;head&gt;;&nbsp; <BR>&lt;title&gt;;增加学生&lt;/title&gt;;&nbsp; <BR>&lt;meta&nbsp;http-equiv="Content-Type"&nbsp;content="text/html;&nbsp;charset=gb2312"&gt;;&nbsp; <BR>&lt;/head&gt;;&nbsp; <BR>&lt;body&gt;;&nbsp; <BR>&lt;p&gt;;&lt;img&nbsp;src="student.gif"&nbsp;width="32"&nbsp;height="32"/&gt;;&nbsp;学生管理系统&lt;/p&gt;;&nbsp; <BR>&lt;form&nbsp;jwcid="form"&gt;;&nbsp; <BR>&lt;span&nbsp;jwcid="ifError"&gt;;&nbsp; <BR>&lt;font&nbsp;size=+2&nbsp;color=red&gt;;&lt;span&nbsp;jwcid="insertError"/&gt;;&lt;/font&gt;;&nbsp; <BR>&lt;/span&gt;;&nbsp; <BR>&lt;p&gt;;学号：&nbsp; <BR>&lt;input&nbsp;jwcid="id"/&gt;;&nbsp; <BR>&lt;/p&gt;;&nbsp; <BR>&lt;p&gt;;姓名：&nbsp; <BR>&lt;input&nbsp;jwcid="name"/&gt;;&nbsp; <BR>&lt;/p&gt;;&nbsp; <BR>&lt;span&nbsp;jwcid="gender"&gt;;&nbsp; <BR>&lt;p&gt;;性别：&nbsp; <BR>&lt;input&nbsp;jwcid="male"/&gt;;&nbsp; <BR>男&nbsp; <BR>&lt;input&nbsp;jwcid="female"/&gt;;&nbsp; <BR>女&nbsp; <BR>&lt;/p&gt;;&nbsp; <BR>&lt;/span&gt;;&nbsp; <BR>&lt;p&gt;;班级：&nbsp; <BR>&lt;input&nbsp;jwcid="department"/&gt;;&nbsp; <BR>&lt;/p&gt;;&nbsp; <BR>&lt;p&gt;;&nbsp; <BR>&lt;input&nbsp;type="submit"&nbsp;value="确定"&gt;;&nbsp; <BR>&lt;/p&gt;;&nbsp; <BR>&lt;/form&gt;;&nbsp; <BR>&lt;/body&gt;;&nbsp; <BR>&lt;/html&gt;;&nbsp; <BR><BR><BR>在这个文件中，用到了另外一些常用的组件，先看一下EditStudent.jwc中的这些组件的描述：&nbsp; <BR><BR><BR>&lt;specification&nbsp;class="test.EditStudent"&gt;;&nbsp; <BR>&lt;component&nbsp;id="form"&nbsp;type="Form"&gt;;&nbsp; <BR>&lt;binding&nbsp;name="listener"&nbsp;property-path="listeners.formSubmit"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR>&lt;component&nbsp;id="gender"&nbsp;type="RadioGroup"&gt;;&nbsp; <BR>&lt;binding&nbsp;name="selected"&nbsp;property-path="gender"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR>&lt;component&nbsp;id="ifError"&nbsp;type="Conditional"&gt;;&nbsp; <BR>&lt;binding&nbsp;name="condition"&nbsp;property-path="error"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR>&lt;component&nbsp;id="insertError"&nbsp;type="Insert"&gt;;&nbsp; <BR>&lt;binding&nbsp;name="value"&nbsp;property-path="error"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR>&lt;component&nbsp;id="id"&nbsp;type="TextField"&gt;;&nbsp; <BR>&lt;binding&nbsp;name="value"&nbsp;property-path="id"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR>&lt;component&nbsp;id="male"&nbsp;type="Radio"&gt;;&nbsp; <BR>&lt;field-binding&nbsp;name="value"&nbsp;field-name="test.EditStudent.MALE"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR>&lt;/specification&gt;;&nbsp; <BR><BR><BR>form是一个Form组件，它的参数listener指定submit这个form时有那个函数处理。ifError是一个Conditional组件，这个组件指定当condition满足时才会显示，在本例中，如果error不为空，则condition满足。在这个组件中，有嵌套了一个Insert类型的组件，用于将错误显示。这是Tapestry中经常用到的处理错误的方式。gender是一个RadioGroup组件，它绑定了javabean中的gender属性，selected参数指定那个radio被选中，在这个组件中，又嵌套了两个Radio组件，分别用来表示男，女。Radio的value参数指定当用户选定这个radio时，RadioGroup绑定的属性值将会等于field-name中指定的值（这个值必须是static的），在本例中，gender=test.EditStudent.MALE。id是一个TextField组件，其参数value绑定到javabean中的id属性。&nbsp; <BR>下面是相应的EditStudent类：&nbsp; <BR><BR>package&nbsp;test;&nbsp; <BR>import&nbsp;com.primix.tapestry.*;&nbsp; <BR><BR>public&nbsp;class&nbsp;EditStudent&nbsp;extends&nbsp;BasePage&nbsp; <BR>{&nbsp; <BR>public&nbsp;static&nbsp;final&nbsp;int&nbsp;MALE&nbsp;=&nbsp;1;&nbsp; <BR>public&nbsp;static&nbsp;final&nbsp;int&nbsp;FEMALE&nbsp;=&nbsp;2;&nbsp; <BR><BR>private&nbsp;int&nbsp;gender;&nbsp; <BR>private&nbsp;String&nbsp;error;&nbsp; <BR>private&nbsp;String&nbsp;id;&nbsp; <BR>private&nbsp;String&nbsp;sname;&nbsp; <BR>private&nbsp;String&nbsp;department;&nbsp; <BR><BR>public&nbsp;void&nbsp;detach()&nbsp; <BR>{&nbsp; <BR>error&nbsp;=&nbsp;null;&nbsp; <BR>id=null;&nbsp; <BR>sname=null;&nbsp; <BR>gender=0;&nbsp; <BR>department=null;&nbsp; <BR>super.detach();&nbsp; <BR>}&nbsp; <BR><BR>public&nbsp;int&nbsp;getGender()&nbsp; <BR>{&nbsp; <BR>return&nbsp;gender;&nbsp; <BR>}&nbsp; <BR>public&nbsp;String&nbsp;getId()&nbsp; <BR>{&nbsp; <BR>return&nbsp;id;&nbsp; <BR>}&nbsp; <BR>public&nbsp;String&nbsp;getSname()&nbsp; <BR>{&nbsp; <BR>return&nbsp;sname;&nbsp; <BR>}&nbsp; <BR>public&nbsp;String&nbsp;getDepartment()&nbsp; <BR>{&nbsp; <BR>return&nbsp;department;&nbsp; <BR>}&nbsp; <BR><BR><BR>public&nbsp;void&nbsp;setGender(int&nbsp;value)&nbsp; <BR>{&nbsp; <BR>gender&nbsp;=&nbsp;value;&nbsp; <BR>fireObservedChange("gender",&nbsp;value);&nbsp; <BR>}&nbsp; <BR>public&nbsp;void&nbsp;setId(String&nbsp;value)&nbsp; <BR>{&nbsp; <BR>id&nbsp;=&nbsp;value;&nbsp; <BR>fireObservedChange("id",&nbsp;value);&nbsp; <BR>}&nbsp; <BR>public&nbsp;String&nbsp;getError()&nbsp; <BR>{&nbsp; <BR>return&nbsp;error;&nbsp; <BR>}&nbsp; <BR>public&nbsp;void&nbsp;setSname(String&nbsp;value)&nbsp; <BR>{&nbsp; <BR>sname&nbsp;=&nbsp;value;&nbsp; <BR>fireObservedChange("sname",&nbsp;value);&nbsp; <BR>}&nbsp; <BR>public&nbsp;void&nbsp;setDepartment(String&nbsp;value)&nbsp; <BR>{&nbsp; <BR>department&nbsp;=&nbsp;value;&nbsp; <BR>fireObservedChange("department",&nbsp;value);&nbsp; <BR>}&nbsp; <BR>public&nbsp;void&nbsp;formSubmit(IRequestCycle&nbsp;cycle)&nbsp; <BR>{&nbsp; <BR>//判断用户是否添完了所有数据&nbsp; <BR>if&nbsp;(gender==&nbsp;0||id==null||id.equals("")||sname==null||sname.equals("")||&nbsp; <BR>department==null||department.equals(""))&nbsp; <BR>{&nbsp; <BR>error&nbsp;=&nbsp;"请填充完所有选项";&nbsp; <BR>return;&nbsp; <BR>}&nbsp; <BR>//将学生保存&nbsp; <BR>try{&nbsp; <BR>Student&nbsp;student=new&nbsp;Student();&nbsp; <BR>student.setId(id);&nbsp; <BR>student.setName(sname);&nbsp; <BR>if(gender==1)&nbsp; <BR>student.setGender("男");&nbsp; <BR>else&nbsp; <BR>student.setGender("女");&nbsp; <BR>student.setDepartment(department);&nbsp; <BR>student.save(null);&nbsp; <BR>}catch(Exception&nbsp;e){&nbsp; <BR>e.printStackTrace();&nbsp; <BR>}&nbsp; <BR>//清空当前的各个属性，以免再次进入此页面时，各属性仍旧保留原来的值&nbsp; <BR>setSname(null);&nbsp; <BR>setDepartment(null);&nbsp; <BR>setId(null);&nbsp; <BR>setGender(0);&nbsp; <BR>//重定向到Home页面&nbsp; <BR>cycle.setPage("Home");&nbsp; <BR>}&nbsp; <BR><BR>}&nbsp; <BR><BR><BR>在本类的一些设置属性的函数中使用了fireObservedChange这个函数，这个函数激发一个改变事件，通知当前的属性的值已经改变。<BR>其他应用&nbsp; <BR><BR>Tapestry中自带的例子中的Workbench中的localization例子演示了怎样使用本地化，你只需要创建不同语言的html模板，还有图形等其它一些html中用到的资源。例如创建一个法语版的EditStudent.html，则相应的html文件名为EditStudent_fr.html，而jwc中定义的组件的描述不用有多个版本。这里要介绍一下Tapestry本地化中经常用到的一个概念：assets。assets是一些web应用中用到的资源，如图象，视频。assets有三种：external,&nbsp;internal&nbsp;和private。External类型的assets来源于任意的URL。Internal类型的assets来源于和Tapestry应用在同一个服务器上的URL。Private&nbsp;类型的assets允许部署在WAR的WEB-INF/classes目录下（同上面的html模板，jwc文件一样），这个目录对于web服务器来说是不可见的。&nbsp; <BR>看一下Workbench中localization例子中的localization.jwc文件的片断：&nbsp; <BR><BR>&lt;component&nbsp;id="changeButton"&nbsp;type="ImageSubmit"&gt;;&nbsp; <BR>&lt;binding&nbsp;name="image"&nbsp;property-path="assets.change-button"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR><BR>&lt;private-asset&nbsp;name="change-button"&nbsp;resource-path="/tutorial/workbench/localization/Change.gif"/&gt;;&nbsp; <BR><BR>在changeButton组件中就使用了private&nbsp;assets，而这些图像文件就放在WAR的WEB-INF/classes下，注意图像跟html一样也有多个语言的版本。&nbsp; <BR>注意jwc文件中的inputLocale这个组件，其实localization应用就是通过这个组件来实现本地化。具体参数请看其Developer&nbsp;guide。&nbsp; <BR><BR>&lt;component&nbsp;id="inputLocale"&nbsp;type="PropertySelection"&gt;;&nbsp; <BR>&lt;binding&nbsp;name="value"&nbsp;property-path="page.engine.locale"/&gt;;&nbsp; <BR>&lt;binding&nbsp;name="model"&nbsp;property-path="localeModel"/&gt;;&nbsp; <BR>&lt;/component&gt;;&nbsp; <BR><BR>Tapestry还支持创建自己的可重用组件，其自身带了一个这样的例子：Border。同时它还有其它一些例子：Inspector展示了怎样监视你的应用程序。vlib是一个用tapestry作表示层的j2ee应用程序（用jboss作为应用服务器）。&nbsp; <BR><BR>Tapestry的功能非常强大，本文只是介绍了其一小部分，还有很多方面没有涉及到，例如javascript在Tapestry中的应用。具体可以看其文档，相信如果你用一下这个框架，你就会被它深深吸引。Tapestry的文档做的不是很全，不过经过不断的摸索，相信你会很快掌握它。<img src ="http://www.blogjava.net/jeffy/aggbug/32710.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jeffy/" target="_blank">Live-in Java</a> 2006-02-27 17:46 <a href="http://www.blogjava.net/jeffy/archive/2006/02/27/32710.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>