首先建立一个SpringBoot工程,增加一个IndexController供测试使用。
@ControllerpublicclassIndexController{@GetMapping("/hello")@ResponseBodypublicStringindex(){return"hello";}}过滤器Filter过滤器(Filter),是JavaEE的标准,依赖于Servlet容器,使用的时候是配置在SpringMVC框架中是配置在web.xml文件中的,可以配置多个,执行的顺序是根据配置顺序从上到下。在SpringBoot项目中也可以采用注解的形式实现。
Filter可以认为是Servlet的一种“加强版”,它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理,是个典型的处理链。Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应。使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
创建Filter必须实现javax.servlet.Filter接口,在该接口中定义了如下三个方法。
用这种方式配置TestFilter1、TestFilter2
@WebFilter(urlPatterns="/hello")@Order(4)//预期order值越小,过滤器越靠前,此处配置无效publicclassTestFilter1implementsFilter{@Overridepublicvoidinit(javax.servlet.FilterConfigfilterConfig)throwsServletException{System.out.println("##############Filter1init##############");}@OverridepublicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIOException,ServletException{//在DispatcherServlet之前执行System.out.println("##############doFilter1before##############");filterChain.doFilter(servletRequest,servletResponse);//在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后System.out.println("##############doFilter1after##############");}@Overridepublicvoiddestroy(){System.out.println("##############Filter1destroy##############");}}并且在启动类添加@ServletComponentScan
@SpringBootApplication@ServletComponentScanpublicclassTestbootApplication{publicstaticvoidmain(String[]args){SpringApplication.run(TestbootApplication.class,args);}}2.通过@Bean来配置用这种方式配置TestFilter3、TestFilter4
创建过滤器。
@ComponentpublicclassTestFilter3implementsFilter{@Overridepublicvoidinit(javax.servlet.FilterConfigfilterConfig)throwsServletException{System.out.println("##############Filter3init##############");}@OverridepublicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIOException,ServletException{//在DispatcherServlet之前执行System.out.println("##############doFilter3before##############");filterChain.doFilter(servletRequest,servletResponse);//在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后System.out.println("##############doFilter3after##############");}@Overridepublicvoiddestroy(){System.out.println("##############Filter3destroy##############");}}注册过滤器
@ConfigurationpublicclassFilterConfig{@BeanpublicFilterRegistrationBeantestFilter3RegistrationBean(){FilterRegistrationBeanregistration=newFilterRegistrationBean(newTestFilter3());registration.addUrlPatterns("/hello");registration.setOrder(1);//值越小越靠前,此处配置有效returnregistration;}@BeanpublicFilterRegistrationBeantestFilter4RegistrationBean(){FilterRegistrationBeanregistration=newFilterRegistrationBean(newTestFilter4());registration.addUrlPatterns("/hello");registration.setOrder(2);returnregistration;}}3.SpringMVC在web.xml配置创建一个Filter只需两个步骤
示例:
##############Filter4init############################Filter3init############################Filter2init############################Filter1init############################doFilter3before############################doFilter4before############################doFilter1before############################doFilter2before############################doFilter2after############################doFilter1after############################doFilter4after############################doFilter3after##############配置order,值越小越靠前
##############Filter4init############################Filter3init############################Filter2init############################Filter1init############################doFilter4before############################doFilter3before############################doFilter1before############################doFilter2before############################doFilter2after############################doFilter1after############################doFilter3after############################doFilter4after##############由此可见,@Order的顺序配置没有起作用,registration.setOrder()是有效的。
拦截器(Interceptor)不依赖Servlet容器,依赖Spring等Web框架,在SpringMVC框架中是配置在SpringMVC的配置文件中,在SpringBoot项目中也可以采用注解的形式实现。
拦截器是AOP的一种应用,底层采用Java的反射机制来实现的。与过滤器一个很大的区别是在拦截器中可以注入Spring的Bean,能够获取到各种需要的Service来处理业务逻辑,而过滤器则不行。
afterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandle,Exceptionex)方法,该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
interceptor的执行顺序大致为:
Spring中主要通过HandlerInterceptor接口来实现请求的拦截,实现HandlerInterceptor接口需要实现下面三个方法:
自定义一个拦截器实现HandlerInterceptor,实现preHandle,postHandle,afterCompletion三个方法。
@ComponentpublicclassTestInterceptor1implementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{System.out.println("##############TestInterceptor1preHandle##############");returntrue;}//在Controller之后的DispatcherServlet之后执行@OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{System.out.println("##############TestInterceptor1postHandle##############");}//在页面渲染完成之后返回给客户端执行@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{System.out.println("##############TestInterceptor1afterCompletion##############");}}2.注册拦截器自定义拦截器配置类继承自WebMvcConfigurer,重写addInterceptors将自定义的拦截器添加至注册中心。
@ComponentpublicclassWebMvcConfigimplementsWebMvcConfigurer{@AutowiredprivateTestInterceptor1testInterceptor1;@AutowiredprivateTestInterceptor2testInterceptor2;@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(testInterceptor1).excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg").addPathPatterns("/hello");registry.addInterceptor(testInterceptor2).addPathPatterns("/hello");}}注册顺序即为执行顺序。
Spring的Interceptor(拦截器)与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。不同的是: