Java Servlet的Filter组件

Java Servlet 2.3版本引入了一种新的组件:Filter。Filter动态地转换和使用request和response中的信息。Filters一般来说并不是直接产生response,而是提供一种通用的功能,用于附加到servlet or JSP页面中。

Filters的一些API

这些API都在javax.servlet包下面,包括Filter, FilterChain, FilterConfig接口。
通过实现Filter接口就可以定义一个Filter。

You define a filter by implementing the Filter interface.

FilterChain是通过WEB容器(比如tomcat)传递到Filter中的,它提供了一种调用一系列Filter的机制。

A filter chain, passed to a filter by the container, provides a mechanism for invoking a series of filters.

FilterConfig包含了一些初始化的数据(可能为null)。

A filter config contains initialization data.

Filter接口最重要的方法就是doFilter方法,这是它的核心。
通常具有以下操作:

  • 检查请求头;
  • 用于对request对象进行定制(处理),比如修改一些请求头、请求体,或者直接阻断这个请求。
  • 用于对response对象进行定制(处理),比如修改一些响应头、响应体。
  • 调用FilterChain对象中的下一个Filter,比如chain.doFilter(request, wrapper);
  • 抛出异常,表示处理出错了。

参考:
https://www.oracle.com/technetwork/java/filters-137243.html

除了doFilter之外,还必须实现init和destroy方法。其中init方法是当Filter初始化的时候,由容器调用的,用于传递一些数据。

Examples

比如下面这个不改变任何request和response的Filter,只是用于记录Servlet 的访问次数:

                  
public final class HitCounterFilter implements Filter {
   private FilterConfig filterConfig = null;
   public void init(FilterConfig filterConfig) 
      throws ServletException {
      this.filterConfig = filterConfig;
   }
   public void destroy() {
      this.filterConfig = null;
   }
   public void doFilter(ServletRequest request,
      ServletResponse response, FilterChain chain) 
      throws IOException, ServletException {
      if (filterConfig == null)
         return;
      StringWriter sw = new StringWriter();
      PrintWriter writer = new PrintWriter(sw);
      Counter counter = (Counter)filterConfig.
         getServletContext().
         getAttribute("hitCounter");
      writer.println();
      writer.println("===============");
      writer.println("The number of hits is: " +
         counter.incCounter());
      writer.println("===============");

      // Log the resulting string
      writer.flush();
      filterConfig.getServletContext().
         log(sw.getBuffer().toString());
      ...
      chain.doFilter(request, wrapper);
      ...
   }
}

再比如下面这个例子,修改了request中的字符编码(如果请求中没有指定Content-Type的字符编码,则容器会使用自己的字符编码),当然也可以修改Accept-Language、User-Agent,以及一些存储在当前用户session中的变量。

public void doFilter(ServletRequest request, 
   ServletResponse response, FilterChain chain) throws
   IOException, ServletException {
   String encoding = selectEncoding(request);
   if (encoding != null)
      request.setCharacterEncoding(encoding);
   chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws
   ServletException {
   this.filterConfig = filterConfig;
   this.encoding = filterConfig.getInitParameter("encoding");
}
protected String selectEncoding(ServletRequest request) {
   return (this.encoding);
}

Wrapper 的使用

。。。

Filter 的配置

使用<filter>元素在web.xml中声明,然后给它起一个名字:<filter-name>,指定Filter的实现类<filter-class>;以及一些初始化的参数<init-param>

<filter>
   <filter-name>Compression Filter</filter-name>
   <filter-class>CompressionFilter</filter-class>
   <init-param>
      <param-name>compressionThreshold</param-name>
      <param-value>10</param-value>
   </init-param>
</filter>
<!--
通过`<filter-mapping>`标签可以将一个Filter和一个Servlet进行Mapping。
在这个Mapping中可以指定`<url-pattern>`,这里的值是`/CompressionTest`。
表示这个URL对应的Servlet是CompressionTest名字对应的类:`CompressionTest`;
而其又跟Compression Filter这个Filter表示的`CompressionFilter`进行了Mapping。
-->
<filter-mapping>
   <filter-name>Compression Filter</filter-name>
   <servlet-name>CompressionTest</servlet-name>
</filter-mapping>
<servlet>
   <servlet-name>CompressionTest</servlet-name>
   <servlet-class>CompressionTest</servlet-class>
</servlet>
<servlet-mapping>
   <servlet-name>CompressionTest</servlet-name>
   <url-pattern>/CompressionTest</url-pattern>
</servlet-mapping>

注意:这些元素必须要以这种顺序!

可以将一个Filter对应到多个Servlet中,也可以将多个Filter对应到一个Servlet中。

#TODO

Figure 1 Filter to Servlet Mapping

Recall that a filter chain is one of the objects passed to the doFilter method of a filter. This chain is formed indirectly via filter mappings. The order of the filters in the chain is the same as the order that filter mappings appear in the web application deployment descriptor.

When a URL is mapped to servlet S1, the web container invokes the doFilter method of F1. The doFilter method of each filter in S1’s filter chain is invoked by the preceding filter in the chain via the chain.doFilter method. Since servlet S1’s filter chain contains filters F1 and F3, F1’s call to chain.doFilter invokes the doFilter method of filter F3. When F3’s doFilter method completes, control returns to F1’s doFilter method.

The deployment descriptor just discussed puts the hit counter and XSLT filter in the filter chain of FilteredFileServlet. The hit counter filter logs access whenever FilteredFileServlet is invoked, but inserts the value of the counter into the response after the XSLT transformation only if the response type is HTML:

发布了600 篇原创文章 · 获赞 101 · 访问量 100万+

猜你喜欢

转载自blog.csdn.net/caiqiiqi/article/details/102505942