struts2之拦截器详解

article/2025/9/22 1:13:10

文章目录

  • 1 拦截器
    • 1.1 拦截器是什么
      • 1.1.1 Struts2的拦截器的实现原理
    • 1.2 拦截器的优点是什么
    • 1.3 预定义拦截器
      • 1.3.1 预定义拦截器
        • 1.3.1.1 params拦截器
        • 1.3.1.2 timer拦截器
        • 1.3.1.3 logger拦截器
        • 1.3.1.4 其他默认拦截器
      • 1.3.2 拦截器配置说明
      • 1.3.3 拦截器的调用顺序
      • 1.3.4 全局拦截器的配置
      • 1.3.5 使用execAndWait拦截器
    • 1.4 自定义拦截器
      • 1.4.1 自定义基础拦截器
        • 1.4.1.1 实现Interceptor接口
        • 1.4.1.2 继承AbstractInterceptor类
        • 1.4.1.3 继承MethodFilterInterceptor类
      • 1.4.2 自定义拦截器示例
      • 1.4.3 自定义登录检查拦截器
      • 1.4.4 自定义logger拦截器

1 拦截器

1.1 拦截器是什么

拦截器(Interceptor)是Struts2最强大的特性之一,它是一种可以让你在Action执行之前和Result执行之后进行一些功能处理的机制。来回顾一下官方给出的Struts2系统架构图中关于拦截器的部分,如下图所示:
请添加图片描述
这个图清晰的描述出了拦截器的运行地位,就是用来负责在Action执行之前和Result执行之后处理一些功能的类。也就是说,上图示意了有3个拦截器的类,分别是Interceptor1Interceptor2Interceptor3,它们分别执行不同的功能处理,而运行的时机就是在Action执行之前和Result执行之后。

1.1.1 Struts2的拦截器的实现原理

拦截器方法都是通过代理的方式来调用的。Struts 2的拦截器实现相对简单。当请求到达Struts 2ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list),最后一个一个地调用列表中的拦截器。事实上,我们之所以能够如此灵活地使用拦截器,完全归功于动态代理的使用。动态代理是代理对象根据客户的需求做出不同的处理。对于客户来说,只要知道一个代理对象就行了。
Struts2中,拦截器是如何通过动态代理被调用的呢?当Action请求到来的时候,会由系统的代理生成一个Action的代理对象,由这个代理对象调用Actionexecute()或指定的方法,并在struts.xml中查找与该Action对应的拦截器。如果有对应的拦截器,就在Action的方法执行前(后)调用这些拦截器;如果没有对应的拦截器则执行Action的方法。其中系统对于拦截器的调用,是通过ActionInvocation来实现的
在这里插入图片描述

1.2 拦截器的优点是什么

拦截器能实现很多功能,这里先撇开具体功能不谈,从设计和程序结构上来看看,拦截器有些什么优点:

  • 简化Action的实现
    拦截器能把很多功能从Action中独立出来,大量减少了Action的代码。
  • 功能更单一
    按照上面的描述,把功能从Action中分离出来,分散到不同的拦截器里面,这样每个拦截器的功能,以及Action本身的功能都更单一了。
  • 通用代码模块化
    Action中把功能分离出来,放到拦截器去实现,这样能把一些在多个Action中通用的代码进行模块化,封装在一个或几个拦截器里面。
  • 提高重用性
    当通用的功能代码被封装在拦截器里面,实现了代码模块化过后,就可以对不同的Action,根据功能需要,来配置相同的拦截器了。这大大提高了拦截器所实现的功能的重用性,还变相实现了装配式和可插拔式的体系结构,使得整个系统结构变得更灵活。
  • 实现AOP
    Struts2通过拦截器实现了AOP(面向切面编程),AOP是一种编程范式,它是一种分散实现关注功能的编程方法。拦截器将通用需求功能从不相关的Action之中分离出来,能够使得很多Action共享同一个行为,一旦行为发生变化,不必修改很多Action,只要修改这个行为就可以了。

备注:有web开发经验的朋友看到这里,一定会说,这不就类似于Filter么?过滤器也可以做这些事啊。没错,拦截器和Filter确实有相似之处,但是Interceptor相比于Filter具有更强大的功能,比如拦截器与Servlet的API无关,比如拦截器可以访问到值栈等等。
在之前的示例中,在运行Actionexecute方法的时候,会发现Action的属性已经有值了,而且这些值跟用户请求中的参数值时一样的。这说明,在execute方法之前,有人偷偷的把用户请求中的参数值和Action的属性做了一个对应,并且把请求中的参数赋值到了Action的属性上,这个功能就是由缺省配置的拦截器来实现的。这些缺省配置的拦截器,称之为预定义的拦截器。我们还可以编写自己需要的拦截器类,称之为自定义拦截器,它的具体功能就根据需要,由我们自行实现了。

1.3 预定义拦截器

1.3.1 预定义拦截器

Struts2有默认的拦截器配置,也就是说,虽然我们没有主动去配置任何关于拦截器的东西,但是Struts2会使用默认引用的拦截器。由于Struts2的默认拦截器声明和引用都在这个Struts-default.xml里面,因此我们需要到这个文件的struts-default包里去看一下。定义如下:

