拦截器的基本原理

拦截器---登录状态检查Filter不是struts2的解决方案

         Struts2默认启用了大量通用功能的拦截器,只要配置Action的package继承了struts-default包,这些拦截器就会起到作用

 

拦截器的基本原理

         责任链模式: 责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

         主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

优点:

         降低系统的耦合度,简化对象的相互连接,同时增强对象指派职责的灵活性,增加新处理类很方便

缺点:

         不能保证请求一定被接收,且长的职责链系统性能会受到一定影响,且代码调试不方便

 

拦截接口

public interface Interceptor{

         public void intercept(ActionInvocation ai);    }

 

         当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器

 

1、定义拦截器类

public class CheckLoginInterceptor implements Interceptor {

    @Override

    public void destroy() {

       System.out.println("CheckLoginInterceptor.destroy()");

    }

 

    @Override

    public void init() {当服务器启动时,自动创建拦截器对象,当拦截器创建后自动执行init方法,这个方法在整个生命周期中运行且只运行一次

       System.out.println("CheckLoginInterceptor.init()");

    }

 

    @Override

    public String intercept(ActionInvocation invocation) throws Exception {用于执行拦截处理,多线程的

       System.out.println("CheckLoginInterceptor.intercept()");

       //前置处理,这里可以对请求信息进行处理

       String res=invocation.invoke();//继续向后执行

       //后置处理,这里可以执行资源回收之类的处理

       return res;

    }

}

2、在struts.xml中声明拦截器

<interceptors>

    <interceptor name="checkLogin" class="com.yan.action.interceptors.CheckLoginInterceptor"></interceptor>

</interceptors>

3、引用拦截器

<action name="*" class="com.yan.action.AdminUserAction" method="{1}">

    <interceptor-ref name="checkLogin"/>  声明引用特定的拦截器时,系统的默认拦截器失效;如果没有引用拦截器时Struts2框架提供了默认拦截器

    <param name="rowsPerPage">2</param>

    <result>/WEB-INF/content/user/{1}.jsp</result>

</action>

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

 

<interceptor-stack name="defaultStack">

         <interceptor-ref name="exception"/>

         <interceptor-ref name="alias"/>

… …

</interceptor-stack>

<action name="*" class="com.yan.action.AdminUserAction" method="{1}">

           <interceptor-ref name="checkLogin"/>

           <interceptor-ref name="defaultStack"/>

           <param name="rowsPerPage">2</param>

           <result>/WEB-INF/content/user/{1}.jsp</result>

       </action>

 

public class CheckLoginInterceptor implements Interceptor {

    @Override

    public void destroy() {

       System.out.println("CheckLoginInterceptor.destroy()");

    }

 

    @Override

    public void init() {

       System.out.println("CheckLoginInterceptor.init()");

    }

 

    @Override

    public String intercept(ActionInvocation invocation) throws Exception {

       System.out.println("CheckLoginInterceptor.intercept()");

       ActionContext ac = invocation.getInvocationContext();

       if (ac != null) {

           Map<String, Object> session = ac.getSession();

           if (session != null && session.containsKey("loginUser")) {

              String res = invocation.invoke();// 继续向后执行

              // 后置处理,这里可以执行资源回收之类的处理

              return res;

           }

       }

       return Action.LOGIN;

    }

}

 

<action name="*" class="com.yan.action.AdminUserAction" method="{1}">

           <interceptor-ref name="checkLogin"/>

           <interceptor-ref name="defaultStack"/>

           <param name="rowsPerPage">2</param>

           <result>/WEB-INF/content/user/{1}.jsp</result>

           <result name="login">/WEB-INF/content/user/login.jsp</result>

       </action>

 

?拦截器   --filter

         Action执行前或执行后动态添加方法的组件技术,也可以不执行Action

 

public interface Interceptor extends Serializable {

    void destroy();

    void init();

    String intercept(ActionInvocation invocation) throws Exception;

}

 

简化开发

public abstract class AbstractInterceptor implements Interceptor {

    public void init() {     }

   

    public void destroy() {    }

 

    public abstract String intercept(ActionInvocation invocation) throws Exception;

}

 

日志拦截

执行修改时记录修改信息

         id  user_id  pdate(current_timestamp)  ipaddr  action  params

 

 

需要记忆的系统拦截器

         alias在不同请求之间将请求参数在不同名字件转换,请求内容不变

                  

         exception将异常定位到一个页面,并准备要显示内容

         fileUpload提供文件上传功能

         i18n记录用户选择的locale

        

         params将请求中的参数设置到Action中去,并进行相应的类型转换。

         modelDriven如果一个类实现了ModelDriven,将getModel得到的结果放在Value Stack中。

         conversionError将类型转换异常添加到Action的属性字段中。

        

         store存储或者访问实现ValidationAware接口的Action类出现的消息,错误,字段错误等。

         validation使用actionName-validation.xml文件中定义的内容校验。

         workflow调用Action的validate方法,一旦有错误返回,重新定位到INPUT页面

        

         scope将Action状态存入session和application的简单方法。

         servletConfig提供访问HttpServletRequest和HttpServletResponse等的方法以及以Map的方式访问。

        

         staticParams从struts.xml文件中将中的中的内容设置到对应的Action中。

 

         timer输出Action执行的时间

         token通过Token来避免重复提交       

        

        

 

解析servletConfig拦截器代码理解拦截器机制

public class ServletConfigInterceptor extends AbstractInterceptor implements StrutsStatics {

public String intercept(ActionInvocation invocation) throws Exception {

        final Object action = invocation.getAction();

        final ActionContext context = invocation.getInvocationContext();

 

        if (action instanceof ServletRequestAware) {

            HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);

            ((ServletRequestAware) action).setServletRequest(request);

        }

 

