Struts2拦截器的使用心得和理解

一、先来说说在项目中遇到的问题:由于需要对用户权限进行控制,在控制过程中采用的Sturts2的拦截器:为了获得session,我在拦截器类上实现了SessionAware(愚蠢的错误),才开始是想方便,结果怎么也得不到session,相关代码如下:

package edu.cqupt.iactg.helper;

import java.util.Map;

import org.apache.commons.fileupload.servlet.ServletRequestContext;
import org.apache.struts2.interceptor.SessionAware;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

import edu.cqupt.iactg.action.UserAction;

public class UserInterceptor implements Interceptor ,SessionAware{
	private Map<String ,Object> session=null;//获得session
	private Map<String,Object> session3=null;
	public static final String LOGIN="index";//全局返回值

	

	public void destroy() {
		System.out.println("拦截器销毁");
	}

	public void init() {
		System.out.println("拦截器加载");
	}

	public String intercept(ActionInvocation actionInvocation) throws Exception {
		System.out.println("进入拦截器");
		//如果访问的是登陆acton则不需要对其拦截
		if(actionInvocation.getAction() instanceof UserAction){
			
			System.out.println("Useraction=========================");
			return actionInvocation.invoke();//执行其他的拦截器
		}
		
		session = actionInvocation.getInvocationContext().getSession();  //  从Invocation得到session对象
		Map<String,Object> session2=ActionContext.getContext().getSession();
		System.out.println(session+"actionInvocation的session");
		System.out.println(session2+"ActionCOntext的session");
		System.out.println(session3+"注入的session");
		String user=(String) session.get("username");//得到session中的值
		//如果存在该用户,放行
		System.out.println(user);
		if(user!=null&&!user.isEmpty()){
			System.out.println("存在该用户");
			return actionInvocation.invoke();
		}else{
			//如果不存在该用户
			System.out.println("不岑在该用户");
			return LOGIN;//跳转到登陆页面
		}
		
		
	}

	public void setSession(Map<String, Object> arg0) {
		this.session3=arg0;
		System.out.println("注入session3");
		
	}

}

然后换成用ActionInvocation和ActionContext都能得到session,一直在思考这个愚蠢的问题,查阅资料发现,Struts2要访问ServletApi是通过

servletConfig拦截器
这个拦截器提供Action直接对Servlet API的访问,把Servlet API的对象注入到Action中。包括:ServletRequestAware、ServletResponseAware、ParameterAware、SessionAware、ApplicationAware。所以在拦截器中实现SessionAware接口是不能注入session的.调试发现setSession方法根本没有调用过

二、下面我们来认识一下拦截器
Struts2只所以如此强大,跟他的拦截器脱不了关系。比如上文说到的ServletApi的注入就是Struts2一个强大的拦截器,Struts2还有很多有用的拦截器“Struts-default.xml
  <interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="debugging"/>
                <interceptor-ref name="profiling"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                  <param name="excludeParams">dojo\..*,^struts\..*</param>
                </interceptor-ref>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
            </interceptor-stack>

            <!-- The completeStack is here for backwards compatibility for
                 applications that still refer to the defaultStack by the
                 old name -->
            <interceptor-stack name="completeStack">
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>

            <!-- Sample execute and wait stack.
                 Note: execAndWait should always be the *last* interceptor. -->
            <interceptor-stack name="executeAndWaitStack">
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
            </interceptor-stack>

       </interceptors>

        <default-interceptor-ref name="defaultStack"/>
大家可以发现,Struts2已经帮我们做好了一个默认的拦截器,里面的功能大多了!大家不难发现里面有诸如modelDriven,fileupload等大家经常用到的东西。
拦截器的思想正是我们大家口中的AOP思想,也就是面向切面编程。相信大家一定对这个很熟悉了,我就不在多说,Aop的思想在Spring才是正在能够体现出来,当然拦截器也是AOP的一种实现。
三、自定义拦截器
那么我们如何在定义自己的拦截器呢?
方法一、实现Interceptor接口。方法二、继承AbstractInterceptor

public abstract class AbstractInterceptor implements Interceptor {  
   
     public void init() {  
    }  
     
    public void destroy() {  
    }  
   
   
    public abstract 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;  
}  

如果不需要init和destpry方法的话,建议大家采用后者。就用登陆拦截做例子吧看代码

package edu.cqupt.iactg.helper

import java.util.Map;

import org.apache.commons.fileupload.servlet.ServletRequestContext;
import org.apache.struts2.interceptor.SessionAware;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

