过滤器_雷慧_新浪博客

 

过滤器的简介

Servlet实现的过滤器功能是Web中的一个小型组件,其拦截来自客户端的请求和响应信息,从而进行查看、提取或者对客户端和服务器之间交换的数据信息进行某项特定的操作。实现的过滤器通常是用来封装一些辅助性的功能方法,这些过滤器方法可能对真正意义上的客户端请求和响应处理不起决定性作用,但还是非常重要的。可以使用Servlet中的过滤器来记录有关客户端请求和响应的数据、处理数据传递过程中所存在的安全性问题以及管理会话属性等。过滤器提供了一种面向对象的模块化机制,将公共的过滤器方法封装到可插入组件中,然后再由一个配置文件来声明这些组件,并动态地进行调用和处理。

Servlet中的过滤器结合了许多元素,已经使得过滤器成为独特、强大和模块化的Web组件。从而概括起来,Servlet过滤器是:

  声明式的:编写好过滤器之后,在动态调用过滤器来处理客户端请求以及响应之前,还需要通过Web部署描述符(web.xml)来声明这个过滤器。通过部署描述符,可以允许动态地添加和删除过滤器,并不需改动任何应用程序代码或者JSP页面。

  动态的:通过部署配置文件(web.xml),过滤器在运行时,会动态地由Servlet容器调用特定的方法来拦截和处理请求和响应。

  灵活的:过滤器在Web应用处理过程中的使用还是很广泛的,其中涉及到诸如日志记录和安全检测等许多最为公共的辅助任务。过滤器的使用也是很灵活的,因为它可以用来对来自客户端的直接调用执行预处理和后期等处理,以及处理防火墙后面的Web组件间的调度请求。{zh1},还可以将多个过滤器链接起来以提供更多必需的功能。

  模块化的:通过将应用程序中的对请求和响应进行的逻辑处理封装到单个类文件(Servlet文件)中,过滤器中已经定义了可容易地从请求/响应链中添加或删除的模块化单元。

  可移植的:与Java平台中开发的其他许多类文件一样,Servlet过滤器也是跨平台、跨容器以及可移植的,从而更能支持Servler过滤器的模块化和可重用本质。

  可重用的:由于过滤器实现类的模块化设计,以及通过部署描述符web.xml进行声明的过滤器配置方式,过滤器可以容易地进行添加和删除,以及进行过滤器的可重用性。

  透明的:允许对客户端请求和响应编写特定的过滤器,这是为了补充对(而不是以任何方式替代)Servlet或JSP页面数据提供一定的额外处理。因而,可以根据需要,在部署描述符web.xml添加或删除过滤器,而不会破坏Servlet或JSP页面程序。

Servlet实现的过滤器是需要通过一个配置文件(web.xml)来灵活声明的模块化以及可重用组件。过滤器是动态地(不需要程序员编写程序进行调用)处理传入的客户端请求和传出的响应,并且也不需要修改任何应用程序代码就可以透明地通过配置文件添加或删除某个过滤器。{zh1},过滤器也具有可移植性,可以独立于任何平台或者Servlet容器,从而允许将这些过滤器容易地部署到大部分的J2EE环境中。

在接下来的小节中,将进一步考察Servlet过滤器的总体设计,以及如何实现、配置和部署过滤器所涉及的步骤。{zh1},还将继续探讨Servlet过滤器的一些实际应用,简要考察一下模型-视图-控制器(MVC)体系结构中包含的Servlet过滤器。

Servlet过滤器的体系结构

其实,过滤器就是一个Servlet,只是比较特殊而已,可以用它来对客户端请求以及发出的响应进行部分的过滤操作。

过滤器并不是真正意义上对来自客户端的请求作出最终的响应,而是进行部分的过滤工作,对请求数据进行检测或者安全性检查等工作。多个特定的过滤器可以一起组成一个过滤器链。

过滤器只有在客户端请求或者发出响应时才会自动进行调用,所有没有必要把这些过滤器字节嵌入到整个Web应用系统的框架中,而是通过配置文件来设定。

当然,大部分情况下,并不需要给Web应用程序设置过滤器,因为它不是必需的。如果需要设置过滤器,除了可以设置单个过滤器关联,还可以设置Web应用程序与一个过滤器链(多个单过滤器相串联)相关联。那么整个过滤器的工作过程是怎样的呢?下面列举出过程步骤:

(1)通过部署描述符web.xml中对过滤器的配置,特定过滤器会捕捉到客户端的请求信息。

(2)过滤器调用内置方法来检查捕获到的请求对象,根据分析结果来决定是把该请求传递给下一个过滤器(如果存在另一个过滤器的话),还是中止该请求并向客户端发出一个响应。如果不存在过滤器链,即仅为单个过滤器,则上一个过滤器直接把客户端请求转发给Web服务器作相应处理。

