JAVAWEB學習(8) -過濾器
過濾器(Filter)
1. 什麼是過濾器
過濾器是servlet規範當中定義的一種特殊的元件,用來攔截servlet容器的呼叫過程。
當servlet容器收到請求之後,如果有過濾器,會先呼叫過濾器
過濾器一般用於登入許可權驗證、資源訪問許可權控制、敏感詞彙過濾、字元編碼轉換等等操作,便於程式碼重用,不必每個servlet中還要進行相應的操作。
2. 過濾器是如何實現攔截的
Filter介面中有一個doFilter方法,當我們編寫好Filter,並配置對哪個web資源進行攔截後,WEB伺服器每次在呼叫web資源的service方法之前,都會先呼叫一下filter的doFilter方法,因此,在該方法內編寫程式碼可達到如下目的:
- 呼叫目標資源之前,讓一段程式碼執行。
- 是否呼叫目標資源(即是否讓使用者訪問web資源)。
- 呼叫目標資源之後,讓一段程式碼執行。
web伺服器在呼叫doFilter方法時,會傳遞一個filterChain物件進來,filterChain物件是filter介面中最重要的一個對 象,它也提供了一個doFilter方法,開發人員可以根據需求決定是否呼叫此方法,呼叫該方法,則web伺服器就會呼叫web資源的service方 法,即web資源就會被訪問,否則web資源不會被訪問。
3. 如何寫過濾器
3.1 寫一個java類,實現Filter介面
public class CommentFilter implements Filter {
/**
* 容器啟動之後,會立即將過濾器例項化
* 只會建立一個例項
*/
public CommentFilter() {
System.out.println("CommentFilter的構造器");
}
/**
* 容器在刪除過濾器例項之前,會呼叫destroy方法
* 該方法只會執行一次
*/
public void destroy() {
System.out.println("commentFilter的destroy方法");
}
/**
* 容器會呼叫doFilter放來來處理請求(類似於service方法)
* FilterChain(過濾器鏈):如果呼叫了該物件的doFilter方法,表示繼續向後執行,
* 否則中斷請求,返回處理結果。
*
* ServletRequest是HttpServletRequest的父介面
* ServletResponse是HttpServletResponse的父介面
* 這兒使用父介面是因為這是sun公司過度設計的產物
*/
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
System.out.println("CommentFilter的doFilter方法開始執行...");
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session=request.getSession();
String path=req.getRequestURI();
Integer uid=(Integer)session.getAttribute("userid");
if(path.indexOf("/login.jsp")>-1){//登入頁面不過濾
chain.doFilter(req, res);//遞交給下一個過濾器
return;
}
if(path.indexOf("/register.jsp")>-1){//註冊頁面不過濾
chain.doFilter(req, res);
return;
}
if(uid!=null){//已經登入
chain.doFilter(req, res);//放行,遞交給下一個過濾器
}else{
response.sendRedirect("login.jsp");
}
System.out.println("CommentFilter的doFilter方法執行完畢");
}
/**
* 容器在建立好過濾器例項之後會呼叫該例項的Init方法
* 該方法只會執行一次
* FilterConfig物件類似於ServletConfig,可以用來讀取初始化引數
*/
public void init(FilterConfig arg0) throws ServletException {
System.out.println("CommentFilter的Init方法");
}
}
3.2 配置過濾器(web.xml)
<!--配置過濾器-->
<filter>
<filter-name>commentFilter</filter-name>
<filter-class>web.CommentFilter</filter-class>
</filter>
<!--對映過濾器-->
<filter-mapping>
<filter-name>commentFilter</filter-name>
<url-pattern>/comment</url-pattern>
</filter-mapping>
配置過濾器一般有以下規則:
-
作用與所有web資源:<url—pattern>/*</url-pattern>。則客戶端請求訪問任意資原始檔時都要經過過濾器過濾,通過則訪問檔案,否則攔截
-
作用於某一資料夾下所有檔案:<url—pattern>/dir/*</url-pattern>
-
作用於某一種型別的檔案:<url—pattern>.副檔名</url-pattern>。
比如<url—pattern>.jsp</url-pattern>過濾所有對jsp檔案的訪問請求
-
作用於某一資料夾下某一型別檔案:<url—pattern>/dir/*.副檔名</url-pattern>
4. 過濾器的優先順序(Filter鏈)
在一個web應用中,可以開發編寫多個Filter,這些Filter組合起來稱之為一個Filter鏈。
web伺服器根據Filter在web.xml檔案中的註冊順序,決定先呼叫哪個Filter,當第一個Filter的doFilter方法被呼叫時,web伺服器會建立一個代表Filter鏈的FilterChain物件傳遞給該方法。在doFilter方法中,開發人員如果呼叫了FilterChain物件的doFilter方法,則web伺服器會檢查FilterChain物件中是否還有filter,如果有,則呼叫第2個filter,如果沒有,則呼叫目標資源。
如圖,瀏覽器發出的請求先遞交給第一個filter進行過濾,符合規則則放行,遞交給filter鏈中的下一個過濾器進行過濾。過濾器在鏈中的順序與它在web.xml中配置的順序有關,配置在前的則位於鏈的前端。當請求通過了鏈中所有過濾器後就可以訪問資原始檔了,如果不能通過,則可能在中間某個過濾器中被處理掉。
**在doFilter()方法中,chain.doFilter()前的一般是對request執行的過濾操作,chain.doFilter後面的程式碼一般是對response執行的操作。**過濾鏈程式碼的執行順序如下:
5. 過濾器的生命週期
例項化 --> 初始化 --> 處理攔截 --> 銷燬
注意:init方法也只會執行一次,destroy方法也只會執行一次
5.1 Filter的建立(例項化)
/**
* 容器啟動之後,會立即將過濾器例項化
* 只會建立一個例項
*/
public CommentFilter() {
System.out.println("CommentFilter的構造器");
}
5.2 Filter呼叫Init()方法(初始化)
/**
* 容器在建立好過濾器例項之後會呼叫該例項的Init方法
* 該方法只會執行一次
* FilterConfig物件類似於ServletConfig,可以用來讀取初始化引數
*/
public void init(FilterConfig arg0) throws ServletException {
System.out.println("CommentFilter的Init方法");
}
5.3 Filter方法執行(處理攔截)
/**
* 容器會呼叫doFilter放來來處理請求(類似於service方法)
* FilterChain(過濾器鏈):如果呼叫了該物件的doFilter方法,表示繼續向後執行,
* 否則中斷請求,返回處理結果。
*/
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
System.out.println("CommentFilter的doFilter方法開始執行...");
...
System.out.println("CommentFilter的doFilter方法執行完畢");
}
5.4 Filter呼叫destroy()方法(銷燬)
/**
* 容器在刪除過濾器例項之前,會呼叫destroy方法
* 該方法只會執行一次
*/
public void destroy() {
System.out.println("commentFilter的destroy方法");
}