struts2.1.6教程五、拦截器

在前面我们已经初步使用过拦截器,下面继续细细探讨。

1.概述strust2中的拦截器

拦截器是Struts2框架的核心,它主要完成解析请求参数、将请求参数赋值给Action属性、执行数据校验、文件上传等工作。Struts2设计的灵巧性,拦截器起了关键性的作用,当需要扩展Struts2功能时,只需要提供对应拦截器,并将它配置在Struts2容器中即可;如果不需要该功能时,也只需要取消该拦截器的配置即可。   
Struts2内建了大量的拦截器,这些拦截器以name-class对的形式配置在struts-default. xml文件中,其中name是拦截器的名字,就是以后我们使用该拦截器的唯一标识;class则指定了该拦截器的实现类,如果我们定义的package继承了Struts2的默认struts-default包,则可以自由使用它下面定义的拦截器,否则必须自己定义这些拦截器。

 

2.自定义拦截器

自定义拦截器需要特别注意的是不要忘记引入struts2默认的拦截器为了实现某些操作,我们可以自定义拦截器,自定义拦截器有三种方式定义。分别为实现Interceptor接口,继承抽象类AbstractInterceptor,继承MethodFilterInteceptor类。

 

方式一,实现Interceptor接口。

准备工作,新建struts2interceptor项目。构建一个登录环境:当我们点登录链接时,便成功登录(为了方便,这里不进行验证)。即在link.jsp页面中写如下链接:

<a href="<%=request.getContextPath()%>/login.action">登录</a>

然后,我们点击此链接便可以登录。

login.action在strutst.xml中的的配置如下:

<package name="interceptor"    extends="struts-default">
    <action name="login" class="com.asm.LoginAction">
            <result name="success">/success.jsp</result>
</action>
</package>

编写拦截器:MyInterceptor类,内容如下:

package com.asm;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class MyInterceptor implements Interceptor {
    public void destroy() {
    }
    public void init() {
    }
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("开始拦截");
        String result = invocation.invoke();
        System.out.println("结束拦截");
        return result;
    }
}

为了使用此拦截器,我们必须将此拦截器进行注册,随后再在要使用此拦截器的Action中引用。即首先在<package>中注册,内容如下:

<interceptors>
    <interceptor name="myIpt" class="com.asm.MyInterceptor"></interceptor>
</interceptors>

注册完成后,如果我们要在login.action中使用此拦截器,只需要在<action>中增加如下内容:

<interceptor-ref name="myIpt"></interceptor-ref>

这样便成功为LoginAction配置了我们自定义的拦截器MyInterceptor,下面只需发布测试。

 

实例流程分析:当我们为LoginAction配置了拦截器时,并且有客户端请求此Action时,会首先被此拦截器拦住,然后执行System.out.println("开始拦截"),随后我们调用invocation.invoke()方法,它会把请求继续传递给下一个拦截器,下一个拦截器也会继续执行相应代码后再调用invoke方法继续传递,直到请求到达最后一个拦截器,它会把请求传递给Action,比如,我们这里只用到了一个拦截器,当它执行完成后,会把请求直接转交到LoginAction处理,LoginAction处理完成后,它会返回结果给MyInterceptor拦截器。

 

方式二、继承AbstractInterceptor抽象类

创建拦截器类MyAbstractInterceptor:主要代码如下:

package com.asm;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyAbstractInterceptor extends AbstractInterceptor {
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("Abs开始拦截");
        String result = invocation.invoke();
        System.out.println("Abs结束拦截");
        return result;
    }
}

然后注册此拦截器,在<interceptors>元素进行进行配置,内容如下:

<interceptor name="myAbs" class="com.asm.MyAbstractInterceptor"></interceptor>

随后再在LoginAction中引用此拦截器,即在<action name="login" ...>配置

 

方式三、继承MethodFilterInteceptor类

创建拦截器类MyMethodFilterInterceptor,主要代码如下:

package com.asm;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
public class MyMethodFilterInterceptor extends MethodFilterInterceptor{

    protected String doIntercept(ActionInvocation invocation) throws Exception {
       System.out.println("method开始拦截");
      String result=invocation.invoke();
       System.out.println("method结束拦截");
       return result;

    }

}

然后注册此拦截器

 

