zoukankan      html  css  js  c++  java
  • Struts2学习(六)

    拦截器原理

    1、如图所示,Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。

    2、intercept方法所依赖的参数ActionInvocation则是Action调度者。ActionInvocation中的invoke()方法具备以下2层含义(详细看DefaultActionInvocation源代码):

    • 如果拦截器堆栈中还有其他的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。
    • 如果拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。

    拦截器和过滤器的比较

    1、拦截器和过滤器的概念非常类似,拦截器中的intercept()和过滤器中的doFilter()方法。

    2、拦截器是基于动态代理来实现,而过滤器是基于函数回调。

    3、过滤器隶属于web容器,可以过滤一切请求(包括action、servlet、jsp、html等等)。

    4、而拦截器隶属于struts2框架,只能拦截action(无法拦截对jsp的请求)。

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

    6、执行顺序 :过滤前 - 拦截前 - Action处理 - 拦截后 - 过滤后。

     实现拦截器类

    1、实现com.opensymphony.xwork2.interceptor.Interceptor 接口

    • 实现其中的destroy() 、init() 、intercept() 方法
      package ecut.interceptors.interceptor;
      
      import java.util.Map;
      
      import com.opensymphony.xwork2.ActionContext;
      import com.opensymphony.xwork2.ActionInvocation;
      import com.opensymphony.xwork2.interceptor.Interceptor;
      
      /**
       * 1、通过实现  com.opensymphony.xwork2.interceptor.Interceptor 接口 来实现自定义的拦截器类
       */
      public class CheckLoginInterceptor implements Interceptor {
      
          private static final long serialVersionUID = -3115350062208083018L;
          
          public CheckLoginInterceptor() {
              System.out.println( "创建 CheckLoginInterceptor 的实例" );
          }
      
          @Override
          public void init() {
              System.out.println( "对 CheckLoginInterceptor 的实例进行初始化" );
          }
      
          @Override
          public String intercept( ActionInvocation invocation ) throws Exception {
              System.out.println( this);
              // 获得 Action 的上下文对象
              ActionContext context = invocation.getInvocationContext();
              // 获得正在被访问的 <action> 的名称
              String name = context.getName() ;
              System.out.println( "action name : " +  name +"准备执行");
              String resultName = "input" ;
              // 如果被访问的 <action> 的名称是 main
              if( "main".equals( name ) ) {
                  Map<String,Object> sessionMap = context.getSession();
                  if( sessionMap.containsKey( "username" ) ) {
                      System.out.println( "即将执行: " + name  );
                      resultName = invocation.invoke(); 
                      System.out.println( name + "执行结束并返回: " + resultName );
                  }
              } 
              
              if( "logout".equals( name ) ){
                  resultName = invocation.invoke();
                  System.out.println( name + "执行结束并返回: " + resultName );
              }
              
              return resultName ;
          }
          
          @Override
          public void destroy() {
          }
      
      }
      package ecut.interceptors.interceptor;
      
      import com.opensymphony.xwork2.ActionContext;
      import com.opensymphony.xwork2.ActionInvocation;
      import com.opensymphony.xwork2.interceptor.Interceptor;
      
      public class ParamInterceptor implements Interceptor {
      
          private static final long serialVersionUID = 6273500806976834662L;
          
          private String interceptorParam ;
          
          public ParamInterceptor () {
              System.out.println( "创建实例ParamInterceptor" );
              System.out.println( "实例化 ParamInterceptor ,interceptorParam : " + interceptorParam );
          }
      
          @Override
          public void init() {
              System.out.println( "初始化 ParamInterceptor 实例 , interceptorParam : " + interceptorParam );
          }
      
          @Override
          public String intercept( ActionInvocation invocation ) throws Exception {
              System.out.println( this  + " ," + interceptorParam );
              ActionContext context = invocation.getInvocationContext();
              System.out.println( "准备执行: " + context.getName() );
              String resultName = invocation.invoke();
              System.out.println( "执行结束: " + context.getName() + " , 返回的 Result 名称是 : " + resultName );
              return resultName ;
          }
          
          @Override
          public void destroy() {
          }
      
          public String getInterceptorParam() {
              return interceptorParam;
          }
      
          public void setInterceptorParam(String interceptorParam) {
              this.interceptorParam = interceptorParam;
          }
      
      }

      在拦截器中写一个无参构造,可以在日志中看出,配置文件每引用一次拦截器,就会执行一次实例化操作和初始化操作。

    2、继承com.opensymphony.xwork2.interceptor.AbstractInterceptor 类

    • 实现其中的intercept() 方法

    定义拦截器(声明)

    1、定义拦截器

    • 定义不带参数的拦截器
      <?xml version="1.0" encoding="UTF-8"?>
      
      <!DOCTYPE struts PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
          "http://struts.apache.org/dtds/struts-2.5.dtd">
      
      <struts>
      
          <!-- 允许在 action 的 名称 中使用 / 字符  <constant name="struts.enable.SlashesInActionNames" value="true" /> -->
          <!-- 启用动态方法调用  <constant name="struts.enable.DynamicMethodInvocation" value="true" /> -->
          
          <!-- 修改 action 请求路径的后缀 value="do,,action既可以是action后缀也可以是do后缀也可以啥都不写"-->
          <constant name="struts.action.extension" value="do,," />
          
          <package name="interceptor" namespace="/interceptor" extends="struts-default" >
          
             <!-- 在 package 内部 使用 interceptors 可以定义 拦截器 和 拦截器栈 -->
             <interceptors>
             
                 <!-- 使用 interceptor 声明拦截器(定义),引用一个拦截器,就创建了一个指定类型的对象 -->
                 <interceptor name="checkLogin" class="ecut.interceptors.interceptor.CheckLoginInterceptor" />
             </interceptors>

      </struts>
    • 定义带参数的拦截器
      <?xml version="1.0" encoding="UTF-8"?>
      
      <!DOCTYPE struts PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
          "http://struts.apache.org/dtds/struts-2.5.dtd">
      
      <struts>
      
          <!-- 允许在 action 的 名称 中使用 / 字符  <constant name="struts.enable.SlashesInActionNames" value="true" /> -->
          <!-- 启用动态方法调用  <constant name="struts.enable.DynamicMethodInvocation" value="true" /> -->
          
          <!-- 修改 action 请求路径的后缀 value="do,,action既可以是action后缀也可以是do后缀也可以啥都不写"-->
          <constant name="struts.action.extension" value="do,," />
          
          <package name="interceptor" namespace="/interceptor" extends="struts-default" >
          
             <!-- 在 package 内部 使用 interceptors 可以定义 拦截器 和 拦截器栈 -->
             <interceptors> <!-- 在声明拦截器时指定拦截器的参数值 -->
                 <interceptor name="param" class="ecut.interceptors.interceptor.ParamInterceptor" >
                     <param name="interceptorParam">声明时所指定的拦截器参数的值就是参数的默认值</param>
                 </interceptor>
            </interceptors>
      </struts>

      可以通过param指定拦截器中interceptorParam的默认值,对应的拦截器类中定义跟参数名相同的属性,并提供getter 和setter 。Struts 2 框架会自动把参数的值设置到相应的属性中去。

    2、定义拦截器栈

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
    
    <struts>
    
        <!-- 允许在 action 的 名称 中使用 / 字符  <constant name="struts.enable.SlashesInActionNames" value="true" /> -->
        <!-- 启用动态方法调用  <constant name="struts.enable.DynamicMethodInvocation" value="true" /> -->
        
        <!-- 修改 action 请求路径的后缀 value="do,,action既可以是action后缀也可以是do后缀也可以啥都不写"-->
        <constant name="struts.action.extension" value="do,," />
        
        <package name="interceptor" namespace="/interceptor" extends="struts-default" >
        
           <!-- 在 package 内部 使用 interceptors 可以定义 拦截器 和 拦截器栈 -->
           <interceptors>
     
               <!-- 声明拦截器栈 -->
               <interceptor-stack name="myStack">
                      <!-- 引用已声明的拦截器栈 -->
                   <interceptor-ref name="defaultStack" />
                      <!-- 引用已声明的拦截器,引用一次就创建一个该拦截器的实例,并初始化-->
                   <interceptor-ref name="checkLogin" />
                   <interceptor-ref name="param" >
                       <param name="interceptorParam">拦截器栈</param>
                   </interceptor-ref>
               </interceptor-stack>
               
           </interceptors>
    </struts>

    拦截器的执行顺序按照引用顺序依次执行,拦截器栈中拦截器,按照拦截器栈的顺序去依次执行

    使用拦截器(引用)

    1、可以在拦截器栈中引用拦截器或拦截器栈

    <!-- 声明拦截器栈 -->
    <interceptor-stack name="myStack">
      <!-- 引用已声明的拦截器栈 -->
      <interceptor-ref name="defaultStack" />
      <!-- 引用已声明的拦截器,引用一次就创建一个该拦截器的实例,并初始化-->
      <interceptor-ref name="checkLogin" />
      <interceptor-ref name="param" >
        <param name="interceptorParam">拦截器栈</param>
      </interceptor-ref>
    </interceptor-stack>

    2、也可以在<action> 中引用拦截器

    Action类

    package ecut.interceptors.action;
    
    import java.util.Map;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    import com.opensymphony.xwork2.Action;
    import com.opensymphony.xwork2.ActionContext;
    
    public class LoginAction implements Action {
        
        private static Logger logger = LogManager.getLogger();
    
        private String username;
        private String password;
    
        @Override
        public String execute() throws Exception {
            logger.info( "username : " + username );
            logger.info( "password : " + password );
            
            ActionContext context = ActionContext.getContext();
            
            Map<String,Object> sessionMap = context.getSession();
            
            sessionMap.put( "username" , username );
            
            return SUCCESS ;
        }
        
        
        public String logout() throws Exception {
            
            System.out.println("logout");
            ActionContext context = ActionContext.getContext();
            
            Map<String,Object> sessionMap = context.getSession();
            
            sessionMap.remove( "username");
            
            return SUCCESS ;
        }
    
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
    }

    struts.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
    
    <struts>          
        <!-- 全局的result需要在拦截器之后 -->   
           <global-results>
               <result name="input" type="redirect">
                   <param name="location">/interceptor/index.jsp</param>
               </result>
           </global-results>
        
           <action name="login"  class="ecut.interceptors.action.LoginAction"  method="execute">
               <result name="success" type="redirectAction">
                   <param name="actionName">main</param>
               </result>
           </action>
           
           <action name="main" >
               <result>/WEB-INF/pages/interceptor/main.jsp</result>
                <!--如果引用了自己的拦截器则默认拦截器就不起作用了,默认拦截器在struts-default.xml使用 default-interceptor-ref指定(defaultStack),
               defaultStack中引用了modelDriven拦截器,因此参数都为null,需要在自己的拦截器前面引用默认的拦截器
                -->
               <!-- <interceptor-ref name="defaultStack" /> 
               <interceptor-ref name="checkLogin" /> 
               <interceptor-ref name="param" >
                   <param name="interceptorParam">张三丰</param>
               </interceptor-ref>
               <interceptor-ref name="param" >
                   <param name="interceptorParam">张翠山</param>
               </interceptor-ref> -->
               
               <!-- 引用拦截器栈,以便于对当前的action进行拦截 -->
               <interceptor-ref name="myStack">
                   <!-- 形式上 是在 覆盖 param 的 interceptorParam 参数的值 -->
                   <param name="param.interceptorParam">Action</param>
                   <!-- 实际上 是将本次引用中的 param 对应的对象 替换成一个新的对象 -->
               </interceptor-ref> 
           </action>
           
           <action name="logout"  class="ecut.interceptors.action.LoginAction" method="logout">
                   <result name="success" type="redirectAction">
                   <param name="actionName">main</param>
               </result>
               <!-- 引用之前已经声明好的拦截器,没有明确指定param拦截器里interceptorParam属性值就使用默认的属性值 -->
               <interceptor-ref name="myStack" /> 
           </action>
    </struts>

    在默认包struts-default 中定义了一系列拦截器和拦截器栈,同时使用default-interceptor-ref 定义了一个默认拦截器defaultStack 。因为继承了struts-default 包,同时也就继承了defaultStack ,所以只要没有显式指定拦截器,都会使用默认的拦截器。如果引用了自己的拦截器则默认拦截器就不起作用了,默认拦截器在struts-default.xml使用 default-interceptor-ref指定(defaultStack), defaultStack中引用了modelDriven拦截器,因此参数都为null,需要在自己的拦截器前面引用默认的拦截器。在引用拦截器时可以指定拦截器中的参数值。每引用一次拦截器,就会执行一次实例化操作和初始化操作。

    index.jsp

    <%@ page language = "java" pageEncoding = "UTF-8" %>
    <%@ page contentType = "text/html; charset= UTF-8"%>
    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Interceptor</title> </head> <body> <h1>Interceptor</h1> <form action="${ pageContext.request.contextPath }/interceptor/login" method="post" > <input type="text" name="username" > <input type="password" name="password" > <input type="submit" value="登录"> </form> <a href="${ pageContext.request.contextPath }/interceptor/main">查看主页面</a> </body> </html>

    main.jsp

    <%@ page language = "java" pageEncoding = "UTF-8" %>
    <%@ page contentType = "text/html; charset= UTF-8"%>
    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>主页</title> </head> <body> <h1>Hello , ${ username }</h1> <a href="${ pageContext.request.contextPath }/interceptor/logout">退出登录</a> </body> </html>

    转载请于明显处标明出处

    https://www.cnblogs.com/AmyZheng/p/9224129.html

  • 相关阅读:
    linux常用操作命令
    golang的goroutine调度机制,GC机制
    数据库原理
    linux各文件夹的作用
    c++面试题
    EF 新增数据时提示it has a DefiningQuery and no <InsertFunction> element exists in the <ModificationFunctionMapping> element
    EF 批量插入,sqlhelper 批量插入
    C# 自己用到的几个参数转换方法
    asp.net MVC EF Where 过滤条件怎么写
    EF Code First 数据迁移命令
  • 原文地址:https://www.cnblogs.com/AmyZheng/p/9224129.html
Copyright © 2011-2022 走看看