SpringBoot拦截器和过滤器

477 阅读3分钟

~~本文已参与「新人创作礼」活动,一起开启掘金创作之路。~~

一、定义:

  • 过滤器(Filter):对于满足条件的流程进行过滤,如对所有的web操作设置utf-8编码
  • 拦截器(Interceptor):对所有操作流程进行拦截,进行干预,甚至终止操作

二、异同点

相同点:

都是aop编程思想的体现,可以在程序执行前后做一些操作

不同点:

  • Filter是Servlet组件,Interceptor是Spring组件
  • 触发时机不一样,过滤器是在进入容器后,进入Servlet前进行预处理;拦截器是在进入Servlet之后,Controller之前进行处理
  • 由于拦截器是Spring组件,故可以获取IOC容器中的各个Bean

三、过滤器简单实现

Filter接口由J2EE定义,在Servlet执行之前由容器进行调用。

实现方式:

  1. 新建一个类实现Filter接口
  2. 重写Filter接口里的doFilter接口,里面实现过滤逻辑

1、自定义过滤器

 /**
  *
  * 多过滤器过滤优先级与名称有关
  *  当本类名称为JavaWebFilter时, 本类先于JavaWebFilterB启动
  *  当本类名称改为JavaWebFilterC时, 本类将晚于JavaWebFilterB启动
  *
  * 下面通过 @Order() 设置的优先级并不生效
  *
  */
 //@Order(2)
 @WebFilter("/*")
 public class JavaWebFilter implements Filter {
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
         BasicLogUtil.info("进入过滤器");
         chain.doFilter(request, response);
     }
 ​
     @Override
     public void init(FilterConfig filterConfig) throws ServletException {
         BasicLogUtil.info("过滤器启动");
     }
 ​
     @Override
     public void destroy() {
         BasicLogUtil.info("过滤器被摧毁");
     }
 }

2、配置过滤器

1)自动配置

springboot启动类通过@ServletComponentScan注解配置自动扫描Servlet组件

该配置方式通过@Order注解设置的优先级不生效,优先级只能通过其默认的方式:按名称来决定

 @SpringBootApplication
 //@ServletComponentScan   // 自动扫描Servlet组件,此处是Filter
 public class Springboot04Application {
 ​
     public static void main(String[] args) {
         SpringApplication.run(Springboot04Application.class, args);
     }
 }

2)手动配置(可以通过order设置优先级)

 @Configuration
 public class FilterConfig {
 ​
     @Bean
     public FilterRegistrationBean<CustomFilter> filterRegistrationBean(){
         FilterRegistrationBean<CustomFilter> filterFilterRegistrationBean=
                 new FilterRegistrationBean<>();
         filterFilterRegistrationBean.setFilter(new JavaWebFilter());
         filterFilterRegistrationBean.addUrlPatterns("/*");
 //        filterFilterRegistrationBean.setOrder(0); //决定注册的优先级
         return filterFilterRegistrationBean;
     }
 }

四、拦截器简单实现

HandlerInterceptor用于拦截Controller方法的执行,其声明了如下三个方法:

  • preHandle:在Controller方法执行前进行过滤处理
  • postHandle:在Controller方法执行后、视图渲染前进行过滤处理
  • afterCompletion:在整个方法执行后(包括异常处理)进行过滤处理

perHandle()方法的返回值为boolean,返回为true,继续往下执行,否则请求结束

1、自定义拦截器

 public class SelfIntercetor implements HandlerInterceptor {
     /**
      * 请求处理前调用(controller方法之前)
      * @param request
      * @param response
      * @param handler
      * @return  true: 请求继续往下执行,否则该请求在此处终止
      * @throws Exception
      */
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         BasicLogUtil.info("preHandle: 进入拦截器");
 ​
         return true;
     }
 ​
     /**
      * 请求处理之后,渲染视图之前调用(执行完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 {
         BasicLogUtil.info("postHandle: 执行完controller,但未渲染视图");
     }
 ​
     /**
      * 请求执行完后调用(DispatcherServlet渲染视图后执行)
      * @param request
      * @param response
      * @param handler
      * @param ex
      * @throws Exception
      */
     @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
         BasicLogUtil.info("afterCompletion: 渲染视图完成");
     }
 }

2、配置拦截器

  • Spring Boot 1.5,都是靠重写 WebMvcConfigurerAdapter 的方法来添加自定义拦截器
  • SpringBoot 2.0 后,推荐实现 WebMvcConfigurer 或者继承 WebMvcConfigurationSupport 实现
 @Configuration
 public class SelfWebConfig implements WebMvcConfigurer {
 ​
     /**
      * 配置项目中的静态资源不会被拦截,如resources下static文件里的html、js、css等
      * @param registry
      */
     @Override   
     public void addResourceHandlers(ResourceHandlerRegistry registry) {
         registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
         WebMvcConfigurer.super.addResourceHandlers(registry);
     }
 ​
     /**
      * 注册自定义拦截器,使其生效
      * @param registry
      */
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         // 拦截所有路径请求,但忽略/login、/register、/static/**
         registry.addInterceptor(new SelfIntercetor())
                 .addPathPatterns("/**")
                 .excludePathPatterns("/login", "/register", "/static/**");
         WebMvcConfigurer.super.addInterceptors(registry);
     }
 ​
     /**
      * 设置请求的默认页面
      * @param registry
      */
     @Override
     public void addViewControllers(ViewControllerRegistry registry) {
         // 重定向到登录页面
 //        registry.addViewController("/").setViewName("forward:/login.html");
         // 默认访问index.html页面
         registry.addViewController("").setViewName("index");
         // 设置优先级,当地址重复时,执行优先级最高的
         registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
         WebMvcConfigurer.super.addViewControllers(registry);
     }
 }