分析:当配置到此,实质便为LoginAction配置了三个拦截器,当我们点击登录时会在控制台打印出如下语句:
开始拦截

Abs开始拦截

method开始拦截

--先执行拦截器,再执行此Action

method结束拦截

Abs结束拦截

结束拦截

 

其实当我们点击登录时,本来是要访问LoginAction,最后会把LoginAction的执行结果传递给访问者。但是当我们配置了拦截器时,当我们去访问Action时,
会首先被拦截,随后拦截器执行一些操作后才会继续把请求传递下去。下面作图说明拦截流程:

 

结合现实理解:比如我们要去某楼层找某人(LoginAction)取一个资源(LoginAction处理后返回的结果,这里表现为success.jsp),

(1)进楼层时会被大门保安拦截检查(第一个拦截器:MyInterceptor拦截器),

(2)检查通过后再进电梯时会被电梯保安员检查(第二个拦截器:MyAbstractInterceptor拦截器),

(3)检查通过后再上到某楼层会被楼层保安员检查(第三个拦截器:MethodAction拦截器),

(4)检查通过后会找到某个(LoginAction),并与某个交谈(LoginAction处理),随后某个人和我们会带着请求的资源出去,

(5)出去时,会依次被楼层,电梯,大门保安员检查,最终检查通过。某个人把资源给我们(实质就是返回请求资源给客户端)。 其实拦截器的执行流程和过滤器差不多,所以我们不防用过滤器的眼光来看这些拦截器。


注意我们在为LoginAction配置拦截器时,都没使用默认的拦截器,是原因这里的测试可以不用,但是以后在我们使用自定义的拦截器是,一定要加上默认的拦截器,否则会导致许多不可预知的结果。
补充:从上面的图并结合代码,我们可以看出拦截器的核心过程应该是ActionInvocation对这些拦截器回调处理,下面我们建立com.asm.interceptor.simulation来模拟这一过程,具体的代码参源文件,在此略去。在此我们作图分析ActionInvocation的实现过程:

补充2:上面分别使用了三种方式来创建自定义的拦截器,第一种方式是最原始的实现方式,第二种方式的好处是我们可以不必重写所有的方法,较常用。第三种方式进行了扩展,下面将会展示它的扩展性能。

 

3.使用来MethodFilterInterceptor灵活拦截

步骤一、建立MethodAction,代码如下:

package com.asm;
import com.opensymphony.xwork2.ActionSupport;
public class MethodAction extends ActionSupport{
    public String m1(){
        return SUCCESS;
    }
    public String m2(){
        return SUCCESS;
    }
    public String m3(){
        return SUCCESS;
    }
}

步骤二、注册此Action,并为此Action配置拦截器。配置内容如下:

<action name="*_*" class="com.asm.MethodAction" method="{2}">
        <result name="success">/{2}Suc.jsp</result>
        <interceptor-ref name="myMet">
        </interceptor-ref>
</action>

我们为此Action配置了前面写的MyMethodFilterInterceptor拦截器,并在link.jsp中增加如下链接:

<a href="<%=request.getContextPath()%>/Method_m1.action">m1</a><br>
<a href="<%=request.getContextPath()%>/Method_m2.action">m2</a><br>
<a href="<%=request.getContextPath()%>/Method_m3.action">m3</a><br>

 

当点m1时会访问到m1Suc.jsp页面, 点m2、m3会分别访问到m2Suc.jsp、m3Suc.jsp页面。现在假如我们想访问m2、m3时不被拦截,我们只需修改MyMethodFilterInterceptor注册:修改内容为:

<interceptor name="myMethod"     class="com.asm.MyMethodFilterInterceptor">
                <param name="excludeMethods">m2,m3</param>
</interceptor>

它的作用和增加

<param name="includeMethods">m1</param>

等价。上面是指定m2,m3方法调用时不被拦截,这里是指定只拦截m1。除了这种在注册拦截器时指定拦截外,还可以在引用拦截器时指定,即如下形式:

<interceptor-ref name="myMethod">
                <param name="excludeMethods">m2,m3</param>
                <param name="includeMethods">m1</param>
</interceptor-ref>

上面的两处<param>配置是等价的,但是如果〈param〉配置冲突,谁起作用?即如果我们对m1配置了excludeMethods同时又配置了includeMethods时,谁起作用,我们可以进行这些冲突的验证。以下是验证结果:

 

