Struts2.0第04章Interceptor_第1页
Struts2.0第04章Interceptor_第2页
Struts2.0第04章Interceptor_第3页
Struts2.0第04章Interceptor_第4页
Struts2.0第04章Interceptor_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、.第四章 InterceptorInterceptor(拦截器)顾名思义就是在某个事件发生之前将其拦截,并插入相应的处理过程。从这点上来看,拦截器类似于在Servelet规范中定义的Filter,但是Struts2的拦截器完全独立于Servelet的Filter,而且两者有着截然不同的实现。Interceptor将很多通用的功能从Action中独立出来,大大减少了Action中重复的代码量,通过组装Interceptor可以使得通用的逻辑按照顺序执行,并且当业务逻辑顺序发生变化的时候也不需要重新编写代码,只需重新组装Interceptor即可,从而降低web应用的耦合性。在开发Web应用的过程

2、中,会碰到很多可以复用的模块,如果不采取任何策略,无疑会增加应用的重复代码量。Interceptor就是Struts2对这些可复用的应用模块加以管理的策略。通过Interceptor可以把通用的模块从Action中提取出来,供应用中的其它Action应用,甚至是供其它项目复用。4.1 Interceotor基础对于拦截器而言,最主要就是要清楚拦截器在什么时候开始被调用,以及Struts2中是如何实现拦截器,最后还要清楚Struts2中自带的拦截器有哪些,只有了解这些,才可以为以后使用拦截器打下基础。4.1.1 Interceptor何时调用让我们来看看Interceptor到底在什么时候被调用

