Filter作为Servlet中的基础组件,位于javax.servlet包下。这里介绍如何在SpringBoot的环境下使用Filter
概述
Filter作为Servlet中的组件,其可以对进入Web容器的请求进行预处理,然后再将请求转交给Servlet进行处理;当Servlet处理完毕生成响应后,Filter可以再次对响应结果进行后处理,最后再返回给客户端。故其常用于校验请求的参数、设置请求/响应的Header、修改请求/响应的内容等场景当中。Filter是通过回调实现的。事实上,我们可以同时使用多个Filter。其采用责任链的设计模式以组成链式结构,使得请求在到达Servlet之前会在这个链上依次处理、传递
实践
基于@Component注解
事实上,我们只需实现Filter接口中定义的方法,并通过@Component注解将其交由Spring管理即可。从下述代码不难看出,Filter接口定义三个方法,分别应用于初始化过滤器、销毁过滤器、处理请求。此外我们还可以使用@Order注解来设置Filter的顺序。此种方式虽然简单,但会拦截所有请求,无法拦截指定URL的请求。故我们需要在doFilter方法中筛选出我们需要拦截的请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException;
@Order(5) @Component @Slf4j public class MyFilter1 implements Filter {
@Override public void init(FilterConfig filterConfig) throws ServletException { log.info("MyFilter 1: 初始化过滤器"); } @Override public void destroy() { log.info("MyFilter 1: 销毁过滤器 "); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { log.info("MyFilter 1: 前置处理"); HttpServletRequest req = (HttpServletRequest) request; String uri = req.getRequestURI(); String name = req.getParameter("name");
chain.doFilter(request, response);
log.info("MyFilter 1: 后置处理"); if( uri.endsWith("test1") && "Aaron".equals(name) ) { ServletOutputStream outputStream = response.getOutputStream(); String str = " Bye~~~~"; outputStream.write(str.getBytes("utf-8")); outputStream.flush(); } } }
|
测试结果如下所示
基于@WebFilter、@ServletComponentScan注解
我们只需在我们实现的Filter上添加@WebFilter注解,然后通过该注解指定Filter需要拦截的URL。但该方式下无法指定Filter的执行顺序,即使用@Order注解无效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException;
@WebFilter(urlPatterns = {"/testFilter/test2", "/hello/*"} ) @Slf4j public class MyFilter2 implements Filter {
private String minAge;
@Override public void destroy() { log.info("MyFilter 2: 销毁过滤器 "); }
@Override public void init(FilterConfig filterConfig) throws ServletException { log.info("MyFilter 2: 初始化过滤器"); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { log.info("MyFilter 2: 前置处理"); HttpServletRequest req = (HttpServletRequest) request; String id = req.getParameter("id");
chain.doFilter(request, response);
log.info("MyFilter 2: 后置处理"); if( id!=null && Integer.parseInt(id)<18 ) { ServletOutputStream outputStream = response.getOutputStream(); String str = " <Tag: 未成年>"; outputStream.write(str.getBytes("utf-8")); outputStream.flush(); } } }
|
然后在启动类上增加@ServletComponentScan注解即可
1 2 3 4 5 6 7 8 9 10 11 12
| import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan @SpringBootApplication public class SpringBoot1Application { public static void main(String[] args) { SpringApplication app = new SpringApplication(SpringBoot1Application.class); app.run(args); } }
|
效果如下所示
基于Java Config类
通过Java Config类通过FilterRegistrationBean配置Filter,此种方式功能强大、配置灵活。下面即是一个普通的Filter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import lombok.extern.slf4j.Slf4j; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException;
@Slf4j public class MyFilter3 implements Filter {
private Integer minAge;
@Override public void init(FilterConfig filterConfig) throws ServletException { String minAgeStr = filterConfig.getInitParameter("minAge"); minAge = Integer.valueOf(minAgeStr); log.info("MyFilter 3: 初始化过滤器, minAge: {}", minAge); }
@Override public void destroy() { log.info("MyFilter 3: 销毁过滤器 "); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { log.info("MyFilter 3: 前置处理"); HttpServletRequest req = (HttpServletRequest) request; String age = req.getParameter("age");
chain.doFilter(request, response);
log.info("MyFilter 3: 后置处理"); if( age!=null && Integer.parseInt(age)>=minAge ) { ServletOutputStream outputStream = response.getOutputStream(); String str = " <Tag: 高寿人士>"; outputStream.write(str.getBytes("utf-8")); outputStream.flush(); } } }
|
现在我们通过Java配置类来进行管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class MyFilterConfig {
@Value("${my.filter3.minAge}") private String minAge;
@Bean public FilterRegistrationBean registerMyFilter3() { FilterRegistrationBean<MyFilter3> filterRegistration = new FilterRegistrationBean<>(); filterRegistration.setName("myFilter3"); filterRegistration.setOrder(3); filterRegistration.addUrlPatterns( "/testFilter/test3" ); filterRegistration.addUrlPatterns( "/hello/*" ); filterRegistration.addInitParameter("minAge", minAge); filterRegistration.setFilter( new MyFilter3() ); return filterRegistration; }
}
|
其中,在项目的application.properties中我们添加了如下自定义参数配置项
测试效果如下所示