SpringBoot入坑指南之六:使用过滤器或拦截器

开篇

在Web应用中,常常存在拦截全部或部分请求进行统一处理的应用场景,如权限校验、参数校验、性能监控等。 在SpringMVC框架中,我们可以通过过滤器或拦截器实现相关功能,spring-boot-starter-web模块底层实际就是SpringMVC框架,那么在SpringBoot项目中如何使用过滤器或拦截器呢?

过滤器与拦截器的区别

SpringBoot入坑指南之六:使用过滤器或拦截器_第1张图片

过滤器与拦截器的使用

创建项目

创建一个maven项目spring-boot-examples-intercept,添加一下依赖:

.springframework.boot spring-boot-starter-web org.projectlombok lombok

添加业务接口

添加一个HelloController类,实现一个Restful的测试接口/hello,代码如下:

@RestController@Slf4jpublic classHelloController{

    /**    * 测试请求方法    *    *@return*/    @GetMapping("/hello")

    publicStringhello(){

        log.info("[{}]执行{}方法!", this.getClass().getSimpleName(), "hello");

        return "Hello!";

    }

}

添加过滤器

过滤器开发

添加第一个过滤器FirstFilter类,实现Filter接口,代码如下:

@Slf4jpublic classFirstFilterimplementsFilter{

    /**    *    *@paramservletRequest    *@paramservletResponse    *@paramfilterChain    *@throwsIOException    *@throwsServletException    */    @Override    publicvoiddoFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throwsIOException, ServletException{

        log.info("[{}]执行{}方法:Before!", this.getClass().getSimpleName(), "doFilter");

        //执行下一个filter        filterChain.doFilter(servletRequest, servletResponse);

        log.info("[{}]执行{}方法:After!", this.getClass().getSimpleName(), "doFilter");

    }

}

添加第二个过滤器SecondFilter类,实现Filter接口,代码如下:

@Slf4jpublic classSecondFilterimplementsFilter{

    /**    *@paramservletRequest    *@paramservletResponse    *@paramfilterChain    *@throwsIOException    *@throwsServletException    */    @Override    publicvoiddoFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throwsIOException, ServletException{

        log.info("[{}]执行{}方法:Before!", this.getClass().getSimpleName(), "doFilter");

        //执行下一个filter        filterChain.doFilter(servletRequest, servletResponse);

        log.info("[{}]执行{}方法:After!", this.getClass().getSimpleName(), "doFilter");

    }

}

过滤器配置

配置过滤器有两种方式,分别是通过配置类或者注解的方式,两种方式都可以将过滤器配置到服务中,但是通过注解的方式我还没发现指定过滤器顺序的方法(通过@Order注解是无效的),所以如果需要指定过滤器执行顺序的,建议使用方式一,否则使用方式二代码更简洁。

方式一:通过配置类配置过滤器。 添加一个Spring Boot的配置类FilterConfig,里面注册两个FilterRegistrationBean类型的Bean,代码如下:

@Configurationpublic classFilterConfig{

    /**    * 注册第一个过滤器    *@return*/    @Bean    publicFilterRegistrationBeanfirstFilter(){

        FilterRegistrationBean registrationBean = new FilterRegistrationBean(new FirstFilter());

        //可不设置,默认过滤路径即为:/*        registrationBean.addUrlPatterns("/*");

        registrationBean.setOrder(1);

        return registrationBean;

    }

    /**    * 注册第二个过滤器    *@return*/    @Bean    publicFilterRegistrationBeansecondFilter(){

        FilterRegistrationBean registrationBean = new FilterRegistrationBean(new SecondFilter());

        //可不设置,默认过滤路径即为:/*        registrationBean.addUrlPatterns("/*");

        registrationBean.setOrder(2);

        return registrationBean;

    }

}

方式二:通过注解配置过滤器 在FirstFilter和SecondFilter类上分别添加注解配置@WebFilter(urlPatterns = "/*"),由于@WebFilter并不是Spring提供的注解,所以还需要在项目的启动类中添加注解配置@ServletComponentScan,告诉Spring扫描路径,如下:

