SpringMVC学习笔记:拦截器和过滤器

首先说明一下二者的区别:

  1. 拦截器基于java的反射机制,而过滤器是基于函数回调

  2. 拦截器不依赖于servlet容器,过滤器依赖servlet容器

  3. 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用

  4. 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

  5. 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器注入一个service,可以调用业务逻辑

过滤器和拦截器之间的关系如下图,Filter包裹Servlet,Servlet包裹Interceptor

SpringMVC学习笔记:拦截器和过滤器_第1张图片

 过滤器的触发时机是容器后,servlet之前,所以过滤器的  doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) 的入参是ServletRequest,而不是HttpServletRequest,因为过滤器在HttpServlet之前

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    System.out.println("before...");

    chain.doFilter(request, response);

    System.out.println("after...");
}

 这个chain.doFilter(request, response) 作用是将请求转发给过滤器链上下一个对象,下一个对象是指filter,如果没有filter那就是你请求的资源

 拦截器是被包裹在过滤器之中

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("preHandle");
    return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    System.out.println("postHandle");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    System.out.println("afterCompletion");
}

preHandle 这个方法是在过滤器的 chain.doFilter( request, response ) 方法的前一步执行,且在调用Controller之前调用,当返回false后,会跳过之后的拦截器,并且不会执行所有的拦截器 postHandle ,并且调用返回true的拦截器的 afterCompletion 方法

postHandle 是调用 Controller 之后被调用,但是在渲染 View 页面之前

afterCompletion 是调用完 Controller 接口,渲染 View 页面最后调用,返回true的拦截器都会调用该拦截器的 afterCompletion 方法,顺序相反。这个方法也是在过滤器返回给前端前一步执行 

 

多个过滤器和拦截器是如何配置的呢,下面结合Spring Boot写个demo,地址是 https://gitee.com/colin220/intercept

首先写一个Controller,内容如下:

@Controller
public class InterceptController {

    @RequestMapping("/index")
    public ResponseEntity index() {
        System.out.println("Controller        Handler");
        return ResponseEntity.ok("index");
    }
}

这个Controller比较简单,浏览器访问 http://localhost:8080/index 会返回一个字符串 "index"。

写三个过滤器,需要实现javax.servlet.Filter接口,实现其中的三个方法。这三个过滤器分别命名为 FirstFilter SecondFilter ThirdFilter,以FirstFilter为例,其他的两个类内容和其基本一致,其代码内容如下:

import javax.servlet.*;
import java.io.IOException;

public class FirstFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("FirstFilter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        System.out.println("FirstFilter       doFilter pre");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("FirstFilter       doFilter aft");
    }

    @Override
    public void destroy() {
        System.out.println("FirstFilter destroy");
    }
}

然后写一个配置类,来配置这三个过滤器,其代码内容如下:

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean filterRegistrationBeanFirst() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new FirstFilter());
        filterRegistrationBean.addUrlPatterns("/index/*");
        filterRegistrationBean.setName("FirstFilter");
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBeanSecond() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new SecondFilter());
        filterRegistrationBean.addUrlPatterns("/index/*");
        filterRegistrationBean.setName("SecondFilter");
        filterRegistrationBean.setOrder(2);
        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBeanThird() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new ThirdFilter());
        filterRegistrationBean.addUrlPatterns("/index/*");
        filterRegistrationBean.setName("ThirdFilter");
        filterRegistrationBean.setOrder(3);
        return filterRegistrationBean;
    }

}

因为有三个Filter,因此需要三个org.springframework.boot.web.servlet.FilterRegistrationBean,每个FilterRegisterationBean中需要设置属性 filterRegistrationBean.setFilter(new FirstFilter( )) ,并设置这个Filter拦截的url,顺序order等属性。

SpringMVC学习笔记:拦截器和过滤器_第2张图片

 

接下来写三个拦截器,需要实现 org.springframework.web.servlet.HandlerInterceptor 接口,重写其中的三个方法,这三个拦截器分别命名为FirstInterceptor SecondInterceptor ThirdInterceptor,以FirstInterceptor为例,其他两个类内容基本一致,其代码内容如下:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在请求处理之前进行调用(Controller方法调用之前)
        System.out.println("FirstInterceptor  preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后 )
        System.out.println("FirstInterceptor  postHandle");
    }

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

然后写一个配置类,来配置这三个拦截器。这个配置类要实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer。因为WebMvcConfigurerAdapter 在Spring5.0已被废弃,所以采用WebMvcConfigurer,其代码内容如下:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/index/**");
        registry.addInterceptor(new SecondInterceptor()).addPathPatterns("/index/**");
        registry.addInterceptor(new ThirdInterceptor()).addPathPatterns("/index/**");
    }

}

其中InterceptorRegistry内部有个List,这个addInterceptor( )方法是用来存放添加进去的interceptor,按照添加的先后顺序,依次拦截。 

这样就完成了多个过滤器和多个拦截器的配置,浏览器访问 http://localhost:8080/index 可以看到控制台打印内容如下:

SpringMVC学习笔记:拦截器和过滤器_第3张图片

 

END

转载于:https://www.cnblogs.com/colin220/p/9606412.html

你可能感兴趣的:(java,前端)