spring mvc controller interceptor拦截器介绍以及应用场景

1,090 阅读3分钟

背景

要实现一个拦截器,确保每次请求线程的所有日志的日志戳唯一。

解决方法?
1.进控制器方法的时候,删除日志戳
2.第一次打印日志的时候,设置日志戳
3.从第二次打印日志开始,用第一次的日志戳
4.控制器方法结束的时候,删除日志戳

基于拦截器实现,关于删除日志戳和设置日志戳,这个需要自定义日志类,拦截器只是调用自定义日志类的方法去删除日志戳和设置日志戳。本文只讲拦截器,忽略自定义日志类。

拦截器介绍

和servlet的filter过滤器作用一样,只不过到了spring里名字就叫拦截器interceptor,但是作用一样,而且生命周期也一样,就是进入方法之前、进入方法之后,做一些统一操作。

实现

实现类

package com.xxx.payment.intercepter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import xxx.log.logback.layout.converter.LogPreFixConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 日志戳拦截器,作用是确保每次请求的线程的日志戳唯一
 *
 * @author gzh
 * @createTime 2021/2/2 9:37 AM
 */
public class LogPreInterceptor implements HandlerInterceptor {
  public static final Logger log = LoggerFactory.getLogger(LogPreInterceptor.class);

  /**
   * 进入控制器的方法之后,立即删除日志戳。然后第一次打印日志的时候,会设置随机日志戳。从第二次打印日志开始,用第一次设置的日志戳。
   *
   * @param request
   * @param response
   * @param handler
   * @return
   * @throws Exception
   */
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    LogPreFixConverter.resetLogPreFix();
    return true;
  }

  /**
   * 控制器的方法结束之后,删除日志戳(postHandle()方法是Controller方法正常返回后才执行)
   *
   * @param request
   * @param response
   * @param handler
   * @param modelAndView
   * @throws Exception
   */
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
      ModelAndView modelAndView) throws Exception {
//    LogPreFixConverter.resetLogPreFix();
  }

  /**
   * 控制器的方法结束之后,删除日志戳(无论Controller方法是否抛异常都会执行afterCompletion方法)
   *
   * @param request
   * @param response
   * @param handler
   * @param ex
   * @throws Exception
   */
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
      Object handler, Exception ex) throws Exception {
    LogPreFixConverter.resetLogPreFix();
  }
}

配置

<!-- 日志戳拦截器-->
<mvc:interceptors>
 <mvc:interceptor>
  <mvc:mapping path="/**/*.do"/>
  <bean class="com.xxx.payment.intercepter.LogPreInterceptor"></bean>
 </mvc:interceptor>
</mvc:interceptors>

过滤请求路径说明

1.匹配任意目录路径
/**
2.匹配指定后缀路径
/**/*.do


参考

AntPathMatcher

This is a path pattern that used in Apache ant, spring team implement it and use it throughout the framework.

The mapping matches URLs using the following rules:

? matches one character //?,匹配任意单个字符
* matches zero or more characters //*,匹配0或多个字符
** matches zero or more 'directories' in a path //**,匹配0多多个目录
Some examples:

com/t?st.jsp - matches com/test.jsp but also com/tast.jsp or com/txst.jsp
com/*.jsp - matches all .jsp files in the com directory
com/**/test.jsp - matches all test.jsp files underneath the com path
org/springframework/**/*.jsp - matches all .jsp files underneath the org/springframework path
org/**/servlet/bla.jsp - matches org/springframework/servlet/bla.jsp but also org/springframework/testing/servlet/bla.jsp and org/servlet/bla.jsp

opensourceforgeeks.blogspot.com/2016/01/dif…

方法调用栈

preHandle:32, LogPreInterceptor (com.xxx.payment.intercepter) //自定义拦截器

applyPreHandle:133, HandlerExecutionChain (org.springframework.web.servlet)
doDispatch:962, DispatcherServlet (org.springframework.web.servlet) //spring mvc请求转发类

doService:901, DispatcherServlet (org.springframework.web.servlet)
processRequest:970, FrameworkServlet (org.springframework.web.servlet)
doGet:861, FrameworkServlet (org.springframework.web.servlet)
service:621, HttpServlet (javax.servlet.http)
service:846, FrameworkServlet (org.springframework.web.servlet)
service:728, HttpServlet (javax.servlet.http)
internalDoFilter:303, ApplicationFilterChain (org.apache.catalina.core)
doFilter:208, ApplicationFilterChain (org.apache.catalina.core)
doFilter:52, WsFilter (org.apache.tomcat.websocket.server)
internalDoFilter:241, ApplicationFilterChain (org.apache.catalina.core)
doFilter:208, ApplicationFilterChain (org.apache.catalina.core)
handle:438, CatFilter$Context (com.dianping.cat.servlet)
handle:235, CatFilter$CatHandler$3 (com.dianping.cat.servlet)
handle:436, CatFilter$Context (com.dianping.cat.servlet)
handle:328, CatFilter$CatHandler$4 (com.dianping.cat.servlet)
handle:436, CatFilter$Context (com.dianping.cat.servlet)
handle:218, CatFilter$CatHandler$2 (com.dianping.cat.servlet)
handle:436, CatFilter$Context (com.dianping.cat.servlet)
handle:127, CatFilter$CatHandler$1 (com.dianping.cat.servlet)
handle:436, CatFilter$Context (com.dianping.cat.servlet)
doFilter:65, CatFilter (com.dianping.cat.servlet)
internalDoFilter:241, ApplicationFilterChain (org.apache.catalina.core)
doFilter:208, ApplicationFilterChain (org.apache.catalina.core)
doFilter:31, EncodingFilter (hikefa.core.web.filter)
internalDoFilter:241, ApplicationFilterChain (org.apache.catalina.core)
doFilter:208, ApplicationFilterChain (org.apache.catalina.core)
invoke:219, StandardWrapperValve (org.apache.catalina.core)
invoke:110, StandardContextValve (org.apache.catalina.core)
invoke:444, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:169, StandardHostValve (org.apache.catalina.core)
invoke:104, ErrorReportValve (org.apache.catalina.valves)
invoke:1025, AccessLogValve (org.apache.catalina.valves)
invoke:116, StandardEngineValve (org.apache.catalina.core)
service:445, CoyoteAdapter (org.apache.catalina.connector)
process:1137, AbstractHttp11Processor (org.apache.coyote.http11)
process:637, AbstractProtocol$AbstractConnectionHandler (org.apache.coyote)
run:319, JIoEndpoint$SocketProcessor (org.apache.tomcat.util.net)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:748, Thread (java.lang)

参考

www.liaoxuefeng.com/wiki/125259…