zoukankan      html  css  js  c++  java
  • [转]Servlet的学习之Filter过滤器技术

      本篇将讲诉Servlet中一项非常重要的技术,Filter过滤器技术。通过过滤器,可以对来自客户端的请求进行拦截,进行预处理或者对最终响应给客户端的数据进行处理后再输出。

      要想使用Filter过滤器,非常简单,只要实现Servlet  API中的Filter接口即可,同时在该web应用【WEB-INF】目录下的web.xml文件中配置<filter>和<filter-mapping>两个标签。其中可以根据配置指定过滤的页面或者Servlet。

      也就是说我们在web工程中光光写Filter过滤器的Java代码是不会起作用的,要在web.xml文件中对过滤器进行注册和映射,在学习Filter之前我们先来学习如何注册和映射

    关于注册:

      需要在web.xml文件中配置<filter>标签,这还不够,<filter>标签下的<filter-name>与<filter-class>是必须要填的内容。

      <filter>标签中有如下子元素:

      <description>用于描述该标签,非必须;

      <filter-name>为过滤器指定一个名称,必须的

      <filter-class>指定该过滤器使用的web工程中的哪一个filter类,包含包名与类名,必须的;

      <init-param>为过滤器的初始化提供参数,非必须,后面有例子。

    关于映射:

      需要在web.xml文件中配置<filter-mapping>标签,这还不够,<filter-mapping>标签下的<filter-name>以及<url-pattern>或<servlet-name>之一是必须的。

      <filter-mapping>标签中有如下子元素:

      <filter-name>设置要映射过滤器的名称,该名称必须同<filter>标签下的<filter-name>的值一致。

      <url-pattern>设置过滤器要拦截过滤的请求路径,例如“/*”则表示对该web应用下所有的请求都进行拦截过滤,这个值的书写与《Servlet的学习(四)》 中关于<servlet-mapping>下的<url-mapping>是一致的写法。

      <servlet-name>如果只要拦截过滤访问某个Servlet,就可以使用该标签来替代<url-pattern>。

      <dispatcher>设置拦截过滤客户端请求的方式,有REQUEST,INCLUDE,FORWARD,ERROR四种(请注意均为大写)。非必须则默认为REQUEST,使用多个<dispatcher>标签来设置多种请求方式。

      关于<dispathcer>的四种方式,这里再简单的介绍一下:

      REQUEST:当用户直接访问我们的资源时,这时我们设置的过滤器就会进行拦截。但如果以转发和包含方式访问资源,那么该过滤器则不会被调用。

      INCLUDE:当使用RequestDispatch的include方法请求时,该过滤器会被调用。

      FORWARD:当使用RequestDispatch的forward方法时请求资源时,该过滤器会被调用,尤其是在MVC设计模式下,JSP都被保护起来,必须要通过Servlet进行转发才能访问JSP,那么该过滤器就是在Servlet转发到JSP这个过程中被执行。

      ERROR:当请求是通过错误异常进行跳转时就会调用该过滤器。

      一个简单的对过滤器的注册和映射的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <filter>
        <filter-name>FilterDemo1</filter-name>
        <filter-class>com.fjdingsd.web.filter.FilterDemo1</filter-class>
      </filter>
       
      <filter-mapping>
        <filter-name>FilterDemo1</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

      在Servlet API 中关于Filter举例了使用过滤器能用来做些什么:

      

      这里我也说明下平时Filter能在哪些方面会被经常用到:

      ① Filter可以作用在请求资源执行之前,进行权限检查,检查用户是否有权限,如有权限则放行请求;如果没有,则拒绝访问。

      ② Filter可以作用在请求资源执行之前,对Request和Response对象进行预处理操作,从而实现一些web应用的全局性设置,比如解决中文乱码问题。

      ③ Filter可以作用在最终响应输出之前,对输出Response对象中的数据进行处理,例如将输出的数据进行压缩。

       Filter只有3个方法:

      

      其中destroy()方法和init(…)方法是生命周期方法,因为过滤器无论如何都要在请求任何资源之前进行,所以任何Web应用在部署的时候,服务器就会调用Filter过滤器的init方法进行初始化,而关于过滤器的销毁,则是将该过滤器移除或者服务器关闭就会执行destory方法。

      而我们通常要使用过滤器处理请求,则重点在于doFilter(…)方法。当请求要经过一个过滤器的时候,就会由服务器调用doFilter方法。

      我们先来看看一个带有过滤器Filter的web应用的请求和响应流程:

      

      记住:从请求到响应这个流程会经过Filter对象两次!

      在doFilter这一个方法中就可以对着两次经过的过程进行处理,那么这里就有一个问题了,如果能通过过滤器,那么就到过滤器后面了,貌似应该是执行完doFilter方法了,而服务器的响应又经过过滤器,难道又要执行doFilter方法一次?但是这个方法里面的代码不是也有处理最开始请求的吗?

      这就跟doFilter方法中的第三个参数FilterChain有关了,FilterChain对象是过滤器链,这个我们稍后会介绍。在FilterChain对象中只有一个方法:

      

      也是叫doFilter方法(千万别和Filter接口的doFilter方法弄混了)。简单的说下这个方法,只要调用了这个方法,就会将请求交给后面一个Filter进行过滤(一个Web应用中可以有多个Filter),如果该Filter是最后一个,那么调用该方法则将执行请求,也就是到我们的应用中获取资源。

      因此从请求到响应这个流程经过Filter的两次处理分别是在FilterChain.doFilter方法的前面和后面!如下图所示:

      

      那么下面我们就先以一个简单的例子来熟悉下Filter吧:

    例1

      创建web工程FilterLearning,创建一个FilterDemo1类,同时这个类要实现javax.servlet.Filter接口。如下代码:

    复制代码
     1 public class FilterDemo1 implements Filter {
     2 
     3     @Override
     4     public void doFilter(ServletRequest request, ServletResponse response,
     5             FilterChain chain) throws IOException, ServletException {
     6         
     7         System.out.println("hello filter");
     8     }
     9 
    10     //此处省略init方法和destory方法
    11 }
    复制代码

      写好Filter的Java代码还没完,还要在web应用下的web.xml文件中配置如下信息:

    复制代码
    1 <filter>
    2       <filter-name>FilterDemo1</filter-name>
    3       <filter-class>com.fjdingsd.web.filter.FilterDemo1</filter-class>
    4   </filter>
    5   
    6   <filter-mapping>
    7       <filter-name>FilterDemo1</filter-name>
    8       <url-pattern>/*</url-pattern>
    9 </filter-mapping>
    复制代码

      注意:因为我在<url-pattern>中配置为“/*”,则访问我wen应用中任何资源都会经过该Filter过滤器。如果只想对于index.jsp主页的请求进行过滤,可以设为<url-pattern>/index.jsp</url-pattern>。

      我们在index.jsp中简单的使用JSP脚本来演示如果有请求来就输入一段文本到控制台上:

    复制代码
     1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
     2 
     3 <!DOCTYPE HTML>
     4 <html>
     5   <head>    
     6     <title>index</title>
     7   </head>
     8   
     9   <body>
    10     <%
    11         System.out.println("Long live SD !");
    12      %>
    13   </body>
    14 </html>
    复制代码

      接下来将该web应用部署到服务器中,我们就访问index.jsp,以下是我们访问了index.jsp后控制台的情况:

      

      首先,我们可以保证在我们访问index.jsp后这个请求确实经过了Filter过滤器,但是我们的请求好像就只到过滤器而没有到我们真正需要的资源index.jsp?这是因为我们没有在Filter的doFilter方法中调用过滤器链FilterChain对象的doFilter方法,自然无法将请求继续往后面传递。我们将在例2中修改。

    例2

      我们将例1中的FilterDemo1类进行修改,使其能访问到我们所需要的资源,很简单,在doFilter的方法中添加过滤器链FilterChain对象的doFilter方法即可:

     View Code

      其他如web.xml中的配置和index.jsp中的代码保持不变,现在我们再来访问下该web应用中的index.jsp,并观察控制台:

      

      可以看到我们的请求经过过滤器,执行了过滤器的一段代码(System.out.println(“hello filter”)),然后将请求继续执行!正是因为FilterChain.doFilter方法才使我们通过过滤器继续向后寻找我们所需的资源。

      那么还记得我们之前说过的从请求到响应会经过两次过滤器吗,是的在获取了我们所需的资源后还会到过滤器一趟,而至于这时候是否将响应再做处理取决于过滤器链FilterChain.doFilter方法后面还是否有代码。我们将在例3中完整的展现从请求到响应经过过滤器两次的流程。

    例3

      我们将例2中的FilterDemo1类进行修改,只要在FilterChain.doFilter方法后面添加代码,就是第二次(即响应)经过过滤器所要执行的处理:

     View Code

      其他如web.xml中的配置和index.jsp中的代码保持不变,现在我们再来访问下该web应用中的index.jsp,并观察控制台:

      

      这个结果证明了从请求到响应确实经过过滤器两次,同时也说明了在Filter的doFilter方法中“过滤——取资源——再过滤”执行的顺序。

      现在我们再回到Filter接口的init方法,我们可以看到在这个方法内有一个参数FilterConfig,这个是由服务器传给我们的对象。如果我们在web.xml文件中配置了过滤器的初始化参数,就可以通过该FilterConfig对象来在代码中获取使用。

      这个过滤器参数的初始化配置可以在<filter>标签中配置<init-param>,并在这个<init-param>标签下再配置<param-name>和<param-value>。

      FilterConfig有如下方法:

      

      当然如果我们是要获取配置的初始化参数则只需关注getInitParameter方法或getInitParameterNames方法。

      一般来说我们可以在init方法中获取配置初始化参数并进行处理;也可以通过对象引用将FilterConfig对象在doFilter方法中处理参数,如例4所示。

    例4

      在web.xml文件中配置过滤器和初始化参数:

     View Code

      在Java中编写Filter接口的实现类FilterDemo1:

     View Code

      因为配置的原因,所以我们随便访问个资源都可以经过该过滤器,那么就访问index.jsp好了,看看控制台的结果:

      

      正如我们在web.xml文件所配置的初始化参数一样。

      

      上面介绍的都是只有一个Filter过滤器的情况下,有时候我们会因为要过滤的功能不同添加多个过滤器,这就有一个顺序的问题了,尤其是从取得资源后再返回到过滤器的顺序。下面这张图就能很清晰的看到我们要注意的顺序了:

      

    例5

      来写两个Filter来说明下从请求到响应过滤器的处理顺序。

      创建一个web工程,创建一个FilterDemo1类,同时这个类要实现javax.servlet.Filter接口。如下代码:

     View Code

      创建第二个Filter接口实现类FilterDemo2,代码如下:

     View Code

      过滤器要想能被服务器调用,还必须要在该web工程下的web.xml中配置过滤器及其映射,而这个配置的顺序就是影响多个过滤器工作先后的顺序:

     View Code

      而我们要访问的资源文件就以index.jsp为例好了,那么我们用一段JSP脚本通过在控制台打印来验证过滤器工作的顺序过程:

     View Code

    现在启动服务器,部署该工程,通过访问index.jsp来看看控制台情况:

      

      以上简单的说明了关于Servlet技术中的Filter过滤器的使用方法和一些简单的说明,下一篇将介绍一些常用的Filter功能案例。


    参考文章:https://www.cnblogs.com/fjdingsd/p/5439399.html

    Java过滤器链原理解析

    参考文章:https://blog.csdn.net/wonking666/article/details/78981602

  • 相关阅读:
    Allegro PCB Design GXL (legacy) 使用slide无法将走线推挤到焊盘的原因
    OrCAD Capture CIS 16.6 导出BOM
    Altium Designer (17.0) 打印输出指定的层
    Allegro PCB Design GXL (legacy) 将指定的层导出为DXF
    Allegro PCB Design GXL (legacy) 设置十字大光标
    Allegro PCB Design GXL (legacy) 手动更改元器件引脚的网络
    magento产品导入时需要注意的事项
    magento url rewrite
    验证台湾同胞身份证信息
    IE8对css文件的限制
  • 原文地址:https://www.cnblogs.com/atai/p/10196158.html
Copyright © 2011-2022 走看看