Struts2拦截器

来源:互联网 发布:量化投资 python 编辑:程序博客网 时间:2024/06/14 09:56

拦截器是面向切面编程的一种实现策略。

面向切面编程:Aspect-oriented Programming,简称AOP,AOP的原则是将通用的需求功能从不相关的类中间分离出来,使很多类共享一个功能。

一.工作原理:

拦截器是Struts2控制器和Action之间的组件,在Struts2中,Action调用是一个分层的过程,总是有一系列的拦截器在Action执行前后被执行,这些拦截器是通过在struts.xml中配置的。访问action时,框架不直接调用action的execute方法,而是创建一个ActionInvocation对象,它封装了Action和一系列被配置在Action执行前后的拦截器。

示意图如下(图片来源于《Struts2  in Action》):


箭头的方向代表Action的调用过程,箭头中间的矩形代表着不同的拦截器,他们在一个拦截器栈中顺序执行。图中的拦截器并没有进行中断操作,实际上拦截器可以在Action调用和返回的任何一个过程中执行中断操作,返回不同的视图,之后的拦截器就不再工作。

后续拦截器的继续执行,最后Action的调用都是通过递归调用ActionInvocation的invoke方法实现的。invoke方法文档上的解释:

Invokes the next step in processing this ActionInvocation.
If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor to execute. If there are no more Interceptors to be applied, the Action is executed. If the ActionProxy.getExecuteResult() method returns true, the Result is also executed.
之所以称为递归调用,是因为ActionInvocation通过invoke调用第一个拦截器时,拦截器的intercept方法会获得它的实例,并且在拦截器处理过程中调用ActionInvocation实例的invoke来继续调用后续拦截器。

拦截器的意义:由于将公共功能提取为拦截器,提高了代码重用性。在配置文件中配置拦截器,提高了框架的灵活性。

二.拦截器的使用

1.配置拦截器。

拦截器在struts.xml文件中进行配置,在<package>元素下声明<interceptors>,<interceptors>元素下定义一个个拦截器。

<interceptors>            <interceptor name="拦截器名字" class="拦截器的实现类"/>            <interceptor name="拦截器名字2" class="拦截器的实现类2"/>        </interceptors>     
拦截器栈:可以将多个拦截器合并在一起组成一个拦截器栈,当拦截器栈被关联到一个Action时,Action在被调用前必须执行拦截器栈中的所有拦截器。声明方式如下:

            <interceptor-stack name="拦截器栈名称">                <interceptor-ref name="拦截器名1"/>                <interceptor-ref name="拦截器名2"/>            </interceptor-stack>
拦截器栈中可以包含其他的拦截器栈。

拦截器的参数:

            <interceptor-stack name="拦截器栈名称">                <interceptor-ref name="拦截器名1">                    <param name="参数1">参数值1</param>                    <param name="参数2">参数值2</param>                </interceptor-ref>                <interceptor-ref name="拦截器名2"/>            </interceptor-stack>

在Action中使用拦截器:

    <package name="login" extends="struts-default" namespace="/login"><action name="checkLogin" class="com.test.LoginAction"  method="checkLogin">    <result name="success">/index.jsp</result>    <result name="fail">/login.jsp</result>    <interceptor-ref name="inter1"></interceptor-ref></action>    </package>

默认拦截器:

<default-interceptor-ref name="inter1"></default-interceptor-ref>

default-interceptor-ref为package子元素,为package指定默认拦截器后,如果该包中的某些Action没有显示指定其他拦截器,则默认拦截器会起作用。注意一个包只能配置一个默认拦截器,如果需要多个默认拦截器,可以将它们组合为一个拦截器栈,然后配置这个拦截器栈为默认拦截器。

2.内建拦截器

Struts2框架的大部分工作是通过内建拦截器来实现的,如解析请求参数,参数类型转换,数据校验等。它们都配置在struts-default.xml中。struts-default.xml在struts-core.jar文件中。里面配置的拦截器内容如下:

            <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" />
几个拦截器的说明:

params:将请求中的参数设置到Action中。

workflow:调用Action的validate方法,出现错误返回。

timer:输出Action执行时间。

staticParams:从struts.xml文件中将<action>的<param>中的内容设置到对应的Action中。

fileUpload:文件上传功能。

struts-default.xml中定义了一个拦截器栈defaultStack,包含了大部分常用的功能,同时也指定其为默认拦截器栈。

<default-interceptor-ref name="defaultStack"/>

一般的package都继承struts-default,如果不在Action中指定拦截器栈或者默认拦截器栈,则会使用defaultStack。如果开发人员为action指定了其他的拦截器栈,并且仍然需要默认拦截器栈时,可以这样声明:

<action name="checkLogin" class="com.test.LoginAction"  method="checkLogin">    <result name="success">/index.jsp</result>    <result name="fail">/login.jsp</result>    <interceptor-ref name="inter1"></interceptor-ref>    <interceptor-ref name="defaultStack"></interceptor-ref></action> 
下面演示一下使用系统的拦截器timer:

action代码:

package com.test;import com.opensymphony.xwork2.ActionSupport;public class TimerTestAction extends ActionSupport{@Overridepublic String execute() throws Exception {Thread.sleep(2000);return "success";}}
配置文件:

<struts>    <include file="struts-default.xml" />    <package name="test" extends="struts-default" namespace="/test"><action name="timertest" class="com.test.TimerTestAction">    <result name="success">/index.jsp</result>    <interceptor-ref name="timer"></interceptor-ref></action>    </package></struts>
在浏览器输入访问地址:http://localhost:8080/Struts2/test/timertest.action

控制台输出:

二月 03, 2014 10:29:03 下午 com.opensymphony.xwork2.interceptor.TimerInterceptor info
信息: Executed action [/test/timertest!execute] took 2006 ms.

