Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2554400
  • 博文数量: 709
  • 博客积分: 12251
  • 博客等级: 上将
  • 技术积分: 7905
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-17 00:00
个人简介

实现有价值的IT服务

文章存档

2012年(7)

2011年(147)

2009年(3)

2008年(5)

2007年(74)

2006年(431)

2005年(42)

分类: Java

2006-08-21 14:45:59

什麼是Servlet過濾器(filter)?

  Servlet 過濾器是小型的 Web 組件,可以鏈在Servlet容器的處理過程中,攔截請求和響應,檢查和修在客戶機和Web應用程序之間交換的數據。這意味著過濾器會在Servlet處理之前訪問一個進入的請求,並在外發的響應回到客戶前訪問這些信息。

  過濾器可以被添加到請求/響應鏈中,或者在無需影響應用程序中其他 Web 組件的情況下刪除它們。過濾器僅只是改動請求和響應的運行時處理,因而不應該將它們直接嵌入 Web 應用程序框架。

  Servlet可以與一個或者多個過濾器相關聯,後者將形成一個過濾器鏈。

編寫一個 Servlet 過濾器

  實現一個 Servlet 過濾器需要三個步驟:首先要編寫過濾器實現類的程序,然後要把該過濾器添加到 Web 應用程序中(通過在 Web 部署描述符 web.xml 中聲明它),最後要把過濾器與應用程序一起打包部署。

 1. 編寫實現類的程序

  過濾器 API 一共包含 3 個簡單的接口:Filter、FilterChain 和 FilterConfig。過濾器類必須需要實現 Filter 接口:

  init():這個方法在容器實例化過濾器時被調用,它主要設計用于使過濾器為處理做准備。容器為這個方法傳遞一個FilterConfig對象,其中包含著配置信息。

  doFilter ():過濾器擁有單個用于處理請求和響應的方法——doFilter()。這個方法接受三個輸入參數:一個 ServletRequest、response 和一個 FilterChain 對象。FilterChain對于正確的過濾操作至關重要。doFilter()方法必須調用FilterChain的doFilter()方法,除非該 方法用來攔截以後的下游處理。注意:過濾器的一個實例可以同時服務于多個請求,意味著任何共享的變量都必須通過同步塊(synchronized block)來訪問。

  destroy():該方法由容器在銷毀過濾器實例之前調用。
 例1 演示了一個簡單的過濾器,用來計算一個客戶機的 Web 請求所花的大致時間。

PageTimerFilter.java
package cc.ejb.examples;
import java.io.IOException;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class PageTimerFilter implements Filter 
{
 private FilterConfig config = null;
 public void init(FilterConfig config) throws ServletException 
 {  
  this.config = config;
 }
 public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException
 {
  Date startTime, endTime;
  double duration;
  startTime = new Date();
  // Forward the request to the next resource in the chain
  chain.doFilter(request, response);
  // Calculate the duration between the start time and end time
  endTime = new Date();
  duration = (endTime.getTime() - startTime.getTime())/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: " + duration + " seconds.");
  writer.println("===============");
  // Log the resulting string
  writer.flush();
  config.getServletContext().log(sw.getBuffer().toString());
 }
 public void destroy() {
  this.config=null;
 }
}

  在doFilter ()方法實現中,出現在FilterChain的doFilter()方法調用之前的代碼都被看成是預處理,Web資源(包括其他過濾器、Servlet 等等)所做的處理還沒有發生。而在該方法之後的代碼則是後期處理,這時外發的響應信息已經包含了Web資源的完整響應。也就是說,FilterChain的doFilter()將調用接下來的過濾器(在有鏈式關系的時候)或者其他Web資源。


 2. 配置 Servlet 過濾器和 配置Servlet類似,過濾器通過 web.xml 文件中的兩個 XML 標簽來聲明。標簽負責把一個過濾器名和一個特定的類 關聯起來,這種關聯是通過元素指定。其 DTD定義如下:

(((description*,display-name*,icon*)),filter-name,filter-class,init-param*)

  可以為過濾器指定初始化參數,和Servlet類似,參數是使用和成對的來指定的,如下所示:


    counter
       100

 例 2 顯示了 web.xml 文件,它展示了如何聲明過濾器的包含關系:

