SpringMVC 拦截器 详解

来源:互联网 发布:洋葱英语软件 编辑:程序博客网 时间:2024/06/05 00:27
HandlerExecutionChain 是一个执行链,包含一个请求的处理器,同时包括若干个对该请求的拦截器。当 HandlerMapping 返回 HandlerExecutionChain 后,DispatchServlet 将请求交给定义在 HandlerExecutionChain 中的拦截器和处理器一并处理

HandlerExecutionChain 的结构


HandlerExecutionChain 是负责处理请求并返回 ModelANdView 的处理执行链。请求在被 Handler 执行的前后,链中装配的 HandlerInterceptor 会实施拦截操作

拦截器的接口方法
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) : 在请求到达 Handler 之前,先执行这个前置处理方法。当该方法返回false时,请求直接返回,不会传递到链中下一个拦截器,更不会调用处理器链末端的 Handler 中,只有返回 true 时请求才向链中的下一个处理节点传递

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) : 请求被 HandlerAdapter 执行后,执行这个后置处理方法

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) : 在响应已经被渲染后,执行该方法

位于处理器末端是一个 Handler,DispatcherServlet 通过 HandlerAdapter 适配器对 Handler 进行封装,并按统一的适配器接口对 Handler 处理方式进行调用

在 spring-mvc.xml 中
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mappingpath="/**"/>
        <!-- 排除前端页面-->
       <mvc:exclude-mappingpath="/insurance/**"/>
       <beanclass="com.insurance.web.component.interceptor.LoggerInterceptor"/>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mappingpath="/member/status"/>
        <mvc:mappingpath="/member/mobile"/>
       <beanclass="com.insurance.consumer.web.intercept.BigPlatformLoginInterceptor"/>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mappingpath="/member/status"/>
        <mvc:mappingpath="/member/mobile"/>
       <mvc:mappingpath="/order/*"/>
       <beanclass="com.insurance.consumer.web.intercept.LoginTokenInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

拦截器实现类中
public classLoggerInterceptor extends HandlerInterceptorAdapter {
    private static Loggerlog = LoggerFactory.getLogger(LoggerInterceptor.class);
    // 重写initial method , 解决相同线程进入多次报exception
   private ThreadLocal<Long> startTimeThreadLocal= new ThreadLocal<Long>() {
        @Override
       protectedLong initialValue() {
            return System.currentTimeMillis();
        }
    };
    @Override
   public booleanpreHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)throws Exception {
        startTimeThreadLocal.set(System.currentTimeMillis());
        String accessUri = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length());
        log.info("call method:"+ accessUri);
        return true;
    }
    @Override
   public voidpostHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView)throws Exception {
    }
    @Override
   public voidafterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e)throws Exception {
        long endTime = System.currentTimeMillis();//2、结束时间
       long beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量(开始时间)
       startTimeThreadLocal.remove();
        String accessUri = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length());
        StringBuilder logs =new StringBuilder("\n");
        logs.append("**************** call method ****************");
        logs.append("\n").append("call method :" + accessUri + " , used time :" + (endTime - beginTime) +" ms.");
        Map<String, String[]> parameters = httpServletRequest.getParameterMap();
        for (String key : parameters.keySet()) {
            logs.append("\n").append(key + " = "+ parameters.get(key)[0]);
        }
        if (e != null) {
            log.error(e.getMessage(), e);
        }
        logs.append("\n").append("**************** call method end ****************");
        log.info(logs.toString());
    }
}
可以配置多个拦截器,每个拦截器都可以指定一个匹配的映射路径,以限制拦截器作用范围