3、,又是如何被调用。首先让我们来分析com.opensymphony.xwork2.DefaultActionInvocation源代码看看一般的Action调用流程,注意下面的代码片断。DefaultActionInvoation.java/*省略其他方法*/ public String invoke() throws Exception if (executed) throw new IllegalStateException(Action has already executed); if (interceptors.hasNext() InterceptorMapping interce

4、ptor = (InterceptorMapping) interceptors.next(); resultCode = interceptor.getInterceptor().intercept(this); else resultCode = invokeActionOnly(); /*省略语句*/ 在执行Action之前,Struts2会检查Action是否配置有拦截器,如果有,遍历所有拦截器并且执行之,如果对应的Action没有配置拦截器,那么Struts2将只执行Action。但是似乎并没有看到Action和Interceptor的执行的先后次序,别着急,让我们看看其它的代码里有

5、没有关于Interceptor的执行先后次序。Xwork的拦截器都必须实现Interceptor接口,但是实际上大部分的拦截器都是通过继承抽象类AbstractInterceptor实现拦截器的功能。下面来了解下AbstractInterceptor类的具体代码。AbstractInterceptor.javapackage erceptor;import com.opensymphony.xwork2.ActionInvocation;public abstract class AbstractInterceptor implements

6、 Interceptor public void init() public void destroy() public abstract String intercept(ActionInvocation invocation) throws Exception;在这个抽象类中没有实现任何方法,就是一个简单Interceptor接口的实现。那么拦截器要在Action之前执行,那么只有在继承这个类时,通过实现它的抽象方法intercept()来完成拦击器的功能。也就是说在intercept()方法中会先执行拦截器想要完成的任务,然后再转向Action执行,一般函数最后会加上这句代码:Strin

7、g result = invocation.invoke();通过上面的介绍,不难发现,Interceptor的本质也是一个Action,毕竟其产生的目的就是为了提高Action代码的复用性,降低Action的耦合性。但是Interceptor又是一种特殊的Action,因为其执行于指定Action或之前,或之后完成可复用的模块化业务逻辑。Interceptor能够拦截Action的执行,它的出现使得开发者能够在Action执行之前或者之后执行一段业务逻辑。它们同时也可以阻止Action的执行,使得开发者对一段通用的业务逻辑进行封装,然后用在其它地方。下面通过对Interceptor的源代码中

8、的类和接口的展示,希望能够使读者对Interceptor的本质有更深一层次的认识。4.1.2 Interceptor接口拦截器是一个Struts2框架很好的特性,它的使用十分灵活,同时框架为了满足特定的需要实现了一些特定的API,用户可以根据自己的需要选用。表4-1 Interceptor提供的预定义接口Interceptor定义的接口描述Interceptorinterceptor 是采用 interceptor 模式的一种无状态类NoParameters这个接口通常由不需要参数附加的Action实现ParameterNameAware这个接口通常由需要参数附加的Action实现PreRes

9、ultListener实现这个接口可以获得一个在Action之后但是结果之前的回调n Interceptor:是所有拦截器必须实现的一个接口。n NoParameters:这个标记接口应该由那些不想要任何参数附加的Action来实现,这种情况通常是这样的,用户在使用Action标签,不想框架附加任何参数给次Action,而是想要手动的来设置这些参数。n ParameterNameAware:这个接口通常由那些需要参数附加的Action实现,通常和ParametersInterceptor配合起来实现参数的附加,例如Action可能有这样一份参数的白名单和黑名单,前者列出的参数是允许用户设置的,

10、而后者列出的则拒绝用户的设置。n PreResultListener:实现这个接口的Action可以获得一个在Action执行之后但是结果执行之前的回调。4.1.3 Interceptor相关类在进行Interceptor编写的时候,同Action的编写一样,Struts2也提供了一些框架支持的类,这些类的使用,可以大大便利我们进行相关的拦截器的开发。读者可以在实际的应用中根据自己需要使用这些类。表4-2 Interceptor 提供的相关类类描述AbstractLifecycleInterceptor提供了before(),after() 以及result之前的拦截AliasIntercep

11、tor为类似的Action 的类似参数提供别名服务AroundInterceptor提供了before(),after() 拦截ChainingInterceptor将值栈中所有的对象拷贝到当前对象,当前对象实现unchainable()接口的除外ConversionErrorInterceptor如果Action执行了ValidationAware()接口,那么将所有转换错误添加到域错误表DefaultWorkflowInterceptor在允许ActionChain继续执行之前完成一些基本的操作如校验ExceptionHolder对Exception的简单封装,方便使用ExceptionM

12、appingInterceptor次拦截器是异常处理的核心I18nInterceptor设置ActionRequest国际化的本地信息LoggingInterceptor记录Action执行的日志拦截器MethodFilterInterceptor可以包含和排除一些方法执行的拦截器ModelDrivenInterceptor观察modelDriven的Action执行情况并将其添加到值栈ParameterFilterInterceptor参数过滤的拦截器ParametersInterceptor将所有参数设置到值栈PrefixMethodInvocationUtil一个执行一些固定方法的工具类

13、PrepareInterceptor调用实现了preparable接口方法的Action的prepare()方法TimerInterceptor记录以秒为单位的时间日志仔细的分析这些类可以发现,其涉及了Struts2 Interceptor的全部。类的功能涉及了Action执行的方方面面。几乎在Action执行的任何时刻,都可以找到适合的拦截器截断Action的执行。使其完成想要的业务逻辑功能。灵活的运用这些类,那么我们几乎就掌握了Action执行的每一个方面,就能够对Action的执行进行精准的控制。4.2使用预定义的InterceptorStruts2预先设计了很多通用性很强的Interc

14、eptor供用户使用。灵活的使用这些拦截器,不仅可以更好的设计更具通用性的业务模块,而且可以增加Web应用的可测试性,使得Web应用的开发和维护变得更为便捷。4.2.1预定义Interceptor类拦截器的使用,可以抽取系统的各个方面的可复用代码。当然在实际的开发中可能有一些模块是经常使用到的,或者说是每一个进行Web应用开发的程序员都要使用到的,Struts2考虑到了这样的情况,并且预先抽取了这些复用性很强的模块。那么Struts2自带的拦截器的配置在struts-default.xml都有配置,在struts-2.0.9-all.zip压缩包的src目录下。通过搜索,在路径struts-2

15、.0.9-allstruts-2.0.9srccoresrcmainresources下可以找到这个文件,打开之后下面是其关于拦截器配置部分的代码:struts-default.xml/*省略其他配置语句*/ /*省略其他配置语句*/配置文件中指出了每个自带拦截器对应的类以及它们的名字,那么它们具体的功能可以通过阅读类的源代码知道,表4-3中提供一些常用拦截器实现的功能表4-3 Struts2框架预定义的拦截器名称描述chain将参数从一个Action复制到另一个Actioncomponent为Action应用IoC的逻辑处理conversionError如果出现类型转换错误,则增加对应字段错

16、误execAndWait生成一个独立的线程来执行ActionfileUpload设置上传文件为Action文件logger记录Action执行的起始时间model-driven将Action模型压入值栈params将HTTP参数应用于Actionprepare调用Action的prepare()方法servlet-config提供对通用HTTP对象的访问static-params将Action映射设定的参数应用到Action实例中timer控制Action的定时执行token防止表单重复提交的基本实现token-session防止表单重复提交的高级实现validation校验Action中的字

17、段值workflow如果发生错误则自动返回INPUT这个返回类型例如校验拦截器validation这个拦截器就对表单的校验提供了极大的便利,这一点在以后的章节中,将继续讲解。为了方便初学者的使用,Struts2框架还预定义了若干拦截器栈,所谓的拦截器栈就是将拦截器一个接一个的组装起来,这些装配好的拦截器栈往往有着特殊的用途,让我们大致了解一下这些栈。看看这些组合在一起的拦截器又将为开发带来什么样的便捷特性。拦截器栈的相关配置也是在struts-default.xml实现的,下面是这个文件中关于拦截器栈的配置部分。struts-default.xml/*省略其他配置语句*/ /*省略其他配置语句

18、*/上面的拦截器栈的配置只是所有拦截器栈的一部分,读者可以自己找到这个文件,找出所有栈的配置。表4-4中列出部分常用拦截器栈的功能。表4-4 Struts2 框架预定义的拦截器栈名称描述defaultStack基本的拦截器栈validationWorkflowStack配置了validation和workflow拦截的栈fileUploadStack配置了fileupload的拦截器栈componentStack配置了反转控制的拦截器栈modelDrivenStack配置了modelDriven的拦截器栈chainStack配置了chain的拦截器栈execAndWaitStack配置了exe

19、cAndWait的拦截器栈completeStack配置了所有拦截器的拦截器栈这里面的拦截栈其实是在实际的开发过程中经常要用到的,例如文件上传拦截栈,这个拦截栈的定义,使得在开发有关文件上传的组件的时候,就不必考虑文件上传的细节了,而是可以把精力集中在业务逻辑上,又如拦截栈,这个框架定义的拦截栈,是用户在使用框架定义的拦截器,不可或缺的一个部分。4.2.2 LoggingInterceptor示例这一节我们使用框架为我们定义的日志拦截器(LoggingInterceptor)为我们的Action记录日志。框架实现的这个拦截器的功能很简单,下面让首先来看看这个例子。LoggingAction.j

20、avapackage example;import com.opensymphony.xwork2.Action;public class LoggingAction implements Actionpublic String execute()delay();return SUCCESS;private void delay()for ( int i=0;i10000;i+);这个Action简单的做一个延迟,(后面为了计算Action的执行时间),然后转向success页面。它的确是够简单,因为这里要重点演示的是Interceptor。struts.xml 在这个文件里面,我们配置了一个

21、Struts2框架预定义的日志拦截器,名称为logger然后在action里面引用了这个拦截器,指示这个拦截器和这个Action装配,对这个Action起作用。这样当Struts2框架发现了这个装配的拦截器之后,在调用Action之前就会去调用这个拦截器,从而达到预期的目的。这个例子的目录图如图4-1所示:图4-1例子的完整目录如果配置正确的话,部署到Tomcat下,然后在浏览器地址栏输入:http:/localhost:8080/Logging/logging.action页面会有一个“result null not found”的信息,是因为我们没有配置返回页面,但是可以在控制台得到这样的

22、输出:图4-2 LoggingAction的对应输出可以看到,在控制器执行的前后,日志拦截器分别截获了控制器的执行,并输出了对应的日志新日,如“/logging”这个Interceptor好像完成的工作也并不是很多,让我们看看它到底是如何工作的。该文件在erceptor.LoggingInterceptor中。LoggingInterceptor.java/省略导入包public class LoggingInterceptor extends AbstractInterceptor private static final Log log

23、 = LogFactory.getLog(LoggingInterceptor.class); private static final String FINISH_MESSAGE = Finishing execution stack for action ; private static final String START_MESSAGE = Starting execution stack for action ; public String intercept(ActionInvocation invocation) throws Exception logMessage(invoc

24、ation, FINISH_MESSAGE); /记录结束信息 String result = invocation.invoke(); logMessage(invocation, START_MESSAGE);/记录开始信息 return result; private void logMessage(ActionInvocation invocation, String baseMessage) if (log.isInfoEnabled() StringBuffer message = new StringBuffer(baseMessage); String namespace =

25、invocation.getProxy().getNamespace(); if (namespace != null) & (namespace.trim().length() 0) message.append(namespace).append(/); message.append(invocation.getProxy().getActionName(); (message.toString(); 这个是框架实现的一个日志拦截器,通过对源代码的分析,用户可以在编写自己的模块的时候可以参考Struts2的源代码,比如下面的记时拦截器就是参考了这里的日志拦截器。通过对源代码

26、的分析,我们还可以了解到拦截器的具体实现方式,并编写自己的拦截器去实现Interceptor接口。参考源代码,发现原来也可以通过继承这样的基类AbstractInterceptor来实现interceptor接口从而实现自己的拦截器,同时这样做一个好处就是代码的逻辑很清楚,在执行Action之前,首先执行logMessage()函数在控制台有一个输出,在Action执行结束后又有一个信息输出,在两个信息输出之间通过ActionInvocation类可以获得当前要执行的Action有关的信息,然后执行Action相关操作。掌握了拦截器的这几个方面那么用户就可以对拦截器的执行进行粒度很小的控制。4

27、.3使用自定义的Interceptor阅读了框架的Logging拦截器的源代码,可以发现一个拦截器的实现也很简单,下面模仿框架的日志拦截器设计一个记时拦截器,这个拦截器不仅记录Action的执行时间,而且同时还输出执行日志。大致可以分为一下几个步骤:1. 定义自己的拦截器逻辑2. 配置自己的拦截器3. 将自定义的拦截器装配到对应的控制器进行拦截4. 运行实例查看效果4.3.1自定义Interceptor的配置Interceptor的配置大同小异,注意struts.xml中的粗体显示的片断。struts.xml 这些地方就是用户在框架中配置拦截器的地方。从上面的配置文件的代码我们也可以看出,首先

28、我们是先定义了一个自定义的拦截器,然后在对应的要使用的控制器中使用了这个拦截器,通过这样的配置,拦截器和控制器的装配工作就完成了,下面看看这个拦截器的具体内容。4.3.2实现自己的Interceptor本小节使用一个自定义的Interceptor,对Action执行前和执行后进行计时,并且在Action执行结束后向控制台输出对应的日志信息。同时在Action执行完成之后使用这两个时间计算出整个Action的运行时间。LogAndTime.javapackage example;import mons.logging.Log;import mons.logging.LogFactory;impo

29、rt com.opensymphony.xwork2.ActionInvocation;import erceptor.AbstractInterceptor;SuppressWarnings(serial)public class LogAndTime extends AbstractInterceptor private static final Log log = LogFactory.getLog(LogAndTime.class); private static final String FINISH_MESSAGE = Syst

30、em Administrator Finishing execution stack for action ; private static final String START_MESSAGE = System Administrator Starting execution stack for action ; /设定了一些输出信息字符串 private long startTime; /声明了开始时间 private long executeTime; / 声明了执行时间 private void logMessage(ActionInvocation invocation, Strin

31、g baseMessage) if (log.isInfoEnabled() StringBuffer message = new StringBuffer(baseMessage); String namespace = invocation.getProxy().getNamespace(); if (namespace != null) & (namespace.trim().length() 0) message.append(namespace).append(/); message.append(invocation.getProxy().getActionName(); log.

32、info(message.toString(); /记录日志信息 Overridepublic String intercept(ActionInvocation invocation) throws Exception logMessage(invocation, START_MESSAGE); startTime = System.currentTimeMillis(); String result = invocation.invoke(); logMessage(invocation, FINISH_MESSAGE); executeTime = System.currentTimeM

33、illis() - startTime; /执行时间,等于当前时间-开始时间。当前时间是控制器的Execute()方法执行后 String TIMESTRING=The Action: +invocation.getProxy().getActionName()+has executed +executeTime+ MilliSeconds;/设定时间信息 System.out.println(TIMESTRING); /获得当前的执行时间付给开始执行时间return result;在这个interceptor的实现里面,使用了框架对Interceptor的支持类。使用这些支持类的好处是:这样

34、可以更加方便,便捷的构建自己想要的拦截器。在这个例子中在Action执行的前后都对Action进行了拦截,在Action执行前,将其拦截,记录下此时的时间,然后输出一行控制信息到控制台,表明已经执行到Action之前。然后Interceptor会唤醒Action继续执行,执行完之后,Interceptor会继续将Action捕获,获得此时的时刻,和执行开始前的一比较,便得出了整个Action执行所耗费的时间,同时向控制台输出信息表明已经执行完这个Action了。那么再看下这个例子的目录,如图4-3所示:图4-3例子的完整目录如果配置无误,在浏览器地址栏输入:http:/localhost:80

35、80/Logging/logging.action 那么将得到下面的结果:图4-4自定义拦截器的输出结果首先要注意的一点就是这里的所有的控制信息都是在标准输出(控制台)输出的,而不是在相应的页面。本例中的结果是输出在eclipse的控制台的。从输出的结果可以看出编写的拦截器成功的执行了,首先在Action执行前,拦截器记录当前的时间并输出日志”.starting execution.”然后在Action执行之后,又输出日志信息”.fininshing execution.”同时记录当前的执行时间,并计算除整个Action的执行时间(执行后-执行前)。输出执行时间。4.4 Interceptor

36、应用实例在前面学习的知识,在这一节将完成一个综合的Interceptor例子。这个例子中既会用到自定义的拦截器也会使用Struts2提供的预定义的拦截器。完成页面等待的效果,由于某个Action要执行较长的一段时间,在页面跳转到另一个页面之前,先会进入一个等待的页面,等待页面装载。其实在互联网上这种页面等待的效果会经常被用到,现在就借用Struts2的拦截器来实现这个功能。自定义拦截器部分将会使用第二章最后小节的自定义拦截器,即GreetingInterceptor。为了达到页面等待的效果,要借助Struts2提供execAndWait拦截器,这个拦截器的功能在前面的表中可以查到,就是生成一个独立的线程来执行Action。为什么选择这个拦截器,将会在下面的源码分析部分详细解释。有了这两个拦截器就可以完成这个实例。整个流程是这样的:输入访问地址之后,首先会出现一个等待的页面,大概等待10秒之后,跳入一个输入页面,用户输入姓名提交之后,根据当前的时间生成特定的问候语。为了让读者能够正确阿使用Struts2提供e

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论