Filter的执行顺序与实例

Posted winner-0715

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Filter的执行顺序与实例相关的知识,希望对你有一定的参考价值。

 Filter介绍 

Filter可认为是Servlet的一种“变种”,它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理,是个典型的处理链。它与Servlet的区别在于:它不能直接向用户生成响应。完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

Filter有如下几个用处。

  • 在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。
  • 根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
  • 在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
  • 根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

Filter有如下几个种类。

  • 用户授权的Filter:Filter负责检查用户请求,根据请求过滤用户非法请求。
  • 日志Filter:详细记录某些特殊的用户请求。
  • 负责解码的Filter:包括对非标准编码的请求解码。
  • 能改变XML内容的XSLT Filter等。
  • Filter可负责拦截多个请求或响应;一个请求或响应也可被多个请求拦截。

创建一个Filter只需两个步骤:

  • 建Filter处理类;
  • web.xml文件中配置Filter。

下面先介绍一个简单的记录日志的Filter,这个Filter负责拦截所有的用户请求,并将请求的信息记录在日志中。

public class LogFilter implements Filter {

    /**
     * FilterConfig可用于访问Filter的配置信息
     */
    private FilterConfig config;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.config = config;
    }

    /**
     * 执行过滤的核心方法
     *
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //---------下面代码用于对用户请求执行预处理---------
        //获取ServletContext对象,用于记录日志
        ServletContext context = this.config.getServletContext();
        long before = System.currentTimeMillis();
        System.out.println("开始过滤...");
        //将请求转换成HttpServletRequest请求
        HttpServletRequest hrequest = (HttpServletRequest) request;
        //记录日志
        context.log("Filter已经截获到用户的请求地址: " + hrequest.getServletPath());
        //Filter只是链式处理,请求依然放行到目的地址
        chain.doFilter(request, response);
        //---------下面代码用于对服务器响应执行后处理---------
        long after = System.currentTimeMillis();
        //记录日志
        context.log("过滤结束");
        //再次记录日志
        context.log("请求被定位到" + hrequest.getRequestURI() + "所花的时间为: " + (after - before));
    }

    @Override
    public void destroy() {
        this.config = null;
    }
}

 上面程序实现了doFilter()方法,实现该方法就可实现对用户请求进行预处理,也可实现对服务器响应进行后处理——它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。

在上面的请求Filter中,仅在日志中记录请求的URL,对所有的请求都执行chain.doFilter (request,reponse)方法,当Filter对请求过滤后,依然将请求发送到目的地址。如果需要检查权限,可以在Filter中根据用户请求的HttpSession,判断用户权限是否足够。如果权限不够,直接调用重定向即可,无须调用chain.doFilter(request,reponse)方法。

 FirstFilter.java 

public class FirstFilter implements Filter {

    @Override
    public void destroy() {
        System.out.println("1st destroy()...");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        System.out.println("before invoke 1stFilter‘s chain.doFilter() ..");
        chain.doFilter(request, response);
        System.out.println("after invoke 1stFilter‘s chain.doFilter() ..");
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        System.out.println("1stFilter init()...");
    }
}

SecondFilter.java 

public class SecondFilter implements Filter {

    @Override
    public void destroy() {
        System.out.println("2ndFilter destroy()...");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        System.out.println("before invoke 2ndFilter‘s chain.doFilter() ..");
        chain.doFilter(request, response);
        System.out.println("after invoke 2ndFilter‘s chain.doFilter() ..");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("2ndFilter init()...");
    }
}

MyServlet.java 

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("servlet doGet be invoked...");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        this.doGet(req, resp);
    }
}

web.xml  

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>

    <filter>
        <filter-name>firstFilter</filter-name>
        <filter-class>com.winner.FirstFilter</filter-class>
    </filter>
    <filter>
        <filter-name>secondFilter</filter-name>
        <filter-class>com.winner.SecondFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>secondFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>firstFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.winner.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/MyServlet</url-pattern>
    </servlet-mapping>
</web-app>

然后发布,发现打印的日志如下:

1stFilter init()...
2ndFilter init()...

这里过滤器初始化好了。

当我们访问我们的 应用:http://localhost:8080/MyServlet

before invoke 2ndFilter‘s chain.doFilter() ..
before invoke 1stFilter‘s chain.doFilter() ..
servlet doGet be invoked...
after invoke 1stFilter‘s chain.doFilter() ..
after invoke 2ndFilter‘s chain.doFilter() ..

当我们将web.xml中filter的位置进行调整后(注意filter-mapping的顺序):

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>

    <filter>
        <filter-name>firstFilter</filter-name>
        <filter-class>com.winner.FirstFilter</filter-class>
    </filter>
    <filter>
        <filter-name>secondFilter</filter-name>
        <filter-class>com.winner.SecondFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>firstFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>secondFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.winner.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/MyServlet</url-pattern>
    </servlet-mapping>
</web-app>

当我们访问我们的 应用:http://localhost:8080/MyServlet

before invoke 1stFilter‘s chain.doFilter() ..
before invoke 2ndFilter‘s chain.doFilter() ..
servlet doGet be invoked...
after invoke 2ndFilter‘s chain.doFilter() ..
after invoke 1stFilter‘s chain.doFilter() ..

技术分享图片

以上是关于Filter的执行顺序与实例的主要内容,如果未能解决你的问题,请参考以下文章

Spring filter和拦截器的区别和执行顺序

Spring filter和拦截器的区别和执行顺序

java 过滤器Filter中chain.doFilter()之前和之后代码的执行顺序

拦截器(Interceptor)和过滤器(Filter)的区别和执行顺序)

JavaWeb--Filter(过滤器)学习(附加)

Filter介绍,运行顺序,实例