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

JavaWeb Filter 過濾器全解析:原理、生命周期、配置映射與實戰應用

     編輯:Java 綜合教學

什麼是過濾器?

Filter(過濾器)是 JavaWeb 規範(Servlet 2.3+)定義的**服務器端組件**,它位於**客戶端請求**與**目標資源(Servlet/JSP/靜態文件)**之間,能攔截、檢查、修改請求(ServletRequest)與響應(ServletResponse)。

形象比喻:請求像水,Filter 是一道道過濾網,層層把關,最後流向目標資源;響應回流時再經過同樣的過濾網。

過濾器生命周期

  1. 初始化:Web 容器啟動,讀取 web.xml,實例化 Filter,調用 init(FilterConfig config),**僅一次**。
  2. 過濾:每次請求命中映射規則,容器調用 doFilter(req, resp, chain)。**多線程並發**,需注意線程安全。
  3. 銷毀:Web 容器關閉或應用卸載,調用 destroy() 釋放資源,**僅一次**。

核心 API 接口

接口核心方法作用
javax.servlet.Filterinit、doFilter、destroy開發者實現的核心接口
FilterConfiggetInitParameter、getServletContext初始化參數訪問,類似 ServletConfig
FilterChaindoFilter(req, resp)調用鏈中下一個 Filter 或目標資源
ServletRequest/ResponseWrapper包裝器模式修改請求/響應內容(如加密、壓縮、編碼統一)

Filter 配置映射詳解(web.xml)

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>com.filter.EncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

映射規則優先級與匹配

  • /*:攔截**所有**請求(含靜態資源、轉發、包含)。
  • /api/*:攔截 /api/ 路徑下請求。
  • *.do、*.jsp:後綴匹配。
  • 同一 Filter 可配置多個 filter-mapping;多個 Filter 按 web.xml 中聲明順序執行。

Dispatcher 類型(決定何時觸發)

類型觸發場景默認
REQUEST用戶直接訪問 URL✓
FORWARDRequestDispatcher.forward()
INCLUDERequestDispatcher.include()
ERROR錯誤頁面跳轉 (error-page)
ASYNC (Servlet 3.0+)異步請求啟動/完成

實戰案例 1:統一字符編碼過濾器

package com.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class EncodingFilter implements Filter {
    private String encoding = "UTF-8";

    @Override
    public void init(FilterConfig config) {
        String param = config.getInitParameter("encoding");
        if (param != null) encoding = param;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        // 設置請求編碼(POST 表單)
        if (request.getCharacterEncoding() == null) {
            request.setCharacterEncoding(encoding);
        }
        // 設置響應編碼
        response.setCharacterEncoding(encoding);
        response.setContentType("text/html;charset=" + encoding);

        chain.doFilter(request, response); // 傳遞給下一個 Filter 或目標資源
    }

    @Override
    public void destroy() { /* 釋放資源 */ }
}

實戰案例 2:登錄權限攔截過濾器

public class AuthFilter implements Filter {
    private static final String[] EXCLUDE_PATHS = {"/login.jsp", "/register.jsp", "/static/", "/api/public/"};

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        String uri = request.getRequestURI();
        // 排除靜態資源與公開頁面
        for (String path : EXCLUDE_PATHS) {
            if (uri.startsWith(request.getContextPath() + path)) {
                chain.doFilter(request, response);
                return;
            }
        }

        // 檢查 Session
        Object user = request.getSession().getAttribute("loginUser");
        if (user == null) {
            // 未登錄,重定向到登錄頁
            response.sendRedirect(request.getContextPath() + "/login.jsp");
            return;
        }

        chain.doFilter(request, response); // 已登錄,放行
    }
}

Servlet 3.0+ 註解配置(無 web.xml)

@WebFilter(
    filterName = "encodingFilter",
    urlPatterns = {"/*"},
    dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD},
    initParams = @WebInitParam(name = "encoding", value = "UTF-8")
)
public class EncodingFilter implements Filter { ... }

Filter 典型應用場景

  1. 字符編碼統一(防止中文亂碼)
  2. 登錄/權限檢查(單點登錄、RBAC)
  3. 請求日誌/審計(記錄 IP、URL、耗時、參數)
  4. XSS 防護(包裝 Request,過濾腳本標籤)
  5. 響應壓縮(GZIP/Deflate,節省帶寬)
  6. 敏感詞過濾/替換(包裝 Response,輸出時替換)
  7. 圖片防盜鏈/水印
  8. API 簽名驗證/限流

常見坑與最佳實踐

  • 務必調用 chain.doFilter(),否則請求鏈中斷,目標資源不會執行。
  • 不要在 Filter 中處理業務邏輯,保持輕量、通用;複雜業務交給 Interceptor 或 Service。
  • 線程安全:Filter 實例單例多線程共享,**不要**在實例字段存儲請求相關狀態。
  • 響應提交後不可再操作:chain.doFilter() 返回後,響應可能已提交,不可再 sendRedirect 或寫入流。
  • 異常處理:在 doFilter 中捕獲異常,統一轉向錯誤頁,避免容器默認堆棧頁面。

掌握 Filter 的原理與配置,是 JavaWeb 開發者進階的必修課。合理使用 Filter,能讓橫切關注點(安全、編碼、日誌、壓縮)與業務代碼徹底解耦,構建整潔、可維護的 Web 應用架構。

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