Struts2的拦截器

Struts2拦截器:

一、Struts2的工作原理:

1、Struts2基本工作过程

1) 客户端初始化一个指向Servlet容器(例如Tomcat)的请求

2) 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin);

3) 接着StrutsPrepareAndExecuteFilter被调用,StrutsPrepareAndExecuteFilter询问ActionMapper来决定这个请求是否需要调用某个Action;

4) 如果ActionMapper决定需要调用某个Action, StrutsPrepareAndExecuteFilter 把请求的处理交给ActionProxy

5) ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类;

6) ActionProxy创建一个Action Invocation的实例。

7) Action Invocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用

8) 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2框架中继承的标签。在这个过程中需要涉及到ActionMapper。

2、拦截器介绍

1)使用拦截器可以实现横切功能并使这些实现相对action甚至Struts2框架保 持独立。

2)可以实现和使用自己所需的特性且不用修改框架的底层代码。

3)使用拦截器可以达到以下目的:

① 在调用Action之前,提供预处理逻辑

② 与Action进行交互,提供执行信息,比如设置请求中的参数

③ 在调用Action之后,提供后处理逻辑

④ 修改返回的结果,进而修改呈现给用户的内容

⑤ 捕获异常从而替换可执行的处理过程或返回一个不同结果

 4)常见的拦截器和拦截器栈

    5)详见struts-default.xml

 6)配置一个内置的timer拦截器

获取执行某个Action组件所耗费的时间,以便做一个粗略的性能调试。 

在struts.xml中的某个Action组件的配置中添加<interceptor-ref>标签

比如:

<action name="helloworld"  class="demo.web.HelloWorldAction">

<interceptor-ref  name="timer" />

<result>/success.jsp</result>

</)action>

说明:<interceptor-ref>的name属性为拦截器的别名,这里引用的是Struts2的内 置的,具体地在struts-default.xml的struts-default包中定义有。

请求该Action组件观察服务器控制台输出,(以下为参考结果,具体机器可能不一 样)

第一次请求

