SpringMVC 拦截器 详解

本文详细介绍了Spring MVC框架中的拦截器机制,包括HandlerExecutionChain的工作原理及其如何利用拦截器进行请求处理前后的操作。文中还提供了具体的配置示例及自定义拦截器实现,帮助读者深入理解拦截器的作用和配置。
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());
    }
}
可以配置多个拦截器,每个拦截器都可以指定一个匹配的映射路径,以限制拦截器作用范围

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值