引用配置(在Action引用拦截器时配置)时,以includeMethods的配置为准。一旦我们为拦截器使用了<param>配置,而对m1这样的方法不配置任何,就不会被拦截。但是如果不使用<param>,它们全部都要被拦截。
注册配置时(在注册拦截器时配置),情况和“引用配置”完全一样。
引用配置和注册配置冲突时,以引用配置为准。

 

4.使用默认的execAndWait拦截器

 

当我们进行数据库查询等相关的操作时,如果服务器负荷过重可能不能及时把数据查询出来,进而会在状态拦显示“正在打开...”,但却一直转不到相关的页面,这将给客户端带来不便,甚于很多人会因此不愿使用网站的所有服务。对此我们可以在客户提交时,马上转到一个页面,并在该页面显示“您的请求已提交,服务器正在查询,请等待...”的内容,这样客户将不会陷于无赖的等待中。 对于此要求,struts2可以轻松帮我们完成。下面新建struts2wait项目演示此实例。

建立LoginAction,代码如下:

package com.asm;
public class LoginAction extends ActionSupport {

    public String execute() throws Exception {

       Thread.sleep(5000);

       return SUCCESS;

    }

}

说明:为了模拟服务器负荷过重,查询时间要很长。我们在使用了线程休眠的方式。

随后配置此Action,配置的主要内容如下:

<action name="login" class="com.asm.LoginAction">
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="execAndWait"></interceptor-ref>
            <result name="wait">/wait.jsp</result>
            <result name="success">/success.jsp</result>
</action>

注意在配置前我们先是使用了默认的拦截器,再此强调在我们为Action配置拦截器时,应该总是配上默认的拦截器

随后我们使用了execAndWait拦截器,如需要配置此拦截器,此拦截器一定要配置在最后,否则会出现一些难预知的结果。如果使用此拦截器,我们通常还会配置wait的result结果集,因为“On the initial request or any subsequent requests (before the action has completed), the wait result will be returned. The wait result is responsible for issuing a subsequent request back to the action, giving the effect of a self-updating progress meter”,大概意思就是当我们请求的Action在未执行完,就是未返回结果时,会首先把wait result返回,而在wait result所指定的页面中通常会再次发送请求给原始的Action。所以wait.jsp的主要内容如下:

<head>
    <meta http-equiv="refresh" content="1;login.action">
</head>
    <body>        查询请求已提交,正在查询数据,请等待...    </body>

 

在此页面中,我们指定了每隔1秒便发送请求到login.action中去。这样,客户端便可以及时获取查询结果。结合此实例,我们简要分析流程:当我们发出请求到此Login.Action中去时,首先会被exeAndWait拦截器拦截到,这样它便跳转到wait.jsp页面,在wait.jsp页面中每隔1秒我们会继续发送此Action的请求,当再次请求到达LoginAction时,如果它已经返回,则会跳到此Action返回的页面,如果LoginAction未返回,则继续停留在wait.jsp中,再隔1秒又再次发送请求到LoginAction中去。

其实如果服务器能很快查询出结果,我们则不需要用到wait.jsp页面,我们只需在<interceptor-ref name="execAndWait"></interceptor-ref>中增加如下一段配置:
<param name="delay">6000</param> 这样便延迟请求到达wait.jsp页面,这样当请求到达时它会在LoginAction中执行6秒时间再到wait.jsp,而6秒LoginAction足以执行完并返回结果,所以当拦截器

执行时首先检查到此Action已经返回结果。则拦截器会直接用此返回页面,如果此时发现LoginAction并未执行完,它便会把wait resutl指定的页面返回。需要说明的是,通常我们设定的延迟最多一秒,这里为了演示,设置的很长。图示此拦截器原理:

关于此拦截器的详细的配置及文档说明可以参看ExecuteAndWaitInterceptor类的api信息。

 

5. TokenInterceptor防止表单重复提交。

由于某些原因,用户在进行类似表单提交的操作后,以为表单未被提交,会进行多次的重复提交。为了避免用户多次提交给服务器带来负荷。我们会对表单提交这样的操作进行一些处理,以告诉用户不要重复提交。下面我们建立struts2token项目,使用struts2的token拦截器来实现此案例。
步骤一,编写login.jsp页面,内容如下:

