首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

J2EE探索者:深入掌握 Servlet 2.4 過濾器機制與應用

     編輯:Java 相關知識

Servlet 過濾器是可插拔的 Web 組件,允許在 Web 應用程式中實作前置與後置處理邏輯。它支援 Servlet 和 JSP 頁面的基礎請求處理功能,如日誌記錄、效能監控、安全控制、會話管理、XSLT 轉換等。過濾器隨 Java Servlet 2.3 規範首次發布,2.4 規範對其進行重大升級。本文將介紹 Servlet 過濾器的基礎架構、實作細節、典型應用,並展望新規範的擴充功能。

什麼是 Servlet 過濾器?

Servlet 過濾器是小型 Web 組件,攔截請求與回應,以檢視、擷取或操作客戶端與伺服器間交換的資料。它們封裝重要但非核心的輔助功能,如記錄請求/回應資料、處理安全協定、管理會話屬性等。過濾器提供面向物件的模組化機制,將通用任務封裝為可插拔組件,透過設定檔宣告並動態處理。

過濾器核心特性

  • 宣告式: 透過 web.xml XML 標籤宣告,增刪過濾器無需修改應用程式碼或 JSP。
  • 動態: 運行時由 Servlet 容器調用攔截處理請求/回應。
  • 靈活: 涵蓋日誌、安全等常見輔助任務,可用於客戶端直接呼叫的預/後處理,亦可處理防火牆後 Web 組件間調度的請求,並可鏈結提供所需功能。
  • 模組化: 將處理邏輯封裝於單一類別,定義可從請求/回應鏈輕鬆增刪的模組單元。
  • 可移植: 跨平台、跨容器可移植,支援模組化與重用。
  • 可重用: 得益於模組化類別設計與宣告式配置,易跨專案應用。
  • 透明: 補充而非取代 Servlet/JSP 核心處理,增刪不破壞現有組件。

綜上,Servlet 過濾器是透過設定檔靈活宣告的模組化可重用組件,動態處理請求/回應,無需修改程式碼即可透明增刪,且獨立於平台與容器。

Servlet 過濾器架構

過濾器攔截傳入請求及/或傳出回應,監視、修改或處理通過的資料流。它們是自包含的模組化組件,可加入請求/回應鏈或移除而不影響其他 Web 組件。過濾器僅改變請求/回應的運行時處理,不應直接嵌入應用框架,除非透過 Servlet API 標準介面。

Web 資源可配置無過濾器(預設)、單一過濾器(典型)、或過濾器鏈。過濾器接受請求與回應物件,檢查請求決定轉發給鏈中下一組件,或中止請求直接回應客戶端。若轉發,請求傳遞給下一資源(另一過濾器、Servlet 或 JSP)。請求經過鏈被處理後,回應以相反順序通過鏈返回,各過濾器皆有機會處理回應物件。

Servlet 2.3 時過濾器僅能過濾客戶端與指定資源間內容,資源若調度給其他資源,幕後委託請求無法套用過濾器。2.4 規範移除此限制,過濾器可應用於 J2EE Web 環境中任何存在請求/回應物件的地方:客戶端與 Servlet 間、Servlet 與 Servlet/JSP 間、各包含的 JSP 頁面間。這才是真正的強大與靈活!

實作 Servlet 過濾器的三個步驟

1. 編寫實作類別

過濾器 API 包含三個介面:Filter、FilterChain、FilterConfig(均在 javax.servlet 套件)。過濾器類別實作 Filter 介面,使用另外兩個介面。FilterChain 參考傳遞給過濾器,允許將控制權傳給鏈中下一資源;FilterConfig 由容器提供,允許存取初始化資料。

為完整實作 Filter 介面,需實作三個方法:

  • init(FilterConfig config):容器實例化過濾器時調用,準備處理環境。
  • doFilter(ServletRequest req, ServletResponse res, FilterChain chain):處理請求/回應的核心方法,類似 Servlet 的 service()。
  • destroy():垃圾回收前執行清理操作。

以下展示一個簡單過濾器,追蹤滿足客戶端 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 destroy() {
        this.filterConfig = null;
    }
    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()) / 1000; // 毫秒轉秒
        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());
    }
}

生命週期解析

  • 初始化: 容器首次載入過濾器調用 init(),範例中保存 FilterConfig 參考(雖未使用初始化資料,僅為示範)。
  • 過濾: doFilter() 由容器調用,傳入請求、回應、鏈參考。過濾器處理請求,調用 chain.doFilter() 轉交下一資源,控制權返回時處理回應。
  • 銷毀: 容器在垃圾回收前調用 destroy() 執行清理。

2. 配置 Servlet 過濾器

透過 web.xml 兩個 XML 標籤宣告:<filter> 定義名稱、實作類別、初始化參數;<filter-mapping> 將過濾器關聯至 Servlet 或 URL 模式。

<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」過濾器映射到「Main Servlet」,並定義 Servlet 映射將所有請求(通配符)發送給該 Servlet。此為控制器組件典型映射。注意宣告順序不可顛倒。

3. 部署 Servlet 過濾器

部署極簡單:將過濾器類別與其他 Web 組件類別打包,連同 web.xml(含過濾器定義與映射)置於 Web 應用結構中,Servlet 容器處理其餘一切。

過濾器的多樣應用場景

過濾器應用僅受限於創意與設計能力。適用於裝飾器模式或攔截器模式的場合。常見應用包括:

  • 稽核: 記錄所有請求的瀏覽器類型、時間、轉向 URL 等資訊。
  • 效能: 解壓縮傳入內容、壓縮回應內容再發送客戶端。
  • 安全: 管理認證令牌、限制安全資源存取、提示認證或導向第三方認證、管理存取控制列表(ACL)提供授權。將安全邏輯置於過濾器而非 Servlet/JSP,提供極大彈性:開發時可關閉(註解 web.xml),生產環境啟用;可疊加多過濾器提升安全等級。
  • 會話處理: 避免 Servlet/JSP 混雜會話代碼,讓頁面專注內容顯示與委託處理。
  • XSLT 轉換: 在 XML 語法間轉換,無需嵌入應用邏輯,對行動客戶端或 XML Web Services 極有價值。

過濾器在 MVC 架構中的定位

模型-視圖-控制器(MVC)架構已整合進 Jakarta Struts、Turbine 等主流 Web 框架。過濾器旨在擴充 MVC 的請求/回應處理流。無論請求/回應發生在客戶端-伺服器間或伺服器組件間,過濾器在處理流中的應用一致。從 MVC 觀點,調度器組件(包含於控制器或與其協作)將請求轉發給適當應用組件處理,使控制器層成為放置 Servlet 過濾器的最佳位置。過濾器置於控制器前可應用於所有請求;置於控制器/調度器與模型/視圖間可針對單一 Web 組件。

結語

雖然過濾器出現僅數年,已成為所有敏捷、面向物件 J2EE Web 應用的關鍵組件。本文介紹了過濾器的高階設計、2.4 與 2.3 規範比較、精確實作步驟、宣告與部署方式、常見應用,以及如何融入傳統 MVC 架構。

這是 J2EE 探索者系列的最後一篇。我們從 Enterprise JavaBean 組件開始,轉向 Web 層,涵蓋 Servlet、JSP、JavaBean 及 Servlet API 無數選擇。與您共同探索是件樂事,感謝參與,祝好運、探索愉快!

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved