up:: 过滤器urlpattern设置过滤范围


一:过滤链简介

如下图,过滤器1,过滤器2,Servlet这三者组成了一个完整的过滤链。

注意事项:即chain.doFilter()向后传递的时候是根据web.xml中<filter-mapping>的书写顺序为依据的;


二:过滤链案例

案例:包括,FilterA,FilterB,FilterC三个过滤器,web.xml配置文件,HelloServlet这个Servlet:

web.xml:循规蹈矩的配置:

 
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
      <display-name>filter-chain</display-name>
      <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
      </welcome-file-list>
 
      <filter>
      	<filter-name>filterAA</filter-name>
      	<filter-class>com.imooc.filter.FilterA</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>filterAA</filter-name>
      	<url-pattern>/*</url-pattern>
      </filter-mapping>
 
      <filter>
      	<filter-name>filterBB</filter-name>
      	<filter-class>com.imooc.filter.FilterB</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>filterBB</filter-name>
      	<url-pattern>/*</url-pattern>
      </filter-mapping>
 
      <filter>
      	<filter-name>filterCC</filter-name>
      	<filter-class>com.imooc.filter.FilterC</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>filterCC</filter-name>
      	<url-pattern>/*</url-pattern>
      </filter-mapping>
    </web-app>

HelloServlet.java:这个Servlet不是本篇博客的重点啦

 
    package com.imooc.filter;
 
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
 
    /**
     * Servlet implementation class HelloServlet
     */
    @WebServlet("/hello")
    public class HelloServlet extends HttpServlet {
    	private static final long serialVersionUID = 1L;
 
        /**
         * @see HttpServlet#HttpServlet()
         */
        public HelloServlet() {
            super();
            // TODO Auto-generated constructor stub
        }
 
    	/**
    	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
    	 */
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.getWriter().println("hello world!");
    		System.out.println("hello nihao!!!");
    	}
 
    	/**
    	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
    	 */
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		doGet(request, response);
    	}
 
    }
 

启动应用后,访问localhost:8080/filter-chain/hello:浏览器页面可以显示HelloServlet返回的内容,这个很简单;

同时,在控制台:按照在web.xml中<filter-mapping>的书写顺序,依次执行三个过滤器;当执行到过滤器C的时候,接下来没有过滤器了,就将请求传递到HelloServlet;


三:第一个需要注意的问题:chain.dofilter()书写位置 与 请求和响应过程中执行的关系

但是如果把FilterA,FilterB,FilterC三个过滤器的chain.doFilter()都写在前面:

此时启动应用,访问localhost:8080/filter-chain/hello时候:

原因解释:FilterA,FilterB,FilterC这三个过滤器的doFilter()方法中,chain.doFilter()都放在了前面,这意思就是,当请求过来的时候,这个过滤器会执行chain.doFilter()方法,当执行到chain.doFilter()这条语句的时候,就会把请求传递给下一个过滤器了,这样从FilterA传到FilterB,从FilterB传到FilterC,控制台就依次打印了A!,B!和C!;一直传给了HelloServlet,输出“hello nihao!!!”;

然后,当 响应的时候,按照反方向,依次执行FilterC中的doFilter()方法中的chain.doFilter()语句后面的内容 ,然后是FilterB,然后是FilterA;这样,控制塔就依次打印出了This is Filter C! ;This is Filter B! 和 This is Filter A!;( _ _ 注解,这个仅仅在这儿ok,并没有经过多次验证哎,但大概率应该是没问题的~~~__ )


补:控制过滤链中断:阻挡请求(一种简单的防火墙)

启动应用:

这种在程序中刻意控制chain.doFilter()方法调用的场景是比较常见的;比如:互联网安全是非常重要的,比如,开发的网站只对中国的IP开发,外国的IP不能访问,怎么做呐?

可以获取请求的IP,如果IP是中国的,就去调用chain.doFilter()方法,将请求放行;如果IP是外国的,就 通过if else判断,不去执行chain.doFilter()这句话,中断请求 ,从而这个IP为外国的请求就被过滤器挡在了外面;(这也是简单的一种防火墙)


四:第二个需要注意的问题:注解形式时,过滤器执行的顺序(仅供了解,因为在实际工作中基本不会采用这种策略)

关于过滤器的执行顺序:(1)当过滤器采用web.xml配置的方式的时候,按照在web.xml中<filter-mapping>的书写顺序,来依次执行;(2) 过滤器采用注解的时候,过滤器的执行顺序怎么确定呐???

如下:

启动应用,访问localhost:8080/filter-chain/hello:

其实当过滤器采用注解的形式的时候:其按照类名来决定前后顺序的,按照字母升序,从小到大,且字母不区分大小写;所以先执行FilterA,然后执行FilterB,最后执行FilterC;

如,把FilterA过滤器类的类名改成FilterZ时:再次访问的时候: