Spring MVC拦截器实现分析

Spring MVC拦截器实现分析

 一、Servlet Filter与Spring interceptor的执行顺序

  Filter有顺序吗?我们怎么控制filter的执行顺序。通过Tomcat的代码分析,servlet在Filter执行完成后才调用,如有多个filter怎么控制执行顺序,首先会想到在web.xml配置某个参数,例如order之类的,但查找一下一番,servlet并没有这个参数。试试filter Mapping的配置的先后顺序,果然有效,原来filter的执行顺序就考filter mapping在web.xml中的顺序。

  spring interceptor也是这样的执行顺序,不过interceptor多一个配置参数order通过他也可以来实现interceptor的执行顺序。很多应用场景中,执行顺序还是重要的,比如cache和transaction interceptor的执行顺序,很显然cache应该在transaction之前,这样发现命中了就不用打开事务,如果transaction在前,每次都打开事务即使cache命中,这是一个无谓东动作。

  二、利用springMVC的interceptor实现页面性能监控(Filter亦可)

  调优第一步,找出耗时比较长的页面进行优化。利用interceptor能轻易搞定。interceptor提供了preHandle和postHandle以及afterCompletion三个方法。preHandle调用controller具体方法之前调用,postHandle完成具体方法之后调用,afterCompletion完成对页面的render以后调用,至此整个页面渲染完成。也就是说我们在preHandle记录开始的时间,在afterCompletion记录结束的时间,就可或者整个页面生成的时间。Spring自带StopWatch工具类来实现时间跟踪,关键一点interceptor不是线程安全的。我们需要借助threadlocal来实现线程安全。

@Override 
    public boolean preHandle(HttpServletRequest request, 
            HttpServletResponse response, Object handler) throws Exception { 
        if(usePerformance){ 
            StopWatch stopWatch = new StopWatch(handler.toString()); 
            stopWatchLocal.set(stopWatch); 
            stopWatch.start(handler.toString()); 
        } 
         
        return true
    } 

 @Override 
    public void afterCompletion(HttpServletRequest request, 
            HttpServletResponse response, Object handler, Exception ex) 
            throws Exception { 
        if(usePerformance){ 
            StopWatch stopWatch = stopWatchLocal.get(); 
            stopWatch.stop(); 
            String currentPath = request.getRequestURI(); 
            String queryString  = request.getQueryString(); 
            queryString = queryString == null ? "":"?" + queryString; 
            log.info("access url path:" + currentPath + queryString +  " |time:" + stopWatch.getTotalTimeMillis()); 
            stopWatchLocal.set(null); 
        } 
    }

  如果你没有使用springMVC可以使用filter来完成:

stopWatch.start(); 
doFilterChain(); 
stopWatch.stop();

  三、SpringMVC 拦截器实现分析

  SpringMVC的拦截器不同于Spring的拦截器,SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也没有代理,同时SpringMVC管理的Controller也不有代理。哪不难想到我们在执行controller之前做某些动作,执行完毕做某些动作,render完成做某些动作。SpringMVC的拦截器对应提供了三个preHandle,postHandle,afterCompletion方法。只需在三个方法内写我们需要的逻辑就行,多了都是废话,还是代码实在。

HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); 
                if (interceptors != null) { 
                    for (int i = 0; i < interceptors.length; i++) { 
                        HandlerInterceptor interceptor = interceptors[i]; 
//ha.handle是调用具体的controller在此之前执行preHandle                      if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { 
                            triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); 
                            return
                        } 
                        interceptorIndex = i; 
                    } 
                } 

                // Actually invoke the handler. 
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

  完成调用之后,调用render(),最后执行afterCompletion()。

if (interceptors != null) { 
                for (int i = interceptors.length - 1; i >= 0; i--) { 
                    HandlerInterceptor interceptor = interceptors[i]; 
                    interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); 
                } 
            } 
        } 
        catch (ModelAndViewDefiningException ex) { 
            logger.debug("ModelAndViewDefiningException encountered", ex); 
            mv = ex.getModelAndView(); 
        } 
        catch (Exception ex) { 
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); 
            mv = processHandlerException(processedRequest, response, handler, ex); 
            errorView = (mv != null); 
        } 

        // Did the handler return a view to render? 
        if (mv != null && !mv.wasCleared()) { 
            render(mv, processedRequest, response); 
            if (errorView) { 
                WebUtils.clearErrorRequestAttributes(request); 
            } 
        } 
        else { 
            if (logger.isDebugEnabled()) { 
                logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + 
                        "': assuming HandlerAdapter completed request handling"); 
            } 
        } 

        // Trigger after-completion for successful outcome. 
        triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);

