HandlerInterceptor:SpringBoot拦截器的基本使用(详解)

拦截器我想大家都并不陌生,最常用的登录拦截、或是权限校验、或是防重复提交、或是根据业务像12306去校验购票时间,总之可以去做很多的事情。

简介

SpringWebMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于处理器进行预处理和后处理。

应用场景

  1. 日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。

  2. 权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。

  3. 性能监控:典型的是慢日志。

HandlerInterceptor定义实现类

定义一个Interceptor 非常简单,方式也有几种,我这里简单列举两种:

  1. 类要实现Spring 的HandlerInterceptor 接口;
  2. 类继承实现了HandlerInterceptor 接口的类,例如:已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter。

HandlerInterceptor方法介绍

public interface HandlerInterceptor {
 
   /**
     * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller
     * 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断
(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
   */
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;
 
   /**
     * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以
通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
   */
    void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;
 
   /**
    * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输
出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中
   */
    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;
 

}
  • preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
  • postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView (这个博主就基本不怎么用了);
  • afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);

拦截器实现

我们来实现一个访问权限校验的拦截器吧,以第二种方法--继承HandlerInterceptorAdapter为例:

  • 新建TestFilter:验证用户信息
package com.xxx.core.filter;

import com.xxx.common.exception.FastRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class TestFilter extends HandlerInterceptorAdapter {
	private final Logger logger = LoggerFactory.getLogger(TestFilter.class);
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		logger.info("request请求地址path[{}] uri[{}]", request.getServletPath(),request.getRequestURI());
		//request.getHeader(String) 从请求头中获取数据
		//从请求头中获取用户token(登陆凭证根据业务而定)
		Long userId= getUserId(request.getHeader("H-User-Token"));
		if (userId != null && checkAuth(userId,request.getRequestURI())){
			return true;
		}
		//这里的异常是我自定义的异常,系统抛出异常后框架捕获异常然后转为统一的格式返回给前端, 其实这里也可以返回false
		throw new FastRuntimeException(20001,"No access");
	}

	/**
	 * 根据token获取用户ID
	 * @param userToken
	 * @return
	 */
	private Long getUserId(String userToken){
		Long userId = null;
		return userId;
	}

	/**
	 * 校验用户访问权限
	 * @param userId
	 * @param requestURI
	 * @return
	 */
	private boolean checkAuth(Long userId,String requestURI){
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
						   ModelAndView modelAndView) throws Exception {}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {}
}
  • 新建WebAppConfigurer:实现WebMvcConfigurer接口,拦截请求
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 可添加多个,/**是对所有的请求都做拦截
        registry.addInterceptor(new TestFilter())
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/register");
    }

    ....
}

注意:过滤器可以添加多个,可以指定Path,这里的/**是对所有的请求都做拦截。

关于请求的处理,有两个常用方法:

  • .addPathPatterns():增加url的拦截路径,“/**”意思是所有请求都要拦截;
  • .excludePathPatterns():排除url的拦截路径,如:"/login", "/register"意为登录和注册不做拦截;

其实以前都是继承WebMvcConfigurerAdapter类,不过springBoot2.0以上 WebMvcConfigurerAdapter 方法过时,有两种替代方案:

  • 继承 WebMvcConfigurationSupport 类;
  • 实现 WebMvcConfigurer 接口;

但是,继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效,所以小编一直用实现WebMvcConfigurer接口的方式。

不过,现在大多数项目是前后端分离,并没有对静态资源有自动配置的需求所以继承WebMvcConfigurationSupport也未尝不可。

更多精彩,请关注我的"今日头条号":Java云笔记
随时随地,让你拥有最新,最便捷的掌上云服务

发布了151 篇原创文章 · 获赞 245 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/weixin_44259720/article/details/104615086