﻿<?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-henry1451 的专栏-文章分类-Struts,Webwork,Xwork技术</title><link>http://www.blogjava.net/henry1451/category/32233.html</link><description>共同学习,共同进步</description><language>zh-cn</language><lastBuildDate>Mon, 23 Jun 2008 08:59:40 GMT</lastBuildDate><pubDate>Mon, 23 Jun 2008 08:59:40 GMT</pubDate><ttl>60</ttl><item><title>(转)Interceptor(拦截器)</title><link>http://www.blogjava.net/henry1451/articles/210086.html</link><dc:creator>henry1451</dc:creator><author>henry1451</author><pubDate>Mon, 23 Jun 2008 08:18:00 GMT</pubDate><guid>http://www.blogjava.net/henry1451/articles/210086.html</guid><wfw:comment>http://www.blogjava.net/henry1451/comments/210086.html</wfw:comment><comments>http://www.blogjava.net/henry1451/articles/210086.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/henry1451/comments/commentRss/210086.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/henry1451/services/trackbacks/210086.html</trackback:ping><description><![CDATA[<p><span><span>1、 </span></span><span>一个拦截器就是在</span>xwork.xml<span>文件中定义的一个无状态</span>Java<span>类，它至少要实现</span>XWork<span>的</span>com.opensymphony.xwork.interceptor.Interceptor<span>接口。代码如下：</span></p>
<p>public interface Interceptor extends Serializable {</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>void destroy();</p>
<p>&nbsp;</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>void init();</p>
<p>&nbsp;</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>String intercept(ActionInvocation invocation) throws Exception;</p>
<p>}</p>
<p><span><span>2、 </span></span><span>实现</span>Interceptor<span>接口的拦截器，代码部分在</span>intercept<span>方法中实现。在</span>intercept<span>方法中，可以直接返回一个</span>Result<span>字符串，这样整个执行直接&#8220;短路&#8221;，这时</span>Action<span>的</span>execute<span>方法也不会执行（一般很少会这么用）。所以，一般都会在这个方法里调用参数对象</span>invocation<span>的</span>invoke<span>方法，并返回这个方法执行的结果。这样会持续执行后面的拦截器方法以及</span>Action<span>的</span>execute<span>方法等。</span></p>
<p><span><span>3、 </span></span><span>大部分的时候，拦截器直接继承</span>WebWork<span>的抽象类</span>com.opensymphony.xwork.interceptor.AroundInterceptor<span>就可以了。这时，需要实现它的</span>before<span>和</span>after<span>方法。</span>Before<span>方法会在</span>Action<span>执行之前调用，</span>after<span>方法在</span>Action<span>执行之后调用。</span></p>
<p><span><span>4、 </span></span><span>拦截器的执行顺序。我们可将多个拦截器放一起组装成一个拦截器栈。这样拦截器会按照栈的顺序由上而下执行</span>before<span>方法，所有</span>before<span>方法执行结束，再执行</span>Action<span>的方法，执行</span>Result<span>的方法，再返回执行结果，最后再从下而上执行拦截器的</span>after<span>方法。</span></p>
<p><span><span>5、 </span></span><span>拦截器的过滤功能。我们通常会在应用中使用一个通用的定义多个拦截器的拦截器栈。但有些</span>Action<span>方法在调用的时候，不需要要其中的部分拦截器。这时，我们就可以使用拦截器过滤功能。如果拦截器要拥有过滤功能，必须实现抽象类</span>com.opensymphony.xwork.interceptor.MethodFilterInterceptor<span>。这样，拦截器在定义的时候或者在</span>Action<span>引用拦截器栈的时候，我们就可以指定哪些</span>Action<span>方法是需要过滤的，哪些</span>Action<span>是不需要过滤的。</span></p>
<p>&nbsp;</p>
<p>WebWork<span>提供的拦截器介绍</span></p>
<p><span><span>1、 </span></span><span>自动为</span>Action<span>设置</span>Http<span>请求数据的拦截器</span>(Parameters Interceptor)<span>。这个拦截器非常方便实用，但完全自动组装对象数据，很可能会带来安全问题。如果</span>Action<span>不需要设置数据，那么这个</span>Action<span>只要实现</span>com.opensymphony.xwork.interceptor.NoParameters<span>接口即可。如果是</span>Action<span>中部分数据需要自动设置，部分数据不允许设置，这样可以实现接口</span>com.opensymphony.xwork.interceptor.ParameterNameAware<span>，可以在这个接口的</span>acceptableParameterName(String parameterName)<span>方法中，定义我们可以接受哪些方法，如果允许只要让这个方法返回</span>True<span>就可以了。</span></p>
<p><span><span>2、 </span></span><span>过虑参数功能的拦截器（</span>Parameter Filter Interceptor<span>）。它可以全局阻止非法或不允许</span>Action<span>访问的参数。可以很好的和上面的组装参数的拦截器一起使用。</span></p>
<p><span><span>3、 </span></span><span>为</span>Action<span>设置静态数据的拦截器（</span>Static Parameters Interceptor<span>）。它可以将</span>Action<span>定义的静态</span>&lt;param/&gt;<span>参数，设置到</span>Action<span>中。</span></p>
<p><span><span>4、 </span></span><span>数据验证拦截器（</span>Validation Interceptor<span>）。定义之后，会调用验证文件或实现验证接口</span>com.opensymphony.xwork.Validateable<span>的所有验证。</span></p>
<p><span><span>5、 </span></span><span>验证流程处理拦截器（</span>Workflow Interceptor<span>）。它和上面的拦截器一起使用，处理验证的流程。如果验证通过则继续前进，如果发现有验证错误消息，直接转到</span>Action<span>中定义的输入结果（</span>input<span>）页面。</span></p>
<p><span><span>6、 </span></span><span>类型转换错误处理拦截器（）。它首先去取得类型转换的错误消息（主要是由设置</span>Http<span>请求参数的拦截器产生），如果取到错误消息，它会将错误消息传递给实现接口</span>com.opensymphony.xwork.ValidationAware<span>的</span>Action<span>，这样我们可以将这些错误消息暴露到页面中。</span></p>
<p><span><span>7、 </span></span>Action<span>链拦截器（</span>Chaining Interceptor<span>）。它是用来拷贝前一个</span>Action<span>的属性数据到当前</span>Action<span>中。它要求前一个</span>Action<span>必须是</span>chain Result<span>（</span>&lt;result type="chain"&gt;<span>），这样才能进行</span>Action<span>的数据拷贝。</span></p>
<p><span><span>8、 </span></span><span>防止页面重复提交（或页面重复刷新）拦截器。</span>Token Interceptor<span>和</span>Token Session Interceptor<span>都是防止重复提交的拦截器。不同点是后者在</span>Session<span>存贮了最近一次请求的结果数据。</span></p>
<p><span><span>9、 </span></span><span>文件上传的拦截器（</span>File Upload Interceptor<span>）。实现文件上传的功能。如果有人曾经手工写过文件上传程序，那一定会惊叹于这个拦截器。我们可以在这个拦截器中设定上传文件的大小和类型限制。记得需要第三方的文件上传库的支持，只要在</span>webwork.properties<span>中配置过，并拷贝相应的</span>jar<span>包就可以了。</span></p>
<p><span><span>10、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>进度条等待拦截器（</span>Execute and Wait Interceptor<span>）。当</span>Action<span>的执行需要很长实际的时候，我们可以使用这个进度条等待的拦截器。它会将</span>Action<span>放到后台执行，而在前端显示进度条或等待消息提示的页面。</span></p>
<p><span><span>11、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>还有一些其它不常用的拦截器，我们可以在</span>WebWork<span>文档中找到，这里就不再做介绍。</span></p>
<h3><font face="Arial">IoC</font> <span>容器</span></h3>
<p><span>关于</span>IoC<span>容器的描述：</span></p>
<p><span><span>1、 </span></span><span>它是一个容器。用来处理不同对象之间的依赖，组装不同的程序元素。</span></p>
<p><span><span>2、 </span></span>IoC<span>全名是</span>Inversion of Control<span>，即依赖反转控制。它是一种设计模式，</span>IoC<span>容器就是基于这个模式的实现。</span></p>
<p><span><span>3、 </span></span><span>有一个比</span>IoC<span>更适合用来命名这一原理的名词，它叫</span>Dependency Injection<span>，即依赖注入。</span></p>
<p><span><span>4、 </span></span><span>有了依赖注入，我们可以将</span>IoC<span>容器简单理解为：它是一个用来为对象组装其依赖的对象的容器；也就是说对象本身不用关心它依赖的对象（可以是组件或者服务，反正就是提供业务方法的对象）的创建，初始化，生命周期等，而是由容器来控制。</span></p>
<p><span><span>5、 </span></span><span>关于</span>IoC<span>的更多信息可以查看</span>Martin Fowler<span>的经典文章《</span>IoC <span>容器和</span>Dependency Injection <span>模式》</span></p>
<p>WebWork<span>框架本身就提供了一个基于接口的</span>IoC<span>容器。同时</span>WebWork<span>框架和提供了和第三方</span>IoC<span>容器的集成。在</span>WebWork<span>的项目中，我们可以直接使用</span>Spring<span>框架和</span>Pico<span>框架作为自己的</span>IoC<span>容器。而且</span>Spring<span>是</span>WebWork<span>官方推荐的</span>IoC<span>容器。</span></p>
<p><span>下面我们将介绍如何使用</span>Spring<span>作为</span>WebWork<span>的</span>IoC<span>容器。在讨论如何集成</span>Spring<span>之前，我们要讨论一个非常有意义的架构问题：</span></p>
<p>WebWork<span>的</span>Action<span>类是否需要由</span>Spring<span>管理？</span></p>
<p><span><span>1、 </span></span><span>否。这样</span>Action<span>类还是象以前那样在</span>xwork<span>文件中定义，我们可以通过标签</span>&lt;external-ref/&gt;<span>定义</span>Action<span>所依赖的</span>Bean<span>组件，或者根据</span>Bean<span>的名字或类型进行自动注入。</span></p>
<p><span><span>2、 </span></span><span>是。</span>Action<span>类本身也是有</span>Spring<span>来管理。在</span>xwork<span>定义文件中的</span>Action class<span>就是对</span>Bean<span>的引用，具体的类在</span>Spring<span>的</span>Bean<span>配置文件中定义。这样可以更好的使用</span>Sping<span>为我们提供的更多功能，例如：</span>Spring<span>的复杂</span>AOP<span>功能，基于</span>Acegi<span>的权限控制，等等。</span></p>
<p><span>两种方法，根据需要选择一种，我个人更倾向后者。下面我们介绍一下</span>Spring<span>容器的安装步骤：</span></p>
<p><span><span>1、 </span></span><span>拷贝</span>Spring<span>依赖的所有</span>jar<span>文件</span></p>
<p><span><span>2、 </span></span><span>在</span>web.xml<span>文件定义和开启</span>Spring<span>的监听器，代码如下：</span></p>
<p>&lt;listener&gt;</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>&lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;</p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/listener&gt;</p>
<p><span><span>3、 </span></span><span>在</span>webwork.properties<span>中设置</span>WebWork<span>对</span>Spring<span>的支持：</span>webwork.objectFactory = spring</p>
<p><span><span>4、 </span></span><span>可以在</span>webwork.properties<span>中设置</span>Bean<span>组件的默认组装方式，默认是按照</span>Bean<span>的名称，可以选择按照类型、构造函数、自动选择等方式。</span></p>
<p>&nbsp;</p>
<h3><font face="Arial">WebWork</font> <span>原理</span></h3>
<br />
<img height="668" alt="webwork archit.png" src="http://www.blogjava.net/images/blogjava_net/moxie/webwork%20archit.png" width="609" border="0" /> <br />
<p>WebWork<span>的网站上提供了一个完整的</span>WebWork<span>架构图。它描述了从客户端的一次请求到最后服务器端响应的的整个执行过程。架构图如下：</span></p>
<p>&nbsp;</p>
<p><span>此架构图一个分为五个部分，其中五个部分分别有五中不同颜色表示。</span></p>
<p><span><span>1、 </span></span><span>浅灰色方框。分别代表了客户端的一次</span>Http<span>请求，和服务器端运算结束之后的一次响应。</span></p>
<p><span><span>2、 </span></span><span>浅红色方框。表示一次</span>Action<span>请求所要经过的</span>Servlet filters<span>（</span>Servlet <span>过滤器）。我们可以看到最后一个</span>filter<span>就是我们前面介绍的</span>WebWork<span>的前端控制器。</span></p>
<p><span><span>3、 </span></span><span>蓝色方框。这是</span>WebWork<span>框架的核心部分。</span></p>
<p><span><span>1） </span></span><span>一次请求到了</span>WebWork<span>的前端控制器，它首先会根据请求的</span>URL<span>解析出对应的</span>action <span>名称，然后去咨询</span>ActionMapper<span>这个</span>action<span>是否需要被执行。</span></p>
<p><span><span>2） </span></span><span>如果</span>ActionMapper<span>决定这个</span>action<span>需要被执行，前端控制器就把工作委派给</span>ActionProxy<span>。接着她们会咨询</span>WebWork<span>的配置管理器，并读取在</span>web.xml<span>文件中定义的配置信息。接下来</span>ActionProxy<span>会创建</span>ActionInvocation<span>对象。</span></p>
<p><span><span>3） </span></span>ActionInvocation<span>是</span>Xwork<span>原理的（</span>Command<span>模式）实现部分。它会调用这个</span>Action<span>已定义的拦截器</span>(before<span>方法</span>)<span>，</span>Action<span>方法，</span>Result<span>方法。</span></p>
<p><span><span>4） </span></span><span>最后，看上面流程的图的方向，它会再执行拦截器（</span>after<span>方法）</span><span>，再回到</span>Servlet Filter<span>部分，最后结束并传给用户一个结果响应。</span></p>
<p><span><span>4、 </span></span><span>靛色方框。这是拦截器部分，在上面的拦截器章节我们已经有了详细的介绍。</span></p>
<p><span><span>5、 </span></span><span>黄色方框。这是我们在开发</span>Web<span>应用时，需要自己开发的程序。其中包括：</span>Action<span>类，页面模板，配置文件</span>xwork.xml<span>。</span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<h2><em><font face="Arial">WebWork</font> <span>实战和技巧</span> </em></h2>
<p><span>限于篇幅，我们无法在本章节给出很多详尽的具体实例。其实，在</span>WebWork<span>的代码包中，有一个非常好的演示项目——</span>showcase<span>，它用例子演示了</span>WebWork<span>的几乎所有特性。值得初学的朋友反复研究。我们在本章节中会截取其中的部分代码脚本。</span></p>
<p>&nbsp;</p>
<p><span><span>1、 </span></span><span>多视图支持。</span>WebWork<span>框架天生支持多种视图技术，包括：</span>Jsp<span>、</span>FreeMarker<span>、</span>Velocity<span>、</span>Jasper Reports<span>、</span>XSLT<span>，还有其它的视图技术。这将在敏捷项目中特别有用。在我咨询的项目中，就有一个因为技术的原因，视图技术由最先的</span>Jsp<span>改为</span>Velocity<span>，后来又改造为</span>FreeMarker<span>。其中，</span>Action<span>类以及后台的程序没有做任何的改动。如果您需要一个视图展现层技术，我在这会好不犹豫的向您推荐</span>FreeMarker<span>。这也是官方的推荐。</span></p>
<p><span>关于视图技术的使用，首先是搭建视图技术运行的环境。然后就是编写页面脚本，最后就是在</span>xwork.xml<span>文件中配置。</span>Xwork<span>配置文件中，</span>Result<span>的</span>type<span>参数，就是用来标示所使用的视图技术。在</span>showcase<span>项目中，使用到的视图技术有：</span>Jsp<span>、</span>FreeMarker<span>、</span>Velocity<span>、</span>Jasper Reports<span>。</span></p>
<p>&nbsp;</p>
<p><span><span>2、 </span></span>Action<span>的数据验证功能。在</span>WebWork<span>中，可以在三处实现数据验证功能。一、验证文件（例如</span>:ActionClass-validation.xml<span>文件）中定义数据验证规则。二、在</span>Action<span>中实现</span>com.opensymphony.xwork.Validateable<span>接口的</span>validate<span>方法。三、在</span>Action<span>的执行方法中，硬编码实现验证功能。当然，在实现验证时，我们尽可能的用前面两中方法。</span></p>
<p><span>关于验证的说明：</span></p>
<p>1<span>）、第一种验证需要&#8220;</span>validation<span>&#8221;拦截器的支持。并可以从任意层次绑定验证文件，可以为一个</span>Action<span>类绑定一个验证文件，也可以为一个具体在</span>xwork.xml<span>文件中的</span>Action<span>定义绑定一个验证文件，可以为</span>Action<span>的一个属性对象绑定一个验证文件，甚至可以为</span>Action<span>的父类绑定验证文件。</span></p>
<p>2<span>）、</span>WebWork<span>为验证文件提供了一些标准的验证实现</span>:<span>例如：字段必须填写，整型、</span>E-mail<span>地址等等。我们也可以使用表达式语言实现更复杂的数据验证。</span></p>
<p>&nbsp;</p>
<p><span><span>3、 </span></span><span>类型转换。前面外面一直提到过，</span>WebWork<span>会自动从请求的字符串参数中组装</span>Action<span>需要的数据对象。这样，就会存在一个类型转换的问题。如果</span>Action<span>的字段是基本类型或是一个数据对象，</span>WebWork<span>会自动帮我们处理。如果</span>Action<span>的字段是一个集合，或者我们需要特定的类型转换，这时，我们可以在类型转换的定义文件（</span>ClassName-conversion.properties<span>）中定义转换规则。</span></p>
<p><span><span>4、 </span></span><span>一个</span>Action<span>的多个执行方法。</span>WebWork<span>的</span>Action<span>是基于</span>Command<span>模式的实现，在</span>WebWork<span>中，除了实现</span>Action<span>接口的</span>execute()<span>方法之外，</span>Action<span>还可以定义多个执行方法。这些方法必须要是无方法参数，并且返回返回字符串的方法。这样我们在</span>Url<span>中可以用类似下面的格式访问：</span>actionName!methodName.action<span>，例如</span>user!doAdd.action<span>，调用</span>user Action<span>类的</span>doAdd<span>方法。在最新的</span>WebWork<span>中，</span>Action<span>类甚至可以不实现</span>Action<span>接口。</span></p>
<p><span><span>5、 </span></span>Action<span>链（</span>Action Chaining<span>）。在</span>WebWork<span>中，一次用户请求，可由多个</span>Action<span>共同完成。每个</span>Action<span>可以只实现自己本身的功能单元，这样我们可以根据业务需要为用户的一次请求选择一个或多个</span>Action<span>功能单元来实现。</span><span>在这样的多个</span>Action<span>之间可以通过</span>chain<span>拦截器共享数据。如果请求由</span>Action x <span>链到</span>Action y<span>，如果这时</span>y<span>需要获得</span>x<span>的数据，我们就需要为</span>Action y<span>添加</span>chain<span>拦截器。</span></p>
<p><span>例如：在</span>showcase<span>中就由</span>Action Chaining<span>的应用。它将</span>Action<span>&#8220;</span>actionChain2<span>&#8221;链到另外一个</span>Action<span>&#8220;</span>actionChain3<span>&#8221;，配置文件代码如下：</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;</span> <span>action </span><span>name</span> <span>=</span> <span>"actionChain2" </span><span>class</span> <span>=</span> <span>"com.opensymphony.webwork.showcase.actionchaining.ActionChain2"</span> <span>&gt;</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;</span> <span>result </span><span>type</span> <span>=</span> <span>"chain"</span> <span>&gt;</span> <span>actionChain3</span> <span>&lt;/</span> <span>result</span> <span>&gt;</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;/</span> <span>action</span> <span>&gt;</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;</span> <span>action </span><span>name</span> <span>=</span> <span>"actionChain3" </span><span>class</span> <span>=</span> <span>"com.opensymphony.webwork.showcase.actionchaining.ActionChain3"</span> <span>&gt;</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;</span> <span>result</span> <span>&gt;</span> <span>/actionchaining/actionChainingResult.jsp</span> <span>&lt;/</span> <span>result</span> <span>&gt;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;/</span> <span>action</span> <span>&gt;</span></p>
<p><span>注意：如果要加</span> <span>chain</span> <span>拦截器，是需要加到</span> <span>actionChain3</span> <span>中，而不是</span> <span>actionChain2</span> <span>。</span></p>
<p>&nbsp;</p>
<p><span><span>6、 </span></span><span>多模块支持解决方案。</span> <span>WebWork</span> <span>提供了很灵活的多模块解决方案，这样我们可以很好的组织复杂的</span> <span>Web</span> <span>应用项目。</span></p>
<p><span>1</span> <span>）可以在</span> <span>xwork.xml</span> <span>文件中，用</span> <span>include</span> <span>标签包含另外的一个</span> <span>xwork</span> <span>配置文件。例如：</span> <span>&lt;include file="webwork-default.xml"/&gt;</span></p>
<p><span>2</span> <span>）</span> <span>xwork.xml</span> <span>配置文件支持</span> <span>package</span> <span>。我们可以将一个业务模块的定义方到一个</span> <span>package</span> <span>，</span> <span>package</span> <span>支持继承功能，子</span> <span>package</span> <span>可以享有父</span> <span>package</span> <span>的所有定义。</span></p>
<p><span>3</span> <span>）可以为</span> <span>package</span> <span>定义一个命名空间。不同的命名空间可以定义相同的</span> <span>action</span> <span>名字。命名空间会用于访问</span> <span>action</span> <span>的</span> <span>URL</span> <span>，基于这个命名空间，我们可以实现资源权限的访问控制。</span></p>
<p>&nbsp;</p>
<p><span><span>7、 </span></span><span>doInput</span> <span>方法。这是我们常用的小技巧，有时候请求的就是一个页面模板，总不能为这个单独写一个</span> <span>Action</span> <span>类吧，这时我们就可以用</span> <span>ActionSupport</span> <span>的</span> <span>doInput</span> <span>方法，直接返回在</span> <span>Actoion</span> <span>中定义为&#8220;</span> <span>input</span> <span>&#8221;的</span> <span>result</span> <span>。</span></p>
<p><span><span>8、 </span></span>prepare<span>方法。如果在</span>Action<span>执行之前，必须要初始化一些数据。我们可以将这些初始化的代码方到</span>prepare<span>方法中。这时，</span>Action<span>类要实现接口</span>com.opensymphony.xwork.Preparable<span>，同时这个</span>Action<span>的定义还需要</span>PrepareInterceptor<span>拦截器的支持。</span></p>
<p><span><span>9、 </span></span>Action<span>的</span>Model Driven<span>。我们大部分的时候用得都是</span>Action<span>的</span>Field Driven<span>，即直接将</span>Action<span>的字段作为数据模型。</span>Model Driven<span>是专门为这个</span>Action<span>指定一个模型对象，这样有什么好处呢？好处是在表达式语言中少了一个对象名的前缀。例如：前面值堆栈部分关于</span>Employee<span>的例子，要设置雇员名称，我们必须要表达式语言例如：&#8220;</span>employee.name<span>&#8221;，如果这个数据是有页面输入得到，那么你就必须有一个</span>Input<span>输入框的</span>name<span>为&#8220;</span>employee.name<span>&#8221;，因为它有关键字符&#8220;</span>.<span>&#8221;，如果</span>Javascript<span>脚本使用这个输入框的名字，就会有错误。使用</span>Model Driven<span>之后，这个表达式就可以变为&#8220;</span>name<span>&#8221;，省去了前面的&#8220;</span>employee.<span>&#8221;。</span></p>
<p><span><span>10、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>Quick Start<span>。这是</span>WebWork2.2.2<span>中非常激动人心的特性。它可以象</span>perl<span>或</span>PHP<span>可以快速看到程序运行结果。这样在</span>Web<span>开发时，可以不用编译</span>Java<span>源代码，也不用去做打包和部署，就可以快速看到最新程序的运行结果，提高开发效率。我们可以在</span>WebWork<span>源码解压包的根目录，输入命令：</span>java -jar webwork-2.2.2.jar quickstart:showcase<span>（需要</span>jdk1.5<span>的支持），以</span>Quick Start<span>模式，运行</span>showcase<span>项目。</span></p>
<h2><em><span>展望</span> <font face="Arial">WebWork</font> <span>未来</span> </em></h2>
<p><span>这是很多人非常关心的一个问题。特别是</span>WebWork2.2<span>版本发布之后，官方宣称</span>WebWork<span>框架将要和</span>Struts<span>合并。这让一些</span>WebWork<span>的用户产生了担忧，合并之后，是不是就意味着自己在</span>WebWork<span>这方面技术和经验的积累都已浪费？已使用或即将使用</span>WebWork<span>的项目是不是就意味着更多的风险？</span></p>
<p><span>答案是：完全不用担心这些。</span>WebWork<span>和</span>Struts<span>的合并，是各取所长，然后诞生出一个更加高效的</span>Web<span>框架。而这个框架用得就是</span>WebWork<span>的优秀技术和</span>Struts<span>的强大社区。</span></p>
<p><span>合并的情况如下：</span></p>
<p><span><span>1、 </span></span><span>产生一个新的项目</span>Struts Action 2.0 = WebWork2.2 + <span>一些</span>Struts<span>的功能和特性。</span></p>
<p><span><span>2、 </span></span>WebWork<span>框架将会中止新功能的增加，如果有新的版本发布都会是</span>Bug<span>的修改。</span></p>
<p><span><span>3、 </span></span><span>代码、框架的开发者、社区都将移到</span>Struts<span>。</span></p>
<p><span><span>4、 </span></span><span>合并的目标是致力于生产率的提高。</span></p>
<p><span><span>5、 </span></span>Struts<span>不再是一个框架，它是一个社区。</span></p>
<p><span><span>6、 </span></span>Struts<span>社区中主要有两个</span>Web<span>框架。一个是基于</span>Action<span>模型的</span>Struts Action<span>；另一个是基于组件模型的</span>Struts Shale<span>。</span></p>
<h2><span><em>总结</em> </span></h2>
<p>&nbsp;</p>
<p>WebWork<span>是本人工具箱中最爱的一个</span>J2EE Web<span>框架。本人开发过单纯使用</span>Jsp<span>和</span>JavaServlet<span>的项目；也曾经自己开发过基于</span>MVC<span>的</span>Web<span>框架；在</span>2002<span>年开始使用</span>Struts<span>开发；后来也在项目中分别使用过</span>Tapestry<span>和</span>Spring MVC Web<span>框架；也在当今的</span>AJAX<span>潮流中随波逐流。上面的一些技术也都非常优秀，擅用他们任何一个都会给您带来很多生产效率的提高。但我仍然是偏爱</span>WebWork<span>。</span>WebWork<span>的与众不同，得力于它基于</span>OGNL<span>的强大的数据存、取方式，得力于它那解耦的拦截器功能，得力于它那无侵入的架构设计。正是由于它，才让</span>Web<span>编程变得更加的自然、简单、灵活、高效。</span></p>
<img src ="http://www.blogjava.net/henry1451/aggbug/210086.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/henry1451/" target="_blank">henry1451</a> 2008-06-23 16:18 <a href="http://www.blogjava.net/henry1451/articles/210086.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Interceptor(拦截器)</title><link>http://www.blogjava.net/henry1451/articles/210084.html</link><dc:creator>henry1451</dc:creator><author>henry1451</author><pubDate>Mon, 23 Jun 2008 08:17:00 GMT</pubDate><guid>http://www.blogjava.net/henry1451/articles/210084.html</guid><wfw:comment>http://www.blogjava.net/henry1451/comments/210084.html</wfw:comment><comments>http://www.blogjava.net/henry1451/articles/210084.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/henry1451/comments/commentRss/210084.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/henry1451/services/trackbacks/210084.html</trackback:ping><description><![CDATA[<p><span><span>1、 </span></span><span>一个拦截器就是在</span>xwork.xml<span>文件中定义的一个无状态</span>Java<span>类，它至少要实现</span>XWork<span>的</span>com.opensymphony.xwork.interceptor.Interceptor<span>接口。代码如下：</span></p>
<p>public interface Interceptor extends Serializable {</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>void destroy();</p>
<p>&nbsp;</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>void init();</p>
<p>&nbsp;</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>String intercept(ActionInvocation invocation) throws Exception;</p>
<p>}</p>
<p><span><span>2、 </span></span><span>实现</span>Interceptor<span>接口的拦截器，代码部分在</span>intercept<span>方法中实现。在</span>intercept<span>方法中，可以直接返回一个</span>Result<span>字符串，这样整个执行直接&#8220;短路&#8221;，这时</span>Action<span>的</span>execute<span>方法也不会执行（一般很少会这么用）。所以，一般都会在这个方法里调用参数对象</span>invocation<span>的</span>invoke<span>方法，并返回这个方法执行的结果。这样会持续执行后面的拦截器方法以及</span>Action<span>的</span>execute<span>方法等。</span></p>
<p><span><span>3、 </span></span><span>大部分的时候，拦截器直接继承</span>WebWork<span>的抽象类</span>com.opensymphony.xwork.interceptor.AroundInterceptor<span>就可以了。这时，需要实现它的</span>before<span>和</span>after<span>方法。</span>Before<span>方法会在</span>Action<span>执行之前调用，</span>after<span>方法在</span>Action<span>执行之后调用。</span></p>
<p><span><span>4、 </span></span><span>拦截器的执行顺序。我们可将多个拦截器放一起组装成一个拦截器栈。这样拦截器会按照栈的顺序由上而下执行</span>before<span>方法，所有</span>before<span>方法执行结束，再执行</span>Action<span>的方法，执行</span>Result<span>的方法，再返回执行结果，最后再从下而上执行拦截器的</span>after<span>方法。</span></p>
<p><span><span>5、 </span></span><span>拦截器的过滤功能。我们通常会在应用中使用一个通用的定义多个拦截器的拦截器栈。但有些</span>Action<span>方法在调用的时候，不需要要其中的部分拦截器。这时，我们就可以使用拦截器过滤功能。如果拦截器要拥有过滤功能，必须实现抽象类</span>com.opensymphony.xwork.interceptor.MethodFilterInterceptor<span>。这样，拦截器在定义的时候或者在</span>Action<span>引用拦截器栈的时候，我们就可以指定哪些</span>Action<span>方法是需要过滤的，哪些</span>Action<span>是不需要过滤的。</span></p>
<p>&nbsp;</p>
<p>WebWork<span>提供的拦截器介绍</span></p>
<p><span><span>1、 </span></span><span>自动为</span>Action<span>设置</span>Http<span>请求数据的拦截器</span>(Parameters Interceptor)<span>。这个拦截器非常方便实用，但完全自动组装对象数据，很可能会带来安全问题。如果</span>Action<span>不需要设置数据，那么这个</span>Action<span>只要实现</span>com.opensymphony.xwork.interceptor.NoParameters<span>接口即可。如果是</span>Action<span>中部分数据需要自动设置，部分数据不允许设置，这样可以实现接口</span>com.opensymphony.xwork.interceptor.ParameterNameAware<span>，可以在这个接口的</span>acceptableParameterName(String parameterName)<span>方法中，定义我们可以接受哪些方法，如果允许只要让这个方法返回</span>True<span>就可以了。</span></p>
<p><span><span>2、 </span></span><span>过虑参数功能的拦截器（</span>Parameter Filter Interceptor<span>）。它可以全局阻止非法或不允许</span>Action<span>访问的参数。可以很好的和上面的组装参数的拦截器一起使用。</span></p>
<p><span><span>3、 </span></span><span>为</span>Action<span>设置静态数据的拦截器（</span>Static Parameters Interceptor<span>）。它可以将</span>Action<span>定义的静态</span>&lt;param/&gt;<span>参数，设置到</span>Action<span>中。</span></p>
<p><span><span>4、 </span></span><span>数据验证拦截器（</span>Validation Interceptor<span>）。定义之后，会调用验证文件或实现验证接口</span>com.opensymphony.xwork.Validateable<span>的所有验证。</span></p>
<p><span><span>5、 </span></span><span>验证流程处理拦截器（</span>Workflow Interceptor<span>）。它和上面的拦截器一起使用，处理验证的流程。如果验证通过则继续前进，如果发现有验证错误消息，直接转到</span>Action<span>中定义的输入结果（</span>input<span>）页面。</span></p>
<p><span><span>6、 </span></span><span>类型转换错误处理拦截器（）。它首先去取得类型转换的错误消息（主要是由设置</span>Http<span>请求参数的拦截器产生），如果取到错误消息，它会将错误消息传递给实现接口</span>com.opensymphony.xwork.ValidationAware<span>的</span>Action<span>，这样我们可以将这些错误消息暴露到页面中。</span></p>
<p><span><span>7、 </span></span>Action<span>链拦截器（</span>Chaining Interceptor<span>）。它是用来拷贝前一个</span>Action<span>的属性数据到当前</span>Action<span>中。它要求前一个</span>Action<span>必须是</span>chain Result<span>（</span>&lt;result type="chain"&gt;<span>），这样才能进行</span>Action<span>的数据拷贝。</span></p>
<p><span><span>8、 </span></span><span>防止页面重复提交（或页面重复刷新）拦截器。</span>Token Interceptor<span>和</span>Token Session Interceptor<span>都是防止重复提交的拦截器。不同点是后者在</span>Session<span>存贮了最近一次请求的结果数据。</span></p>
<p><span><span>9、 </span></span><span>文件上传的拦截器（</span>File Upload Interceptor<span>）。实现文件上传的功能。如果有人曾经手工写过文件上传程序，那一定会惊叹于这个拦截器。我们可以在这个拦截器中设定上传文件的大小和类型限制。记得需要第三方的文件上传库的支持，只要在</span>webwork.properties<span>中配置过，并拷贝相应的</span>jar<span>包就可以了。</span></p>
<p><span><span>10、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>进度条等待拦截器（</span>Execute and Wait Interceptor<span>）。当</span>Action<span>的执行需要很长实际的时候，我们可以使用这个进度条等待的拦截器。它会将</span>Action<span>放到后台执行，而在前端显示进度条或等待消息提示的页面。</span></p>
<p><span><span>11、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>还有一些其它不常用的拦截器，我们可以在</span>WebWork<span>文档中找到，这里就不再做介绍。</span></p>
<h3><font face="Arial">IoC</font> <span>容器</span></h3>
<p><span>关于</span>IoC<span>容器的描述：</span></p>
<p><span><span>1、 </span></span><span>它是一个容器。用来处理不同对象之间的依赖，组装不同的程序元素。</span></p>
<p><span><span>2、 </span></span>IoC<span>全名是</span>Inversion of Control<span>，即依赖反转控制。它是一种设计模式，</span>IoC<span>容器就是基于这个模式的实现。</span></p>
<p><span><span>3、 </span></span><span>有一个比</span>IoC<span>更适合用来命名这一原理的名词，它叫</span>Dependency Injection<span>，即依赖注入。</span></p>
<p><span><span>4、 </span></span><span>有了依赖注入，我们可以将</span>IoC<span>容器简单理解为：它是一个用来为对象组装其依赖的对象的容器；也就是说对象本身不用关心它依赖的对象（可以是组件或者服务，反正就是提供业务方法的对象）的创建，初始化，生命周期等，而是由容器来控制。</span></p>
<p><span><span>5、 </span></span><span>关于</span>IoC<span>的更多信息可以查看</span>Martin Fowler<span>的经典文章《</span>IoC <span>容器和</span>Dependency Injection <span>模式》</span></p>
<p>WebWork<span>框架本身就提供了一个基于接口的</span>IoC<span>容器。同时</span>WebWork<span>框架和提供了和第三方</span>IoC<span>容器的集成。在</span>WebWork<span>的项目中，我们可以直接使用</span>Spring<span>框架和</span>Pico<span>框架作为自己的</span>IoC<span>容器。而且</span>Spring<span>是</span>WebWork<span>官方推荐的</span>IoC<span>容器。</span></p>
<p><span>下面我们将介绍如何使用</span>Spring<span>作为</span>WebWork<span>的</span>IoC<span>容器。在讨论如何集成</span>Spring<span>之前，我们要讨论一个非常有意义的架构问题：</span></p>
<p>WebWork<span>的</span>Action<span>类是否需要由</span>Spring<span>管理？</span></p>
<p><span><span>1、 </span></span><span>否。这样</span>Action<span>类还是象以前那样在</span>xwork<span>文件中定义，我们可以通过标签</span>&lt;external-ref/&gt;<span>定义</span>Action<span>所依赖的</span>Bean<span>组件，或者根据</span>Bean<span>的名字或类型进行自动注入。</span></p>
<p><span><span>2、 </span></span><span>是。</span>Action<span>类本身也是有</span>Spring<span>来管理。在</span>xwork<span>定义文件中的</span>Action class<span>就是对</span>Bean<span>的引用，具体的类在</span>Spring<span>的</span>Bean<span>配置文件中定义。这样可以更好的使用</span>Sping<span>为我们提供的更多功能，例如：</span>Spring<span>的复杂</span>AOP<span>功能，基于</span>Acegi<span>的权限控制，等等。</span></p>
<p><span>两种方法，根据需要选择一种，我个人更倾向后者。下面我们介绍一下</span>Spring<span>容器的安装步骤：</span></p>
<p><span><span>1、 </span></span><span>拷贝</span>Spring<span>依赖的所有</span>jar<span>文件</span></p>
<p><span><span>2、 </span></span><span>在</span>web.xml<span>文件定义和开启</span>Spring<span>的监听器，代码如下：</span></p>
<p>&lt;listener&gt;</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>&lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;</p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/listener&gt;</p>
<p><span><span>3、 </span></span><span>在</span>webwork.properties<span>中设置</span>WebWork<span>对</span>Spring<span>的支持：</span>webwork.objectFactory = spring</p>
<p><span><span>4、 </span></span><span>可以在</span>webwork.properties<span>中设置</span>Bean<span>组件的默认组装方式，默认是按照</span>Bean<span>的名称，可以选择按照类型、构造函数、自动选择等方式。</span></p>
<p>&nbsp;</p>
<h3><font face="Arial">WebWork</font> <span>原理</span></h3>
<br />
<img height="668" alt="webwork archit.png" src="http://www.blogjava.net/images/blogjava_net/moxie/webwork%20archit.png" width="609" border="0" /> <br />
<p>WebWork<span>的网站上提供了一个完整的</span>WebWork<span>架构图。它描述了从客户端的一次请求到最后服务器端响应的的整个执行过程。架构图如下：</span></p>
<p>&nbsp;</p>
<p><span>此架构图一个分为五个部分，其中五个部分分别有五中不同颜色表示。</span></p>
<p><span><span>1、 </span></span><span>浅灰色方框。分别代表了客户端的一次</span>Http<span>请求，和服务器端运算结束之后的一次响应。</span></p>
<p><span><span>2、 </span></span><span>浅红色方框。表示一次</span>Action<span>请求所要经过的</span>Servlet filters<span>（</span>Servlet <span>过滤器）。我们可以看到最后一个</span>filter<span>就是我们前面介绍的</span>WebWork<span>的前端控制器。</span></p>
<p><span><span>3、 </span></span><span>蓝色方框。这是</span>WebWork<span>框架的核心部分。</span></p>
<p><span><span>1） </span></span><span>一次请求到了</span>WebWork<span>的前端控制器，它首先会根据请求的</span>URL<span>解析出对应的</span>action <span>名称，然后去咨询</span>ActionMapper<span>这个</span>action<span>是否需要被执行。</span></p>
<p><span><span>2） </span></span><span>如果</span>ActionMapper<span>决定这个</span>action<span>需要被执行，前端控制器就把工作委派给</span>ActionProxy<span>。接着她们会咨询</span>WebWork<span>的配置管理器，并读取在</span>web.xml<span>文件中定义的配置信息。接下来</span>ActionProxy<span>会创建</span>ActionInvocation<span>对象。</span></p>
<p><span><span>3） </span></span>ActionInvocation<span>是</span>Xwork<span>原理的（</span>Command<span>模式）实现部分。它会调用这个</span>Action<span>已定义的拦截器</span>(before<span>方法</span>)<span>，</span>Action<span>方法，</span>Result<span>方法。</span></p>
<p><span><span>4） </span></span><span>最后，看上面流程的图的方向，它会再执行拦截器（</span>after<span>方法）</span><span>，再回到</span>Servlet Filter<span>部分，最后结束并传给用户一个结果响应。</span></p>
<p><span><span>4、 </span></span><span>靛色方框。这是拦截器部分，在上面的拦截器章节我们已经有了详细的介绍。</span></p>
<p><span><span>5、 </span></span><span>黄色方框。这是我们在开发</span>Web<span>应用时，需要自己开发的程序。其中包括：</span>Action<span>类，页面模板，配置文件</span>xwork.xml<span>。</span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<h2><em><font face="Arial">WebWork</font> <span>实战和技巧</span> </em></h2>
<p><span>限于篇幅，我们无法在本章节给出很多详尽的具体实例。其实，在</span>WebWork<span>的代码包中，有一个非常好的演示项目——</span>showcase<span>，它用例子演示了</span>WebWork<span>的几乎所有特性。值得初学的朋友反复研究。我们在本章节中会截取其中的部分代码脚本。</span></p>
<p>&nbsp;</p>
<p><span><span>1、 </span></span><span>多视图支持。</span>WebWork<span>框架天生支持多种视图技术，包括：</span>Jsp<span>、</span>FreeMarker<span>、</span>Velocity<span>、</span>Jasper Reports<span>、</span>XSLT<span>，还有其它的视图技术。这将在敏捷项目中特别有用。在我咨询的项目中，就有一个因为技术的原因，视图技术由最先的</span>Jsp<span>改为</span>Velocity<span>，后来又改造为</span>FreeMarker<span>。其中，</span>Action<span>类以及后台的程序没有做任何的改动。如果您需要一个视图展现层技术，我在这会好不犹豫的向您推荐</span>FreeMarker<span>。这也是官方的推荐。</span></p>
<p><span>关于视图技术的使用，首先是搭建视图技术运行的环境。然后就是编写页面脚本，最后就是在</span>xwork.xml<span>文件中配置。</span>Xwork<span>配置文件中，</span>Result<span>的</span>type<span>参数，就是用来标示所使用的视图技术。在</span>showcase<span>项目中，使用到的视图技术有：</span>Jsp<span>、</span>FreeMarker<span>、</span>Velocity<span>、</span>Jasper Reports<span>。</span></p>
<p>&nbsp;</p>
<p><span><span>2、 </span></span>Action<span>的数据验证功能。在</span>WebWork<span>中，可以在三处实现数据验证功能。一、验证文件（例如</span>:ActionClass-validation.xml<span>文件）中定义数据验证规则。二、在</span>Action<span>中实现</span>com.opensymphony.xwork.Validateable<span>接口的</span>validate<span>方法。三、在</span>Action<span>的执行方法中，硬编码实现验证功能。当然，在实现验证时，我们尽可能的用前面两中方法。</span></p>
<p><span>关于验证的说明：</span></p>
<p>1<span>）、第一种验证需要&#8220;</span>validation<span>&#8221;拦截器的支持。并可以从任意层次绑定验证文件，可以为一个</span>Action<span>类绑定一个验证文件，也可以为一个具体在</span>xwork.xml<span>文件中的</span>Action<span>定义绑定一个验证文件，可以为</span>Action<span>的一个属性对象绑定一个验证文件，甚至可以为</span>Action<span>的父类绑定验证文件。</span></p>
<p>2<span>）、</span>WebWork<span>为验证文件提供了一些标准的验证实现</span>:<span>例如：字段必须填写，整型、</span>E-mail<span>地址等等。我们也可以使用表达式语言实现更复杂的数据验证。</span></p>
<p>&nbsp;</p>
<p><span><span>3、 </span></span><span>类型转换。前面外面一直提到过，</span>WebWork<span>会自动从请求的字符串参数中组装</span>Action<span>需要的数据对象。这样，就会存在一个类型转换的问题。如果</span>Action<span>的字段是基本类型或是一个数据对象，</span>WebWork<span>会自动帮我们处理。如果</span>Action<span>的字段是一个集合，或者我们需要特定的类型转换，这时，我们可以在类型转换的定义文件（</span>ClassName-conversion.properties<span>）中定义转换规则。</span></p>
<p><span><span>4、 </span></span><span>一个</span>Action<span>的多个执行方法。</span>WebWork<span>的</span>Action<span>是基于</span>Command<span>模式的实现，在</span>WebWork<span>中，除了实现</span>Action<span>接口的</span>execute()<span>方法之外，</span>Action<span>还可以定义多个执行方法。这些方法必须要是无方法参数，并且返回返回字符串的方法。这样我们在</span>Url<span>中可以用类似下面的格式访问：</span>actionName!methodName.action<span>，例如</span>user!doAdd.action<span>，调用</span>user Action<span>类的</span>doAdd<span>方法。在最新的</span>WebWork<span>中，</span>Action<span>类甚至可以不实现</span>Action<span>接口。</span></p>
<p><span><span>5、 </span></span>Action<span>链（</span>Action Chaining<span>）。在</span>WebWork<span>中，一次用户请求，可由多个</span>Action<span>共同完成。每个</span>Action<span>可以只实现自己本身的功能单元，这样我们可以根据业务需要为用户的一次请求选择一个或多个</span>Action<span>功能单元来实现。</span><span>在这样的多个</span>Action<span>之间可以通过</span>chain<span>拦截器共享数据。如果请求由</span>Action x <span>链到</span>Action y<span>，如果这时</span>y<span>需要获得</span>x<span>的数据，我们就需要为</span>Action y<span>添加</span>chain<span>拦截器。</span></p>
<p><span>例如：在</span>showcase<span>中就由</span>Action Chaining<span>的应用。它将</span>Action<span>&#8220;</span>actionChain2<span>&#8221;链到另外一个</span>Action<span>&#8220;</span>actionChain3<span>&#8221;，配置文件代码如下：</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;</span> <span>action </span><span>name</span> <span>=</span> <span>"actionChain2" </span><span>class</span> <span>=</span> <span>"com.opensymphony.webwork.showcase.actionchaining.ActionChain2"</span> <span>&gt;</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;</span> <span>result </span><span>type</span> <span>=</span> <span>"chain"</span> <span>&gt;</span> <span>actionChain3</span> <span>&lt;/</span> <span>result</span> <span>&gt;</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;/</span> <span>action</span> <span>&gt;</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;</span> <span>action </span><span>name</span> <span>=</span> <span>"actionChain3" </span><span>class</span> <span>=</span> <span>"com.opensymphony.webwork.showcase.actionchaining.ActionChain3"</span> <span>&gt;</span></p>
<p align="left"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;</span> <span>result</span> <span>&gt;</span> <span>/actionchaining/actionChainingResult.jsp</span> <span>&lt;/</span> <span>result</span> <span>&gt;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;/</span> <span>action</span> <span>&gt;</span></p>
<p><span>注意：如果要加</span> <span>chain</span> <span>拦截器，是需要加到</span> <span>actionChain3</span> <span>中，而不是</span> <span>actionChain2</span> <span>。</span></p>
<p>&nbsp;</p>
<p><span><span>6、 </span></span><span>多模块支持解决方案。</span> <span>WebWork</span> <span>提供了很灵活的多模块解决方案，这样我们可以很好的组织复杂的</span> <span>Web</span> <span>应用项目。</span></p>
<p><span>1</span> <span>）可以在</span> <span>xwork.xml</span> <span>文件中，用</span> <span>include</span> <span>标签包含另外的一个</span> <span>xwork</span> <span>配置文件。例如：</span> <span>&lt;include file="webwork-default.xml"/&gt;</span></p>
<p><span>2</span> <span>）</span> <span>xwork.xml</span> <span>配置文件支持</span> <span>package</span> <span>。我们可以将一个业务模块的定义方到一个</span> <span>package</span> <span>，</span> <span>package</span> <span>支持继承功能，子</span> <span>package</span> <span>可以享有父</span> <span>package</span> <span>的所有定义。</span></p>
<p><span>3</span> <span>）可以为</span> <span>package</span> <span>定义一个命名空间。不同的命名空间可以定义相同的</span> <span>action</span> <span>名字。命名空间会用于访问</span> <span>action</span> <span>的</span> <span>URL</span> <span>，基于这个命名空间，我们可以实现资源权限的访问控制。</span></p>
<p>&nbsp;</p>
<p><span><span>7、 </span></span><span>doInput</span> <span>方法。这是我们常用的小技巧，有时候请求的就是一个页面模板，总不能为这个单独写一个</span> <span>Action</span> <span>类吧，这时我们就可以用</span> <span>ActionSupport</span> <span>的</span> <span>doInput</span> <span>方法，直接返回在</span> <span>Actoion</span> <span>中定义为&#8220;</span> <span>input</span> <span>&#8221;的</span> <span>result</span> <span>。</span></p>
<p><span><span>8、 </span></span>prepare<span>方法。如果在</span>Action<span>执行之前，必须要初始化一些数据。我们可以将这些初始化的代码方到</span>prepare<span>方法中。这时，</span>Action<span>类要实现接口</span>com.opensymphony.xwork.Preparable<span>，同时这个</span>Action<span>的定义还需要</span>PrepareInterceptor<span>拦截器的支持。</span></p>
<p><span><span>9、 </span></span>Action<span>的</span>Model Driven<span>。我们大部分的时候用得都是</span>Action<span>的</span>Field Driven<span>，即直接将</span>Action<span>的字段作为数据模型。</span>Model Driven<span>是专门为这个</span>Action<span>指定一个模型对象，这样有什么好处呢？好处是在表达式语言中少了一个对象名的前缀。例如：前面值堆栈部分关于</span>Employee<span>的例子，要设置雇员名称，我们必须要表达式语言例如：&#8220;</span>employee.name<span>&#8221;，如果这个数据是有页面输入得到，那么你就必须有一个</span>Input<span>输入框的</span>name<span>为&#8220;</span>employee.name<span>&#8221;，因为它有关键字符&#8220;</span>.<span>&#8221;，如果</span>Javascript<span>脚本使用这个输入框的名字，就会有错误。使用</span>Model Driven<span>之后，这个表达式就可以变为&#8220;</span>name<span>&#8221;，省去了前面的&#8220;</span>employee.<span>&#8221;。</span></p>
<p><span><span>10、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>Quick Start<span>。这是</span>WebWork2.2.2<span>中非常激动人心的特性。它可以象</span>perl<span>或</span>PHP<span>可以快速看到程序运行结果。这样在</span>Web<span>开发时，可以不用编译</span>Java<span>源代码，也不用去做打包和部署，就可以快速看到最新程序的运行结果，提高开发效率。我们可以在</span>WebWork<span>源码解压包的根目录，输入命令：</span>java -jar webwork-2.2.2.jar quickstart:showcase<span>（需要</span>jdk1.5<span>的支持），以</span>Quick Start<span>模式，运行</span>showcase<span>项目。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2><em><span>展望</span> <font face="Arial">WebWork</font> <span>未来</span> </em></h2>
<p><span>这是很多人非常关心的一个问题。特别是</span>WebWork2.2<span>版本发布之后，官方宣称</span>WebWork<span>框架将要和</span>Struts<span>合并。这让一些</span>WebWork<span>的用户产生了担忧，合并之后，是不是就意味着自己在</span>WebWork<span>这方面技术和经验的积累都已浪费？已使用或即将使用</span>WebWork<span>的项目是不是就意味着更多的风险？</span></p>
<p><span>答案是：完全不用担心这些。</span>WebWork<span>和</span>Struts<span>的合并，是各取所长，然后诞生出一个更加高效的</span>Web<span>框架。而这个框架用得就是</span>WebWork<span>的优秀技术和</span>Struts<span>的强大社区。</span></p>
<p><span>合并的情况如下：</span></p>
<p><span><span>1、 </span></span><span>产生一个新的项目</span>Struts Action 2.0 = WebWork2.2 + <span>一些</span>Struts<span>的功能和特性。</span></p>
<p><span><span>2、 </span></span>WebWork<span>框架将会中止新功能的增加，如果有新的版本发布都会是</span>Bug<span>的修改。</span></p>
<p><span><span>3、 </span></span><span>代码、框架的开发者、社区都将移到</span>Struts<span>。</span></p>
<p><span><span>4、 </span></span><span>合并的目标是致力于生产率的提高。</span></p>
<p><span><span>5、 </span></span>Struts<span>不再是一个框架，它是一个社区。</span></p>
<p><span><span>6、 </span></span>Struts<span>社区中主要有两个</span>Web<span>框架。一个是基于</span>Action<span>模型的</span>Struts Action<span>；另一个是基于组件模型的</span>Struts Shale<span>。</span></p>
<h2><span><em>总结</em> </span></h2>
<p>&nbsp;</p>
<p>WebWork<span>是本人工具箱中最爱的一个</span>J2EE Web<span>框架。本人开发过单纯使用</span>Jsp<span>和</span>JavaServlet<span>的项目；也曾经自己开发过基于</span>MVC<span>的</span>Web<span>框架；在</span>2002<span>年开始使用</span>Struts<span>开发；后来也在项目中分别使用过</span>Tapestry<span>和</span>Spring MVC Web<span>框架；也在当今的</span>AJAX<span>潮流中随波逐流。上面的一些技术也都非常优秀，擅用他们任何一个都会给您带来很多生产效率的提高。但我仍然是偏爱</span>WebWork<span>。</span>WebWork<span>的与众不同，得力于它基于</span>OGNL<span>的强大的数据存、取方式，得力于它那解耦的拦截器功能，得力于它那无侵入的架构设计。正是由于它，才让</span>Web<span>编程变得更加的自然、简单、灵活、高效。</span></p>
<img src ="http://www.blogjava.net/henry1451/aggbug/210084.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/henry1451/" target="_blank">henry1451</a> 2008-06-23 16:17 <a href="http://www.blogjava.net/henry1451/articles/210084.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts2拦截器概述(转)</title><link>http://www.blogjava.net/henry1451/articles/208521.html</link><dc:creator>henry1451</dc:creator><author>henry1451</author><pubDate>Tue, 17 Jun 2008 01:55:00 GMT</pubDate><guid>http://www.blogjava.net/henry1451/articles/208521.html</guid><wfw:comment>http://www.blogjava.net/henry1451/comments/208521.html</wfw:comment><comments>http://www.blogjava.net/henry1451/articles/208521.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/henry1451/comments/commentRss/208521.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/henry1451/services/trackbacks/208521.html</trackback:ping><description><![CDATA[<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">Struts2的拦截器和Servlet过滤器类似。在执行Action的execute方法之前，Struts2会首先执行在struts.xml中引用的拦截器，在执行完所有引用的拦截器的intercept方法后，会执行Action的execute方法。</span>
<p style="text-indent: 21.75pt"><span style="font-size: 12pt">Struts2拦截器类必须从com.opensymphony.xwork2.interceptor.Interceptor接口继承，在Intercepter接口中有如下三个方法需要实现：<br />
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--></span></p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;destroy();<br />
</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;init();<br />
String&nbsp;intercept(ActionInvocation&nbsp;invocation)&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;Exception;<br />
</span></div>
<p style="text-indent: 21.75pt"><span style="font-size: 12pt">其中intercept方法是拦截器的核心方法，所有安装的拦截器都会调用这个方法。在Struts2中已经在struts-default.xml中预定义了一些自带的拦截器，如timer、params等。如果在&lt;package&gt;标签中继承struts-default，则当前package就会自动拥有struts-default.xml中的所有配置。代码如下：</span></p>
<span style="font-size: 12pt">
<p><span>&lt;package name="demo" extends="struts-default" &gt; ... &lt;/package&gt;</span></p>
<span style="font-size: 10.5pt; font-family: 宋体">在</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">struts-default.xml</span><span style="font-size: 10.5pt; font-family: 宋体">中有一个默认的引用，在默认情况下（也就是</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">&lt;action&gt;</span><span style="font-size: 10.5pt; font-family: 宋体">中未引用拦截器时）会自动引用一些拦截器。这个默认的拦截器引用如下：</span></span>
<p>&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">&lt;</span><span style="color: #800000">default-interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="defaultStack"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
<br />
</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-stack&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="defaultStack"</span><span style="color: #0000ff">&gt;</span>&nbsp;&nbsp; <span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="exception"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="alias"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="servletConfig"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="prepare"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="i18n"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="chain"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="debugging"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="profiling"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="scopedModelDriven"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="modelDriven"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="fileUpload"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="checkbox"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="staticParams"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="params"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">param&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="excludeParams"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">dojo\..*</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">param</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">interceptor-ref</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="conversionError"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="validation"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">param&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="excludeMethods"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">input,back,cancel,browse</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">param</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">interceptor-ref</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="workflow"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">param&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="excludeMethods"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">input,back,cancel,browse</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">param</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">interceptor-ref</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">interceptor-stack</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span></div>
<p style="text-indent: 21.75pt"><span style="font-family: 宋体">上面在</span>defaultStack<span style="font-family: 宋体">中引用的拦截器都可以在</span>&lt;action&gt;<span style="font-family: 宋体">中不经过引用就可以使用（如果在</span>&lt;action&gt;<span style="font-family: 宋体">中引用了任何拦截器后，要使用在</span>defaultStack<span style="font-family: 宋体">中定义的拦截器，也需要在</span>&lt;action&gt;<span style="font-family: 宋体">中重新引用，在后面将详细讲解）。</span></p>
<p style="text-indent: 21.75pt"><span style="font-family: 宋体">下面我们来看几个简单的拦截器的使用方法。</span></p>
<p><strong><span style="font-family: 宋体">一、记录拦截器和</span>execute</strong><strong><span style="font-family: 宋体">方法的执行时间</span>(timer)</strong></p>
???? <span style="font-size: 10.5pt; font-family: 'Times New Roman'">timer</span><span style="font-size: 10.5pt; font-family: 宋体">是</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Struts2</span><span style="font-size: 10.5pt; font-family: 宋体">中最简单的拦截器，这个拦截器对应的类是</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">com.opensymphony.xwork2.interceptor.TimerInterceptor</span><span style="font-size: 10.5pt; font-family: 宋体">。它的功能是记录</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">execute</span><span style="font-size: 10.5pt; font-family: 宋体">方法和其他拦截器（在</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">timer</span><span style="font-size: 10.5pt; font-family: 宋体">后面定义的拦截器）的</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">intercept</span><span style="font-size: 10.5pt; font-family: 宋体">方法执行的时间总和。如下面的配置代码所示：<br />
<br />
</span>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">&lt;</span><span style="color: #800000">action&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="first"</span><span style="color: #ff0000">&nbsp;class</span><span style="color: #0000ff">="action.FirstAction"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="logger"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="timer"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">action</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span></div>
<br />
<p style="text-indent: 21.75pt"><span style="font-family: 宋体">由于在</span>timer<span style="font-family: 宋体">后面没有其他的拦截器定义，因此，</span>timer<span style="font-family: 宋体">只能记录</span>execute<span style="font-family: 宋体">方法的执行时间，在访问</span>first<span style="font-family: 宋体">动作时，会在控制台输出类似下面的一条信息：</span><span><br />
<br />
</span><span style="color: red; font-family: 宋体">信息</span><span style="color: red">: Executed action [/test/first!execute] took 16 ms.<br />
<br />
</span><span style="font-size: 10.5pt; font-family: 宋体">在使用</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">timer</span><span style="font-size: 10.5pt; font-family: 宋体">拦截器时，需要</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">commons-logging.jar</span><span style="font-size: 10.5pt; font-family: 宋体">的支持。将</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">logger</span><span style="font-size: 10.5pt; font-family: 宋体">引用放到</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">timer</span><span style="font-size: 10.5pt; font-family: 宋体">的后面，就可以记录</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">logger</span><span style="font-size: 10.5pt; font-family: 宋体">拦截器的</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">intercept</span><span style="font-size: 10.5pt; font-family: 宋体">方法和</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Action</span><span style="font-size: 10.5pt; font-family: 宋体">的</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">execute</span><span style="font-size: 10.5pt; font-family: 宋体">方法的执行时间总和，代码如下：<br />
<br />
</span></p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">&lt;</span><span style="color: #800000">action&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="first"</span><span style="color: #ff0000">&nbsp;class</span><span style="color: #0000ff">="action.FirstAction"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="timer"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="logger"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">action</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span></div>
<br />
<span style="font-size: 10.5pt; font-family: 宋体">大家可以使用如下的</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Action</span><span style="font-size: 10.5pt; font-family: 宋体">类来测试一下</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">timer</span><span style="font-size: 10.5pt; font-family: 宋体">拦截器：</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'"><br />
<br />
</span>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">package</span><span style="color: #000000">&nbsp;action;<br />
<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;com.opensymphony.xwork2.ActionSupport;<br />
<br />
</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;FirstAction&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;ActionSupport&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;String&nbsp;execute()&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;Exception<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(</span><span style="color: #000000">1000</span><span style="color: #000000">);&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;延迟1秒</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">null</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
}</span></div>
<br />
<p style="text-indent: 21.75pt"><span style="font-family: 宋体">如果只记录</span>execute<span style="font-family: 宋体">方法的执行时间，一般会输出如下的信息：</span></p>
<p><span style="color: red; font-family: 宋体">信息</span><span style="color: red">: Executed action [/test/first!execute] took 1000 ms.</span></p>
<p><strong><span style="font-family: 宋体">二、通过请求调用</span>Action</strong><strong><span style="font-family: 宋体">的</span>setter</strong><strong><span style="font-family: 宋体">方法</span>(params)</strong></p>
<span style="font-size: 10.5pt; font-family: 'Times New Roman'"><br />
&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10.5pt; font-family: 宋体">当客户端的一个</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">form</span><span style="font-size: 10.5pt; font-family: 宋体">向服务端提交请求时，如有一个</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">textfield</span><span style="font-size: 10.5pt; font-family: 宋体">，代码如下：</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'"><br />
<br />
</span>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:form&nbsp;</span><span style="color: #ff0000">action</span><span style="color: #0000ff">="first"</span><span style="color: #ff0000">&nbsp;namespace</span><span style="color: #0000ff">="/test"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:textfield&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="name"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:submit</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:form</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span></div>
<br />
<p style="text-indent: 21.75pt"><span style="font-family: 宋体">在提交后，</span>Struts2<span style="font-family: 宋体">将会自动调用</span>first<span style="font-family: 宋体">动作类中的</span>setName<span style="font-family: 宋体">方法，并将</span>name<span style="font-family: 宋体">文本框中的值通过</span>setName<span style="font-family: 宋体">方法的参数传入。实际上，这个操作是由</span>params<span style="font-family: 宋体">拦截器完成的，</span>params<span style="font-family: 宋体">对应的类是</span>com.opensymphony.xwork2.interceptor.ParametersInterceptor<span style="font-family: 宋体">。由于</span>params<span style="font-family: 宋体">已经在</span>defaultStack<span style="font-family: 宋体">中定义，因此，在未引用拦截器的</span>&lt;action&gt;<span style="font-family: 宋体">中是会自动引用</span>params<span style="font-family: 宋体">的，如下面的配置代码，在访问</span>first<span style="font-family: 宋体">动作时，</span>Struts2<span style="font-family: 宋体">是会自动执行相应的</span>setter<span style="font-family: 宋体">方法的。</span></p>
<p><span>&lt;action name="first" class="action.FirstAction"&gt;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>... ...</span></p>
<p>&lt;/action&gt;</p>
<p style="text-indent: 21.75pt"><span style="font-family: 宋体">但如果在</span>&lt;action&gt;<span style="font-family: 宋体">中引用了其他的拦截器，就必须再次引用</span>params<span style="font-family: 宋体">拦截器，</span>Struts2<span style="font-family: 宋体">才能调用相应的</span>setter<span style="font-family: 宋体">方法。如下面的配置代码所示：</span></p>
<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">&lt;</span><span style="color: #800000">action&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="first"</span><span style="color: #ff0000">&nbsp;class</span><span style="color: #0000ff">="action.FirstAction"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="timer"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="params"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">action</span><span style="color: #0000ff">&gt;</span></div>
<br />
<p><strong><span style="font-family: 宋体">三、通过配置参数调用</span>Action</strong><strong><span style="font-family: 宋体">的</span>setter</strong><strong><span style="font-family: 宋体">方法</span>(static-params)</strong></p>
<span style="font-size: 10.5pt; font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">static-params</span><span style="font-size: 10.5pt; font-family: 宋体">拦截器可以通过配置&lt;params&gt;标签来调用</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Action</span><span style="font-size: 10.5pt; font-family: 宋体">类的相应的</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">setter</span><span style="font-size: 10.5pt; font-family: 宋体">方法，static-params拦截器对应的类是com.opensymphony.xwork2.interceptor.StaticParametersInterceptor。<br />
&nbsp;&nbsp;&nbsp; 下面配置代码演示了如何使用static-params拦截器：</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'"><br />
<br />
<br />
</span>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">&lt;</span><span style="color: #800000">action&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="first"</span><span style="color: #ff0000">&nbsp;class</span><span style="color: #0000ff">="action.FirstAction"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="timer"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">param&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="who"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">比尔</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">param</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="params"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="static-params"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">action</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span></div>
<br />
<p style="text-indent: 21.75pt"><span style="font-family: 宋体">如果</span>first<span style="font-family: 宋体">动作使用上面的配置，在访问</span>first<span style="font-family: 宋体">动作时，</span>Struts2<span style="font-family: 宋体">会自动调用</span>setWho<span style="font-family: 宋体">方法将&#8220;比尔&#8221;作为参数值传入</span>setWho<span style="font-family: 宋体">方法。</span></p>
<p><strong><span style="font-family: 宋体">四、使用拦截器栈</span></strong></p>
<span style="font-size: 10.5pt; font-family: 宋体">为了能在多个动作中方便地引用同一个或几个拦截器，可以使用拦截器栈将这些拦截器作为一个整体来引用。拦截器栈要在</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">&lt;package&gt;</span><span style="font-size: 10.5pt; font-family: 宋体">标签中使用</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">&lt;interceptors&gt;</span><span style="font-size: 10.5pt; font-family: 宋体">和子标签</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">&lt;interceptor-stack&gt;</span><span style="font-size: 10.5pt; font-family: 宋体">来定义。代码如下：</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'"><br />
</span>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">&lt;</span><span style="color: #800000">package&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="demo"</span><span style="color: #ff0000">&nbsp;extends</span><span style="color: #0000ff">="struts-default"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptors</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-stack&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="mystack"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="timer"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="logger"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="params"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="static-params"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">interceptor-stack</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">interceptors</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">action&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="first"</span><span style="color: #ff0000">&nbsp;class</span><span style="color: #0000ff">="action.FirstAction"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">param&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="who"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">比尔</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">param</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="mystack"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">action</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">package</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span></div>
&nbsp;<br />
可以象使用拦截器一样使用拦截器栈，如上面代码所示。
<img src ="http://www.blogjava.net/henry1451/aggbug/208521.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/henry1451/" target="_blank">henry1451</a> 2008-06-17 09:55 <a href="http://www.blogjava.net/henry1451/articles/208521.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>