一、簡介
在servlet開發中,對於請求的攔截,常使用filter過濾器,這裡結合原始碼對Filter過濾器進行介紹。
二、Filter過濾器
Filter過濾器是實現特殊介面的java類,由servlet容器呼叫執行,可用於許可權過濾、日誌記錄、圖片轉換、加密、資料壓縮等操作。
2.1 核心類
Filter過濾器核心類是Filter,關聯的還有有FilterConfig、FilterChain,其實是三個介面,。下面結合原始碼分別介紹。
2.1.1 Filter介面
Filter是在請求到響應(servlet或靜態資源),或者一個響應到另一個響應中間,執行過濾任務的物件。Filter執行過濾任務是在方法doFilter中。原始碼如下:
package javax.servlet;
import java.io.IOException;
public interface Filter {
//初始化方法,容器建立Filter物件後,立即呼叫init方法,整個生命週期中只執行一次。
//在init方法成功(失敗如拋異常等)執行完前,不能提供過濾服務。
//引數FilterConfig用於獲取初始化引數
public void init(FilterConfig filterConfig) throws ServletException;
//執行過濾任務的方法,引數FilterChain表示Filter鏈,doFilter方法中只有執行FilterChain只有執行了doFilter方法,
//才能將請求交給下一個Filter或Servlet執行
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException;
//銷燬方法,當移出服務時由web容器呼叫。整個生命週期中destroy方法只會執行一次
//destroy方法可用於釋放持有的資源,如記憶體、檔案控制代碼等
public void destroy();
}
2.1.2 FilterConfig
FilterConfig用於獲取過濾器的初始化引數。原始碼如下:
package javax.servlet;
import java.util.Enumeration;
public interface FilterConfig {
//獲取過濾器名稱
public String getFilterName();
//獲取關聯的ServletContext
public ServletContext getServletContext();
//獲取指定名稱的初始化引數
public String getInitParameter(String name);
//獲取初始化引數名稱集合
public Enumeration<String> getInitParameterNames();
}
2.1.3 FilterChain
FilterChain是容器提供給開發者的,用於呼叫Filter鏈上的下一個Filter或最終servlet服務。
package javax.servlet;
import java.io.IOException;
public interface FilterChain {
//呼叫引用鏈的下一個filter或最終servlet服務
public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
}
2.2 註冊
過濾器註冊有兩種方式,使用常規的xml註冊和使用註解註冊(會在示例程式碼中以註釋的方式體現)。這裡以常規xml註冊為例。xml註冊是在專案的web.xml上註冊的,可以對指定訪問路徑或指定servlet進行攔截,示例如下:
<filter-name>demoFitler</filter-name>
<filter-class>filter.DemoFilter</filter-class>
<init-param>
<param-name>forbidIds</param-name>
<param-value>002,003,004</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>demoFitler</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
三、示例
資源servlet類DemoServlet.java如下:
package filter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name="DemoServlet", urlPatterns = "/demoServlet")
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write("this is a demo test");
}
}
過濾器DemoFilter.java
package filter;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
import java.util.Objects;
//可以使用下面註解方式註冊Filter,其中urlPatterns攔截指定路徑,demoServlet攔截指定servlet
// initParams = {@WebInitParam(name = "forbidIds", value = "002,003,004")})
public class DemoFilter implements Filter {
private FilterConfig filterConfig;
private String forbidIds;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
//獲取初始化引數
forbidIds = filterConfig.getInitParameter("forbidIds");
System.out.println("forbidIds:" + forbidIds);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String id = request.getParameter("id");
if (StringUtils.isBlank(forbidIds) || !forbidIds.contains(Objects.toString(id, "001"))) {
//不攔截,呼叫後續訪問
chain.doFilter(request, response);
} else {
//攔截,輸出錯誤資訊
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("forbid");
}
}
@Override
public void destroy() {
System.out.println("DemoFilter destroy");
}
}
響應:
請求:http://localhost:8080/demoServlet?id=001
響應:this is a demo test
請求:http://localhost:8080/demoServlet?id=002
響應:forbid