Servlet Filter和Spring mvc Interceptor

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

===========before doFilter1
===========before doFilter2
===========HandlerInterceptorAll preHandle
===========HandlerInterceptor1 preHandle
===========HandlerInterceptor2 preHandle
执行Controller
Controller return前
===========HandlerInterceptor2 postHandle
===========HandlerInterceptor1 postHandle
===========HandlerInterceptorAll preHandle
Controller return后,Jsp加载完成
===========HandlerInterceptor2 afterCompletion
===========HandlerInterceptor1 afterCompletion
===========HandlerInterceptorAll preHandle
===========before doFilter2
===========before doFilter1

Filter:
Java中的Filter并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest。根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。在HttpServletResponse 到达客户端之前,拦截HttpServletResponse。根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。

Filter随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。
1.启动服务器时加载过滤器的实例,并调用init()方法来初始化实例;
2.每一次请求时都只调用方法doFilter()进行处理;
3.停止服务器时调用destroy()方法,销毁实例。

自定义Servlet Filter:

    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;

    public class ErrorHandleFilter implements Filter {

        @Override
        public void destroy() {
            // ...
        }

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            //
        }

        @Override
        public void doFilter(ServletRequest request,
                   ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

            try {
                long before = System.currentTimeMillis();
                System.out.println("===========before doFilter")
                chain.doFilter(request, response);
                long after = System.currentTimeMillis();
                System.out.println("===========after doFilter")
            } catch (Exception ex) {
                request.setAttribute("errorMessage", ex);
                request.getRequestDispatcher("/WEB-INF/views/jsp/error.jsp")
                                   .forward(request, response);
            }

        }

    }

上面程序实现了doFilter()方法,实现该方法就可实现对用户请求进行预处理,也可实现对服务器响应进行后处理——它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。调用Servlet的doService()方法是就是在chain.doFilter(request, response)这个方法中进行的。

在web.xml中配置:

<filter>
    <filter-name>errorHandlerFilter</filter-name>
    <filter-class>com.mkyong.form.web.ErrorHandleFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>errorHandlerFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

