SpringBoot自定义拦截器interceptor使用详解

Spring Boot拦截器Intercepter详解

Intercepter是由Spring提供的Intercepter拦截器,主要应用在日志记录、权限校验等安全管理方便。

使用过程

1.创建自定义拦截器,实现HandlerInterceptor接口,并按照要求重写指定方法

HandlerInterceptor接口源码:

java 复制代码
public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

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

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

根据源码可看出HandlerInterceptor接口提供了三个default方法,这三个方法作用不同,用户想要自定义个一个指定拦截规则的拦截器,需要重写其中一个或者多个方法,这三个方法作用如下:

  • perHandle:preHandle方法的作用是,当请求在进入controller之前拦截请求,对请求进行预处理,比如登录验证(cookie,token,referer)或者单点登录cookie解析都可以在这方法中进行。该方法的返回值,如果返回true,表示放行至controller业务层,如果false,表示请求非法,结束请求并返回错误信息。
  • postHandler:postHandle方法是在请求被controller处理完但是还未传递到业务模板进行渲染拦截,即controller处理完,返回ModelAndView 之前执行该方法,可以操控ModelAndView的值;所以该方法多了一个参数,ModelAndView,这个参数包含了controller处理完后需要传递的Model参数,因此,我们可以在该方法通过ModelAndView对象对返给前端的额视图做一定的修改。
  • afterCompletion:afterCompletion方法作用就是做些收尾工作,在ModelAndView返回前端进行渲染后执行,比如有时候我们需要把每个线程的局部变量(如User信息)放入到TheradLocal中,为了防止内存泄露,在最后需要清除ThreadLocal的内容,此操作就可以放在该方法中执行。

自定义一个获取并返回某个静态资源的内容已整个请求所花费时间的时间拦截器

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class MyInterceptor implements HandlerInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyInterceptor.class);

    private static final ThreadLocal<Long> START_THREAD_LOCAL = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        String uri = request.getRequestURI();
        LOGGER.info(uri + " preHandle");
        Long startTime = System.currentTimeMillis();    //获取开始时间
        START_THREAD_LOCAL.set(startTime);  //线程绑定变量(该数据只有当前请求的线程可见)
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        String uri = request.getRequestURI();
        LOGGER.info(uri + " postHandle");
        Long startTime = START_THREAD_LOCAL.get();//得到线程绑定的局部变量(开始时间)
        Long endTime = System.currentTimeMillis(); 	//2、结束时间
        Long time = endTime - startTime;
        LOGGER.info("http request all time: " + time + "ms");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) throws Exception {
        String uri = request.getRequestURI();
        LOGGER.info(uri + " afterCompletion");
        if (START_THREAD_LOCAL != null) {
            START_THREAD_LOCAL.remove();    // 移除ThreadLocal中的局部变量
        }
    }
}

2.添加配置类,实现WebMvcController接口,并添加@Configuration注解,在配置类中,重写addIntercepters方法,添加要拦截的url以及url白名单(需要排除拦截的url)

WebMvcConfigurer源码:

java 复制代码
public interface WebMvcConfigurer {

	default void configurePathMatch(PathMatchConfigurer configurer) {
	}

	default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
	}

	default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
	}

	default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
	}

	default void addFormatters(FormatterRegistry registry) {
	}

	default void addInterceptors(InterceptorRegistry registry) {
	}

	default void addResourceHandlers(ResourceHandlerRegistry registry) {
	}

	default void addCorsMappings(CorsRegistry registry) {
	}

	default void addViewControllers(ViewControllerRegistry registry) {
	}

	default void configureViewResolvers(ViewResolverRegistry registry) {
	}

	default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
	}

	default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
	}

	default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
	}

	default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
	}

	default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
	}

	default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
	}

	@Nullable
	default Validator getValidator() {
		return null;
	}

	@Nullable
	default MessageCodesResolver getMessageCodesResolver() {
		return null;
	}
}

根据源码可以看出,WebMvcConfigurer提供了多个方法,并且也都是default方法,也是根据我们自定义配置,重写其中一个或者多个方法,这里就介绍两个常用的方法:

  • addInterceptors:从该方法名就可以了解到该方法是添加拦截器,即将拦截器交给IOC去执行,拦截器需要拦截的路径以及需要排除拦截的路径在该方法中配置。
  • addResourceHandlers:该方法的作用是配置静态资源路径。即某些请求需要读取某个路径下的静态资源内容,需要配置该静态资源的路径,通过该方法可以统一给这些请求配置指定静态资源路径 。

实例:

java 复制代码
import com.eureka.intercrpotor.MyInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Bean
    public MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor())  // 添加拦截器
                .addPathPatterns("/**")          // 配置拦截请求url( ** 表示拦截所有请求url)
                .excludePathPatterns("/hello"); // 排除某些不需要拦截的请求url(即带有/hello请求不会被拦截)
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")   // 配置需要添加静态资源的请求url
                .addResourceLocations("classpath:/mydata/");   //配置静态资源路径
    }
}

测试:

java 复制代码
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    
    @GetMapping("/test/interceptor")
    public ResponseEntity<String> testInterceptor() {
        return ResponseEntity.ok("successful");
    }
}

静态资源:

启动项目后访问 localhost:60011/test/interceptor:

控制台打印的日志:

我们再通过url访问静态资源请求 localhost:60011/test.jpg

相关推荐
豪宇刘1 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意1 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
FF在路上2 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进2 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
众拾达人2 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.2 小时前
Mybatis-Plus
java·开发语言
不良人天码星2 小时前
lombok插件不生效
java·开发语言·intellij-idea
守护者1703 小时前
JAVA学习-练习试用Java实现“使用Arrays.toString方法将数组转换为字符串并打印出来”
java·学习
源码哥_博纳软云3 小时前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
禾高网络3 小时前
租赁小程序成品|租赁系统搭建核心功能
java·人工智能·小程序