struts2之拦截器详解
文章目录
- 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个拦截器的类,分别是Interceptor1
、Interceptor2
和Interceptor3
,它们分别执行不同的功能处理,而运行的时机就是在Action执行之前和Result执行之后。
1.1.1 Struts2的拦截器的实现原理
拦截器方法都是通过代理的方式来调用的。Struts 2
的拦截器实现相对简单。当请求到达Struts 2
的ServletDispatcher
时,Struts 2
会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list
),最后一个一个地调用列表中的拦截器。事实上,我们之所以能够如此灵活地使用拦截器,完全归功于动态代理
的使用。动态代理是代理对象根据客户的需求做出不同的处理。对于客户来说,只要知道一个代理对象就行了。
那Struts2
中,拦截器是如何通过动态代理被调用的呢?当Action
请求到来的时候,会由系统的代理生成一个Action
的代理对象,由这个代理对象调用Action
的execute()
或指定的方法,并在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无关,比如拦截器可以访问到值栈等等。
在之前的示例中,在运行Action
的execute
方法的时候,会发现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
方法。运行的时候,Action
的account
属性在初始化过后,会接到这里的赋值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 其他默认拦截器
- 异常处理拦截器(
exception
)
<interceptorname="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
- 别名拦截器(
aliasInterceptor
)
该拦截器主要作用是将一个参数别名成为另一个参数,在不同的action之间相似的参数(但是不同名)扮演着胶水的角色。该拦截器在action链中有很大的作用。 - 配置拦截器(
servletConfig
)
该拦截器设置基于action
接口实现的action
属性。比如说,一个action
实现{@link ParameterAware} 接口,那么action
上下文的参数map将会被设置到action
中。该拦截器设计成如果action
需要获取基于servlet
的参数,则设置所有的属性到action
中,包括servlet context,session
等。 - 国际化拦截器(
i18n
) - 预处理拦截器(
prepare
)
在action
方法执行前,调用prepare
方法。(只对实现了prepareAble
接口的aciton
有效)。 - action链拦截器(
chain
)
能将所有实例的所有属性都拷贝到当前执行的对象的valueStack
中。除非该对象实现了Unchainable
接口。该连接器同action
返回类型为chain
联合使用。 - debug拦截器(
debugging
) - scopedModelDriven:该拦截器只对实现了
ScopedModelDriven
接口的action
实例起作用。 - modelDriven类:
com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor
该拦截器同上面原理一样,是只对实现了ModelDriven
接口的action
起作用 - 文件上传拦截器(
fileUpload
)
类:org.apache.struts2.interceptor.FileUploadInterceptor
- checkBox处理拦截器(
checkbox
)
类:org.apache.struts2.interceptor.CheckboxInterceptor
此拦截器是针对checkbox
表单控件的。 - 多选拦截器(
multiselect
)
类:org.apache.struts2.interceptor.MultiselectInterceptor
同checkbox
一样,如果没有选中,则设置默认的值。 - 静态参数拦截器(
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
类:可以通过includeMethods
和excludeMethods
属性配置拦截
或不拦截
的方法
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; }
}
可以看到,这个Interceptor
的init
方法和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 自定义登录检查拦截器
在实际开发中,一个常见的功能要求是:有很多操作都需要登录后才能操作,如果操作的时候还没有登录,那么通常情况下会要求跳转回到登录页面。
在具体实现之前,先来考虑几个问题:
- 这个功能应该在哪里实现?
要实现登录检查的功能,很明显是在Action
运行之前,就要判断用户是否登陆了,判断方式是看session
里面是否有相关信息,如果有,则继续操作;如果没有,则要跳转到预先制定好的登录页面。简单点说,登录检查应该写在invocation.invoke();
语句之前。 - 是否需要参数?
要判断是否需要参数,其实就是判断这个拦截器有没有什么可变的量,可以把这些可变量从程序中分离出来,通过struts.xml
来配置。经过分析,可以抽出两个参数:
代表登陆页面的Result
判断session中哪个attribute
,也就是attribute
的名称 - 如何引用呢?
现在的情况是只有部分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
,如果有则继续执行后续的拦截器、Action
和Result
,如果没有则跳转到指定的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
参数
这次请求最后跳转到哪个页面。
如果我们现在就要在拦截器中实现这样的功能,该怎么实现呢?
ActionInvocation
接口
在实现拦截器的功能的时候,需要使用ActionInvocation
接口,这个接口有很多的功能,这里并不打算全部讲到,只描述一下接下来我们要用到的功能,更多的功能请参见Struts2
的API
文档。
getAction
方法:返回这次请求准备执行的Action
对象。
getProxy
方法:返回这次请求的ActionProxy
对象,可以在这个对象上获得要运行Action
的哪个方法。
getInvocationContext
方法:返回这个Action
执行的上下文(ActionContext
),可以在这个上下文对象中获取到大量的数据,比如请求的parameter
值、session
的值等等。
在ActionContext
中取到的parameter
值是一个Map<String,Object>
,其中以String
为key
,以String[]
为value
。这个Map
中记录了所有的request
参数。
getResult
方法:返回Result
运行之后代表结果的Result
对象。- 具体的
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; }
}
- 在
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>
- 测试一下,运行登录页面,填入用户名和密码,点击提交按钮。然后查看后台的输出,示例如下:
=================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
struts2之拦截器详解相关推荐
- struts2 18拦截器详解(五)
I18nInterceptor 该拦截器处理defaultStack第四的位置,是用来方便国际化的,如果说我们的一个Web项目要支持国际化的话,通常的做法是给定一个下拉框列出所支持的语言,当用户选择了 ...
- java参数action_Struts2之Action接收请求参数和拦截器详解
技术分析之在Struts2框架中使用Servlet的API 1. 在Action类中也可以获取到Servlet一些常用的API 需求:提供JSP的表单页面的数据,在Action中使用Servlet的A ...
- 第五章 处理器拦截器详解——跟着开涛学SpringMVC
5.1.处理器拦截器简介 Spring Web MVC的处理器拦截器(如无特殊说明,下文所说的拦截器即处理器拦截器)类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理. ...
- structs2拦截器详解
Struts2(XWork)提供的拦截器的功能说明: 拦截器 名字 说明 Alias Interceptor alias 在不同请求之间将请求参数在不同名字件转换,请求内容不变 Chaining In ...
- 第五章 处理器拦截器详解
5.1.处理器拦截器简介 Spring Web MVC的处理器拦截器(如无特殊说明,下文所说的拦截器即处理器拦截器) 类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理. ...
- springMVC教程--拦截器详解
3 拦截器 3.1 定义 Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理. 3.2 拦截器定义 实现HandlerInte ...
- AspectCore动态代理中的拦截器详解(一)
前言 在上一篇文章使用AspectCore动态代理中,简单说明了AspectCore.DynamicProxy的使用方式,由于介绍的比较浅显,也有不少同学留言询问拦截器的配置,那么在这篇文章中,我们来 ...
- 一文贯通→过滤器与拦截器详解
一.过滤器Filter 过滤器英文叫 Filter,是 JavaEE 的标准,依赖于 Servlet 容器,可以按照指定顺序配置多个.常用来配置请求编码以及过滤一些非法参数,垃圾信息或者是网站登录验证 ...
- 过滤器和拦截器详解
过滤器 和 拦截器的 6个区别,别再傻傻分不清了_程序员小富的博客-CSDN博客_过滤器和拦截器 若依登陆过程及过滤器拦截器的使用: 用户登陆接口:1.把用户信息通过uuid即token作为key,存 ...
- Flutter 网络请求 Dio 拦截器详解
老王的烦恼 昔日的小王凭借这他的小心谨慎和借助漂亮能干的女友 Dio 的辅助,终于干下了一番事业,成为中华大地响当当的人物,小王也变成老王.如今,老王已经年近花甲,看似迈上了人生巅峰,却也遇到了人生的 ...
最新文章
- 调用管道模型:高敏感、高性能
- 利用 Laravel 花 2 小时撸一个 RSS 生成器
- javascript学习(11)——[设计模式]工厂模式
- 大型网站的 HTTPS 实践(二)——HTTPS 对性能的影响
- PAT乙级(1003 我要通过!)
- 4G + 1G = 5G?
- 跨浏览器的元素的竖直排列
- 一张图读懂MVC设计模式,从用户发起请求到获取响应,应用内部到底是如何数据流转、业务串联的
- sql server 2005 使用Log Explorer查看和恢复数据
- 浪潮ssr服务器安全加固系统贵吗,浪潮SSR加固服务器安全
- ENVI学习总结(九)——图像裁剪
- 【计算机网络】计网笔记知识点整理篇(1-3章,后续章节持续更新)
- JavaScript的基础语句整理
- 【数据挖掘】数据统计性描述与相似度
- JavaScript中如何严格的判断NaN
- 第一行代码-android-第三版-pdf扫描-思维导图-课件-源码
- a eraser eraser还是an_an. eraser是什么意思
- 迎接混合云时代 IBM云计算发展大提速
- 优秀开源项目之三:高性能、高并发、高扩展性和可读性的网络服务器架构State Threads...
- Altium Sesigner 测量距离后留下的距离图标如何删除的问题解决