信息: Executed action [//helloworld!execute] took 356 ms.

第二次请求

信息: Executed action [//helloworld!execute] took 4 ms.

自行分析:为什么第二次所耗费的时间最小?

3、Struts2拦截器有关API

Interceptor接口与AbstractInterceptor

init() 方法用来初始化拦截器

destroy()方法为拦截器提供清理

intercept()方法为拦截器处理业务规则

其中,init()和destroy()仅在Struts2初始化时和框架关闭时分别执行一次, 而intercept()会在每次请求中都会被调用,所以拦截器需要线程安全,尤其 是intercept()方法如果想创建一个自定义拦截器来实现某个特性,则只需要 实现Interceptor接口即可

参考如下:

public class MyTimerInterceptor implements Interceptor {

public void destroy() {

System.out.println("服务器关闭的时候执行一次destory的方法.....");}

public void init() {

System.out.println("服务器初始化的时候执行一次init方法....");}

// 每次请求的时候都执行intercept的方法

public String intercept(ActionInvocation ai) throws Exception {

long beforetime = new Date().getTime();// 得到action被执行之前的时间

String result = ai.invoke(); // 得到后续的拦截器和action的操作

long aftertime = new Date().getTime();// 得到action被执行之后的时间

System.out.println("执行的action共计执行了:" + (aftertime -  beforetime));

System.out.println("返回从action中得到返回值是:"+result);

return result;}}

说明:

调用invocation.invoke()方法可将请求进一步传递给下一个拦截器去处理

否则,请求就不会到达Action组件

struts.xml文件拦截器的配置

<package name=“sinter" extends="struts-default" namespace="/">

<!-- 声明自定义的拦截器 -->

<interceptors>

<interceptor name="MyTimer"

class="com.redarmy.intercepter.MyTimerInterceptor"></interceptor>

</interceptors>

<action name="login" class="com.redarmy.action.LoginAction">

<!-- 使用自己定义的拦截器 -->

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

<result name="success">/user/reg.jsp</result>

<result name="input">/index.jsp</result>

</action>

</package>

部署运行,查看控制台输出,参考结果如下:

服务器初始化的时候执行一次init方法....

==============login.action

2010-8-16 10:52:56  com.opensymphony.xwork2.util.logging.commons.CommonsLogger info

信息: Executed action [//login!execute] took 32 ms.

执行的action共计执行了:32

返回从action中得到返回值是:success

如果不需要初始化和清理代码,则可以继承AbstractInterceptor。该类提供了一个默认实现,但是init()和destroy()方法没有任何操作,只需要覆盖intercetor()即可。

public abstract class AbstractInterceptor 

implements Interceptor{ ... }

AbstractInterceptor

功能要求: 能够拦截Struts请求,并打印一些提示信息。

这里,我们继承 AbstractInterceptor,覆盖intercept()方法

public class LoginInteceptor extends AbstractInterceptor {

@Override //登录校验的拦截器

public String intercept(ActionInvocation ai) throws Exception {

  System.out.println("用户是否登录的拦截处理......");

//如果用户操作的是要进行登录的操作,就继续进行

if(ai.getAction() instanceof UserLoginAction){return ai.invoke();

}else{//判断session中是否存在用户的信息,如果存在则用户已经登录

Map<String,Object> session = ai.getInvocationContext().getSession();//获取session

if(session.get("username")==null){

//如果用户没有登录,直接跳转到登录界面

return "login";}else{return ai.invoke();

}

}

}

}

当多个action中都使用到了相同视图,这时我们应该把result定义为全局视图。struts1中提供了全局forward,struts2中也提供了相似功能:

<package ....>

<global-results>

<result name="message">/message.jsp</result>

</global-results>

</package>

Struts.xml文件的配置如下:

<package name="ssh" extends="struts-default" namespace="/">

<!-- 声明自定义的拦截器 -->

<interceptors>

<interceptor name="UserLogin"

class="com.redarmy.intercepter.LoginInteceptor"></interceptor>

</interceptors>

<!-- 声明全局结果 -->

<global-results>

    <result name="login">/user/login.jsp</result>

</global-results>

<action name="listUser" class="redarmy.shop.action.UserAction"

method="listUsers">

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

<!-- 当使用自己定义拦截器的时候,默认拦截器将不能使用,必须手动添加defaultStack的支持 -->

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

<result name="success">/user/listUser.jsp</result>

<result name="input">/index.jsp</result>

</action>

</package>

说明:

因为struts2中如文件上传,数据验证,封装请求参数到action等功能都是由系统默认的defaultStack中的拦截器实现的,所以我们定义的拦截器需要引用系统默认的defaultStack,这样应用才可以使用struts2框架提供的众多功能。

如果一个action中引入多个拦截器的时候,可以采用拦截器栈处理具体配置如下

<package name="ssh" extends="struts-default" namespace="/">

<!-- 声明自定义的拦截器 -->

<interceptors>

<interceptor name="MyTimer“ class="com.redarmy.intercepter.MyTimerInterceptor"></interceptor>

<interceptor name="UserCheckLogin  class="com.redarmy.intercepter.LoginInteceptor"></interceptor>

<!-- 定义拦截器的栈 -->

<interceptor-stack name="mystack">

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

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

<!-- 添加Struts2默认拦截器的支持 -->

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

</interceptor-stack>

</interceptors>

<action name="listUser" class="redarmy.shop.action.UserAction  method="listUsers">

<!-- 直接引用自己定义的拦截器栈 -->

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

<result name="success">/user/listUser.jsp</result>

<result name="input">/index.jsp</result>

</action>

</package>

如果希望包下的所有action都使用自定义的拦截器,可以通过<default-interceptor-ref name=“mystack”/>把拦截器定义为默认拦截器。注意:每个包只能指定一个默认拦截器。另外,一旦我们为该包中的某个action显式指定了某个拦截器,则默认拦截器不会起作用

在大部分应用里,随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿。为了避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,我们可以将一个struts.xml配置文件分解成多个配置文件,然后在struts.xml文件中包含其他配置文件。下面的struts.xml通过<include>元素指定多个配置文件:

<?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>

<include file="redarmy\\shop\\action\\struts-zhuru.xml"></include>

    <include file="user.xml"></include>

</struts>

margin-top: 0pt;

分享到:
评论

猜你喜欢

转载自wangyujie.iteye.com/blog/1051209