(3)如果Web应用程序关联了过滤器,在客户端请求设法通过各个过滤器被服务器处理时,最终的响应将以相反的顺序通过过滤器链,{zh1}发送给客户端。

过滤器的概念是从Servlet 2.3才开始引入的,一开始仅仅能够过滤Web客户端和客户首次所需访问服务器资源之间的数据信息。当{dy}个访问的资源(例如某一个JSP页面)把客户端请求再转发给另外一个服务器资源(例如另外一个JSP页面)时,这时过滤器就不起作用了。到了Servlet 2.4发布之后,这样的过滤器限制得到了修改。也就是说,现在的过滤器可以作用于J2EE环境中的任何请求过程中,可以在客户端和Servlet以及JSP之间,也可以是服务器端的Servlet与Servlet以及JSP页面之间,这大大增加了过滤器在Web应用程序中的可适用性。

实现一个Servlet过滤器

在Web应用程序中实现一个Servlet过滤器需要经历3个步骤:

(1)编写Servlet过滤器的实现类程序。

(2)需要把实现的过滤器添加到Web应用程序中,也就是说,需要在Web部署描述文件web.xml中声明该过滤器。

(3){zh1}要把相关联的过滤器与应用程序一起打包并部署。

下面将详细介绍其中的每个步骤:

1.编写过滤器的实现类程序

编写过滤器一般需要使用3个简单的接口: Filter.java、FilterChain.java和FilterConfig.java,这3个接口封装在java.servlet包中。从编程的角度来看,过滤器类必须要实现Filter 接口,然后使用这个过滤器类中的FilterChain和FilterConfig接口。该过滤器类的一个引用将传递给FilterChain对象,以允许过滤器把控制权传递给链中的下一个资源。FilterConfig对象将由容器提供给过滤器,以允许访问该过滤器的初始化数据。

与实现Servlet过滤器的3步模式保持一致,过滤器必须实现如下的3个方法,以便xx实现Filter接口:

   ● init():和普通Servlet中的init()方法一样,该方法是在Servlet容器实例化过滤器时被调用,主要设计用于使过滤器为处理做准备。该方法接受一个FilterConfig类型的对象作为输入。

   ● doFilter():与Servlet拥有一个service()方法(这个方法又调用doPost()或者doGet())来处理请求一样,过滤器拥有单个用于处理请求和响应的方法——doFilter()。这个方法接受3个输入参数:一个ServletRequest、response和一个FilterChain对象。

   ● destroy():正如您想象的那样,这个方法执行任何清理操作,这些操作可能需要在自动垃圾收集之前进行。

下面创建的TimeTrackFilter.java类展示了一个非常简单的过滤器,它跟踪满足一个客户机的Web请求所花的大致时间

import javax.servlet.*;

import java.util.*;

import java.io.*;

public class TimeTrackFilter implements Filter {

private FilterConfig filterConfig = null;

                                                                                    //初始化过滤器

public void init(FilterConfig filterConfig)throws ServletException {

    this.filterConfig = filterConfig;

}

                                                                                      //执行过滤器功能

         public void doFilter( ServletRequest request,ServletResponse response, FilterChain chain )

                                               throws IOException, ServletException {

                   Date startTime, endTime;

                   double totalTime;

                   startTime = new Date();

                   chain.doFilter(request, response);       //把处理发送到下一个过滤器

                                                                                       //接下来的语句就是处理请求的过程:计算开始到结束的时间

                   endTime = new Date();

                   totalTime = endTime.getTime() - startTime.getTime();

                   totalTime = totalTime / 1000; //Convert from milliseconds to seconds

                   StringWriter sw = new StringWriter();

                   PrintWriter writer = new PrintWriter(sw);

                   writer.println();

                   writer.println("===============");

                   writer.println("Total elapsed time is: " + totalTime + " seconds." );

                   writer.println("===============");

                                                                                             //把结果写到日志当中

                   writer.flush();

                   filterConfig.getServletContext().

                   log(sw.getBuffer().toString());

}

                                                                                         //销毁过滤器

         public void destroy() {

                   this.filterConfig = null;

         }

}

程序说明:

   ● 初始化:当容器{dy}次加载该过滤器时,init()方法将被调用。该类在这个方法中包含了一个指向FilterConfig对象的引用。我们的过滤器实际上并不需要这样做,因为其中没有使用初始化信息,这里只是出于演示的目的。

   ● 过滤:过滤器的大多数时间都消耗在这里。doFilter()方法被容器调用,同时传入分别指向这个请求/响应链中的ServletRequest、ServletResponse和FilterChain对象的引用。然后过滤器就有机会处理请求,将处理任务传递给链中的下一个资源(通过调用FilterChain对象引用上的doFilter()方法),之后在处理控制权返回该过滤器时处理响应。

   ● 析构:容器紧跟在垃圾收集之前调用destroy()方法,以便能够执行任何必需的清理代码。

2.在web.xml文件中配置Servlet过滤器

实现了Servlet过滤器之后,还需要通过web.xml文件中的两个XML元素来声明该过滤器。<filter>元素定义过滤器的名称,并且声明实现类和init()参数。<filter-mapping>元素将过滤器与Servlet或URL模式相关联。

下面展示在web.xml配置文件中声明一个过滤器的方法,把下面这段配置代码插入到web.xml文件中的</web-app>标记前面:

<filter>

<filter-name>Page Request Timer</filter-name>

<filter-class>TimeTrackFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>Page Request Timer</filter-name>

<servlet-name>Main Servlet</servlet-name>

</filter-mapping>

<servlet>

<servlet-name>Main Servlet</servlet-name>

<servlet-class>MainServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>Main Servlet</servlet-name>

<url-pattern>/*</url-pattern>

</servlet-mapping>

上面的代码示例声明了一个过滤器("Page Request Timer"),并把它映射到一个servlet("Main Servlet")。然后为该servlet定义了一个映射,以便把每个请求(由通配符指定)都发送到该servlet。这是控制器组件的典型映射声明。应该注意这些声明的顺序,千万不能背离这些元素的顺序。

3.部署Servlet过滤器

Servlet过滤器的部署非常简单,只需把过滤器的实现类和其他Web组件类放置在一起。重点是部署描述符web.xml对各类过滤器的配置要正确,然后把配置文件web.xml文件(连同过滤器定义和过滤器映射声明)放进Web应用程序结构中,servlet容器将处理之后的其他所有事情。

过滤器的应用

过滤器不是真正用来完成客户端请求的,客户端请求操作最终还是要交付给服务器进行相应处理,过滤器只是做一些辅助性的工作。但是在某些情况下,过滤器是非常有用的,例如安全性检查等。在适合可以使用装饰过滤器模式或者拦截模式的地方都可以使用过滤器。总结起来,过滤器可以使用在如下方面:

  加载:对所有到达系统的客户端请求,可以使用过滤器来收集诸如浏览器类型、{yt}中的时间、转发URL等相关信息,并把这些信息记录到日志中。

  性能:通过使用过滤器可以提供处理性能。例如,当客户端数据通过协议传送并在到达Servlet和JSP页面之前,可以使用过滤器将请求数据打包压缩,然后再取得响应内容。同样地,在将响应内容发送到客户端机器之前,过滤器再将它转换为压缩格式在网络上传输。

  安全:有时在安全性要求特别高的Web应用系统中,过滤器的作用可以得到很好发挥。过滤器可用来对发出请求的客户身份进行验证,以防止非法用户访问特定资源,从而限制某些资源的访问。过滤器除了可以进行客户身份验证之外,还可以管理客户访问列表(Access Control List,ACL),从而可以对客户进行授权管理。使用过滤器来进行安全性管理,而不是让Servlet或者JSP程序来执行,这是为了提供更高的灵活性,因为过滤器可以随时通过web.xml配置文件进行添加和关闭。所以一般情况下,这些辅助的工作都可以放置在过滤器中完成。

  会话处理:将Servlet和JSP页面与会话处理代码混杂在一起可能会带来相当xxx烦。使用过滤器来管理会话可以让Web页面集中精力考虑内容显示和委托处理,而不必担心会话管理的细节。

  XSLT转换:在Web应用程序中如果用到XML,经常会涉及到XSLT转换的问题,这时就可以把转换工作写入到过滤器中,而让服务器端的Servlet或者JSP真正去处理数据和逻辑。

   使过滤器适应MVC体系结构

在第13章中将会向读者重点介绍模型-视图-控制器(Model-View-Controller,MVC)体系结构,和Model1模式相比,MVC模式的优势非常明显,而且MVC现在已经成为一个非常重要和流行的框架设计方法。第13章介绍的Struts技术就是使用的MVC框架结构,而且使用Servlet过滤器技术来管理客户端请求和服务器端响应之间的处理流,例如页面的定向。

过滤器可以在MVC框架中作为一个调度器组件,根据xml配置文件可以将客户端请求转发给相应的应用程序组件进行逻辑处理。过滤器也是成为MVC框架中的控制层的{zj0}选择。

通过使用过滤器作为MVC框架中的控制层,负责页面的转发以及安全检测等工作,这样仅仅需要通过xml配置文件就可以统一对页面转换进行管理。使得应用程序的结构清晰,易于后期程序的维护和管理。

郑重声明:资讯 【过滤器_雷慧_新浪博客】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——