三.自定义拦截器

实现自定义拦截器,可以实现Interceptor接口,它提供3个方法。

init:在拦截器执行前调用,用于初始化

destory:执行后调用,用于销毁资源

intercept:实现具体的拦截操作,它决定返回视图或者是将后续操作交给下一个拦截器或者Action。

自定义拦截器示例:文字过滤拦截器

功能:论坛上将不合法的关键字用*号过滤

news.jsp:

<%@ page language="java" contentType="text/html"    pageEncoding="UTF-8"%><%@taglib prefix="s" uri="/struts-tags" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title></title></head><body><div style="margin:30px 50px 20px 50px;text-align:center">  <div style="font-size:14px">用户登录</div>  <s:form action="public" namespace="/test" method="post">     <s:textfield name="title" label="标题" />     <s:textarea name="content" label="内容" />     <s:submit value="提交" />  </s:form></div></body></html>
success.jsp:

<%@ page language="java" contentType="text/html"    pageEncoding="UTF-8"%><%@taglib prefix="s" uri="/struts-tags" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title></title></head><body><div style="text-align:center">  标题:<s:property value="title"/><br/>  内容:<s:property value="content"/></div></body></html>
PublicAction:

package com.test;import com.opensymphony.xwork2.ActionSupport;public class PublicAction extends ActionSupport{private String title;private String content;public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String execute() throws Exception {return "success";}}
拦截器ForumInterceptor:

package com.test;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.Interceptor;public class ForumInterceptor implements Interceptor{@Overridepublic void destroy() {}@Overridepublic void init() {}@Overridepublic String intercept(ActionInvocation ai) throws Exception {Object obj = ai.getAction();if(obj != null) {if (obj instanceof PublicAction) {PublicAction publicAction = (PublicAction)obj;String content = publicAction.getContent();if (content.contains("操你妈")) {content = content.replaceAll("操你妈", "*");publicAction.setContent(content);}}//继续执行return ai.invoke();} else {return null;}}}

struts.xml:

<struts>    <include file="struts-default.xml" />    <package name="test" extends="struts-default" namespace="/test">        <interceptors>            <interceptor name="replace" class="com.test.ForumInterceptor"></interceptor>        </interceptors><action name="public" class="com.test.PublicAction">    <result name="success">/success.jsp</result>    <interceptor-ref name="defaultStack"></interceptor-ref>    <interceptor-ref name="replace"></interceptor-ref></action>    </package></struts>

运行演示:


点击提交以后的效果:


拦截器方法过滤:

在默认情况下,如果为某个Action配置拦截器,则该拦截器会拦截Action中的所有方法,如果不想拦截所有方法,只需要拦截其中的某几个方法,可以使用MethodFiledInterceptor。这个类提供一个doIntercept方法,实现方法过滤的特性。

需要过滤的方法和不需要过滤的方法通过includeMethods和excludeMethods在struts.xml中配置

测试action:

public class MethodAction extends ActionSupport{public String method1() {System.out.println("method1");return SUCCESS;}public String method2() {System.out.println("method2");return SUCCESS;}}
方法拦截器:

public class MethodIntercepter extends MethodFilterInterceptor{@Overrideprotected String doIntercept(ActionInvocation ai) throws Exception {System.out.println("拦截器MethodIntercepter");return null;}}
struts.xml:

            <interceptor name="method" class="com.test.MethodIntercepter"></interceptor>

<action name="method" class="com.test.MethodAction" method="method2">    <result name="success">/success.jsp</result>    <interceptor-ref name="defaultStack"></interceptor-ref>    <interceptor-ref name="method">        <!-- 不被拦截的方法 -->        <param name="excludeMethods">method1</param>        <!-- 被拦截的方法 -->        <param name="includeMethods">method2</param>    </interceptor-ref></action> 
在浏览器中访问这个action:http://localhost:8080/Struts2/test/method.action

控制台输出:拦截器MethodIntercepter

修改action元素中的method属性为method="method1",重新访问action,

控制台输出:method1

可以看到这个拦截器对method2进行了过滤,没有对method1进行过滤。

四.拦截结果监听器

Struts2提供了拦截Action执行结果的监听器,使用方法:新建监听类实现PreResultListener接口并在拦截器的intercept方法中注册这个监听。

MyPreResultListener:

public class MyPreResultListener implements PreResultListener{@Overridepublic void beforeResult(ActionInvocation arg0, String arg1) {System.out.println("拦截结果监听器执行,返回视图为:"+arg1);}}
BeforeResultInterceptor:

public class BeforeResultInterceptor implements Interceptor{@Overridepublic void destroy() {}@Overridepublic void init() {}@Overridepublic String intercept(ActionInvocation ai) throws Exception {ai.addPreResultListener(new MyPreResultListener());System.out.println("execute方法执行前");String result = ai.invoke();System.out.println("execute方法执行后");return result;}}

BeforeResultAction:

public class BeforeResultAction extends ActionSupport{@Overridepublic String execute() throws Exception {return SUCCESS;}}
struts.xml:

    <package name="test" extends="struts-default" namespace="/test">        <interceptors>            <interceptor name="result" class="com.test.BeforeResultInterceptor"></interceptor>        </interceptors><action name="beforeresult" class="com.test.BeforeResultAction">    <result name="success">/success.jsp</result>    <interceptor-ref name="defaultStack"></interceptor-ref>    <interceptor-ref name="result"></interceptor-ref></action>    </package>

访问地址:http://localhost:8080/Struts2/test/beforeresult.action

输出结果:

execute方法执行前
拦截结果监听器执行,返回视图为:success
execute方法执行后

可以看到,监听在返回视图之前起作用。


0 0
原创粉丝点击