Filter简介

  Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
  Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,如下所示:

Filter请求和响应

Filter是可以转换请求或响应的标头和内容 (或两者) 的对象。Filter与 web 组件的区别在于, Filter本身通常不会创建响应。相反, Filter提供了可 "附加" 到任何类型的 web 资源的功能。因此, Filter不应依赖于它充当其Filter的 web 资源。这样, 它可以由多种类型的 web 资源组成。

Filter可以执行的主要任务如下所示。

  • 查询请求并采取相应的操作。

  • 阻止请求和响应对通过任何进一步。

  • 修改请求标头和数据。您可以通过提供请求的自定义版本来执行此操作。

  • 修改响应标头和数据。您可以通过提供响应的自定义版本来执行此操作。

  • 与外部资源交互。

Filter的应用包括身份验证、日志记录、图像转换、数据压缩、加密、令牌流、XML 转换等。

您可以将 web 资源配置为按特定顺序按零、一个或多个Filter链进行筛选。此链是在部署包含该组件的 web 应用程序时指定的, 并且在 web 容器加载组件时实例化。

 

编程Filter

筛选 APIjavax.servlet servlet 包中的Filter"、 FilterChainFilterConfig配置" 接口定义。通过实现Filter接口来定义Filter。

使用@WebFilter批注在 web 应用程序中定义Filter。此批注是在类上指定的, 包含有关要声明的Filter的元数据。带注释的Filter必须至少指定一个 URL 模式。这是通过使用批注上urlPatternsvalue属性来完成的。所有其他属性都是可选的, 具有默认设置。当批注上的唯一属性是 URL 模式时, 请使用值属性; 如果批注上的唯一属性是 url 模式, 则使用value属性。当也使用其他属性时, 请使用urlPatterns属性。

使用@WebFilter批注批注进行批注的类必须实现javax.servlet.Filter接口。

若要将配置数据添加到Filter, 请指定@WebFilter批注的initParams属性。initParams一个@WebInitParam批注。下面的代码段定义了一个Filter, 指定了一个初始化参数:

import javax.servlet.Filter;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

@WebFilter(filterName = "TimeOfDayFilter",
urlPatterns = {"/*"},
initParams = {
    @WebInitParam(name = "mood", value = "awake")})
public class TimeOfDayFilter implements Filter {
    ...

 

Filter接口中最重要的方法是doFilter, 它传递请求、响应和筛选链对象。此方法可以执行以下操作。

  • 检查请求标头。

  • 如果Filter希望修改请求标头或数据, 则自定义请求对象。

  • 如果Filter希望修改响应标头或数据, 则自定义响应对象。

  • 调用Filter链中的下一个实体。如果当前Filter是以目标 web 组件或静态资源结尾的链中的最后一个Filter, 则下一个实体是链末尾的资源; 如果当前Filter是以目标 web 组件或静态资源结尾的链中的最后一个Filter, 则下一个实体是链的末尾的资源。否则, 它是在 WAR 中配置的下一个Filter。Filter通过调用链对象上的doFilter方法来调用下一个实体, 传递使用它调用的请求和响应或它可能创建的包装版本。或者, Filter可以选择通过不调用调用下一个实体来阻止请求。在后一种情况下, Filter负责填写响应。

  • 调用链中的下一个Filter后, 检查响应标头。

  • 引发异常以指示处理中的错误。

除了doFilter之外, 还必须实现initdestroy方法。在实例化Filter时, 容器将调用init方法。如果要将初始化参数传递给Filter, 则会从传递给init FilterConfig对象检索这些参数.

编程自定义的请求和响应

Filter有多种方法可以修改请求或响应。例如, Filter可以向请求中添加属性, 也可以在响应中插入数据。

修改响应的Filter通常必须在将响应返回到客户端之前捕获该响应。为此, 您需要将备用流传递给生成响应的 servlet。备用流阻止 servlet 在完成时关闭原始响应流, 并允许Filter修改 servlet 的响应。

若要将此备用流传递给 servlet, Filter将创建一个响应包装器, 该包装器将覆盖getWritergetOutputStream方法, 以返回此备用流。包装被传递给Filter链的doFilter方法。包装方法默认调用到包装的请求或响应对象。

若要重写请求方法, 请将请求包装在扩展ServletRequestWrapperHttpServletRequestWrapper的对象中。若要重写响应方法, 请将响应包装在扩展ServletResponseWrapper HttpServletResponseWrapper.

 

指定Filter映射

web 容器使用Filter映射来决定如何将Filter应用于 web 资源。Filter映射按名称将Filter与 web 组件匹配, 或按 URL 模式将Filter与 web 资源匹配。Filter是按Filter映射在 WAR 的Filter映射列表中出现的顺序调用的。通过使用 NetBeans IDE 或使用 XML 对列表进行编码, 可以在 war 的部署描述符中为其指定Filter映射列表。

如果要将每个请求记录到 web 应用程序, 请将命中计数器Filter映射到 URL 模式/*.

可以将Filter映射到一个或多个 web 资源, 也可以将多个Filter映射到 web 资源。如图18-1 所示, 其中Filter f1 映射到 Servlets s1、s2 和 s3;过滤器 F2 映射到 servlet S2;和过滤器 F3 映射到 servlets S1 和 S2。

图18-1 筛选到服务映射

Diagram of filter-to-servlet mapping with filters F1-F3 and servlets S1-S3. F1 filters S1-S3, then F2 filters S2, then F3 filters S1 and S2.

Filter链是传递给Filter的doFilter方法的对象之一。此链是通过Filter映射间接形成的。链中Filter的顺序与Filter映射在 web 应用程序部署描述符中出现的顺序相同。

当Filter映射到 servlet S1 时, web 容器将调用 F1 的doFilter方法。S1 筛选链中每个Filter的doFilter方法是由链中的前面的Filter通过chain.doFilter方法调用的。由于 S1 的筛选链包含Filter F1 和 F3, 因此 F1 对chain.doFilter的调用调用Filter F3 的doFilter方法。当 F3 的doFilter方法完成时, 控件返回到 F1 的doFilter方法。