import edu.cqupt.iactg.action.UserAction;

public  class UserInterceptor implements Interceptor {
	private Map<String ,Object> session=null;//获得session
	public static final String LOGIN="index";//全局返回值

	

	public void destroy() {
		System.out.println("拦截器销毁");
	}

	public void init() {
		System.out.println("拦截器加载");
	}

	public String intercept(ActionInvocation actionInvocation) throws Exception {
		System.out.println("进入拦截器");
		//如果访问的是登陆acton则不需要对其拦截
		if(actionInvocation.getAction() instanceof UserAction){
			
			return actionInvocation.invoke();//执行其他的拦截器
		}
		
		session = actionInvocation.getInvocationContext().getSession();  //  从Invocation得到session对象
		
		String user=(String) session.get("username");//得到session中的值
		//如果存在该用户,放行
		System.out.println(user);
		if(user!=null&&!user.isEmpty()){
			System.out.println("存在该用户");
			return actionInvocation.invoke();
		}else{
			//如果不存在该用户
			System.out.println("不岑在该用户");
			return LOGIN;//跳转到登陆页面
		}
		
		
	}



}


 
 
这里提出两个点1、返回值是一个String类型,如果返回的是invoke();则代表此拦截器已经放行,将执行下一个拦截器,否则返回一个字符串(一般是全局result)看下列代码
<package name="basic" abstract="true" extends="json-default">
		<!-- 定义自己的拦截器 -->
	 	<interceptors>
	 	<!-- z指定改拦截器的位置 -->
		<interceptor name="userInterceptor" class="edu.cqupt.iactg.helper.UserInterceptor"></interceptor>
		<!-- 指定拦截器栈 -->
		<interceptor-stack name="myStack">
		<interceptor-ref name="defaultStack"></interceptor-ref><!-- Struts2自己提供的默认拦截器 -->
	  	<interceptor-ref name="userInterceptor"></interceptor-ref><!-- 我们自己定义的拦截器 -->
		</interceptor-stack>
		
		</interceptors> 
	
	 	<!-- <default-interceptor-ref name="myStack"></default-interceptor-ref> --><!--设置为默认拦截器 -->
	 	<global-results>
			<result name="ERROR" type="redirectAction">disparter/error</result>
			<result name="index" type="redirect">/</result><!-- 登陆界面地址 -->
		</global-results>
	 	
	 	<!-- 异常处理 -->
		<global-exception-mappings>
			<exception-mapping result="ERROR" exception="java.lang.Exception"/>
		</global-exception-mappings>
			 	
 </package>

现在我们就定义好了自己的代码了,我的拦截器定义时放在最终的一个父包里面的,如果要让继承该包的xml文件都使用这个拦截器就应该加上一条
<!-- <default-interceptor-ref name="myStack"></default-interceptor-ref> -->

如果不让所有的都这样的话可以这样:
	<package name="disparter" namespace="/disparter" extends="basic">

		<action name="main">
			<interceptor-ref name="myStack"></interceptor-ref>
			<result>/jsp/index_main.jsp</result>
		</action>
		<action name="home">
		<interceptor-ref name="myStack"></interceptor-ref>
			<result>/jsp/home.jsp</result>
		</action>
		<action name="index">
			<result>index.jsp</result>
		</action>
		<action name="error">
			<result>/jsp/error.html</result>
		</action>

	</package>

在要使用的的action下指定拦截器就行了。

四、过滤器和拦截器的区别
相信大家读到这里有很多疑问了。Serlvet提供的过滤器和我们的拦截器有什么区别呢?
这里引用http://blog.sina.com.cn/s/blog_8bcfeeda010107q0.html的博客,写得很详细

过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符

拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。

 

拦截器与过滤器的区别 :

  1. 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
  2. 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
  3. 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
  4. 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  5. 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

执行顺序 :过滤前 - 拦截前 - Action处理 - 拦截后 - 过滤后。个人认为过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后,拦截器将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;Action处理完成返回后,拦截器还可以做其他过程(还没想到要做啥),再向上返回到过滤器的后续操作。

 

 面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。
      但是人们也发现,在分散代码的同时,也增加了代码的重复性。什么意思呢?比如说,我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。

    也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。 
      一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。
这样看来,AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP变得立体了。如果加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来说,AOP基本上是通过代理机制实现的。 
     AOP在编程历史上可以说是里程碑式的,对OOP编程是一种十分有益的补充。

欢迎大家指正!!!







 
 

你可能感兴趣的:(继承,面向对象,namespace,struts2,redirect)