@SpringBootApplication@ServletComponentScan(basePackages = "org.cent.springboot.example.intercept.filter")public classApplication{

    publicstaticvoidmain(String[] args){

        SpringApplication.run(Application.class, args);

    }

}

添加拦截器

开发拦截器

添加第一个拦截器FirstInterceptor类,实现HandlerInterceptor接口,代码如下:

@Slf4jpublic classFirstInterceptorimplementsHandlerInterceptor{

    /**    * controller方法调用前调用。    *    *@paramrequest    *@paramresponse    *@paramhandler    *@return往下执行则返回true,否则返回false    *@throwsException    */    @Override    publicbooleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throwsException{

        log.info("[{}]执行{}方法!", this.getClass().getSimpleName());

        return true;

    }

    /**    * controller方法调用后视图渲染前执行。    *    *@paramrequest    *@paramresponse    *@paramhandler    *@parammodelAndView    *@throwsException    */    @Override    publicvoidpostHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throwsException{

        log.info("[{}]执行{}方法!", this.getClass().getSimpleName(), "postHandle");

    }

    /**    * controller方法调用且视图渲染完成后执行    *    *@paramrequest    *@paramresponse    *@paramhandler    *@paramex    *@throwsException    */    @Override    publicvoidafterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throwsException{

        log.info("[{}]执行{}方法!", this.getClass().getSimpleName(), "afterCompletion");

    }

添加第二个拦截器SecondInterceptor类,实现HandlerInterceptor接口,代码如下:

@Slf4jpublic classSecondInterceptorimplementsHandlerInterceptor{

    /**    * controller方法调用前调用。    *    *@paramrequest    *@paramresponse    *@paramhandler    *@return往下执行则返回true,否则返回false    *@throwsException    */    @Override    publicbooleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throwsException{

        log.info("[{}]执行{}方法!", this.getClass().getSimpleName(), "preHandle");

        return true;

    }

    /**    * controller方法调用后视图渲染前执行。    *    *@paramrequest    *@paramresponse    *@paramhandler    *@parammodelAndView    *@throwsException    */    @Override    publicvoidpostHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throwsException{

        log.info("[{}]执行{}方法!", this.getClass().getSimpleName(), "postHandle");

    }

    /**    * controller方法调用且视图渲染完成后执行    *    *@paramrequest    *@paramresponse    *@paramhandler    *@paramex    *@throwsException    */    @Override    publicvoidafterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throwsException{

        log.info("[{}]执行{}方法!", this.getClass().getSimpleName(), "afterCompletion");

    }

配置拦截器

添加一个Spring Boot配置类,实现WebMvcConfigurer接口以覆盖容器默认配置,代码如下:

@Configurationpublic classInterceptorConfigimplementsWebMvcConfigurer{

    /**    * 重写添加拦截器方法    *    *@paramregistry    */    @Override    publicvoidaddInterceptors(InterceptorRegistry registry){

        registry.addInterceptor(new FirstInterceptor())

                .addPathPatterns("/**")

                .order(1);//指定执行顺序,数值越小越优先        registry.addInterceptor(new SecondInterceptor())

                .addPathPatterns("/hello")

                .order(2);//指定执行顺序,数值越小越优先    }

}

启动测试

启动服务,访问http://localhost:8120/hello接口,后台输入日志如下图,会发现Filter执行会在Interceptor之前,也验证上面表格中的说法。 

SpringBoot入坑指南之六:使用过滤器或拦截器_第2张图片

示例代码

码云:https://gitee.com/centy/spring-boot-examples/tree/master/spring-boot-examples-intercept

尾巴

过滤器依赖于Servlet容器,而Interceptor则为SpringMVC的一部分。过滤器能够拦截所有请求,而Interceptor只能拦截Controller的请求,所以从覆盖范围来看,Filter应用更广一些。但是在Spring逐渐一统Java框架、前后端分离越演越烈,实际上大部分的应用场景,拦截器都可以满足了。

“我自己是一名从事了8年Java的老程序员,辞职目前在做讲师,今年年初我花了一个月整理了一份最适合2019年学习的Java干货,送给每一位Java小伙伴,欢迎进阶中的小伙伴。"

加QQ群:798891710(招募中)

你可能感兴趣的:(SpringBoot入坑指南之六:使用过滤器或拦截器)