Spring MVC 拦截器


什么是拦截器

            拦截器是指通过统一拦截浏览器发往服务器的请求来完成功能的增强。

            其使用场景一般是为了解决请求的共性问题,如:乱码问题、权限验证问题等。

            拦截器和过滤器的工作原理非常相似,最后再总结。


实现方式

            拦截器有两种实现方式

            1、  通过实现Spring的HandlerInterceptor接口,或者集成实现HandlerInterceptor接口的类,如该接口的抽象类HandlerInterceptorAdapter.

            2、  通过实现Spring的WebRequestInterceptor接口,或者集成WebRequestInterceptor的类。


实现步骤

            1、  编写拦截器类实现HandlerInterceptor接口。

            2、  将拦截器注册进SpringMVC框架中。

            3、  配置拦截器的拦截规则。


实现demo

            此处以Maven管理SpringMVC的项目


1.    预备文件配置

@@@@Pom.xml配置,添加依赖项

……

<dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-framework-bom</artifactId>

            <version>${spring.version}</version>

            <type>pom</type>

            <scope>import</scope>

        </dependency>

    <dependency>

        <groupId>javax.servlet</groupId>

         <artifactId>servlet-api</artifactId>

         <version>2.5</version>

         <scope>provided</scope>

   </dependency>

……

        上述spring-framework-bom是为了提供springMVC框架,servlet-api是为了提供页面请求HttpServletRequest和页面返回HttpServletResponse等对象,但是Tomcat包含有这些对象,所以,使用Tomcat服务器的可以不用加入后面的servlet-api依赖,使用Jetty容器的则需要加入servlet-api依赖。


@@@@公共上下文applicationContext配置

<?xmlversion="1.0"encoding="UTF-8"?> 

<beans xmlns="http://www.springframework.org/schema/beans" 

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:p="http://www.springframework.org/schema/p"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:context="http://www.springframework.org/schema/context" 

    xmlns:aop="http://www.springframework.org/schema/aop" 

    xmlns:mvc="http://www.springframework.org/schema/mvc" 

    xsi:schemaLocation="

                 http://www.springframework.org/schema/beans

                 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

                 http://www.springframework.org/schema/tx

                 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

                 http://www.springframework.org/schema/aop

                 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

                 http://www.springframework.org/schema/context

                 http://www.springframework.org/schema/context/spring-context-3.0.xsd

                 http://www.springframework.org/schema/mvc

                 http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <!--启动基于AnnotationDI管理 -->

    <context:annotation-config/>

    <context:component-scanbase-package="com.terence.mvcdemo">

        <context:exclude-filtertype="annotation"

            expression="org.springframework.stereotype.Controller"/>

    </context:component-scan>

</beans>


@@@@DispatcherServlet.xml文件配置

<?xmlversion="1.0"encoding="UTF-8"?> 

<beans xmlns="http://www.springframework.org/schema/beans" 

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:p="http://www.springframework.org/schema/p"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:context="http://www.springframework.org/schema/context" 

    xmlns:aop="http://www.springframework.org/schema/aop" 

    xmlns:mvc="http://www.springframework.org/schema/mvc" 

    xsi:schemaLocation="

                 http://www.springframework.org/schema/beans

                 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

                 http://www.springframework.org/schema/tx

                 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

                 http://www.springframework.org/schema/aop

                 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

                 http://www.springframework.org/schema/context

                 http://www.springframework.org/schema/context/spring-context-3.0.xsd

                 http://www.springframework.org/schema/mvc

                 http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

     <context:annotation-config/>

     <context:component-scanbase-package="com.terence.mvcdemo.controller">

       <context:include-filtertype="annotation"expression="org.springframework.stereotype.Controller"/>

     </context:component-scan>

     

     <mvc:annotation-driven/>

     <mvc:interceptors>

     <mvc:interceptor>

         <!--拦截规则:只拦截viewAll.form结尾的请求 -->

         <mvc:mappingpath="/viewAll.form"/>

         <beanclass="com.terence.mvcdemo.interceptor.Test1Interceptor"></bean>

     </mvc:interceptor>    

     </mvc:interceptors>

     <beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver">

       <propertyname="viewClass"value="org.springframework.web.servlet.view.JstlView"/>

       <propertyname="prefix"value="/WEB-INF/jsps/"/>

       <propertyname="suffix"value=".jsp"/>

     </bean>

    <!-- 注册拦截器 -->  

</beans>

 

2 编写拦截器,实现HandlerInterceptor接口

package com.terence.mvcdemo.interceptor;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

 

public  class Test1Interceptor implements HandlerInterceptor {

 

    public void afterCompletion(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2,

            Exception arg3) throws Exception {

        System.out.println("执行到了afterCompletion1()");      

    }

 

    public void postHandle(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2,

            ModelAndView arg3) throws Exception {

        arg3.addObject("msg","这是拦截器postHandle方法修改之后的消息");

                //更改传回的参数值。

        arg3.setViewName("hello2");//更改请求页面,类似于重定向

        System.out.println("执行到了postHandle1()");   

    }

 

    public boolean preHandle(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2)

            throws Exception {

        arg0.setCharacterEncoding("utf-8");    

        System.out.println("执行到了preHandle1()");

        //如果用户没有登录,则终止请求,并返回到登录页面

        if(arg0.getSession().getAttribute("user")==null)

        {

            arg0.getRequestDispatcher("/login").forward(arg0, arg1);

                //return false;

        }

        return true;

    }

}


preHandle方法