        if (action instanceof ServletResponseAware) {

            HttpServletResponse response = (HttpServletResponse) context.get(HTTP_RESPONSE);

            ((ServletResponseAware) action).setServletResponse(response);

        }

 

        if (action instanceof ParameterAware) {

            ((ParameterAware) action).setParameters((Map)context.getParameters());

        }

 

        if (action instanceof ApplicationAware) {

            ((ApplicationAware) action).setApplication(context.getApplication());

        }

       

        if (action instanceof SessionAware) {

            ((SessionAware) action).setSession(context.getSession());

        }

       

        if (action instanceof RequestAware) {

            ((RequestAware) action).setRequest((Map) context.get("request"));

        }      

        if (action instanceof ServletContextAware) {

            ServletContext servletContext = (ServletContext) context.get(SERVLET_CONTEXT);

            ((ServletContextAware) action).setServletContext(servletContext);

        }

        return invocation.invoke();

    }

 

 

使用Timer拦截器记录输出Action执行的时间

 

使用Token拦截器避免重复提交

 

自定义拦截器AbstractInterceptor  Interceptor

         struts2拦截器的interceptor方法中,参数ActionInvocation可用来获取页面用户输入的信息

 

系统对于拦截器的调用,是通过ActionInvocation来实现的。

if (interceptors.hasNext()) { 

Interceptor interceptor=(Interceptor)interceptors.next(); 

resultCode = interceptor.intercept(this); 

} else { 

if (proxy.getConfig().getMethodName() == null)    resultCode = getAction().execute(); 

else resultCode = invokeAction(getAction(), proxy.getConfig()); 

 

 

 

         注意:如果为Action指定了一个拦截器,则系统默认的拦截器栈将会失去作用。为了继续使用默认拦截器,所以上面配置文件中手动引入了默认拦截器

 

 

 

方法过滤拦截MethodFilterInterceptor

         includeMethods  excludeMethods

 

 

<interceptors>

         <interceptor name="myInterceptor11" class="com.yan.MyInterceptor11">

                   <param name="hello">world</param>

         </interceptor>

         为拦截器增加一个名为hello值为world的属性

         <interceptor name="myInterceptor22" class="com.yan.MyInterceptor22"/>

         <interceptor name="myInterceptor33" class="com.yan.MyInterceptor33">

                   <param name="includeMethods">test,abc</param>

         </interceptor>

</interceptors>

 

<action name="methodFilter" class="com.yan.MethodFilterAction" method="test">

         <result name="success">/abc.jsp</result>

 

         <interceptor-ref name="defaultStack"/>

         <interceptor-ref name="myInterceptor11"/>

         <interceptor-ref name="myInterceptor22"/>

         <interceptor-ref name="myInterceptor33">

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

         </interceptor-ref>

</action>

 

 

 

1、默认的情况下,拦截器会拦截Action中的所有的方法,这里不包括setter或getter方法。这时就可以使用方法过滤拦截器来拦截指定的方法,这是一种更加细化的拦截器的配置方式。它可以细化到拦截具体的某个方法。而不是拦截某个Action,因为拦截Action是一种粗粒度的实现方式

2、使用includeMethods指明拦截器所要拦截的方法。使用excludeMethods指明拦截器不再拦截的方法。这里excludeMethods和includeMethods是在MethodFilterInterceptor类中定义的成员变量。而且只要includeMethods进来的方法就一定会被拦截,而不管是否已经把它excludeMethods在外了,也就是说includeMethods的优先级要高于excludeMethods。也可以使用<param name="includeMethods"/>在上面定义拦截器的时候指定全局性过滤的方法

区别就是对方法的过滤有全局性和局部性区分。而当发生冲突时,则依照【就近原则】以局部性的配置为准

3、假设全局性过滤定义为<param name="includeMethods">test</param>。而在局部性过滤中定义为<param name="excludeMethods">test</param>。这种情况下<param name="includeMethods">test</param>将生效,即拦截Action中的test()方法。这个时候全局中配置的是拦截,局部中配置的是不拦截,二者并没有发生冲突,所以仍是以includeMethods优先级高。可以认为在局部的配置中,已经隐含的把<param name="includeMethods">test</param>继承过来了

 

 

修改Action返回值PreResultListener

 

 

Struts2中过滤器,拦截器之间有什么区别?

         1、拦截器是基于java反射机制的,而过滤器是基于函数回调的。

         2、过滤器依赖与servlet容器,而拦截器不依赖与servlet容器。

         3、拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用。

         4、拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。

         5、在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。

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

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

3) 接着StrutsPrepareAndExecuteFilter被调用,StrutsPrepareAndExecuteFilter询问ActionMapper来决定这个请求是否需要调用某个Action。它同时会创建ActionContext,是action上下文,ActionContext是一个容器,这个容易主要存储request、session、application、parameters等相关信息.ActionContext是一个线程的本地变量,这意味着不同的action之间不会共享ActionContext,所以也不用考虑线程安全问题。其实质是一个Map,key是标示request、session、……的字符串,值是其对应的对象

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

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

6) ActionProxy创建一个ActionInvocation的实例。ActionInvocation 实例使用命名模式来调用,回调Action的execute方法,该execute方法先获取用户请求参数,然后它会调用业务逻辑组件来处理用户的请求。在调用Action的过程前后,涉及到相关拦截器Intercepter的调用。

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

在上述过程中所有的对象(Action,Results,Interceptors等)都是通过ObjectFactory来创建的。

将按照顺序逐一加载:default.properties,struts-default.xml,struts-plugin.xml,struts.properties,struts.xml,web.xml

猜你喜欢

转载自blog.csdn.net/java_laoming/article/details/81214360