Filter(過濾器)是 JavaWeb 規範(Servlet 2.3+)定義的**服務器端組件**,它位於**客戶端請求**與**目標資源(Servlet/JSP/靜態文件)**之間,能攔截、檢查、修改請求(ServletRequest)與響應(ServletResponse)。
形象比喻:請求像水,Filter 是一道道過濾網,層層把關,最後流向目標資源;響應回流時再經過同樣的過濾網。
web.xml,實例化 Filter,調用 init(FilterConfig config),**僅一次**。doFilter(req, resp, chain)。**多線程並發**,需注意線程安全。destroy() 釋放資源,**僅一次**。| 接口 | 核心方法 | 作用 |
|---|---|---|
javax.servlet.Filter | init、doFilter、destroy | 開發者實現的核心接口 |
FilterConfig | getInitParameter、getServletContext | 初始化參數訪問,類似 ServletConfig |
FilterChain | doFilter(req, resp) | 調用鏈中下一個 Filter 或目標資源 |
ServletRequest/ResponseWrapper | 包裝器模式 | 修改請求/響應內容(如加密、壓縮、編碼統一) |
<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-mapping;多個 Filter 按 web.xml 中聲明順序執行。| 類型 | 觸發場景 | 默認 |
|---|---|---|
| REQUEST | 用戶直接訪問 URL | ✓ |
| FORWARD | RequestDispatcher.forward() | |
| INCLUDE | RequestDispatcher.include() | |
| ERROR | 錯誤頁面跳轉 (error-page) | |
| ASYNC (Servlet 3.0+) | 異步請求啟動/完成 |
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() { /* 釋放資源 */ }
}
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); // 已登錄,放行
}
}
@WebFilter(
filterName = "encodingFilter",
urlPatterns = {"/*"},
dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD},
initParams = @WebInitParam(name = "encoding", value = "UTF-8")
)
public class EncodingFilter implements Filter { ... }
chain.doFilter(),否則請求鏈中斷,目標資源不會執行。chain.doFilter() 返回後,響應可能已提交,不可再 sendRedirect 或寫入流。doFilter 中捕獲異常,統一轉向錯誤頁,避免容器默認堆棧頁面。掌握 Filter 的原理與配置,是 JavaWeb 開發者進階的必修課。合理使用 Filter,能讓橫切關注點(安全、編碼、日誌、壓縮)與業務代碼徹底解耦,構建整潔、可維護的 Web 應用架構。