web.xml

  Page Timers
  cc.ejb.examples.PageTimerFilter
 
 
  Page Timers
  /*
 

  必須有一個或者元素。我們可以通過來指定通配符,將過濾器應用到Web資源范圍,在上面的例子中,Page Timer過濾器被應用到每個Web資源。也可以通過將過濾器指定到某一個特定的Servlet上。應該注意這 些聲明的順序,所引用的過濾器名必須在前面的過濾器定義給出。


 3. 部署 Servlet 過濾器 事實上, 部署過濾器是非常簡單的事情。只需把過濾器類和其他 Web 組件類包括在一起,並像通常所做的那樣把 web.xml 文件(連同過濾器定義和過濾器映射聲明)放進 Web 應用程序結構中,servlet 容器將處理之後的其他所有事情。

 Servlet 2.4中的新特性

  我們通過下面的例子來研究Servlet 2.4的新特性。例3和例4是兩個很簡單的程序片斷,JSP程序將來自客戶的請求forward到Thank.html。

<%@ page language="java" %>
  

"/Thank.html"/>


Thank.html

  
    Thank you for coming Filter worlds

  將這兩個程序和上面的過濾器一起打包部署並運行Test.jsp,我們發現控制台只有一行而不是兩行輸出:

11:06:57,045 INFO  [Engine] StandardContext[/Test]
===============
Total elapsed time is: 0.0 seconds.
===============

  因為,在Servlet 2.3 規范中的過濾器只能過濾 Web 客戶機和其所訪問的指定 Web 資源之間的內容。如果該資源然將請求調度給其他 Web 資源(這里是Thank.html),就不能向幕後委托的任何請求應用過濾器。

  2.4 規范消除了這個限制,通過增強filter和request dispatcher的配合,過濾器可以根據請求分發器(request dispatcher)所使用的方法有條件地對Web請求進行過濾。該功能是通過中的元素來實現的:

  只有當request直接來自客戶,過濾器才生效,對應為REQUEST條件。

  只有當request被一個請求分發器使用forward()方法轉到一個Web構件時(采用或定義),對應稱為FORWARD條件。

  類似地,只有當request被一個請求分發器使用include()方法轉到一個Web構件時(采用或定義),對應稱為INCLUDE條件。

  只有當request被一個請求分發器使用“錯誤信息頁”機制方法轉到一個Web構件時,對應稱為ERROR條件。

  以上四種條件的組合使用。

  修改之後web.xml的如下所示:

web.xml

  Page Timers
  cc.ejb.examples.PageTimerFilter
 
 
  Page Timers
  /*
  REQUEST
  FORWARD
 

  再次部署運行這個Web應用,結果如下:

11:17:51,165 INFO  [Engine] StandardContext[/Test]
===============
Total elapsed time is: 0.0 seconds.
===============
11:17:51,165 INFO  [Engine] StandardContext[/Test]
===============
Total elapsed time is: 10.0 seconds.
===============

過濾器的運用

  在適合使用裝飾過濾器模式或者攔截器模式的任何地方,您都可以使用過濾器。過濾器的一些最普遍的應用如下:

 加載: 對于到達系統的所有請求,過濾器收集諸如瀏覽器類型、一天中的時間、轉發 URL 等相關信息,並對它們進行日志記錄。

 性能: 過濾器在內容通過線路傳來並在到達 servlet 和 JSP 頁面之前解壓縮該內容,然後再取得響應內容,並在將響應內容發送到客戶機機器之前將它轉換為壓縮格式。

 安全: 過濾器處理身份驗證令牌的管理,並適當地限制安全資源的訪問,提示用戶進行身份驗證和/或將他們指引到第三方進行身份驗證。過濾器甚至能夠管理訪問控制列 表(Access Control List,ACL),以便除了身份驗證之外還提供授權機制。將安全邏輯放在過濾器中,而不是放在 servlet 或者 JSP 頁面中,這樣提供了巨大的靈活性。在開發期間,過濾器可以關閉(在 web.xml 文件中注釋掉)。在生產應用中,過濾器又可以再次啟用。此外還可以添加多個過濾器,以便根據需要提高安全、加密和不可拒絕的服務的等級。

 會話處理: 將 servlet 和 JSP 頁面與會話處理代碼混雜在一起可能會帶來相當大的麻煩。使用過濾器來管理會話可以讓 Web 頁面集中精力考慮內容顯示和委托處理,而不必擔心會話管理的細節。

 XSLT 轉換: 不管是使用移動客戶端還是使用基于 XML 的 Web 服務,無需把邏輯嵌入應用程序就在 XML 語法之間執行轉換的能力都絕對是無價的。

===========================

Servlets 2.4的过滤器

Posted on 2005年2月16日 13:48

什么是Servlet过滤器(filter)?
Servlet 过滤器是小型的 Web 组件,可以链在Servlet容器的处理过程中,拦截请求和响应,检查和修在客户机和Web应用程序之间交换的数据。这意味着过滤器会在Servlet处理之前访问一个进入的请求,并在外发的响应回到客户前访问这些信息。

过滤器可以被添加到请求/响应链中,或者在无需影响应用程序中其他 Web 组件的情况下删除它们。过滤器仅只是改动请求和响应的运行时处理,因而不应该将它们直接嵌入 Web 应用程序框架。

Servlet可以与一个或者多个过滤器相关联,后者将形成一个过滤器链。

编写一个 Servlet 过滤器
实现一个 Servlet 过滤器需要三个步骤:首先要编写过滤器实现类的程序,然后要把该过滤器添加到 Web 应用程序中(通过在 Web 部署描述符 web.xml 中声明它),最后要把过滤器与应用程序一起打包部署。

1. 编写实现类的程序
过滤器 API 一共包含 3 个简单的接口:Filter、FilterChain 和 FilterConfig。
过滤器类必须需要实现 Filter 接口:

  • init():这个方法在容器实例化过滤器时被调用,它主要设计用于使过滤器为处理做准备。容器为这个方法传递一个FilterConfig对象,其中包含着配置信息。
  • doFilter():过滤器拥有单个用于处理请求和响应的方法——doFilter()。这个方法接受三个输入参数:一个 ServletRequest、response 和一个 FilterChain 对象。FilterChain对于正确的过滤操作至关重要。doFilter()方法必须调用FilterChain的doFilter()方法,除非该方法用来拦截以后的下游处理。注意:过滤器的一个实例可以同时服务于多个请求,意味着任何共享的变量都必须通过同步块(synchronized block)来访问。 
  • destroy():该方法由容器在销毁过滤器实例之前调用。

例1 演示了一个简单的过滤器,用来计算一个客户机的 Web 请求所花的大致时间。

package cc.ejb.examples;

import java.io.IOException;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class PageTimerFilter implements Filter
{

 private FilterConfig config = null;

 public void init(FilterConfig config) throws ServletException
 {  
  this.config = config;
 }
 public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException
 {
  Date startTime, endTime;
  double duration;
  startTime = new Date();
  // Forward the request to the next resource in the chain
  chain.doFilter(request, response);
  // Calculate the duration between the start time and end time
  endTime = new Date();
  duration = (endTime.getTime() - startTime.getTime())/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: " + duration + " seconds.");
  writer.println("===============");
  // Log the resulting string
  writer.flush();
  config.getServletContext().log(sw.getBuffer().toString());

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

在doFilter()方法实现中,出现在FilterChain的doFilter()方法调用之前的代码都被看成是预处理,Web资源(包括其他过滤器、Servlet等等)所做的处理还没有发生。而在该方法之后的代码则是后期处理,这时外发的响应信息已经包含了Web资源的完整响应。也就是说,FilterChain的doFilter()将调用接下来的过滤器(在有链式关系的时候)或者其他Web资源。

2. 配置 Servlet 过滤器 
和配置Servlet类似,过滤器通过 web.xml 文件中的两个 XML 标签来声明。
标签负责把一个过滤器名和一个特定的类关联起来,这种关联是通过元素指定。其 DTD定义如下:

(((description*,display-name*,icon*)),filter-name,filter-class,init-param*)

可以为过滤器指定初始化参数,和Servlet类似,参数是使用和成对的来指定的,如下所示:


counter
100

例 2 显示了 web.xml 文件,它展示了如何声明过滤器的包含关系:

 
  Page Timers
  cc.ejb.examples.PageTimerFilter
 

 
  Page Timers
  /*

 


 

必须有一个或者元素。我们可以通过来指定通配符,将过滤器应用到Web资源范围,在上面的例子中,Page Timer过滤器被应用到每个Web资源。也可以通过将过滤器指定到某一个特定的Servlet上应该注意这些声明的顺序,所引用的过滤器名必须在前面的过滤器定义给出。

3. 部署 Servlet 过滤器
事实上, 部署过滤器是非常简单的事情。只需把过滤器类和其他 Web 组件类包括在一起,并像通常所做的那样把 web.xml 文件(连同过滤器定义和过滤器映射声明)放进 Web 应用程序结构中,servlet 容器将处理之后的其他所有事情。

Servlet 2.4中的新特性
我们通过下面的例子来研究Servlet 2.4的新特性。例3和例4是两个很简单的程序片断,JSP程序将来自客户的请求forward到Thank.html。

<%@ page language="java" %><%@ page language="java" %>

 





 
    Thank you for coming Filter worlds

 

将这两个程序和上面的过滤器一起打包部署并运行Test.jsp,我们发现控制台只有一行而不是两行输出:

11:06:57,045 INFO  [Engine] StandardContext[/Test]
===============
Total elapsed time is: 0.0 seconds.
===============

因为,在Servlet 2.3 规范中的过滤器只能过滤 Web 客户机和其所访问的指定 Web 资源之间的内容。如果该资源然将请求调度给其他 Web 资源(这里是Thank.html),就不能向幕后委托的任何请求应用过滤器。

2.4 规范消除了这个限制,通过增强filter和request dispatcher的配合,过滤器可以根据请求分发器(request dispatcher)所使用的方法有条件地对Web请求进行过滤。该功能是通过中的元素来实现的:

  • 只有当request直接来自客户,过滤器才生效,对应为REQUEST条件。 
  • 只有当request被一个请求分发器使用forward()方法转到一个Web构件时(采用或定义),对应称为FORWARD条件。 
  • 类似地,只有当request被一个请求分发器使用include()方法转到一个Web构件时(采用或定义),对应称为INCLUDE条件。 
  • 只有当request被一个请求分发器使用“错误信息页”机制方法转到一个Web构件时,对应称为ERROR条件。
  • 以上四种条件的组合使用。

修改之后web.xml的如下所示:

 
  Page Timers
  cc.ejb.examples.PageTimerFilter
 

 
  Page Timers
  /*
  REQUEST
  FORWARD
 

再次部署运行这个Web应用,结果如下:

11:17:51,165 INFO  [Engine] StandardContext[/Test]
===============
Total elapsed time is: 0.0 seconds.
===============

11:17:51,165 INFO  [Engine] StandardContext[/Test]
===============
Total elapsed time is: 10.0 seconds.
===============

过滤器的运用
在适合使用装饰过滤器模式或者拦截器模式的任何地方,您都可以使用过滤器。过滤器的一些最普遍的应用如下:


加载:对于到达系统的所有请求,过滤器收集诸如浏览器类型、一天中的时间、转发 URL 等相关信息,并对它们进行日志记录。

性能:过滤器在内容通过线路传来并在到达 servlet 和 JSP 页面之前解压缩该内容,然后再取得响应内容,并在将响应内容发送到客户机机器之前将它转换为压缩格式。

安全:过滤器处理身份验证令牌的管理,并适当地限制安全资源的访问,提示用户进行身份验证和/或将他们指引到第三方进行身份验证。过滤器甚至能够管理访问控制列表(Access Control List,ACL),以便除了身份验证之外还提供授权机制。将安全逻辑放在过滤器中,而不是放在 servlet 或者 JSP 页面中,这样提供了巨大的灵活性。在开发期间,过滤器可以关闭(在 web.xml 文件中注释掉)。在生产应用中,过滤器又可以再次启用。此外还可以添加多个过滤器,以便根据需要提高安全、加密和不可拒绝的服务的等级。

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

XSLT 转换:不管是使用移动客户端还是使用基于 XML 的 Web 服务,无需把逻辑嵌入应用程序就在 XML 语法之间执行转换的能力都绝对是无价的。

阅读(793) | 评论(0) | 转发(0) |
0

上一篇:Filter技术的应用

下一篇:j2ee十大风险

给主人留下些什么吧!~~