Java过滤器(Filter)

1.什么是过滤器

Servlet中的过滤器Filter实现了javax.servlet.Filter接口的服务器端程序,主要用途是过滤字符编码,做一些业务逻辑判断如是否有权限访问页面等

拦截请求,过滤响应

2.运行原理

当客户端向服务器端发送一个请求时,如果有对应的过滤器进行拦截,过滤器可以改变请求的内容、或者重新设置请求协议的相关信息等,然后再将请求发送给服务器端的Servlet进行处理。当Servlet对客户端做出响应时,过滤器同样可以进行拦截,将响应内容进行修改或者重新设置后,再响应给客户端浏览器。在上述过程中,客户端与服务器端并不需要知道过滤器的存在。

在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链。过滤器链中的每个过滤器负责特定的操作和任务,客户端的请求在这些过滤器之间传递,直到服务器端的Servlet。具体执行流程如下
image-20210625190754
应用场景
自动登录
统一设置编码格式
访问权限控制
敏感字符过滤等

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
@Order(1)//@Order里边的数字越小代表越先被该Filter过滤
@WebFilter(filterName = "firstFilter",urlPatterns = "/*")//@WebFilter代表这是个Filter类并把这个类注入到容器中
@Component
public class MyFilterTest implements Filter {

//初始化方法
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilterTest 初始化 init(FilterConfig filterConfig)");
//获取Filter的名称 filter-name 的内容(web-xml 中配置的名称)
String filterName = filterConfig.getFilterName();
System.out.println("filter-name:"+filterConfig.getFilterName());
System.out.println("初始化参数url的值是:"+filterConfig.getInitParameter("url"));
//获取ServletContext 对象
System.out.println(filterConfig.getServletContext());
//返回过滤器的所有初始化参数的名字的枚举集合。
Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();

System.out.println(filterName);
while (initParameterNames.hasMoreElements()) {
String paramName = (String) initParameterNames.nextElement();
System.out.println(paramName);
}
}

//销毁方法
@Override
public void destroy() {
System.out.println("MyFilterTest 销毁");
}

//过滤方法 主要是对request和response进行一些处理,然后交给下一位过滤器或者servlet处理
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("MyFilterTest执行前");
chain.doFilter(request,response);//让目标资源执行,放行
System.out.println("MyFilterTest执行后");
}
}

img

注:@ServletComponentScan注解的含义在SpringBootApplication(启动类)上使用@ServletComponentScan注解后,Servlet、Filter(过滤器)、Listener(监听器)可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码!@WebFilter+@ServletComponentScan 注解方式支持对 Filter 匹配指定URL,但是不支持指定 Filter 的执行顺序。

使用方式 排序 指定URL
@Component @Order 1 0
@WebFilter @ServletComponentScan 0 1
JavaConfig 1 1

2.Filter的生命周期

1.构造器方法

2.init 初始化方法

3.doFilter 过滤方法

  1. 通过控制对chain.doFilter方法的调用,来决定是否需要目标资源。比如可以在用户权限验证,判断用户是否有访问某些资源的权限,有权限放行,没权限不执行chain.doFilter方法
  2. 解决中文乱码的问题
  3. Filter不仅可以通过url-pattern来指定拦截哪些url匹配的资源。而且还可以通过servlet-name来指定拦截哪个指定的servlet(专门为某个servlet服务了,servlet-name对应Servlet的相关配置)

4.destroy 销毁方法

3.Filter的执行流程

在我们的请求到达Servle之间是可以经过多个Filter的,一般来说,建议Filter之间不要有关联,各自处理各自的逻辑即可。这样,我们也无需关心执行顺序问题。
如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下

在web.xml中,filter执行顺序跟的顺序有关,先声明的先执行
使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行
如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter

@Order(1)//@Order里边的数字越小代表越先被该Filter过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Order(1)//@Order里边的数字越小代表越先被该Filter过滤
@WebFilter(filterName = "firstFilter",urlPatterns = "/*")//@WebFilter代表这是个Filter类并把这个类注入到容器中
@Component
public class FirstFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("first filter 1");
System.out.println("before:" + response);
chain.doFilter(request, response);
System.out.println("after:" + response);
System.out.println("first filter 2");
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
@Order(2)
@WebFilter(filterName = "secondFilter",urlPatterns = "/*")
@Component
public class SecondFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("second filter 1");
System.out.println("before:" + response);
chain.doFilter(request, response);
System.out.println("after:" + response);
System.out.println("second filter 2");
}
}

控制台打印

1
2
3
4
5
6
7
8
9
10
first filter 1
before:org.apache.catalina.connector.ResponseFacade@5be0afc
second filter 1
before:org.apache.catalina.connector.ResponseFacade@5be0afc
1login
session 创建成功...
after:org.apache.catalina.connector.ResponseFacade@5be0afc
second filter 2
after:org.apache.catalina.connector.ResponseFacade@5be0afc
first filter 2

4.FilterConfig类

FilterConfig类 是Filter过滤器的配置文件类

Tomcat每次创建Filter的时候,会同时创建一个FilterConfig类,这里包含了Filter配置文件的配置信息

  1. 获取 Filter 的名称 filter-name 的内容
  2. 获取在 Filter 中 wen.xml 配置的 init-param 初始化参数
  3. 获取 ServletContext 对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean registerMyFilter(){
FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();
bean.setOrder(1);
bean.setFilter(new MyFilter());
// 匹配"/hello/"下面的所有url
bean.addUrlPatterns("/hello/*");
return bean;
}
@Bean
public FilterRegistrationBean registerMyAnotherFilter(){
FilterRegistrationBean<MyAnotherFilter> bean = new FilterRegistrationBean<>();
bean.setOrder(2);
bean.setFilter(new MyAnotherFilter());
// 匹配所有url
bean.addUrlPatterns("/*");
return bean;
}
}