springboot创建过滤器filter的方式
springboot创建过滤器filter两种方式和区别
浏览器发出的请求先递交给第一个filter进行过滤,符合规则则放行,递交给filter链中的下一个过滤器进行过滤。在doFilter()方法中,chain.doFilter()前的一般是对request执行的过滤操作,chain.doFilter后面的代码一般是对response执行的操作。过滤链代码的执行顺序如下
过滤器用途:
1)过滤敏感词汇(防止sql注入)
2)设置字符编码
3)URL级别的权限访问控制
4)压缩响应信息
1、使用@WebFilter和@ServletComponentScan注解方式创建filter
首先创建过滤器类,实现 javax.servlet.Filter接口,并添加注解@WebFilter(javax.servlet.annotation.WebFilter),urlPatterns 过滤器要过滤的URL规则配置,filterName 过滤器的名称。有的博客上说使用@Order(int) 注解,可以自定义过滤器的顺序,但经过验证后此种方式并不生效。
package com.test.demo.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter(filterName = "aFilter", urlPatterns = {"/*"}) public class AFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("A Filter before"); filterChain.doFilter(servletRequest, servletResponse); System.out.println("A Filter after"); } }
然后再项目的启动类上加上@ServletComponentScan注解即可
package com.test.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import springfox.documentation.oas.annotations.EnableOpenApi; @EnableOpenApi @SpringBootApplication @ServletComponentScan public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
当使用这种方式启动多个过滤器时,过滤器的顺序是按照类名升序排序的,
经过测试,发现 @Order 注解指定 int 值没有起作用,是无效的。因为看源码发现 @WebFilter 修饰的过滤器在加载时,没有使用 @Order 注解,而是使用的类名来实现自定义Filter顺序,
所以这种方式定义Filter的顺序,就必须限定 Filter 的类名,比如刚才那个 Filter 叫 AFilter ,加入我们现在新写了一个 Filter 叫 BFilter ,那么顺序就是 AFilter > BFilter 。
所以这种方式虽然实现起来简单,只需要注解,但自定义顺序就必须要限定类名,使用类名达到排序效果了。
测试验证如图:
AFilter过滤器设置的order是100,BFilter设置的order是1,但是执行顺序还是AFilter在BFilter之前,证明order注解并没有起作用。
2、FilterRegistrationBean方式创建过滤器
FilterRegistrationBean
是springboot
提供的,此类提供setOrder方法,可以为filter设置排序值,让spring在注册web filter之前排序后再依次注册。
package com.test.demo.config; import com.test.demo.filter.AFilter; import com.test.demo.filter.BFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.ArrayList; import java.util.List; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean filter1() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); AFilter aFilter = new AFilter(); //设置过滤器 filterRegistrationBean.setFilter(aFilter); filterRegistrationBean.setName("A filter"); //设置名称 List list = new ArrayList(); list.add("/*"); //拦截路径 filterRegistrationBean.setUrlPatterns(list); filterRegistrationBean.setOrder(2); //设置访问优先级 值越小越高 return filterRegistrationBean; } @Bean public FilterRegistrationBean filter2() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); BFilter bFilter = new BFilter(); filterRegistrationBean.setFilter(bFilter); filterRegistrationBean.setName("B filter"); List list = new ArrayList(); list.add("/*"); //拦截路径 filterRegistrationBean.setUrlPatterns(list); filterRegistrationBean.setOrder(1); //设置访问优先级 值越小越高 return filterRegistrationBean; } }
执行结果如图:
设置过滤器顺序成功,BFilter在AFilter过滤器之前执行。
当不设置 setOrder 次序时,过滤器的执行顺序默认是 Bean 的加载顺序。在当前 FilterConfig 类中,先加载的是 filter1方法 即 AFilter 过滤器,后加载的是 filter2 方法 即 BFilter 过滤器。
package com.test.demo.config; import com.test.demo.filter.AFilter; import com.test.demo.filter.BFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.ArrayList; import java.util.List; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean filter2() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); BFilter bFilter = new BFilter(); filterRegistrationBean.setFilter(bFilter); filterRegistrationBean.setName("B filter"); List list = new ArrayList(); list.add("/*"); //拦截路径 filterRegistrationBean.setUrlPatterns(list); // filterRegistrationBean.setOrder(1); //设置访问优先级 值越小越高 return filterRegistrationBean; } @Bean public FilterRegistrationBean filter1() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); AFilter aFilter = new AFilter(); //设置过滤器 filterRegistrationBean.setFilter(aFilter); filterRegistrationBean.setName("A filter"); //设置名称 List list = new ArrayList(); list.add("/*"); //拦截路径 filterRegistrationBean.setUrlPatterns(list); // filterRegistrationBean.setOrder(2); //设置访问优先级 值越小越高 return filterRegistrationBean; } }
注释掉setOrder后,将filter2方法放在filter1方法前,再次执行,结果如图:
证明使用此种方式创建过滤器,过滤器的默认顺序就是过滤器的加载顺序,与过滤器类名无关。
3、SpringBoot注册第三方过滤器
假如在项目里引入了第三方的jar,要使用jar里面带的 Filter ,且这个过滤器在实现时没有使用 @Component
标识为Spring Bean,则这个过滤器将不会生效。此时需要通过java代码去注册这个过滤器。也是使用FilterRegistrationBean配置类的方式进行注册。
4、使用@Component注解创建过滤器
package com.test.demo.filter; import org.springframework.stereotype.Component; import javax.servlet.*; import java.io.IOException; @Component public class AFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("A Filter before"); filterChain.doFilter(servletRequest, servletResponse); System.out.println("A Filter after"); } }
package com.test.demo.filter; import org.springframework.stereotype.Component; import javax.servlet.*; import java.io.IOException; @Component public class BFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("B Filter before"); filterChain.doFilter(servletRequest, servletResponse); System.out.println("B Filter after"); } }
然后启动项目后者执行,结果如图所示:
先执行的AFilter过滤器,后执行的BFilter过滤器。通过此种方式无法自定义设置过滤器的顺序。