本文出自seven的测试人生公众号最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2024-08-07 13:01:56

Spring MVC拦截器实现分析的相关文章

spring MVC拦截器01

spring MVC拦截 作用:身份校验,权限检查,防止非法访问. 场景:一个bbs系统,用户没有登录就无法发帖或者删除评论; 一个博客系统,没有登录就无法发表博文,无法增加分类,无法删除博文. spring MVC 拦截实现分为2步 (1)编写拦截器类,必须继承org.springframework.web.servlet.HandlerInterceptor 核心方法: public boolean preHandle(HttpServletRequest request, HttpServ

Spring MVC拦截器+注解方式实现防止表单重复提交

原理:在新建页面中Session保存token随机码,当保存时验证,通过后删除,当再次点击保存时由于服务器端的Session中已经不存在了,所有无法验证通过. 1.新建注解: ? /**  * <p>  * 防止重复提交注解,用于方法上<br/>  * 在新建页面方法上,设置needSaveToken()为true,此时拦截器会在Session中保存一个token,  * 同时需要在新建的页面中添加  * <input type="hidden" name

自定义 spring mvc 拦截器(近期项目需求实现)

          需求背景:特定文件夹下任何文件不经过登录,全部拦截强制跳转登录,并客户端禁止下载服务器定制文件夹文件           经过1天多时间的各种尝试,自定义式的强大拦截器实现了,废话不说了,直接贴代码啦.    demo:       1>   根目录下 index.html 内容:               <a href="html/index.html">index</a><br/>              <

spring mvc拦截器无法拦截DWZ的请求,求指点。。。

问题描述 拦截器是这样配置的: <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*" > </mvc:mapping>如果不配置或/*,将拦截所有的Controller <bean class="com.hangzhou.controller.interceptor.LoginInterceptor"></bean> </m

spring mvc 拦截器路径问题,只拦截固定后缀

拦截固定后缀  匹配url正确配置为 /**/*.htm     错误:**.htm    /**.htm   *.htm  <mvc:interceptors> <!-- <bean class="com.host.app.web.interceptor.AllInterceptor"/> --> <mvc:interceptor> <mvc:mapping path="/**/*.htm" /><

spring mvc拦截器页面不跳转问题

问题描述 就是不跳转到我指定的Controller上.请教大神.publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objectobject)throwsException{StringrequestPath=ResourceUtil.getRequestPath(request);//用户访问的资源地址System.out.println(requestPath+"--->访问路径&qu

spring mvc-SpringMvc拦截器配置怎么配置拦截一个网站

问题描述 SpringMvc拦截器配置怎么配置拦截一个网站 我想拦截一个网址,比如页面的地址是www.XXXX.com.配置文件怎么配? 不拦截全部,只拦截单个网址的那种 解决方案 在controller层中来配置拦截的URL @RequestMapping("configSettRule") public class SettRuleController extends BaseController{ @Resource private SettRuleManager settRul

path-spring Mvc 拦截器拦截不成功

问题描述 spring Mvc 拦截器拦截不成功 拦截不成功,各位大神帮忙看下配置有没错.这样配置可不可以拦截 解决方案 你这样太麻烦了,用springMVC的统一拦截器,然后在controller层中加注解就行了 过程如下:http://blog.csdn.net/evankaka/article/details/45501811 解决方案二: spring MVC - Inteceptors(拦截器)spring MVC - Inteceptors(拦截器) 解决方案三: ,用springM

spring mvc拦截jsp文件,jsp未被解析

问题描述 spring mvc拦截jsp文件,jsp未被解析 采用spring mvc 对jsp文件进行拦截,在preHandle方法里面返回true,结果页面展示的是jsp的源码,而不是我要展示的内容,这是什么原因?如下所示: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib pre