Filter:过滤器,用于在 Servlet 之外对 Request 或者 Response 进行拦截,做一些处理后再交给下一个过滤器或者 Servlet 进行处理,通常用来拦截 Request 进行处理,也可以对返回的 Response 做拦截处理
主要用途:自动登录、统一编码设置、访问权限控制、敏感字符过滤

Filter 类结构:
image.png

Filter 生命周期

javax.servlet.Filter 接口:

  1. // Filter 接口
  2. public interface Filter {
  3. // 初始化方法
  4. default public void init(FilterConfig filterConfig) throws ServletException {}
  5. // 过滤方法,主要是对request和response进行处理,再转交下一个过滤器或Servlet
  6. // chain.doFilter(request,response)
  7. public void doFilter(ServletRequest request, ServletResponse response,
  8. FilterChain chain)
  9. throws IOException, ServletException;
  10. // 销毁方法
  11. default public void destroy() {}
  12. }

Filter的创建和销毁由WEB服务器负责:

  • Filter 创建:web 应用程序启动时,web 服务器将创建 Filter 的实例对象,并调用其 init 方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作,filter对象只会创建一次,init方法也只会执行一次。通过 init 方法的参数,可获得代表当前 filter 配置信息的 FilterConfig 对象
  • Filter 销毁:Web 容器调用 destroy 方法销毁 Filter。destroy 方法在 Filter 的生命周期中仅执行一次。在 destroy 方法中,可以释放过滤器使用的资源

FilterConfig 接口:用户在配置 filter 时,可以使用为 filter 配置一些初始化参数,当 web 容器实例化 Filter 对象,调用其 init 方法时,会把封装了 filter 初始化参数的 filterConfig 对象传递进来。因此开发人员在编写 filter 时,通过 filterConfig 对象的方法,就可获得:

  • String getFilterName():得到 filter 的名称
  • String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回 null
  • Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合
  • public ServletContext getServletContext():返回 Servlet 上下文对象的引用

Filter 实现

Filter 实现分为三步:

  1. 引入 Servlet-API
  2. 创建一个类继承 HttpFilter(或者实现 Filter 接口)
  3. 配置需要过滤的 URL 路径

1、在 pom.xml 中引入 Servlet-API

Servlet-API 一般在 web 容器中会提供,因此我们只需要在开发编译时引入 Servlet-API 提供支持即可,而无需打包到项目中,因此设置其生命周期为 provided

  1. <!-- Servlet3.0之前的版本为servlet-api -->
  2. <dependency>
  3. <groupId>javax.servlet</groupId>
  4. <artifactId>servlet-api</artifactId>
  5. <version>2.5</version>
  6. <scope>provided</scope>
  7. </dependency>
  8. <!-- Servlet3.0之后的版本为javax.servlet-api -->
  9. <dependency>
  10. <groupId>javax.servlet</groupId>
  11. <artifactId>javax.servlet-api</artifactId>
  12. <version>4.0.1</version>
  13. <scope>provided</scope>
  14. </dependency>

2、创建一个类继承 HttpFilter(或者实现 Filter 接口)

  • chain.doFilter(req, res):将当前处理过的 HttpServletRequest 或 HttpServletResponse 转交给下一步处理

    1. public class DemoFilter extends HttpFilter {
    2. @Override
    3. protected void doFilter(HttpServletRequest req,
    4. HttpServletResponse res,
    5. FilterChain chain) throws IOException, ServletException {
    6. // 设置请求的编码格式
    7. req.setCharacterEncoding("utf-8");
    8. // 设置服务端的响应编码格式
    9. res.setCharacterEncoding("utf-8");
    10. // 设置客户端对响应信息的编码格式
    11. res.setHeader("Content-type","text/html;charset=UTF-8");
    12. // 转交刚给下一个Filter或者Servlet
    13. chain.doFilter(req, res);
    14. // 在执行后对响应做一定的处理
    15. after(req , res);
    16. }
    17. }

3、配置过滤器过滤的URL映射,支持注解和web.xml中配置:

  • web.xml中配置:

    1. <filter>
    2. <filter-name>encoding</filter-name>
    3. <filter-class>top.songfang.filter.DemoFilter</filter-class>
    4. <init-param>
    5. <!-- 可以通过FilterConfig进行获取 -->
    6. <param-name>encoding</param-name>
    7. <param-value>UTF-8</param-value>
    8. </init-param>
    9. </filter>
    10. <filter-mapping>
    11. <filter-name>encoding</filter-name>
    12. <!-- 对所有的请求都进行过滤 -->
    13. <url-pattern>/*</url-pattern>
    14. </filter-mapping>
  • 注解方式:@WebFilter 注解

    1. @WebFilter(value = "/*", // 统配符,拦截所有请求
    2. initParams = {
    3. // 初始化参数
    4. @WebInitParam(name = "encoding", value = "UTF-8", description = "字符编码")
    5. })

@WebFilter 注解属性说明

@WebFilter:声明一个类为过滤器,该注解在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。该注解具有下表给出的一些常用属性 ( 以下所有属性均为可选属性,但是 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值 )

属性名 类型 描述
filterName String 指定过滤器的name属性,等价于
value String[] 该属性等价于urlPatterns属性,但两者不能同时使用
urlPatterns String[] 指定一组过滤器的URL匹配模式,等价于
servletNames String[] 指定过滤器将应用于哪些Servlet,取值为@WebServlet中name属性的取值,或者web.xml中的取值
dispatcherTypes DispatcherType 指定过滤器的转发模式,包括ASYNC(异步)、ERROR(出错)、FORWARD(转发)、INCLUDE(包含在页面的)、REQUEST(请求的)
initParams WebInitParam[] 指定一组过滤器初始化参数,等价于
asyncSupported boolean 指定过滤器是否支持异步操作模式,等价于
description String 该过滤器的描述信息,等价于
displayName String 该过滤器的显示名,配合工具使用,等价于

dispatcher 说明:

  • REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过 RequestDispatcher 的 include() 或 forward() 方法访问时,那么该过滤器就不会被调用
  • INCLUDE:如果目标资源是通过 RequestDispatcher 的 include() 方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用
  • FORWARD:如果目标资源是通过 RequestDispatcher 的 forward() 方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用
  • ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用

过滤器链的执行顺序

关于过滤器的注解执行顺序的说明:https://www.concretepage.com/java-ee/jsp-servlet/how-to-use-filter-in-servlet-3-with-webfilter-annotation

过滤器链的执行顺序:

  • 请求时执行顺序:
    • 在 web.xml 中,filter 执行顺序跟 的顺序有关,先声明的先执行
    • 使用注解配置的话,无法决定执行顺序,因此如果需要严格设定执行顺序,需要在 web.xml 中声明
    • 如果既有在 web.xml 中声明的 Filter,也有通过注解配置的 Filter,那么会优先执行 web.xml 中配置的 Filter
  • 响应时执行顺序:以相反的顺序执行

image.png