1. 程式人生 > >JAVAWEB學習(8) -過濾器

JAVAWEB學習(8) -過濾器

過濾器(Filter)

1. 什麼是過濾器

過濾器是servlet規範當中定義的一種特殊的元件,用來攔截servlet容器的呼叫過程。

當servlet容器收到請求之後,如果有過濾器,會先呼叫過濾器

過濾器一般用於登入許可權驗證、資源訪問許可權控制、敏感詞彙過濾、字元編碼轉換等等操作,便於程式碼重用,不必每個servlet中還要進行相應的操作。
在這裡插入圖片描述

2. 過濾器是如何實現攔截的

Filter介面中有一個doFilter方法,當我們編寫好Filter,並配置對哪個web資源進行攔截後,WEB伺服器每次在呼叫web資源的service方法之前,都會先呼叫一下filter的doFilter方法,因此,在該方法內編寫程式碼可達到如下目的:

  1. 呼叫目標資源之前,讓一段程式碼執行。
  2. 是否呼叫目標資源(即是否讓使用者訪問web資源)。
  3. 呼叫目標資源之後,讓一段程式碼執行。

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>

配置過濾器一般有以下規則:

  1. 作用與所有web資源:<url—pattern>/*</url-pattern>。則客戶端請求訪問任意資原始檔時都要經過過濾器過濾,通過則訪問檔案,否則攔截

  2. 作用於某一資料夾下所有檔案:<url—pattern>/dir/*</url-pattern>

  3. 作用於某一種型別的檔案:<url—pattern>.副檔名</url-pattern>

    比如<url—pattern>.jsp</url-pattern>過濾所有對jsp檔案的訪問請求

  4. 作用於某一資料夾下某一型別檔案:<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方法");
 }