From Gossip@caterpillar

JSP/Servlet: Filter(1)

 

 


Filter可以擔任瀏覽器與JSP/Servlet之間的一個中介處理者,一些request的前置處理動作及一些response的後置處理,都可以 交由這個中介處理者來完成,當然Filter可以達到的功能,您也可以直接撰寫在JSP/Servlet中,但如果有很多JSP/Servlet都需要相 同的處理,例如某些網頁都需要統一的身份驗證方式時,與其在每一個網頁中都撰寫驗證的程式碼,不如直接撰寫Filter,讓它來統一進行處理。

Filter實際上是一個純綷的Java類別程式,它要實作javax.servlet.Filter介 面,這個介面中有三個必須實作的方法:init()、destory()與doFilter()。init()是Filter類別被載入時會執行的方法, 而destory()是 Filter物件生命週期結束時會執行的方,至於doFilter()則是實作Filter功能的核心,您想要Filter完成的工作就撰寫在其中,先來 撰寫一個簡單的Filter類,如下:

  • FilterDemo1.java
package onlyfun.caterpillar;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class FilterDemo1 implements Filter {
public void init(FilterConfig config)
throws ServletException {
}

public void destroy() {
}

public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
PrintWriter out = response.getWriter();
out.println("Filter 1 is doing!!!");

chain.doFilter(request, response);

out.println("Filter 1's work is done");
}
}

在這個程式中,只是簡單的顯示一些文字,表示Filter的doFilter()方法有被執行,doFilter()傳入三個參數, ServletRequest、ServletResponse、FilterChain,您可以獲得request與response物件,以對它們進 行一些處理,像是設定標頭、編碼格式或包裝壓縮功能等等,至於FilterChain則是關於Filter執行順序的物件,這個順序是設定在 web.xml中,您必須呼叫它的doFilter()方法,才可以執行下一個Filter,如果是最後一個Filter,則執行客戶端所請求的 JSP/Servlet網頁。

為了要能使用Filter,您必須在web.xml中撰寫一些設定,一個設定範例如下:

  • web.xml
...
<filter>
<filter-name>FilterDemo1</filter-name>
<filter-class>onlyfun.caterpillar.FilterDemo1</filter-class>
</filter>

<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...

<filter>與</filter>之間撰寫Filter的名稱與實際載入的類別,Filter類別檔是放置在WEB- INF/classes/下,而<filter-mapping>與</filter- mapping>之間則撰寫Filter名稱與所要過濾的資源對象,在這邊設定為/*,表示請求這個Web應用程式下的所有資源,都要先經過 Filter的處理。

如果設定的<url-pattern>套用了兩個Filter,則FilterChain在執行doFilter()方法時,其呼叫的 Filter順序就是您在web.xml中撰寫Filter的順序,例如再撰寫一個Filter程式:

  • FilterDemo2.java
package onlyfun.caterpillar;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class FilterDemo2 implements Filter {
public void init(FilterConfig config)
throws ServletException {
}

public void destroy() {
}

public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
PrintWriter out = response.getWriter();
out.println("Filter 2 is doing!!!");

chain.doFilter(request, response);

out.println("Filter 2's work is done");
}
}

web.xml中設定的內容是:
  • web.xml
... 
<filter>
<filter-name>FilterDemo1</filter-name>
<filter-class>onlyfun.caterpillar.FilterDemo1</filter-class>
</filter>

<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
<filter-name>FilterDemo2</filter-name>
<filter-class>onlyfun.caterpillar.FilterDemo2</filter-class>
</filter>

<filter-mapping>
<filter-name>FilterDemo2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...

則請求Web應用程式下的任一個資源,都會先執行FilterDemo1,然後再執行FilterDemo2,最後呼叫請求的資源,如果請求的資源是 JSP網頁,而它的功能只是印出 5 個Hello! World!:
  • test.jsp
<% 
for(int i = 0; i < 5; i++)
out.println("Hello! World!");
%>

則呼叫該JSP網頁時,所得到的結果是:
Filter 1 is doing!!!
Filter 2 is doing!!!
Hello! World!
Hello! World!
Hello! World!
Hello! World!
Hello! World!
Filter 2's work is done
Filter 1's work is done