<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<html>
    <body>
        <form action="<%=request.getContextPath()%>/login.action" >
            姓名:<input type="text" name="username"><br>
            密码:<input type="password" name="password"><br>
            <input type="submit" value="登录">
            <s:token></s:token>
        </form>
    </body>
</html>

说明,此登录页面中的关键技术就是使用了标签库中的<s:token></s:token>标签,它的作用就是在用户访问此页面时会生成一个sessionId,在提交时会服务器会据此验证表单是否已提交。“To set a token in your form, you should use the token tag. This tag is required and must be used in the forms that submit to actions protected by this interceptor”,这句话的大概意思就是我们必须要在提交的表单中使用这个token tag,这样提交到的Action便能配置TokenInterceptor拦截器验证表单是否重复提交。

 

步骤二,编写LoginAction,主要代码如下:

package com.asm;
public class LoginAction extends ActionSupport {
    public String execute() throws Exception {
        System.out.println("---->执行execute方法...");
        return SUCCESS;
    }
}

步骤三,struts.xml主要配置内容如下:

<struts>
    <package name="tokenTest" extends="struts-default">
        <action name="login" class="com.asm.LoginAction">
            <result name="success">/success.jsp</result>
            <result name="invalid.token">/subError.jsp</result>
            <interceptor-ref name="token"></interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>
    </package>
</struts>

说明:在此Action下,我们配置了token拦截器,另注意到在此Action下我们还配置了一个“invalid.token”result,因为“This interceptor uses a fairly primitive technique for when an invalid token is found: it returns the result invalid.token, which can be mapped in your action configuration”。它的大概意思就是:提交时服务器如果根据token标签产生的sessionId判断出表单已提交,它则返回invalid.token指向的视图。比如这里,如果重复提交则会转到.../subError.jsp中去。另不要忘记了引入默认的拦截器栈。补充:关于token拦截器更多细节可以访问org.apache.struts2.interceptor.TokenInterceptor类的api说明。

 

步骤四,编写配置中所用到jsp页面,这些页面编写简单,在此省去。
步骤五、发布测试,请注意访问login.jsp页面时,查看源文件时会发现增加了两个隐藏域信息。
步骤六、更换拦截器:我们还可以使用tokenSession拦截器,它的功能比上面的增强,它能保证持有相同sessionId的并发请求等待第一个完成之后才能被提交处理,但是它返回的是action执行后的result.接着上例,我们只需要在配置中作如下修改:把上面的token拦截器改成

<interceptor-ref name="tokenSession"></interceptor-ref>

即可。随后便可以测试,测试时会发现如果我们重复提交,它总是返回到上一次的success.jsp页面,但是它并不是经过LoginAction中的execute处理后返回(我们System.out.print语句在重复提交时并未打印出来),而是此拦截器判断出是重复后直接返回上一次提交转向的页面。

 

6.使用拦截器实现权限验证

为了说明此问题,我们建立struts2auth项目,流程图如下:

简短说明:当我们访问main.jsp页面,并试图通过此页面中的链接地址:note.action来访问到.../WEB-INF/note.jsp页面时,由于访问的note.action配置了拦截器,所以会被拦截,如果拦截器判断登录则可以访问,否则会跳到登录页面。如果我们从登录页面直接到main.jsp页面,再来访问note.action时,同样被拦截但是由于登录过,所以可以访问到此action对应的内容。由这里的分析可以看出关键点就登录成功时给出标志提供给拦截器判断是否成功登录。


步骤一,搭建好相关的开发环境,并准备好登录页面login.jsp,代码如下:

<form action="<%=request.getContextPath()%>/login.action" method="post">
        姓名:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        <input type="submit" value="登录">
</form>

步骤二,建立相应的Action:LoginAction。代码如下:

package com.asm;
public class LoginAction extends ActionSupport {
    private String username;
    Map session;
    public String execute() throws Exception {
        if(username.equals("admin")){
            session = ActionContext.getContext().getSession();
            session.put("loginSign", "loginSuccess");
            return SUCCESS;
        }else{
            return LOGIN;
        }
}
...省略username的get/set方法
}

说明:我们这里是设定了只有登录用户名为admin时,此Action才设置登录标志。另这里获取Session对象采取的是“与Servlet解耦合的非IOC方式”。

 

步骤三,编写拦截器类,代码如下:
package com.asm.interceptor;