在请求之前进行调用

   public boolean preHandle(HttpServletRequest arg0,

        HttpServletResponse arg1,Object arg2)

        throws Exception {

      System.out.println("preHandle");

      return true;

   }

        此方法含有布尔型返回值,表示是否将当前请求拦截下来,如果返回false,表示请求将被终止,如果返回true,表示当前请求将继续运行。

        HttpServletRequest:表示所有请求内容。

        HttpServletResponse:表示所有返回内容。

        Object:表示的是被拦截的请求的目标,表示的是控制器Controller下的某个方法,可以通过一些参数获取拦截对象中的一些内容。

 

postHandle方法

        在请求之后调用。

   public void postHandle(HttpServletRequest arg0,

        HttpServletResponse arg1,Object arg2,

        ModelAndView arg3) throws Exception {

      System.out.println("postHandle");

   }

        ModelAndView:通过该参数可以改变显示的视图,或修改发往视图的方法。

        比如,如果想要在jsp页面中显示一个后台返回的消息,则在后台可以通过ModelAndView传回一个消息,在jsp页面中写${“msg”}即可,msg是ModelAndView对象里面要显示的消息名。


afterCompletion方法

视图显示步骤完成之后要调用的方法,主要用于资源销毁,用于关闭一些资源或流。

 

3.注册拦截器到SpringMVC框架中

        <mvc:interceptor>

            <!--拦截规则:只拦截viewAll.form结尾的请求  -->

           <mvc:mappingpath="/viewAll.form"/>

           <beanclass="com.terence.mvcdemo.interceptor.Test1Interceptor"></bean>

        </mvc:interceptor> 

      </mvc:interceptors>

 

4.指定拦截规则

……

    <mvc:mappingpath="/viewAll.form"/>

……

        表示只拦截viewAll.form结尾的请求。

 

 

多个拦截器的应用


两个拦截器的编写

拦截器1:

public  class Test1Interceptor implements HandlerInterceptor {

    public void afterCompletion(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2,

            Exception arg3) throws Exception {

        System.out.println("执行到了afterCompletion1()");      

    }

    public void postHandle(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2,

            ModelAndView arg3) throws Exception {

        arg3.addObject("msg","这是拦截器postHandle方法修改之后的消息");//更改传回的参数值。

        arg3.setViewName("hello2");//更改请求页面,类似于重定向

        System.out.println("执行到了postHandle1()");   

    }

    public boolean preHandle(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2)

            throws Exception {

        System.out.println("执行到了preHandle1()");

        return true;

    }

}

拦截器2:

public  class Test2Interceptor implements HandlerInterceptor {

    public void afterCompletion(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2,

            Exception arg3) throws Exception {

        System.out.println("执行到了afterCompletion2()");      

    }

    public void postHandle(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2,

            ModelAndView arg3) throws Exception {

        System.out.println("执行到了postHandle2()");   

    }

    public boolean preHandle(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2)

            throws Exception {

        System.out.println("执行到了preHandle2()");

        return true;

    }

}


多个拦截器的配置

@@@@@viewSpace-servlet.xml配置文件(DispatcherServlet文件)

…………

<mvc:interceptors>

        <mvc:interceptor>

            <!--拦截规则:只拦截viewAll.form结尾的请求  -->

           <mvc:mappingpath="/viewAll.form"/>

           <beanclass="com.terence.mvcdemo.interceptor.Test1Interceptor"></bean>

        </mvc:interceptor>

        <mvc:interceptor>

            <!--拦截规则:只拦截viewAll.form结尾的请求  -->

           <mvc:mappingpath="/viewAll.form"/>

           <beanclass="com.terence.mvcdemo.interceptor.Test2Interceptor"></bean>

        </mvc:interceptor>

</mvc:interceptors>

…………


多个拦截器执行顺序

 

然后可以调拦截器注册的先后顺序,会发现,执行结果和上述拦截器的反应相反。得知拦截器是根据注册的先后顺序实行多拦截器的拦截,那么拦截器的具体执行过程是怎样的呢?可以表示为下图所示:

 

拦截器其他实现方式(WebRequestInterceptor)


拦截器的第二种实现方式就是实现WebRequestInterceptor接口

这两种方法的方法名一样,只有参数有稍微区别,不过大同小异;另外,后者preHandle方法没有返回值,不能终止请求。

通过实现WebRequestInterceptor接口来实现拦截器,其注册方法不变,唯一的缺点就是不能终止请求。

 

使用场景

        使用原则:处理所有请求中的共性问题

1 乱码问题

        可以在preHandle()方法中对请求内容进行统一编码:

public boolean preHandle(HttpServletRequest arg0,

            HttpServletResponse arg1,Object arg2)

            throws Exception {

        arg0.setCharacterEncoding(“utf-8”);

        System.out.println("执行到了preHandle2()");

        return true;

    }


2 权限验证问题

        很多内容都是针对登录用户才能使用,需要统一验证用户

……

public boolean preHandle(HttpServletRequest arg0,

            HttpServletResponsearg1, Object arg2)

            throws Exception {

        arg0.setCharacterEncoding("utf-8");

        System.out.println("执行到了preHandle1()");

        //如果用户没有登录,则终止请求,并返回到登录页面

        if(arg0.getSession().getAttribute("user")==null)

        {

            arg0.getRequestDispatcher("/login").forward(arg0, arg1);

            //return false;

        }

        return true;

    }

……

 

拦截器与过滤器的区别

1) 拦截器Interceptor依赖于框架容器,基于java的反射机制,只过滤请求。    过滤器依赖于servlet容器,基   于回调函数,过滤范围较大。
2) 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
3) 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
4) 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
5) 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以    调用业务逻辑
 

6) 拦截器可以处理web应用中请求的一些通用问题,将拦截单独编写,独立于Controller,可以处理一些共性的     问题,减少了代码服用,便于维护。


 

参考代码


         Reference Demo: testMavenWebDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值