`
peonyzzdx
  • 浏览: 581695 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
社区版块
存档分类
最新评论

struts2 -- interceptor 拦截器

    博客分类:
  • J2EE
 
阅读更多
一、理解Struts2拦截器
1. Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现.
2. 拦截器栈(Interceptor Stack)。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。
二、实现Struts2拦截器原理
Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器
三、定义Struts2拦截器。
Struts2规定用户自定义拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口。该接口声明了3个方法,
void init();
void destroy();
String intercept(ActionInvocation invocation) throws Exception;
其中,init和destroy方法会在程序开始和结束时各执行一遍,不管使用了该拦截器与否,只要在struts.xml中声明了该Struts2拦截器就会被执行。
intercept方法就是拦截的主体了,每次拦截器生效时都会执行其中的逻辑。

不过,struts中又提供了几个抽象类来简化这一步骤。
public abstract class AbstractInterceptor implements Interceptor;
public abstract class MethodFilterInterceptor extends AbstractInterceptor;
都是模板方法实现的。
其中AbstractInterceptor提供了init()和destroy()的空实现,使用时只需要覆盖intercept()方法;
而MethodFilterInterceptor则提供了includeMethods和excludeMethods两个属性,用来过滤执行该过滤器的action的方法。可以通过param来加入或者排除需要过滤的方法。



1.interceptor的配置

拦截器的使用:1.先定义;2.在引用使用;

//定义拦截器
<interceptor name="myInterceptor" class="com.zzz.struts2.interceptor.MyInterceptor">

//引用使用
<interceptor-ref name="myInterceptor">
              </interceptor-ref>

各种引用使用如下图:



方法1. 普通配置法

<struts>
    <package name="struts2" extends="struts-default">
        <interceptors>
            <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor>
        </interceptors>
        <action name="register" class="edu.hust.action.RegisterAction">

            <!-- 在自定义interceptor并将其ref时, 系统会覆盖掉默认的interceptor-stack(defaultStack), 为了保证系统默认的defaultStack不受影响, 我们需要显式的将其引入 -->
            <!-- 注意两个interceptor-ref的顺序, 顺序不同, 执行效果也不同: 先配置的先执行/后配置的先退出(先进后出) -->
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="myInterceptor"></interceptor-ref>
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result>          
        </action>
    </package>
</struts>



[size=medium]
注意:
<package name="struts-shop" extends="struts-default">
    <interceptors>
      <interceptor-stack name="myStack">
        <interceptor-ref name="checkbox">
          <param name="uncheckedValue">0</param>
       </interceptor-ref>
       [color=red]<interceptor-ref name="defaultStack"/> </interceptor-stack>[/color]
    </interceptors>
    <default-interceptor-ref name="myStack"/>(这句是设置所有Action自动调用的拦截器堆栈)
  </package>


<interceptor-ref name="defaultStack"/> </interceptor-stack>
在拦截器站中引用,或者在action中引用,必须得有,否则出错



方法2. 配置拦截器栈(即将多个interceptor串联的一种元素)。然后在<action>中引入该拦截器栈就可以了。[/size]

<struts>
    <package name="struts2" extends="struts-default">
        
        <interceptors>
            <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor>
        
            <interceptor-stack name="myInterceptorStack">
                <interceptor-ref name="myInterceptor"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        
        <action name="register" class="edu.hust.action.RegisterAction">
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result>
            
            <interceptor-ref name="myInterceptorStack"></interceptor-ref>
        </action>
    </package>
</struts>


方法3. 修改默认拦截器,将自定义的拦截器栈定义为struts2的默认拦截器。

<struts>
    <package name="struts2" extends="struts-default">
        
        <interceptors>
            <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor>
            <interceptor-stack name="myInterceptorStack">
                <interceptor-ref name="myInterceptor"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        <!-- 此默认interceptor是针对所有action的 -->
        <!-- 如果某个action中引入了interceptor, 则在这个action中此默认interceptor就会失效 -->
        <default-interceptor-ref name="myInterceptorStack"></default-interceptor-ref>
        
        <action name="register" class="edu.hust.action.RegisterAction">
            <result name="input">/register.jsp</result>
            <result>/result.jsp</result>
        </action>
        
    </package></struts>





拦截器接口interceptor 和抽象类AbstracctInterceptor应用


package com.interceptor;  
import com.opensymphony.xwork2.ActionInvocation;  
import com.opensymphony.xwork2.interceptor.Interceptor;  
  
public class MyInterceptor implements Interceptor{  
    private String hello;//一定要写,后面会用上  
    get和set方法  
      
    public void init() {  
       System.out.println("init");  
    }  
      
    public String intercept(ActionInvocation invoker) throws Exception {  
       System.out.println("intercept");  
  
       String result=invoker.invoke();  
  
       return result;  
    }  
      
    public void destroy() {  
       System.out.println("destory");  
    }  
}  



我们在做拦截器的时候,实现了Interceptor接口,里面有三个方法,但是一般的情况下init() 和 destroy() 方法我们用不上,最关心的就是intercept(ActionInvocation invoker){}方法,所以怎么办呢?其实,struts2给我们提供了一个简化的拦截器类:AbstractInterceptor
AbstractInterceptor 这是一个抽象的类,里面实现了 init() 和 destroy() 方法,所以只要我们继承这个类,就不用再多写这两个方法!


所有拦截器的超级接口Interceptor ,Action去实现这个接口;
Interceptor 它其中有三个方法(init(),destroy() ,interceptor()):
Init()方法:在服务器起动的时候加载一次,并且只加载一次;
Destroy()方法:当拦截器销毁时执行的方法;
Interceptor()方法:其中里边有一个参数invocation

显然intercept()方法,是添加真正执行拦截工作的代码的地方,如果我们不需要初始化和清理的操作,可以直接继承com.opensymphony.xwork2.interceptor.AbstractInterceptor类,覆盖它的intercept()方法。这个方法有个ActionInvocation类型的参数,可以用它取得Session或转发请求等操作。


示例展示

明白了原理之后还需要做几项具体的工作:
1,自己写一个拦截器,实现检查用户是否登陆的功能。
2,添加拦截器的配置,让我们自己写的拦截器起作用。


LogonInterceptor.java

package tutorial.interceptor; 
import java.util.Map; 
import org.apache.struts2.ServletActionContext; 
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor; 
/**
* 登陆验证拦截器,如果用户没有登陆系统则让用户到登陆验证页面进行登陆
* 当用户请求网站资源的时候,例如某个Action,在Action被执行之前,检
* 查用户是否登陆了系统.
* 不足之处是该拦截器只能拦截Action,不能拦截jsp和servlet,所以不能
* 完全限制用户对未授权资源的访问,可以配合filter或将jsp页面放在
* WEB-INF目录下解决这个问题.
* 
* @author coombe
*/
public class LogonInterceptor extends AbstractInterceptor { 
      public String intercept(ActionInvocation invocation) throws Exception {
          // 取得请求的Action名
          String    name = invocation.getInvocationContext().getName();
  
          if (name.equals("Login")) {
              // 如果用户想登录,则使之通过
              return invocation.invoke(); 
          } else {
              // 取得Session。
              ActionContext ac = invocation.getInvocationContext();
              Map session =    (Map)ac.get(ServletActionContext.SESSION);
   
              if (session == null) {
                  // 如果Session为空,则让用户登陆。
                  return "login";
              } else {
                  String username = (String)session.get("username");
                  if (username == null) {
                      // Session不为空,但Session中没有用户信息,
                      // 则让用户登陆
                      return "login";
                  } else {
                      // 用户已经登陆,放行~
                      return invocation.invoke(); 
                  }
              }
          }
      }
} 


/*1,自定义拦截器
2,重定义默认拦截器堆栈
3,添加一个global-results,用户在验证失败的情况下跳转到登陆验证页面
*/


struts.xml

<!DOCTYPE struts PUBLIC
      "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
      "http://struts.apache.org/dtds/struts-2.0.dtd"> 
<struts><!-- Configuration for the default package. -->
<constant name="struts.custom.i18n.resources" value="globalMessages" />

<include file="struts-validation.xml" /> 
<package name="default" extends="struts-default">
  
    <!-- 自定义拦截器 -->
    <interceptors>
     <interceptor name="logon" class="tutorial.interceptor.LogonInterceptor"/>
        <!-- 自定义拦截器堆栈 -->
        <interceptor-stack name="myStack">
        <interceptor-ref name="logon"/>
        <!-- 引用默认的拦截器堆栈
      如果不用defaultStack,则表单值将会被页面跳转后返回-->
        <interceptor-ref name="defaultStack"/>
     </interceptor-stack>
    </interceptors>
  
    <!-- 重定义默认拦截器堆栈 -->
    <default-interceptor-ref name="myStack"/>
  
    <global-results>
     <result name="login" type="redirect-action">Login!input.action</result>
    </global-results>
  
        <action name="HelloWorld" class="tutorial.HelloWorld">
               <result>/HelloWorld.jsp</result>
           </action>
         
           <action name="Login" class="tutorial.Login">
              <result>/Success.jsp</result>
              <result name="input">/Login.jsp</result>
           </action>  
</package>
</struts> 


方法过滤拦截器MethodFilterInterceptor

1:上边的拦截器都要是针对整个action的,如果针对某个方法进行拦截可以去继承这个类;

它的使用跟上边的使用方法差不多,只是需要要配置它对那个方法进行拦截,方法过滤拦截器最好不要配置到自己设置默认的拦截器栈里边,自己手动配置.


<interceptor-ref name="myInterceptor3">
              <param name="includeMethods">execute</param>
              <param name="excludeMethods">execute</param>
             </interceptor-ref>
           <interceptor-ref name="defaultStack"></interceptor-ref>


其中includeMethods ,excludeMethods是固定写法: includeMethods 包含拦截那些方法,多个方法需要用”,”隔开; excludeMehtods是排除拦截的那些方法;



拦截器添加参数

MyInterceptor.java


package com.interceptor;  
import com.opensymphony.xwork2.ActionInvocation;  
import com.opensymphony.xwork2.interceptor.Interceptor;  
  
public class MyInterceptor implements Interceptor{  
    private String hello;//一定要写,后面会用上  
    get和set方法  
      
    public void init() {  
       System.out.println("init");  
    }  
      
    public String intercept(ActionInvocation invoker) throws Exception {  
       System.out.println("intercept");  
  
       String result=invoker.invoke();  
  
       return result;  
    }  
      
    public void destroy() {  
       System.out.println("destory");  
    }  
}  

private String hello;    get和set方法
写个变量,然后加上get和set方法,当然变量的名字必须和设定的参数是相同的,这个是赋值成功的前提条件
 
可以通过以下两种方式添加参数
1. 定义拦截器的时候添加参数:
Xml代码 

<interceptor name="myinterceptor" class="com.interceptor.MyInterceptor">  
    <param name="hello">world</param>  
</interceptor>  

2. 使用拦截器的时候添加参数:
Xml代码 

<interceptor-ref name="myinterceptor">  
     <param name="hello">zhuxinyu</param>  
</interceptor-ref>
 

可是还有个问题,在定义的时候添加了参数hello,使用时同样添加了参数param,当运行MyInterceptor类时会输出哪个呢? world 还是 zhuxinyu。
结果是:zhuxinyu  很明显,覆盖了第一个,这是什么原则:就近原则。形如 OO 中的覆盖,重写


此时,运行MyInterceptor.java,在整个拦截器中任何方法中运行 System.out.println(hello);成功输出: world




Struts2拦截器的执行顺序

1.如果一个系统中配置了多个拦截器,根据拦截器配置的顺序不同,执行拦截器的顺序也不一样。通常认为,先配置的拦截器,会先获得执行的机会,但是实际情况不是这样。execute()方法执行之前,配置在前面的拦截器,会先对用户的请求起作用。execute()方法执行之后,配置在后面的拦截器,会先对用户的请求起作用。(两头向中间靠拢的执行)

定义拦截器
Java代码 

package com.sh.interceptor;  
  
import com.opensymphony.xwork2.ActionInvocation;  
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;  
  
public class DefaultInterceptor extends AbstractInterceptor{  
  
    private String name;  
      
    public void setName(String name) {  
        this.name = name;  
    }  
  
    @Override  
    public String intercept(ActionInvocation invocation) throws Exception {  
        System.out.println(name+"执行了。。。");  
        String result=invocation.invoke();  
        System.out.println(name+"执行完毕。。。");  
        return result;  
    }  
      
}  


action
Java代码 

package com.sh.action;  
  
import com.opensymphony.xwork2.ActionSupport;  
  
public class DefaultAction extends ActionSupport {  
    public String execute(){  
        return SUCCESS;  
    }  
}  


struts.xml
Xml代码

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE struts PUBLIC  
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"  
    "http://struts.apache.org/dtds/struts-2.3.dtd">  
  
<struts>   
    <!-- 如果 注解的action配置改变时候不需要重新启动tomcate -->  
    <constant name="struts.devMode" value="false"/>    
    <constant name="struts.convention.classes.reload" value="true" />   
      
    <package name="default" extends="struts-default">  
        <interceptors>  
            <interceptor name="inter1" class="com.sh.interceptor.DefaultInterceptor"/>  
            <interceptor name="inter2" class="com.sh.interceptor.DefaultInterceptor"/>  
            <interceptor name="inter3" class="com.sh.interceptor.DefaultInterceptor"/>  
        </interceptors>  
        <action name="default" class="com.sh.action.DefaultAction">  
            <result>/index.jsp</result>  
            <interceptor-ref name="inter1">  
                <param name="name">拦截器1</param>  
            </interceptor-ref>  
            <interceptor-ref name="inter2">  
                <param name="name">拦截器2</param>  
            </interceptor-ref>  
            <interceptor-ref name="inter3">  
                <param name="name">拦截器3</param>  
            </interceptor-ref>  
            <interceptor-ref name="defaultStack"/>  
        </action>  
      
    </package>  
      
</struts>  


--访问
http://localhost:8080/Struts2_interceptorSort/default.action

--控制台的信息 如下
拦截器1执行了。。。
拦截器2执行了。。。
拦截器3执行了。。。
拦截器3执行完毕。。。
拦截器2执行完毕。。。
拦截器1执行完毕。。。

[/size]
  • 大小: 8.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics