• Filter过滤器(1)


       Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

      其顺序图如下(Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。)

    过滤器,设计执行流程:

    1. 用户访问服务器
    2. 过滤器: 对Servlet请求进行拦截
    3. 先进入过滤器, 过滤器处理
    4. 过滤器处理完后, 在放行, 此时,请求到达Servlet/JSP
    5. Servlet处理
    6. Servlet处理完后,再回到过滤器, 最后在由tomcat服务器相应用户;

    Filter的生命周期

    (1)、init(FilterConfig filterConfig)throws ServletException:

      与servlet一样(Filter其实也是一个servlet),Filter的创建和销毁是由web服务器负责的。web服务器一启动,就会调用init()方法,完成对象的初始化功能

      (注:filter对象只会创建一次,init方法也只会执行一次。)

    (2)、destroy():

      在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。

    (3)、doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

       The doFilter method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain.(大概的意思是在每次请求/响应时由容器创建)过滤器业务拦截的业务处理方法


    程序示例

    首先写一个要被访问的servlet,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    package com.gqx.filter;
    import java.io.IOException;
    import java.io.PrintWriter;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    public class IndexServlet extends HttpServlet {
        /**
         * 处理用户http request
         */
        private static final long serialVersionUID = 1L;
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            System.out.println("4、处理用户请求开始!");
        }
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            this.doGet(request, response);
        }
    }

    然后就是去访问之前需要对请求或响应内容做处理的过滤器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    package com.gqx.filter;
    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    /**
     * 测试的过滤器
     * @author Administrator
     *
     */
    public class HelloFilter implements Filter {
        //创建实例
        public HelloFilter() {
        // TODO Auto-generated constructor stub
            System.out.println("1、过滤器用例开始创建了。");
        }
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // TODO Auto-generated method stub
            System.out.println("2、执行过滤器初始化方法!");
        }
        //过滤器业务处理方法,在请求到达servlet之前进入此方法处理公用的业务逻辑操作
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            // TODO Auto-generated method stub
            System.out.println("3、执行过滤器的业务处理方法!");
            //放行(去到Servlet)
            chain.doFilter(request, response);
         
            System.out.println("5、Servlet处理完成,又回到Filter了!");
        }
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
            System.out.println("6、同时过滤器被销毁了!");
        }
    }

    最后就是要去web.xml中去配置好先关的过滤器设置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        <!-- 过滤器的配置 -->
    <filter>
        <!-- filter内部名称 -->
        <filter-name>HelloFilter</filter-name>
        <!-- 过滤器类的全名 -->
        <filter-class>com.gqx.filter.HelloFilter</filter-class>
    </filter>
    <filter-mapping>
        <!-- filter内部名称 -->
        <filter-name>HelloFilter</filter-name>
        <!-- 拦截所有的资源 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    一切都ok了现在我在各个打印语句之前都设置了断点,可以观察到如下图所示的变化


    当有多个过滤器的时候,如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <!-- 过滤器的配置 -->
        <filter>
            <!-- filter内部名称 -->
            <filter-name>HelloFilter</filter-name>
            <!-- 过滤器类的全名 -->
            <filter-class>com.gqx.filter.HelloFilter</filter-class>
        </filter>
        <filter-mapping>
            <!-- filter内部名称 -->
            <filter-name>HelloFilter</filter-name>
            <!-- 拦截所有的资源 -->
            <url-pattern>/*</url-pattern>
        </filter-mapping>
         
        <!-- 配置第二个过滤器 -->
        <filter>
            <filter-name>HelloFiler2</filter-name>
            <filter-class>com.gqx.filter.HelloFilter2</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>HelloFiler2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

      

    同理在第一个HelloFilter的doFilter()的方法中写入

    1
    2
    3
    4
    5
      System.out.println("3、第一个过滤器:执行过滤器的业务处理方法!");
    //放行(去到Servlet)
    chain.doFilter(request, response);
    System.out.println("5、第一个过滤器:Servlet处理完成,又回到Filter了!");

    在HelloFiler2的doFilter()的方法中写入

    1
    2
    3
    System.out.println("第二个过滤器!");
            chain.doFilter(request, response);
            System.out.println("第二个过滤器结束了!");

     同样在这些语句中设置断点会发现如下结果

    这个时候就可以知道服务器启动后,用户去访问,根据xml中的过滤器的先后顺序来执行对应的过滤器,执行其对应的doFilter的方法放行request/response,被放行后他们就进入了第二个过滤器HelloFiler2,被第二个过滤器放行后才会回到对应的servlet,servlet运行完之后,回到第二个过滤器,再回到第一个过滤器。(如下图)

     


    过滤器相关Api

    (1)、|-- interface  Filter                            过滤器核心接口

             Void  init(filterConfig);    初始化方法,在服务器启动时候执行

       Void  doFilter(request,response,filterChain);   过滤器拦截的业务处理方法

       Void destroy();                         销毁过滤器实例时候调用

    (2)|-- interface  FilterConfig   获取初始化参数信息(方法类似于servletConfig)

      String getInitParameter(java.lang.String name)

      Enumeration getInitParameterNames() 


    与servlet同样,在web.xml中配置先关信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
        <filter>
        <!-- 配置初始化参数 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>path</param-name>
            <param-value>c:/...</param-value>
        </init-param>
        <filter-name>FilterApi</filter-name>
        <filter-class>com.gqx.filter.FilterApi</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterApi</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>   

    (注意:有时候会出现错误 cvc-complex-type.2.4.a: Invalid content was found starting with element 这个时候可以将“http://www.springmodules.org/schema/cache/springmodules-cache.xsd http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd”这段话加入到xml文件的"xmlns:xsi="的标签中)

    如下:

    1 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance http://www.springmodules.org/schema/cache/springmodules-cache.xsd http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">

    然后就是他的过滤器先关的内容了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class FilterApi implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // TODO Auto-generated method stub
            System.out.println("获取过滤器在web.xml中配置的初始化参数!");
            String encoding=filterConfig.getInitParameter("encoding");
            System.out.println(encoding);
            //filterConfig.getFilterName() 获取单个
            Enumeration<String> enums=filterConfig.getInitParameterNames();
            while (enums.hasMoreElements()) {
                //获取对应的参数名称
                String name = (String) enums.nextElement();
                //获取对应名称的值
                String value=filterConfig.getInitParameter(name);
                System.out.println(name+" "+value);
            }
        }
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
        }
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            // TODO Auto-generated method stub 
        }
    }

    启动服务器就会看到控制台打印的先关数据

    (3)、|-- interface  FilterChain     过滤器链参数;一个个过滤器形成一个执行链;

             void doFilter(ServletRequest request, ServletResponse response)  ;  执行下一个过滤器或放行


    对指定的请求拦截

    刚才看到的是对所有的请求进行拦截

    1
    2
    3
    4
      <filter-mapping>
        <filter-name>FilterApi</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    1
    2
    3
    4
    5
    6
    7
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        System.out.println("指定过滤器的拦截。。。。。");
        chain.doFilter(request, response);
    }

      

    当访问index.jsp的时候,就会出现

    当要对多个指定的请求进行拦截时,可以这样写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        <filter>
        <filter-name>PontedFilter</filter-name>
        <url-pattern>/index.jsp</url-pattern>
        <url-pattern>/list.jsp</url-pattern>
        <!-- 根据servlet的内部名称拦截
        <servlet-name>IndexServlet</servlet-name> -->
        <!-- 拦截指定的servlet -->
        <url-pattern>/IndexServlet</url-pattern>
    </filter-mapping>     

    规则有点像servlet的配置

    对类型的拦截

    1
    2
    3
    4
    5
     <!-- 指定的拦截类型 -->
    <dispatcher>REQUEST</dispatcher>  <!-- 默认的拦截方式 -->
    <dispatcher>FORWARD</dispatcher>  <!-- 拦截转发 -->
    <dispatcher>INCLUDE</dispatcher>  <!-- 拦截包含的页面(RequestDispatcher.include(/page.jsp);    对page.jsp也执行拦截) -->
    <dispatcher>ERROR</dispatcher>

      

    默认拦截的类型:(直接访问或者重定向)

    <dispatcher>REQUEST</dispatcher>

    拦截转发:

                         <dispatcher>FORWARD</dispatcher>

    拦截包含的页面(RequestDispatcher.include(/page.jsp);    对page.jsp也执行拦截)

                         <dispatcher>INCLUDE</dispatcher>

    拦截声明式异常信息:

                         <dispatcher>ERROR</dispatcher>

          类似于如下代码

    1
    2
    3
    4
    5
       <error-page>
        <error-code>404</error-code>
        <exception-type></exception-type>
        <location></location>
    </error-page>

     如下代码示例

    1
    2
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>  <!-- 拦截转发 -->

     在ServletTets中写下

    1 request.getRequestDispatcher("IndexServlet").forward(request, response);

    请求的转发就会被拦截住。

  • 相关阅读:
    更精确地计量程序执行时间(转)
    C++中计算代码的执行时间
    VC实现文件拖拽
    统计程序运行时间的C++源代码
    C++开源库详细介绍
    C++高精度实现计算程序运行时间
    c++计算代码执行时间的方法,毫秒级
    【转】mysql 分析查找执行效率慢的SQL语句
    Chapter 10: Proxy Routing
    Enable remote access to MySQL database server
  • 原文地址:https://www.cnblogs.com/zhangyubao/p/6973794.html
Copyright © 2020-2023  润新知