public class AuthInterceptor extends AbstractInterceptor {
    public String intercept(ActionInvocation invocation) throws Exception {
        Map session = invocation.getInvocationContext().getSession();
        // session=ActionContext.getContext().getSession();
        if (session.get("loginSign") == null) {
            return "login";
        } else {
            String result = invocation.invoke();
            return result;
        }
    }
}

步骤四,配置此Action相关,主要配置内容如下:

<struts>
    <package name="tokenTest" extends="struts-default">
        <interceptors>
            <interceptor name="auth"
                class="com.asm.interceptor.AuthInterceptor">
            </interceptor>
            <interceptor-stack name="authStack">
                <interceptor-ref name="auth"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref> 
            </interceptor-stack>
        </interceptors>
        <action name="login" class="com.asm.LoginAction">
            <result name="success">/main.jsp</result>
            <result name="login">/login.jsp</result>
        </action>

        <action name="note">
            <result>/WEB-INF/note.jsp</result>
            <result name="login">/login.jsp</result>
            <interceptor-ref name="authStack"></interceptor-ref>
        </action>
    </package>
</struts>

说明:结合前面的一些代码来看,当我们为note.action配置了前面写所的AuthInterceptor拦截器时,如果我们要访问note.action,拦截器会首先判断是否登录,如果登录则继续把请求传递下去,如果没有登录则会返回到登录页面。
步骤五、编写相关的其它jsp页面,然后发布测试。此实例应重点是进一步掌握拦截器的配置使用。作为“实现资源权限访问”,此实例不具参考价值。

 

 

7.拦截器中的注解

AnnotationWorkflowInterceptor:Invokes any annotated methods on the action。意思是此拦截器可以调用在Action中任何有注解的方法。下面我们来演示它的使用,具体步骤如下:
步骤一,建立struts2annotationInt项目,并建立LoginAction类,代码如下:

package com.asm;
...省略导入的包
public class LoginAction extends ActionSupport {
    private String username;
    @Before
    public String myBefore() {
        System.out.println("调用myBefore方法");
        return LOGIN;
    }
    @After
    public void myAfter() throws InterruptedException {
        Thread.sleep(5000);
        System.out.println("----调用myAfter方法");
    }
    @BeforeResult
    public void myBeforeResult() {
        System.out.println("----调用myBeforeResult方法");
    }
    public String execute() throws Exception {
        System.out.println("调用execute方法");
        return SUCCESS;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        System.out.println("---调用set方法" + username);
        this.username = username;
    }
}

说明:要想使用方法成为被拦截器监视的注解方法,只需在方法关加上@...这样的形式并导入相关的类即可。

步骤二,编写相关的jsp及配置该Action,主要配置内容如下:

<struts>
    <package name="ano" extends="struts-default">
        <interceptors>
            <interceptor name="anno"                class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor">
            </interceptor>
            <interceptor-stack name="annoStack">
                <interceptor-ref name="anno"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        <action name="login" class="com.asm.LoginAction">
            <result name="success">/success.jsp</result>
            <result name="login">/login.jsp</result>
            <interceptor-ref name="annoStack"></interceptor-ref>
        </action>
    </package>
</struts>

结合配置说明:当我们为LoginAction配置了AnnotationWorkflowInterceptor拦截器时,LoginAction中的所有注解方法才真正生效。下面重点是来讨论这些方法的执行顺序及作用。

加@Before注解的方法:will be invoked before the action method. If the returned value is not null, it is returned as the action result code。意思是在action的execute方法执行之前被调用,但是此方法如果返回不为空的话,它的返回结果将是真正的返回结果,比如这里我们return LOGIN,这样无论以什么用户名登录,它总会返回到login result(这里为login.jsp页面) 。但是从执前结果来看,在返回前仍执行了标记为@BeforeResult的方法:will be invoked after the action method but before the result execution。意思是在返回结果集前调用此方法。下面我们把public String myBefore()方法中的return LOGIN注释掉,并让修改此方法的返回类型为void。随后登录测试(注意要重新部署当前项目),可以发现执行结果如下:
调用myBefore方法

---调用set方法

调用execute方法

----调用myBeforeResult方法
----调用myAfter方法

