【Java Web】Java Server Page总结(Filter篇)

Servlet一样,Filter也是J2EE中的一项规范、一个接口(基于Servlet 4.0.1):

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package javax.servlet;

import java.io.IOException;

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;

    default void destroy() {
    }
}

Filter接口的源码很简洁,一共就三个方法,init()doFilter()destroy()

生命周期

Filter的生命周期分为三个阶段:

  1. 初始化阶段:init()方法,由Web容器在启动时完成实例化及初始化操作,在生命周期中只会调用一次;
  2. 调用阶段:doFilter()方法,请求的位置处于Filter的负责范围之内时,调用该方法;
  3. 销毁阶段:destroy()方法,释放资源,销毁实例。

工作原理

Filter的工作原理主要包括以下两条:

  1. 在用户的请求访问后端资源之前,拦截请求并做处理;
  2. 在服务器的响应返回给用户之前,对响应做一些处理。

当用户将请求发送到服务器后,如果没有配置Filter的话,就会调用Servletservice()方法,但是一旦给这个(些)Servlet配置了Filter之后,就会在调用service()之前先调用FilterdoFilter()方法对请求做一些处理。

Filter对服务器响应的处理也是在doFilter()中进行的,具体见下文。

配置

    <!-- filter 和 filter-mapping 必须成对出现才有效 -->
    <!-- filter-name 可以自己取 -->
    <!-- 同一个 Filter 的 filter 和 filter-mapping 中的 filter-name 必须相同 -->

    <!-- filter-class 是 Filter 的完全限定名 -->
    <!-- init-param 用于为过滤器指定初始化参数,
        它的子元素param-name指定参数的名字,param-value指定参数的值 -->
    <!-- async-supported 启用异步支持 -->
    <filter>
        <filter-name>FilterTest</filter-name>
        <filter-class>com.vingyun.FilterTest</filter-class>
        <init-param>
            <param-name>encoding</param-name>  
            <param-value>UTF-8</param-value>  
        </init-param>
        <async-supported>true</async-supported>
    </filter>

    <!-- servlet-name 配置需要过滤操作的 Servlet 的 servlet-name -->
    <!-- url-pattern 配置需要过滤操作的路径 -->
    <!-- url-pattern 和 servlet-name 可以同时使用 -->
    <!-- dispatcher 设置当以什么方式访问资源时进行过滤:ASYNC、REQUEST、ERROR、FORWARD、INCLUDE -->
    <!-- ASYNC:异步方式,Servlet 3.0 新加特性,
        需要将 filter 标签的 async-supported 子标签设置为 true,
        同时需要将受该 Filter 影响的 Servlet 的 servlet 标签的 async-supported 子标签设置为 true -->
    <!-- REQUEST:当用户直接访问页面时,Web容器将会调用过滤器,
        如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用 -->
    <!-- INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用,
        除此之外,该过滤器不会被调用 -->
    <!-- FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,
        除此之外,该过滤器不会被调用 -->
    <!-- ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用,
    除此之外,过滤器不会被调用。 -->
    <filter-mapping>
        <filter-name>FilterTest</filter-name>
        <servlet-name>Servlet</servlet-name>
        <url-pattern>/test/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

多个Filter对一时的工作顺序

如果对于一个Servlet或是一个路径配置多个Filter(即Filter链),那么将会按照这些Filter<filter-mapping>标签的配置顺序进行过滤操作。

服务器响应过滤

上文说到Filter可以过滤服务器响应的内容,但是在配置<dispatcher>标签的时候并没有RESPONSE这个属性,那么我们该怎么过滤服务器的响应呢?

在新建的Filter中的doFilter()方法中有这么一个调用方法:chain.doFilter(request, response);

    public void doFilter(ServletRequest request, ServletResponse response, 
                            FilterChain chain) throws ServletException, IOException {
        chain.doFilter(request, response);
    }

如果没有,那我们可以自己加上,这个方法的用途下面再说,但是现在我们可以在这个方法之后使用response对象来对响应内容进行操作。

chain.doFilter(request, response)

doFilter()方法中的chain.doFilter(request, response)方法的作用是将请求转发给Filter链上的下一个Filter,如果没有下一个Filter,那就直接转发给被请求的资源。

猜你喜欢

转载自blog.csdn.net/ving_suixin/article/details/80146654