使用Spring进行管理:
DelegatingFilterProxy就是一个对于servlet filter的代理,它没有实现过滤器的任何逻辑。通过spring容器来管理ServletFilter的生命周期。如果filter中需要一些Spring容器的实例,可以通过spring直接注入。
在web.xml中配置:

    <filter>  
    < filter-name>myFilter</filter-name>  
    < filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
    </filter>  
    <filter-mapping>  
    < filter-name>myFilter</filter-name>  
    < url-pattern>/*</url-pattern>  
    </filter-mapping>  

在contextApplication.xml中,配置具体的Filter类的实例。在Spring中配置的bean的name要和web.xml中的<filter-name>一样

    <bean name="myFilter" class="com.*.MyFilter"></bean>

Interceptor:
spring mvc中的Interceptor可以理解为是Spring MVC框架对AOP的一种实现方式。一般简单的功能又是通用的,每个请求都要去处理的,比如判断token是否失效可以使用spring mvc的HanlderInterceptor, 复杂的,比如缓存,需要高度自定义的就用spring aop。一般来说service层更多用spring aop,controller层有必要用到request和response的时候,可以用拦截器。

spring mvc中的Interceptor拦截请求是通过HandlerInterceptor来实现的。所以HandlerInteceptor拦截器只有在Spring Web MVC环境下才能使用。在SpringMVC中定义一个拦截器主要有两种方式,第一种方式是要实现Spring的HandlerInterceptor接口,或者是其它实现了HandlerInterceptor接口的类,比如HandlerInterceptorAdapter。第二种方式是实现WebRequestInterceptor接口,或者其它实现了WebRequestInterceptor的类。

HandlerInterceptor接口中定义了三个方法preHandle, postHandle, 和afterCompletion:

  • preHandle:预处理回调方法,实现处理器的预处理(如登录检查),返回值:true表示继续流程(如调用下一个拦截器或处理器),false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应。
  • postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
  • afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调。该方法也是需要当前对应的Interceptor 的preHandle方法的返回值为true时才会执行。这个方法的主要作用是用于进行资源清理工作的,如性能监控中我们可以在此记录结束时间并输出消耗时间。

流程如下:
先声明的Interceptor 的postHandle 方法反而会后执行。


有时候我们可能只需要实现三个回调方法中的某一个,如果实现HandlerInterceptor接口的话,三个方法必须实现。spring提供了一个HandlerInterceptorAdapter适配器(一种适配器设计模式的实现),允许我们只实现需要的回调方法。
HandlerInterceptor1,HandlerInterceptor2:

    public class HandlerInterceptor1 extends HandlerInterceptorAdapter {
        @Override  
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
            System.out.println("===========HandlerInterceptor1 preHandle");  
            return true;  
        }  
        @Override  
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {  
            System.out.println("===========HandlerInterceptor1 postHandle");  
        }  
        @Override  
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {  
            System.out.println("===========HandlerInterceptor1 afterCompletion");  
        }  
    }  

HandlerInterceptor2同理,只是输出内容为“HandlerInterceptor2”。

TestController:

    public class TestController implements Controller {  
        @Override  
        public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {  
            System.out.println("===========TestController");  
            return new ModelAndView("test");  
        }  
    }  

Spring配置文件:

    <bean id="handlerInterceptor1" class="cn.javass.chapter5.web.interceptor.HandlerInterceptor1"/>  
    <bean id="handlerInterceptor2" class="cn.javass.chapter5.web.interceptor.HandlerInterceptor2"/>  

    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">  
        <property name="interceptors">  
            <list>  
               //拦截器的执行顺序就是此处添加拦截器的顺序。
               <ref bean="handlerInterceptor1"/>  
               <ref bean="handlerInterceptor2"/>  
            </list>  
        </property>  
    </bean> 

如果使用了<mvc:annotation-driven />, 它会自动注册BeanNameUrlHandlerMapping这两个bean,所以就没有机会再给它注入interceptors属性,就无法指定拦截器。推荐使用mvc:interceptors标签来声明需要加入到SpringMVC拦截器链中的拦截器。

在SpringMVC的配置文件中加上支持MVC的schema:

    <beans xmlns:mvc="http://www.springframework.org/schema/mvc"  
    xsi:schemaLocation=" http://www.springframework.org/schema/mvc  
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" >

    <mvc:interceptors>  
        <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求
        <bean class="com.host.app.web.interceptor.HandlerInterceptorAll"/>   -->  
        <mvc:interceptor>  
            <mvc:mapping path="/test/number.do"/> 
            <mvc:exclude-mapping path="/test/goLogin.*"/> 
            <!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->  
            <bean class="com.host.app.web.interceptor.HandlerInterceptor1"/>  
            <!-- <ref bean="handlerInterceptor1"/> -->
        </mvc:interceptor>  
        <mvc:interceptor>  
            <mvc:mapping path="/test/number.do"/> 
            <mvc:exclude-mapping path="/test/goLogin.*"/> 
            <bean class="com.host.app.web.interceptor.HandlerInterceptor2"/>  
            <!-- <ref bean="handlerInterceptor2"/> -->
        </mvc:interceptor>  
    </mvc:interceptors>  

在mvc:interceptors标签下声明interceptor主要有两种方式:
1.直接定义一个Interceptor实现类的bean对象。使用这种方式声明的Interceptor拦截器将会对所有的请求进行拦截。
2.使用mvc:interceptor标签进行声明。这种方式进行声明的Interceptor可以通过mvc:mapping子标签来定义需要进行拦截的请求路径。

视图页面WEB-INF/jsp/test.jsp:

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
    <%System.out.println("==========test.jsp");%>

参考:
http://983836259.blog.51cto.com/7311475/1880286
http://www.cnblogs.com/dreamroute/p/4198087.html
http://www.cnblogs.com/ctxsdhy/p/6421067.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,050评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,184评论 6 345
  • Spring MVC一、什么是 Spring MVCSpring MVC 属于 SpringFrameWork 的...
    任任任任师艳阅读 3,309评论 0 32
  • 拦截一些请求进行处理,比如通过它来进行权限验证,或者是来判断用户是否登陆,日志记录,编码,或者限制时间点访问等等,...
    JackFrost_fuzhu阅读 1,916评论 0 7
  • 场景需求:在没有一个类的实现源码的情况下,想改变其中一个方法(一般指系统的方法)的实现,除了继承它重写、和借助类别...
    船长_阅读 2,057评论 0 17