从执行的顺序来看,标记为@After的方法最后执行,并且可以发现:它会延时5秒执行,但是在延时执行时,浏览器并没有成功跳到success.jsp页面,而是在5秒后,控制台打印出myArter方法中的内容同步跳转到success.jsp页面。@After :will be invoked after the action method and result execution。意为在execute方法执行并且返回结果后此方法被调用。但是从测试来看,标记为@After的方法是会影响到结果的返回(延时返回)。 强调:注意方法的执行顺序,相关的内容可以参看AnnotationWorkflowInterceptor类的api文档。

 

在使用2.1.6包使用注解实测中,execute方式和after方式不执行,2.1.6原因还是代码写错了?

 

 

 

8.使用PreResultListener实现回调

在进行本实例前请前复习:五.2自定义拦截器。因为PreResultListener对象一般是绑定在拦截器上使用。

下面我们新建struts2PreResultListener项目进行测试。

步骤一,建立类,实现PreResultListener接口,主要代码如下:

package com.asm;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.PreResultListener;
public class MyPreResultListener implements PreResultListener {
    public void beforeResult(ActionInvocation invocation, String res) {
        // System.out.println(invocation.getAction());
        // System.out.println(invocation.getResultCode());
        /**回调Action中的方法:
         * LoginAction lg = (LoginAction) invocation.getAction(); try {
         * lg.execute(); } catch (Exception e) { e.printStackTrace(); }
         */
        System.out.println("检验到PreResultListener被执行");
    }
}

步骤二,copy前面在自定义拦截器中用到的三个拦截器,并绑定MyPreResultListener对象,首先是在MyInterceptor类中,我们只需要修改intercept方法即可,代码如下:

public String intercept(ActionInvocation invocation) throws Exception {
        invocation.addPreResultListener(new MyPreResultListener());
        System.out.println("开始拦截");
        String result = invocation.invoke();
        System.out.println("结束拦截");
        return result;
}

随后在MyMethodFilterInterceptor类中作类似修改。为了区别,我们在MyAbstractInterceptor类中不绑定MyPreResultListener对象。

步骤三,编写struts.xml文件,主要配置内容如下:

<struts>
    <package name="interceptor" extends="struts-default">
        <interceptors>
            <interceptor name="myIpt" class="com.asm.MyInterceptor">
            </interceptor>
            <interceptor name="myAbs"
                class="com.asm.MyAbstractInterceptor">
            </interceptor>
            <interceptor name="myMet"
                class="com.asm.MyMethodFilterInterceptor">
            </interceptor>
        </interceptors>

        <action name="login" class="com.asm.LoginAction">
            <interceptor-ref name="myIpt"></interceptor-ref>
            <interceptor-ref name="myAbs"></interceptor-ref>
            <interceptor-ref name="myMet"></interceptor-ref>
            <result name="success">/success.jsp</result>
        </action>                
    </package>
</struts>

步骤四,编写相应的jsp页面,发布测试。

说明:此实例的只是简要地演示了PreResultListener的使用,所以相对简单。对于其它相关操作,我们可以从MyPreResultListener类注释掉的内容中找到一此端倪。强调:从执行结果来看,PreResultListener对象会在返回结果前执行,请注意结合拦截器执行的顺序来看。此实例目前作为了解。

 

 

项目地址:http://pan.baidu.com/s/1gddArjP

 


 

附项目关键代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
    
<struts>
<!-- 包含其他文件 -->
<constant name="struts.configuration.xml.reload" value="true" />
<constant name="struts.devMode" value="true"></constant> 

<package name="interceptor"    extends="struts-default">
<interceptors>
    <interceptor name="myIpt" class="com.asm.MyInterceptor"></interceptor>
    <interceptor name="myAbs" class="com.asm.MyAbstractInterceptor"></interceptor>
    <interceptor name="myMethod" class="com.asm.MyMethodFilterInterceptor"></interceptor>
    
     <interceptor name="anno" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor"></interceptor>
     <interceptor-stack name="annoStack">
         <interceptor-ref name="anno"></interceptor-ref>
         <interceptor-ref name="defaultStack"></interceptor-ref><!--导入默认拦截器配置,不然无法取到值 -->
     </interceptor-stack>    
    
</interceptors>





<action name="login" class="com.asm.LoginAction" method="test">
<!-- 拦截器按顺序执行一个传递下一个 -->
<interceptor-ref name="myIpt"></interceptor-ref>  
<interceptor-ref name="myAbs"></interceptor-ref>  
<interceptor-ref name="myMethod"></interceptor-ref> 

