SpringMVC 拦截器 详解

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 中

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

拦截器实现类中
public class LoggerInterceptor extends HandlerInterceptorAdapter {
    private static Logger log = LoggerFactory. getLogger (LoggerInterceptor. class );
    // 重写initial method , 解决相同线程进入多次报exception
    private ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<Long>() {
        @Override
        protected Long initialValue() {
            return System. currentTimeMillis ();
        }
    };
    @Override
    public boolean preHandle(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 void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(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());
    }
}
可以配置多个拦截器,每个拦截器都可以指定一个匹配的映射路径,以限制拦截器作用范围

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值