zoukankan      html  css  js  c++  java
  • SpringMVC:拦截器和过滤器

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

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

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

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

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

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

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

     过滤器的触发时机是容器后,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;
    
    @component
    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 {
      
      @Autowired
      private FirstFilter firstFilter;
      @Autowired
      private SecondFilter secondFilter;
      @Autowired
      private ThirdFilter thirdFilter; @Bean
    public FilterRegistrationBean filterRegistrationBeanFirst() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
    // 可以采用 spring 的依赖注入 20191117update filterRegistrationBean.setFilter(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等属性。

    接下来写三个拦截器,需要实现 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;
    
    @component
    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 {
       @Autowired
    private FirstInterceptor firstInterceptor;
    @Autowired
    private SecondInterceptor secondInterceptor;
    @Autowired
    private ThirdInterceptor thirdInterceptor;
         @Override
    public void addInterceptors(InterceptorRegistry registry) {
         // 可以将 FirstInterceptor 之类的由 spring 进行管理 不建议采用 new 的方法创建对象 20191117update registry.addInterceptor(firstInterceptor
    ).addPathPatterns("/index/**"); registry.addInterceptor(secondInterceptor).addPathPatterns("/index/**"); registry.addInterceptor(thirdInterceptor).addPathPatterns("/index/**"); } }

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

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

  • 相关阅读:
    asp.net 2.0-实现数据访问(1)
    跨平台跨服务器跨网站SSO(单点登录)方案的DEMO
    (翻译)Windows Communication Foundation (Workshop)-Part 2:在WCF中操作会话
    ipc的remoting
    忙活了半年的书已经交稿,年后就要出版
    一个ASP.NET2.0的小项目-BLOG
    (论坛答疑点滴)上传控件怎么修改样式?怎么设置readonly?
    【LoveCherry】上海.NET招聘!!!!!!!!!!!!!!!!!!!!!!!!!
    【翻译】Scott Mitchell的ASP.NET2.0数据指南中文版索引
    Scott Mitchell 的ASP.NET 2.0数据教程之二十四:: 分页和排序报表数据
  • 原文地址:https://www.cnblogs.com/colin220/p/9606412.html
Copyright © 2011-2022 走看看