SpringMVC 之拦截器

文章目录

  • 拦截器作用
  • 自定义拦截器
  • 拦截器执行流程

拦截器作用

  • 日志记录: 记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
  • 权限检查: 如登录检测,进入处理器检测检测是否登录。
  • 性能监控: 通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。
  • 通用行为: 读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,只要是多个处理器都需要的即可使用拦截器实现。

自定义拦截器

Spring MVC 中所有的拦截器都实现/继承自 HandlerInterceptor 接口。

HandlerInterceptor 接口的源码如下:

public interface HandlerInterceptor {

  	// 在请求处理之前进行调用(Controller方法调用之前)
	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return true;
	}
	
  	// 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后),如果异常发生,则该方法不会被调用
	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}

  	// 在整个请求结束之后被调用,也就是在 DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作
	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
	}

}

自定义拦截器案例:

@Slf4j
@Component
public class TimeInterceptor implements HandlerInterceptor {

    private ThreadLocal<Long> threadLocalStart = new ThreadLocal<>();
    private ThreadLocal<Long> threadLocalEnd = new ThreadLocal<>();

  	// 记录开始时间
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        long startTIme = System.currentTimeMillis();
        threadLocalStart.set(startTIme);
        log.info("开始时间:{}", startTIme);
        return true;
    }

  	// 记录结束时间
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        long endTIme = System.currentTimeMillis();
        threadLocalEnd.set(endTIme);
        log.info("结束时间:{}", endTIme);
    }

  	// 计算接口执行时间
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        long startTime = threadLocalStart.get();
        long endTime = threadLocalEnd.get();
        log.info("接口执行时间:{} 毫秒", endTime - startTime);
    }
}

拦截器注册:

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
    @Autowired
    private TimeInterceptor timeInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration registration = registry.addInterceptor(timeInterceptor);
        // 拦截所有请求
        registration.addPathPatterns("/**");
        // 添加不拦截路径
        registration.excludePathPatterns("/login", "/error", "/logout","/login.html");
    }
}

拦截器执行流程

SpringMVC 之拦截器_第1张图片
1、执行 preHandle 方法,该方法会返回一个布尔值。如果为 false ,则结束本次请求:如果为 true 则继续。
2、执行处理器逻辑,也就是我们的 Controller 。
3、执行 postHandle 方法。
4、执行视图解析和视图渲染 (直接返回了 JSON 对象,所以没有视图处理)。
5、执行 afterCompletion 方法。

可以在 DispatcherServletdoDispatch 方法的源码中进一步验证这个执行逻辑:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	try {
		try {
		
			// 返回 HandlerExecutionChain  其中包含了拦截器队列
			mappedHandler = getHandler(processedRequest);

			//调用拦截器 PreHandle 方法,若返回 false 将直接 return
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// 处理 Controller
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

			// 调用拦截器的 PostHandle 方法
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}

		// 调用拦截器的 afterCompletion 方法
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
}

多个拦截器执行流程:
SpringMVC 之拦截器_第2张图片

你可能感兴趣的:(#,SpringMVC)