<!-- 在使用2.1.6包使用注解实测中,execute方式和after方式不执行,2.1.6原因还是代码写错了? -->
<!--<interceptor-ref name="annoStack"></interceptor-ref> 用了注解不默认执行execute方法? 问题待解决--> 
     <result name="success">/success.jsp</result>
     <result name="failure">/failure.jsp</result>
</action>

<action name="*_*" class="com.asm.MethodAction" method="{2}">
        <result name="success">/success{2}.jsp</result>
<interceptor-ref name="myMethod">
                <param name="excludeMethods">m2,m3</param>
                <param name="includeMethods">m1</param>
</interceptor-ref>
</action>



</package>
</struts>

 

package com.asm;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.annotations.After;
import com.opensymphony.xwork2.interceptor.annotations.Before;
import com.opensymphony.xwork2.interceptor.annotations.BeforeResult;
public class LoginAction  extends ActionSupport implements ServletRequestAware,ServletResponseAware{


    public HttpServletRequest request;
    public HttpServletResponse response;
    
    @Override
    public void setServletResponse(HttpServletResponse response) {
        this.response = response;
    }

    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }
    
    private static final long serialVersionUID = 1L;
    private User user;

    
    
     
    @Before
    public String myBefore() {
        System.out.println("调用myBefore方法");
        return SUCCESS;
    }
    @After
    public void myAfter() throws InterruptedException {
        System.out.println("----调用myAfter方法");
    }
    @BeforeResult
    public void myBeforeResult() {
        System.out.println("----调用myBeforeResult方法");
    }
     
    @Override
    public String execute() throws Exception {      
        System.out.println("LoginAction");
            return SUCCESS;
    }
    
    public String test() throws Exception {      
        System.out.println("testLoginAction");
            return SUCCESS;
    }

    
    public void iamaction() throws Exception {      
        System.out.println("iamaction");
    }
    
    
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
    
}

 

package com.asm;
import com.opensymphony.xwork2.ActionSupport;
public class MethodAction extends ActionSupport{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public String m1(){
        return SUCCESS;
    }
    public String m2(){
        return SUCCESS;
    }
    public String m3(){
        return SUCCESS;
    }
}

 

package com.asm;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class MyInterceptor implements Interceptor {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public void destroy() {
    }
    public void init() {
    }
    public String intercept(ActionInvocation invocation) throws Exception {
        //绑定MyPreResultListener对象
        invocation.addPreResultListener(new MyPreResultListener());
        System.out.println("开始拦截");
        String result = invocation.invoke();
        System.out.println("结束拦截");
        //result="failure";
        //result="success";
        return result;
    }
}

 

package com.asm;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyAbstractInterceptor extends AbstractInterceptor {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("Abs开始拦截");
        String result = invocation.invoke();
        System.out.println("Abs结束拦截");
        return result;
    }
}

 

package com.asm;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
public class MyMethodFilterInterceptor extends MethodFilterInterceptor{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    protected String doIntercept(ActionInvocation invocation) throws Exception {
        invocation.addPreResultListener(new MyPreResultListener());
       System.out.println("method开始拦截");
      String result=invocation.invoke();
       System.out.println("method结束拦截");
       return result;

    }

}

 

package com.asm;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.PreResultListener;

public class MyPreResultListener implements PreResultListener {
    public void beforeResult(ActionInvocation invocation, String res) {
        System.out.println(invocation.getAction());
        System.out.println(invocation.getResultCode());
        // 回调Action中的方法:
        LoginAction lg = (LoginAction) invocation.getAction();
        try {
            //可以执行action的方法
            lg.iamaction();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("检验到PreResultListener被执行");
    }
}

 

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
  </head>
  
  <body>


<a href="<%=request.getContextPath()%>/login.action">登录</a>


<hr>
<a href="<%=request.getContextPath()%>/Method_m1.action">m1</a><br>
<a href="<%=request.getContextPath()%>/Method_m2.action">m2</a><br>
<a href="<%=request.getContextPath()%>/Method_m3.action">m3</a><br>


  </body>
</html>

 

posted @ 2015-04-15 17:18  crazyYong  阅读(375)  评论(0编辑  收藏  举报