过滤器
过滤器(Filter)介绍
Filter可以认为是Servlet的一种“加强版”,它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理,是个典型的处理链。Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应。使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行预处理并生成响应,最后Filter再对服务器响应进行后处理。
Filter有如下几个用处。
-
在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。
-
根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
-
在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
-
根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。
Filter有如下几个种类。
-
用户授权的Filter:Filter负责检查用户请求,根据请求过滤用户非法请求。
-
日志Filter:详细记录某些特殊的用户请求。
-
负责解码的Filter:包括对非标准编码的请求解码。
-
能改变XML内容的XSLT Filter等。
-
Filter可以负责拦截多个请求或响应;一个请求或响应也可以被多个Filter拦截。
创建一个Filter只需两个步骤
-
创建Filter处理类
-
web.xml文件中配置Filter
创建Filter必须实现javax.servlet.Filter接口,在该接口中定义了如下三个方法。
-
void init(FilterConfig config):用于完成Filter的初始化。
-
void destory():用于Filter销毁前,完成某些资源的回收。
-
void doFilter(ServletRequest request,ServletResponse response,FilterChain chain):实现过滤功能,该方法就是对每个请求及响应增加的额外处理。该方法可以实现对用户请求进行预处理(ServletRequest request),也可实现对服务器响应进行后处理(ServletResponse response)—它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。
过滤器的配置
现在我们通过过滤器来实现记录请求执行时间的功能,其实现如下:
public class LogCostFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { long start = System.currentTimeMillis(); filterChain.doFilter(servletRequest,servletResponse); System.out.println("Execute cost="+(System.currentTimeMillis()-start)); } @Override public void destroy() { } }
这段代码的逻辑比较简单,就是在方法执行前先记录时间戳,然后通过过滤器链完成请求的执行,在返回结果之间计算执行的时间。这里需要主要,这个类必须继承Filter类,这个是Servlet的规范,这个跟以前的Web项目没区别。但是,有了过滤器类以后,以前的web项目可以在web.xml中进行配置,但是spring boot项目并没有web.xml这个文件,那怎么配置?在Spring boot中,我们需要FilterRegistrationBean来完成配置。其实现过程如下:
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean registFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new LogCostFilter()); registration.addUrlPatterns("/*"); registration.setName("LogCostFilter"); registration.setOrder(1); return registration; } }
这样配置就完成了,需要配置的选项主要包括实例化Filter类,然后指定url的匹配模式,设置过滤器名称和执行顺序,这个过程和在web.xml中配置其实没什么区别,只是形式不同而已。现在我们可以启动服务器访问任意URL:
大家可以看到上面的配置已经生效了。除了通过 FilterRegistrationBean 来配置以外,还有一种
@WebFilter(urlPatterns = {"/getbotlist","/EXAMPLE12"}, filterName = "logFilter2")//配置请求匹配规则匹配,使能到具体的API public class Filter1 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override//预处理函数 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException, IOException { long start = System.currentTimeMillis(); System.out.println("-----------------------过滤器开始------------------------"); filterChain.doFilter(servletRequest, servletResponse); System.out.println("-----------------------过滤器结束------------------------"); } @Override public void destroy() { } }
这里直接用@WebFilter就可以进行配置,同样,可以设置url匹配模式,过滤器名称等。这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们还需在配置类中加另外一个注解:@ServletComponetScan,指定扫描的包。
@SpringBootApplication @MapperScan("com.pandy.blog.dao") @ServletComponentScan("com.pandy.blog.filters") public class Application { public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } }
现在,我们再来访问一下任意URL:
可以看到,我们配置的两个过滤器都生效了。细心的读者会发现,第二个Filter我们并没有指定执行的顺序,但是却在第一个Filter之前执行。这里需要解释一下,@WebFilter这个注解并没有指定执行顺序的属性,其执行顺序依赖于Filter的名称,是根据Filter类名(注意不是配置的filter的名字)的字母顺序倒序排列,并且@WebFilter指定的过滤器优先级都高于FilterRegistrationBean配置的过滤器。有兴趣的朋友可以自己实验一下。