<interceptors>  
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>  
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/> 
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>              
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>             
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>              <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>               <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />               <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />              <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />            <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>              <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>              <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>              <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>             <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>              <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>              <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>              <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>             <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>             <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>            <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>             <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>      <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/> <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>              <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>              <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>              <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>              <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>              <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />              <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />              <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />              <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />              <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />              <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />              <interceptor name="deprecation" class="org.apache.struts2.interceptor.DeprecationInterceptor" />  <!-- Basic stack -->           
<interceptor-stack name="basicStack">                  <interceptor-ref name="exception"/>                  <interceptor-ref name="servletConfig"/>                  <interceptor-ref name="prepare"/>                  <interceptor-ref name="checkbox"/>                  <interceptor-ref name="multiselect"/>                  <interceptor-ref name="actionMappingParams"/>                  <interceptor-ref name="params">                      <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>                  </interceptor-ref>                  <interceptor-ref name="conversionError"/>                  <interceptor-ref name="deprecation"/>              
</interceptor-stack>  <!-- Sample validation and workflow stack -->             
<interceptor-stack name="validationWorkflowStack">                  <interceptor-ref name="basicStack"/>                 <interceptor-ref name="validation"/>                  <interceptor-ref name="workflow"/>              
</interceptor-stack> <!-- Sample file upload stack -->             
<interceptor-stack name="fileUploadStack">                  <interceptor-ref name="fileUpload"/>                  <interceptor-ref name="basicStack"/>            
</interceptor-stack> <!-- Sample model-driven stack  -->              
<interceptor-stack name="modelDrivenStack">                  <interceptor-ref name="modelDriven"/>                  <interceptor-ref name="basicStack"/>              
</interceptor-stack>  <!-- Sample action chaining stack -->              
<interceptor-stack name="chainStack">                  <interceptor-ref name="chain"/>                  <interceptor-ref name="basicStack"/>             
</interceptor-stack>  <!-- Sample i18n stack -->             
<interceptor-stack name="i18nStack">                 <interceptor-ref name="i18n"/>                 <interceptor-ref name="basicStack"/>              
</interceptor-stack> <interceptor-stack name="paramsPrepareParamsStack">                  		
<interceptor-ref name="exception"/>                  
<interceptor-ref name="alias"/>                 
<interceptor-ref name="i18n"/>                  
<interceptor-ref name="checkbox"/>               
<interceptor-ref name="multiselect"/>                 
<interceptor-ref name="params">                 <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>                
</interceptor-ref>              
<interceptor-ref name="servletConfig"/>                 
<interceptor-ref name="prepare"/>                
<interceptor-ref name="chain"/>                
<interceptor-ref name="modelDriven"/>               
<interceptor-ref name="fileUpload"/>               
<interceptor-ref name="staticParams"/>              
<interceptor-ref name="actionMappingParams"/>                
<interceptor-ref name="params">                     
<param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*
</param>              
</interceptor-ref>                
<interceptor-ref name="conversionError"/>                 
<interceptor-ref name="validation">                    
<param name="excludeMethods">input,back,cancel,browse</param>               
</interceptor-ref>          
<interceptor-ref name="workflow">                    
<param name="excludeMethods">input,back,cancel,browse</param>                
</interceptor-ref>             
</interceptor-stack><interceptor-stack name="defaultStack">                
<interceptor-ref name="exception"/>                 
<interceptor-ref name="alias"/>              
<interceptor-ref name="servletConfig"/>              
<interceptor-ref name="i18n"/>               
<interceptor-ref name="prepare"/>                
<interceptor-ref name="chain"/>                 
<interceptor-ref name="scopedModelDriven"/>                 
<interceptor-ref name="modelDriven"/>             
<interceptor-ref name="fileUpload"/>                 
<interceptor-ref name="checkbox"/>             
<interceptor-ref name="multiselect"/>            
<interceptor-ref name="staticParams"/>                
<interceptor-ref name="actionMappingParams"/>               
<interceptor-ref name="params">                   
<param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*
</param>            
</interceptor-ref>
<interceptor-ref name="conversionError"/>             
<interceptor-ref name="validation">                    
<param name="excludeMethods">input,back,cancel,browse</param>               
</interceptor-ref>      
<interceptor-ref name="workflow">                    
<param name="excludeMethods">input,back,cancel,browse</param>                 
</interceptor-ref>                
<interceptor-ref name="debugging"/>                 
<interceptor-ref name="deprecation"/>            
</interceptor-stack><interceptor-stack name="completeStack">                 
<interceptor-ref name="defaultStack"/>            
</interceptor-stack> 
<interceptor-stack name="executeAndWaitStack">                
<interceptor-ref name="execAndWait">               
<param name="excludeMethods">input,back,cancel</param>                 
</interceptor-ref>               
<interceptor-ref name="defaultStack"/>              
<interceptor-ref name="execAndWait">                 
<param name="excludeMethods">input,back,cancel</param>                 
</interceptor-ref>       
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="defaultStack"/>

1.3.1.1 params拦截器

这个拦截器是必不可少的,因为就是由它偷偷的把请求参数设置到相应的Action的属性去的,并自动进行类型转换。
staticParams拦截器
struts.xml配置文件里定义的Action参数,设置到对应的Action实例中,Action参数使用<param>标签,是<action>标签的子元素。struts.xml的示例如下:

<action name="helloworldAction" class="cn.javass.action.action.HelloWorldAction">  <param name="account">test</param>  
</action> 

这要求Action中一定要有一个account的属性,并有相应的getter/setter方法。运行的时候,Actionaccount属性在初始化过后,会接到这里的赋值test
注意params拦截器和staticParams拦截器都会为Action的属性赋值,如果碰到了都要赋同一个值呢,比如request里面有account参数,而struts.xml中也有account参数,最终的值是谁?其实是Action初始化过后,就会把struts.xml中配置的数据设置到Action实例中相应的属性上去。然后,把用户请求的数据设置到Action实例中相应的属性上去。很明显最后的值是用户请求中account的数据。

1.3.1.2 timer拦截器

该拦截器可以记录ActionInvocation余下部分执行的时间,并做为日志信息记录下来,便于寻找性能瓶颈。也就是说,该拦截器可以记录Action运行的时间。

1.3.1.3 logger拦截器

在日志信息中输出要执行的Action信息 ,这样,在调试的时候,就能很快的定位到这个对应的Action

1.3.1.4 其他默认拦截器

  1. 异常处理拦截器(exception
<interceptorname="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
  1. 别名拦截器(aliasInterceptor
    该拦截器主要作用是将一个参数别名成为另一个参数,在不同的action之间相似的参数(但是不同名)扮演着胶水的角色。该拦截器在action链中有很大的作用。
  2. 配置拦截器(servletConfig
    该拦截器设置基于action接口实现的action属性。比如说,一个action实现{@link ParameterAware} 接口,那么action上下文的参数map将会被设置到action中。该拦截器设计成如果action需要获取基于servlet的参数,则设置所有的属性到action中,包括servlet context,session等。
  3. 国际化拦截器(i18n
  4. 预处理拦截器(prepare
    action 方法执行前,调用prepare方法。(只对实现了prepareAble接口的aciton有效)。
  5. action链拦截器(chain
    能将所有实例的所有属性都拷贝到当前执行的对象的valueStack中。除非该对象实现了Unchainable接口。该连接器同action返回类型为chain联合使用。
  6. debug拦截器(debugging
  7. scopedModelDriven:该拦截器只对实现了ScopedModelDriven接口的action实例起作用。
  8. modelDriven类:com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor
    该拦截器同上面原理一样,是只对实现了ModelDriven接口的action起作用
  9. 文件上传拦截器(fileUpload
    类:org.apache.struts2.interceptor.FileUploadInterceptor
  10. checkBox处理拦截器(checkbox
    类:org.apache.struts2.interceptor.CheckboxInterceptor
    此拦截器是针对checkbox表单控件的。
  11. 多选拦截器(multiselect
    类:org.apache.struts2.interceptor.MultiselectInterceptor
    checkbox一样,如果没有选中,则设置默认的值。
  12. 静态参数拦截器(staticParams
    类:com.opensymphony.xwork2.interceptor.StaticParametersInterceptor
    该拦截器将action中配置的静态参数添加到action中。如果action实现了Parameterizable接口,那么,一个map的静态参数也将会设置到action中。

1.3.2 拦截器配置说明

<interceptor>元素用来定义一个拦截器,这里仅仅是一个定义,还没有任何一个Action来引用它。里面的name属性作为唯一标志,而class属性就是这个拦截器的实现类。拦截器的实现类都应该是com.opensymphony.xwork2.interceptor.Interceptor这个接口的实现类。
<interceptor-stack>定义了一个拦截器栈,这个栈中可以引用其他已经定义好的拦截器。拦截器栈简化了动作类Action在引用拦截器时的操作。
因为大多数动作类Action在引用拦截器的时候都不会仅仅引用一个拦截器,而是引用一组拦截器,而多个动作类Action大概又会引用同一组拦截器,这时候,为了引用的方便,可以把多个拦截器组合成一个拦截器栈。Action在引用的时候,只需要引用这个拦截器栈就可以了,而不是引用每一个拦截器。下面看一下struts-2.1.dtd对于<action>元素的定义:
<!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>

action元素后面出现的interceptor-ref子元素后面用*来修饰,这说明一个action元素可以有不限个数的interceptor-ref子元素。那么在<action>元素中,如何使用<interceptor-ref>子元素呢?其实很简单,只需要在<action>元素中,配置需要的<interceptor-ref>子元素就可以了,<interceptor-ref>子元素里面配置需要使用的拦截器的名称,比如:

<action name="helloworldAction" class="cn.javass.action.action.HelloWorldAction">  <param name="account">test</param>  <result>/s2impl/welcome.jsp</result>  <interceptor-ref name="staticParams"/>  <interceptor-ref name="defaultStack"/>  
</action>  

<interceptor-ref>子元素中的name,不仅仅可以是一个已经定义好的拦截器的名称,还可以是一个已经定义好的拦截器栈的名称。上面的示例,就引用了一个拦截器和一个拦截器栈。
<default-interceptor-ref>在包上声明包内所有的Action都使用的拦截器
先看一下struts-2.1.dtd对于<package>元素的定义:

<!ELEMENT package (result-types?, interceptors?, default-interceptor-ref?, default-action-ref?, default-class-ref?, global-results?, global-exception-mappings?, action*)>  

其实,在配置自己的package的时候所扩展的struts-default包里面,就已经定义了一个<default-interceptor-ref>,在Struts-default.xml中定义的struts-default包内,有如下定义:
<default-interceptor-ref name="defaultStack"/>
正是因为有这个定义,我们都没有主动去配置拦截器,但实际上,是有拦截器在运行并执行很重要的工作,只不过是使用的默认的拦截器,我们不知道罢了。

1.3.3 拦截器的调用顺序

在学习了预定义拦截器的配置使用之后,接下来看看<action>元素引用拦截器的调用顺序。在拿到一个动作类的声明<action>元素后,如何找到它引用的拦截器呢?

  • 首先,要找它自己有没有声明拦截器的引用,即<action>元素有没有<interceptor-ref>子元素,如果有,则不用继续再找,直接使用这些拦截器,如果没有,下一步。
  • 其次,找这个<action>所在的包有没有声明默认的拦截器引用,即<package>元素的<default-interceptor-ref>子元素, 如果有,则不用继续再找,直接使用这些拦截器,如果没有,下一步。
  • 最后,递归地寻找这个包的父包有没有声明默认的拦截器引用,直到找到有拦截器引用就为止。

特别注意:这三个地方的定义是覆盖的关系,什么意思呢?就是如果<action>里面声明了拦截器引用,那么就以它的为准,其他的定义就无效了。也即是<action>里面的拦截器引用声明会覆盖<package>里面的缺省拦截器声明,而<package>里面的缺省拦截器声明又会覆盖父包的<package>里面的缺省拦截器声明,以此类推。

1.3.4 全局拦截器的配置

<package name="helloworld"  extends="struts-default">  <interceptors>  <interceptor-stack name="myStack">  <interceptor-ref name="timer"/>  <interceptor-ref name="defaultStack"/>  </interceptor-stack>  </interceptors>  <default-interceptor-ref name="myStack"/>  <action name="helloworldAction" class="cn.javass.hello.struts2impl.action.HelloWorldAction"> <result name="toWelcome">/${folder}/welcome.jsp</result> <result name="input">/${folder}/login.jsp</result>   </action>  </package>  

1.3.5 使用execAndWait拦截器

使用execAndWait拦截器可以在等待较长时间的后台处理中增加等待页面。
struts.xml主要部分

<action name="test" class="actions.ActionDemo" method="queryall"><interceptor-ref name="defaultStack"/><interceptor-ref name="execAndWait">  <!-- 等待时间,执行时间没有超过此值,将不显示等待画面 (毫秒)--><param name="delay">1000</param><!-- 间隔检查时间,检查后台进程有没有执行完毕,如果完成了它就立刻返回,不用等到等待,用户不会看到等待画面 --><param name="delaySleepInterval">50</param>   </interceptor-ref><result name="wait">/wait.jsp</result><result name="success">/rs.jsp</result>
</action>

action主要部分

public String queryall(){for (int i = 0; i < 500000; i++) {System.out.println(i);}user = "你好";this.setListData();return Action.SUCCESS;
}

jsp页面取值部分(rs.jsp)

  List list =  (List)request.getAttribute("listall"); 取值OK

等待页面部分(wait.jsp)

<%@ page contentType="text/html; charset=GBK" language="java"errorPage=""%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv=Content-Type content="text/html;charset=gbk"><META HTTP-EQUIV="Refresh" content="2;url=<s:url includeParams="all"/>"/> <title> 正在查询,请稍等...</title>
<style type="text/css">
.query_hint{border:5px solid #939393;width:250px;height:50px;line-height:55px;padding:0 20px;position:absolute;left:50%;margin-left:-140px;top:50%;margin-top:-40px;font-size:15px;color:#333;font-weight:bold;text-align:center;background-color:#f9f9f9;
}
.query_hint img{position:relative;top:10px;left:-8px;}
</style>
</head><body><div id="query_hint" class="query_hint"><img src="http://files.cnblogs.com/ningvsban/waiting.gif" />正在查询,请稍<s:url includeParams="all"/>等...</div><!--<a href="<s:url includeParams="all" />"> 点这里 </a> 如果没有自动跳转请点击这里.-->
</body>
</html>

关于<meta http-equiv="refresh" content="0;url= "/>的几点说明:

  • 该句话用于页面定期刷新,如果加url的,则会重新定向到指定的网页,content后面跟的是时间(单位秒),把这句话加到指定网页的<head></head>里一般也用在实时性很强的应用中,需要定期刷新的页面,如新闻页面,论坛等,不过一般不会用这个
  • 对于wait.jsp中的<meta http-equiv="refresh" content="2;url=<s:url includeParams="all"/> "/>意思为:每隔2秒自动刷新定位到目标页面。
  • 对于<s:url includeParams="all"/>struts2的标签<s:url>

1.4 自定义拦截器

什么是自定义的拦截器,所谓自定义的拦截器,就是由我们自己定义并实现的拦截器,而不是由Struts2定义好的拦截器。虽然Struts2的预定义拦截器已经满足了大多数情况的需要。但在有些时候,我们可能会根据项目的实际需要而自定义一些拦截器,来实现一些特别的功能

1.4.1 自定义基础拦截器

1.4.1.1 实现Interceptor接口

Struts2里面,要实现自定义的拦截器是非常简单的,只要写一个实现Interceptor接口的类就可以了。也就是说,所有的拦截器都要实现
com.opensymphony.xwork2.interceptor.Interceptor接口,这个接口中定义如下:

public interface Interceptor extends Serializable {  void destroy();  void init();  String intercept(ActionInvocation invocation) throws Exception;  
} 

方法的基本说明如下:

  • init方法就类似于构造方法,用于初始化一些相关资源
  • destory方法类似于析构方法,用于释放资源
  • intercept方法,就是拦截器执行的处理方法,我们要实现的功能主要就写在这个方法里面。
    对于intercept方法,再说明几点:
    intercept方法中写invocation.invoke();,这句话的意思是继续运行拦截器后续的处理,如果这个拦截器后面还有拦截器,那么会继续运行,一直到运行Action,然后执行Result。如果intercept方法中没有写invocation.invoke();这句话,那就意味着对请求的运行处理到此为止,不再继续向后运行了,换句话说,后续的拦截器和Action就不再执行了。而是在这里返回Result字符串,直接去进行Result处理了。
    invocation.invoke();这句话之前写的功能,会在Action运行之前执行
    invocation.invoke();这句话之后写的功能,会在Result运行之后执行
    intercept方法的返回值就是最终要返回的Result字符串,这个只是在前面没有执行Result的时候才有效,也就是前面没有invocation.invoke();这句话的时候,这个返回值就相当于是最终要返回的Result字符串,然后才执行相应的Result处理。

1.4.1.2 继承AbstractInterceptor类

继承AbstractInterceptor类:无法通过<param name="includeMethods">拦截的方法</param>参数配置包含拦截的方法
通过<param name="excludeMethods">不拦截的方法</param>来控制拦截或不拦截的方法

public abstract class AbstractInterceptor implements Interceptor {
public void init() {
}
public void destroy() {
}
public abstract String intercept(ActionInvocation invocation) throws Exception;
}

1.4.1.3 继承MethodFilterInterceptor类

继承MethodFilterInterceptor类:可以通过includeMethodsexcludeMethods属性配置拦截不拦截的方法

public abstract class MethodFilterInterceptor extends AbstractInterceptor {
protected Set<String> excludeMethods = Collections.emptySet();
protected Set<String> includeMethods = Collections.emptySet();
....
}

1.4.2 自定义拦截器示例

先来个最简单的,就是在Action运行之前,和Result运行之后输出一点信息,当然,有实际功能需求的时候,就写成实际功能的处理代码了,示例代码如下:

package cn.javass.hello.struts2impl.action;import com.opensymphony.xwork2.ActionInvocation;  
import com.opensymphony.xwork2.interceptor.Interceptor;  public class MyInterceptor implements Interceptor{    public void destroy() {  System.out.println("MyInterceptor 销毁");  }     public void init() {  System.out.println("MyInterceptor 初始化");          }  public String intercept(ActionInvocation invocation) throws Exception {  System.out.println("在acton执行之前");  String result = invocation.invoke();  System.out.println("在Result运行之后");  return result;  }  
}  

可以看到,这个Interceptorinit方法和destroy方法只是输出了一句信息,它的intercept方法用来执行响应,在invocation.invoke();这句话之前和之后分别输出了一句信息。最后返回的result,就是invocation.invoke()的返回值。
HelloWorldAction这个类不用修改
需要到struts.xml里面配置拦截器的声明和引用,示例如下:

<package name="helloworld"  extends="struts-default">  <interceptors>  <interceptor name="testInteceptor" class="cn.javass.hello.struts2impl.action.MyInterceptor"/>  <interceptor-stack name="myStack">  <interceptor-ref name="timer"/>  <interceptor-ref name="testInteceptor"/>  <interceptor-ref name="defaultStack"/>  </interceptor-stack>  </interceptors>  <default-interceptor-ref name="myStack"/>  <global-results>  <result name="math-exception">/${folder}/error.jsp</result>  </global-results>  <global-exception-mappings>  <exception-mapping result="math-exception" exception="java.lang.ArithmeticException"/>  <exception-mapping result="math-exception" exception="java.lang.Exception"/>  </global-exception-mappings>  <action name="helloworldAction" class="cn.javass.hello.struts2impl.action.HelloWorldAction"> <result name="toWelcome">/${folder}/welcome.jsp</result> <result name="input">/${folder}/login.jsp</result>   </action>  </package>  

运行测试一下,后台输出:

在acton执行之前
用户输入的参数为===account=11,password=11111111111,submitFlag=login
在Result运行之后
2014-5-18 21:18:46 com.opensymphony.xwork2.interceptor.TimerInterceptor info
信息: Executed action [//helloworldAction!execute] took 152 ms.

1.4.3 自定义登录检查拦截器

在实际开发中,一个常见的功能要求是:有很多操作都需要登录后才能操作,如果操作的时候还没有登录,那么通常情况下会要求跳转回到登录页面。
在具体实现之前,先来考虑几个问题:

  1. 这个功能应该在哪里实现?
    要实现登录检查的功能,很明显是在Action运行之前,就要判断用户是否登陆了,判断方式是看session里面是否有相关信息,如果有,则继续操作;如果没有,则要跳转到预先制定好的登录页面。简单点说,登录检查应该写在invocation.invoke();语句之前。
  2. 是否需要参数?
    要判断是否需要参数,其实就是判断这个拦截器有没有什么可变的量,可以把这些可变量从程序中分离出来,通过struts.xml来配置。经过分析,可以抽出两个参数:
    代表登陆页面的Result
    判断session中哪个attribute,也就是attribute的名称
  3. 如何引用呢?
    现在的情况是只有部分Action需要登陆录检查,另外一些Action不需要,这就需要权衡了。对于大多数Action都要进行登录检查的包,可以在包的默认拦截器引用上设置登录检查,而对于少数不需要登陆检查的Action,可以让它们直接引用默认的defaultStack拦截器栈。

实现满足要求的拦截器,示例代码如下:

package cn.javass.hello.struts2impl.action;import java.util.Map;   
import com.opensymphony.xwork2.ActionInvocation;  
import com.opensymphony.xwork2.interceptor.Interceptor;  public class SessionCheckInterceptor implements Interceptor{  //设置参数  private String sessionAttribute;  private String reloginResult;  public void setSessionAttribute(String sessionAttribute) {  this.sessionAttribute = sessionAttribute;  }  public void setReloginResult(String reloginResult) {  this.reloginResult = reloginResult;  }  public void destroy() { }  public void init() {    }  public String intercept(ActionInvocation invocation) throws Exception {  //读取Session  Map<String, Object> session = invocation.getInvocationContext().getSession();  //判断Session中是否有相应的attribute  if (session.containsKey(sessionAttribute)){  String resultCode = invocation.invoke();  return resultCode;  }else{  return reloginResult;  }         }  
}  

intercept方法中,先读取session中指定的attribute,具体读取哪个attribute由参数从外界传进来,然后判断Session中是否存在这个attribute,如果有则继续执行后续的拦截器、ActionResult,如果没有则跳转到指定的Result所对应的页面,具体跳转到哪个Result也是由参数从外界传进来的。

拦截器配置,配置示例如下:

<package name="helloworld"  extends="struts-default">  <interceptors>  <interceptor name="testInteceptor" class="cn.javass.hello.struts2impl.action.MyInterceptor"/> <interceptor name="myLogger" class="cn.javass.hello.struts2impl.action.LoggerInterceptor"/><interceptor name="loginChecker" class="cn.javass.hello.struts2impl.action.SessionCheckInterceptor"/>    <interceptor-stack name="myStack">  <interceptor-ref name="timer"/>  <interceptor-ref name="testInteceptor"/><interceptor-ref name="myLogger"/>  <interceptor-ref name="loginChecker">  <param name="sessionAttribute">login_user</param>  <param name="reloginResult">login</param>  </interceptor-ref>  <interceptor-ref name="defaultStack"/>  </interceptor-stack>  </interceptors>  <default-interceptor-ref name="myStack"/>  <global-results>  <result name="math-exception">/${folder}/error.jsp</result> <result name="login">/s2impl/login.jsp</result> </global-results>  <global-exception-mappings>  <exception-mapping result="math-exception" exception="java.lang.ArithmeticException"/>  <exception-mapping result="math-exception" exception="java.lang.Exception"/>  </global-exception-mappings>  <action name="helloworldAction" class="cn.javass.hello.struts2impl.action.HelloWorldAction"> <result name="toWelcome">/${folder}/welcome.jsp</result>   </action>  </package>  

1.4.4 自定义logger拦截器

Struts2自带的logger拦截器只是打印出了Action所对应的URL以及执行的方法名称,这对实际开发来说是肯定不够的。实际开发中为了调试方便,要记录的信息比较多,通常需要把这次请求相关的几乎所有信息都打印出来,比如:
要访问哪个Action
要访问这个Action类的哪个方法
打印出这次请求中所有的request中的parameter参数
这次请求最后跳转到哪个页面。
如果我们现在就要在拦截器中实现这样的功能,该怎么实现呢?

  1. ActionInvocation接口
    在实现拦截器的功能的时候,需要使用ActionInvocation接口,这个接口有很多的功能,这里并不打算全部讲到,只描述一下接下来我们要用到的功能,更多的功能请参见Struts2API文档。
    getAction方法:返回这次请求准备执行的Action对象。
    getProxy方法:返回这次请求的ActionProxy对象,可以在这个对象上获得要运行Action的哪个方法。
    getInvocationContext方法:返回这个Action执行的上下文(ActionContext),可以在这个上下文对象中获取到大量的数据,比如请求的parameter值、session的值等等。
    ActionContext中取到的parameter值是一个Map<String,Object>,其中以Stringkey,以String[]value。这个Map中记录了所有的request参数。
    getResult方法:返回Result运行之后代表结果的Result对象。
  2. 具体的LoggerInterceptor,示例代码如下:
package cn.javass.hello.struts2impl.action;import java.util.Map;  
import org.apache.struts2.dispatcher.ServletDispatcherResult;  
import com.opensymphony.xwork2.ActionInvocation;  
import com.opensymphony.xwork2.Result;  
import com.opensymphony.xwork2.interceptor.Interceptor;  public class LoggerInterceptor implements Interceptor{  public void destroy() {  }  public void init() {  }     public String intercept(ActionInvocation invocation) throws Exception {  System.out.println("=================begin=================");  //找到运行的Action对象,并打印其类名  System.out.println("Action:"+invocation.getAction().getClass().getName());  //找到运行的ActionProxy对象,并打印其要运行的方法名  System.out.println("Method:"+invocation.getProxy().getMethod());  //找到这次请求的request中的parameter参数,并打印  Map<String, Object> params = invocation.getInvocationContext().getParameters();  for (String key:params.keySet()){  Object obj = params.get(key);  if(obj instanceof String[]){  String[] arr = (String[]) obj;  System.out.println("Param:"+key);  for (String value:arr){  System.out.println(value);  }  }  }  //运行后续的拦截器、Action和Result  String resultCode = invocation.invoke();  //在Action和Result运行之后,得到Result对象  //并且可以强制转换成ServletDispatcherResult,打印其下一个JSP的位置  Result rresult = invocation.getResult();  if (rresult instanceof ServletDispatcherResult){  ServletDispatcherResult result = (ServletDispatcherResult) rresult;  System.out.println("JSP:"+result.getLastFinalLocation());  }  System.out.println("=================end=================");           return resultCode;  }  
}  
  1. struts.xml中配置和使用这个拦截器,示例如下:
<package name="helloworld"  extends="struts-default">  <interceptors>  <interceptor name="testInteceptor" class="cn.javass.hello.struts2impl.action.MyInterceptor"/> <interceptor name="myLogger" class="cn.javass.hello.struts2impl.action.LoggerInterceptor"/>  <interceptor-stack name="myStack">  <interceptor-ref name="timer"/>  <interceptor-ref name="myLogger"/>  <interceptor-ref name="testInteceptor"/>  <interceptor-ref name="defaultStack"/>  </interceptor-stack>  </interceptors>  <default-interceptor-ref name="myStack"/>  <global-results>  <result name="math-exception">/${folder}/error.jsp</result>  </global-results>  <global-exception-mappings>  <exception-mapping result="math-exception" exception="java.lang.ArithmeticException"/>  <exception-mapping result="math-exception" exception="java.lang.Exception"/>  </global-exception-mappings>  <action name="helloworldAction" class="cn.javass.hello.struts2impl.action.HelloWorldAction"> <result name="toWelcome">/${folder}/welcome.jsp</result> <result name="input">/${folder}/login.jsp</result>   </action>  </package>  
  1. 测试一下,运行登录页面,填入用户名和密码,点击提交按钮。然后查看后台的输出,示例如下:
=================begin=================
Action:cn.javass.hello.struts2impl.action.HelloWorldAction
Method:execute
Param:submitFlag
login
Param:account
212
Param:password
222222222222
在acton执行之前
用户输入的参数为===account=212,password=222222222222,submitFlag=login
在Result运行之后
JSP:/s2impl/welcome.jsp
=================end=================
2014-5-18 21:37:37 com.opensymphony.xwork2.interceptor.TimerInterceptor info
信息: Executed action [//helloworldAction!execute] took 7 ms.

参考资料:http://www.iteye.com/topic/1124526


http://chatgpt.dhexx.cn/article/TuOXdcLd.shtml

相关文章

Struts2之拦截器

目录 拦截器简介拦截器配置内建拦截器自定义拦截器使用拦截器实现权限控制拦截器工作原理 拦截器简介 拦截器&#xff08;Interceptor&#xff09;是Struts2的核心组成部分&#xff0c;它可以动态拦截Action调用的对象&#xff0c;类似于Servlet中的过滤器。 Struts2的拦截器是…

struts2中拦截器

拦截器&#xff08;interceptor&#xff09;概念 拦截器是动态拦截action调用的对象&#xff0c;类似于servlet中的过滤器。在执行action中的业务逻辑处理方法之前&#xff0c;struts会首先执行struts.xml中引用的拦截器。烂拦截器是struts2中的中一个重要的特性&#xff0c;st…

struts2拦截器详解

一、拦截器概念 拦截器(Interceptor)是Struts2的一个重要特性&#xff0c;它可以在Action 执行前和执行后拦截调用。Struts2的拦截器和Servlet过滤器类似。在执行Action的execute方法之前&#xff0c;Struts2会首先执行在struts.xml中引用的拦截器&#xff0c;在执行完所有引用…

android教程 易百教程,Android RadioGroup

RadioGroup中使用类组单选按钮。如果我们选中一个单选按钮属于一个单选按钮组&#xff0c;它会自动取消选中同一组内的任何先前检查的单选按钮。 RadioGroup 属性 以下是RadioGroup中控件有关的重要属性。可以检查Android官方文档的属性和相关方法的完整列表&#xff0c;可以用…

android radiogroup 添加,如何在android中动态添加textview到radiogroup

大家好&#xff0c; 我们想动态地在radiogroup旁边添加textview。基于服务响应&#xff0c;我们需要在不使用xml的情况下将标签添加到radiogroup。 在某些情况下基于最长无线电如何在android中动态添加textview到radiogroup [ ] 这里下面的代码 final RadioGroup rg new Radi…

Android实现RadioGroup之间的互斥

Android实现RadioGroup之间的互斥 关于效果图实现准备工作&#xff0c;附上布局代码解决需求&#xff0c;附上类代码 关于 因为一个页面需求&#xff0c;需要有两个radio group共六个radio button来实现单选互斥&#xff08;为什么不用一个radio group来包裹是因为需要两行展示…

网格RadioGroup实现

RadioGroup只能横向和垂直展示RadioButton&#xff0c;然后设计师们就经常要求我们网格展示。比如要实现如下的效果&#xff1a; 那要怎么做呢&#xff0c;采用继承RadioGroup&#xff0c;重新绘制里面的内容&#xff0c;上代码&#xff1a; 定义所需属性 attrs&#xff1a;…

RadioGroup 使用

xml //布局 <RadioGroupandroid:id"id/rb"android:layout_width"match_parent"android:layout_height"44dp"android:orientation"horizontal"><RadioButtonandroid:id"id/rb_start"android:layout_width"0dp…

radiogroup多选_3.Android之单选按钮RadioGroup和复选框Checkbox学习

单选按钮和复选框在实际中经常看到&#xff0c;今天就简单梳理下。 首先&#xff0c;我们在工具中拖进单选按钮RadioGroup和复选框Checkbox&#xff0c;如图&#xff1a; xml对应的源码&#xff1a; android:layout_width"match_parent" android:layout_height"…

java radiogroup_android 菜单导航 (Fragment + RadioGroup)

网上有很多讲利用Fragment RadioGroup&#xff0c;actionbar viewPager和TabHost做菜单导航和切换的例子。对于第三种现在已经过时了。所以讲讲自己对第一个的理解和经验分享&#xff0c;不过在此也简单说说第二种。 1、actionbar viewpager 对于这种方式&#xff0c;其实在…

java radiogroup_Android基础控件RadioGroup使用方法详解

本文为大家分享了Android基础控件RadioGroup的使用&#xff0c;供大家参考&#xff0c;具体内容如下 1.简单介绍 RadioGroup可以提供几个选项供用户选择&#xff0c;但只能选择其中的一个。其下面可以横着或者竖着挂几个RadioButton&#xff0c;也可以挂载其他控件(如TextView)…

android自定义radiogroup,Android自定义RadioGroup

最近做项目时需要用到RadioGroup&#xff0c;发现Android原生的RadioGroup太丑了&#xff0c;所以自己写了一个&#xff0c;效果如下所示&#xff1a; 其实就是由4个Button组成的LinearLayout&#xff0c;只是为了方便点击效果的切换所以封装了一下。代码如下&#xff1a; pack…

RadioGroup

实现RadioButton由两部分组成,也就是RadioButton和RadioGroup配合使用.RadioGroup是单选组合框&#xff0c;可以容纳多个RadioButton的容器.在没有RadioGroup的情况下&#xff0c;RadioButton可以全部都选中&#xff1b;当多个RadioButton被RadioGroup包含的情况下&#xff0c;…

Android入门之路 - RadioGroup、RadioButton、CheckBox(单复选框)使用进阶

本文只为初级的Android新手而写&#xff0c;多掌握一份简单实用的技能&#xff0c;快速get吧&#xff0c;有问题就留言 2022&#xff1a;蓦然回首&#xff0c;已入行多年&#xff0c;人生的第二个迷茫阶段 初级 - 使用方式RadioGroup RadioButtonCheckBoxDemo示例 CheckBox 自…

Android RadioGroup 单选按钮控件

Android RadioGroup 单选按钮控件 RadioGroup 为单项选择按钮组&#xff0c;其中可以包含多个 RadioButton&#xff0c;即单选按钮&#xff0c;它们共同为用户提供一种多选一的选择方式。在多个 RadioButton 被同一个 RadioGroup 包含的情况下&#xff0c;多个 RadioButton 之间…

RadioGroup控件使用

在只能进行单选的选择上面可以通过&#xff32;adioGroup控件来实现&#xff0c;例如性别选择以及考试的单项选择题。 xml布局如下&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xm…

RedHat9.0下载地址

RedHat下载&#xff1a;http://archive.download.redhat.com/pub/redhat/linux/9/en/iso/i386/ 转载于:https://www.cnblogs.com/XACOOL/p/5679613.html

下载redhat4.8的方法

一、背景 因为老软件需要安装&#xff0c;所以找个了老系统来安装。 二、上官网 https://www.redhat.com/zh/ 点开redhat最新版本&#xff0c;现在是8.0 下载 要求我登录账户&#xff0c;我就登录jhui163的 然后&#xff0c;看到7.0和更早期的超链接&#xff0c;点进去

vmware安装redhat 8

vmware安装redhat 8 1、下载镜像文件1.1 镜像文件 2、安装系统2.1、选择自定义安装2.2、兼容性选择2.3、选择镜像文件导入2.4、设置用户名密码2.5、选择虚拟机在磁盘上的位置2.6、选择处理器数量2.7、选择内存大小2.8、选择桥接或NAT2.9、选择SCSI控制器类型2.10、选择虚拟机磁…

RedHat 7.5 7.6下载磁力链分享

某度最近更新了一波&#xff0c;导致诸多屏蔽弹客户端应用直接显示直链下载的浏览器插件也失效&#xff0c;就连最强的下载神器也400、403报错 csdn的下载站里是有不少资源&#xff0c;但是苦于都要积分&#xff0c;出于服务大众、便利人民的心。 我终于找到了对应的下载磁力…