1. 程式人生 > >Java過濾器Filter詳解

Java過濾器Filter詳解

一、過濾器的定義:

過濾器是處於客戶端與伺服器資原始檔之間的一道過濾網,在訪問資原始檔之前,通過一系列的過濾器對請求進行修改、判斷等,把不符合規則的請求在中途攔截或修改。也可以對響應進行過濾,攔截或修改響應。

如圖,瀏覽器發出的請求先遞交給第一個filter進行過濾,符合規則則放行,遞交給filter鏈中的下一個過濾器進行過濾。過濾器在鏈中的順序與它在web.xml中配置的順序有關,配置在前的則位於鏈的前端。當請求通過了鏈中所有過濾器後就可以訪問資原始檔了,如果不能通過,則可能在中間某個過濾器中被處理掉。

     在doFilter()方法中,chain.doFilter()前的一般是對request執行的過濾操作,chain.doFilter後面的程式碼一般是對response執行的操作。過濾鏈程式碼的執行順序如下:

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

二、過濾器的生命週期:

(1) 載入和例項化 

Web 容器啟動時,即會根據 web.xml 中宣告的 filter 順序依次例項化這些 filter。 web.xml 中宣告的每個 filter 在每個虛擬機器中僅僅只有一個例項。 

(2) 初始化 

Web 容器呼叫 init(FilterConfig) 來初始化過濾器。容器在呼叫該方法時,向過濾器傳遞 FilterConfig 物件,FilterConfig 的用法和 ServletConfig 類似。利用 FilterConfig 物件可以得到 ServletContext 物件,以及在 web.xml 中配置的過濾器的初始化引數。在這個方法中,可以丟擲 ServletException 異常,通知容器該過濾器不能正常工作。此時的 Web 容器啟動失敗,整個應用程式不能夠被訪問。例項化和初始化的操作只會在容器啟動時執行,而且只會執行一次。 

(3) doFilter 

doFilter 方法類似於 Servlet 介面的 service 方法。當客戶端請求目標資源的時候,容器會篩選出符合 filter-mapping 中的 url-pattern 的 filter,並按照宣告 filter-mapping 的順序依次呼叫這些 filter 的 doFilter 方法。在這個鏈式呼叫過程中,可以呼叫 chain.doFilter(ServletRequest, ServletResponse) 將請求傳給下一個過濾器(或目標資源),也可以直接向客戶端返回響應資訊,或者利用 RequestDispatcher 的 forward 和 include 方法,以及 HttpServletResponse 的 sendRedirect 方法將請求轉向到其它資源。需要注意的是,這個方法的請求和響應引數的型別是 ServletRequest 和 ServletResponse,也就是說,過濾器的使用並不依賴於具體的協議。 

(4) 銷燬 

Web 容器呼叫 destroy 方法指示過濾器的生命週期結束。在這個方法中,可以釋放過濾器使用的資源。 

與開發 Servlet 不同的是,Filter 介面並沒有相應的實現類可供繼承,要開發過濾器,只能直接實現 Filer 介面。

 

 

三、過濾器的簡單應用:

(1)建立過濾器

如圖,新建一個class,實現介面Filter(注意:是javax.servlet中的Filter)。

   (2)重寫過濾器的doFilter(request,response,chain)方法。另外兩個init()、destroy()方法一般不需要重寫。在doFilter方法中進行過濾操作。

    常用程式碼有:獲取請求、獲取響應、獲取session、放行。

    剩下的程式碼就是根據session的屬性進行過濾操作、設定編碼格式等等了,看情況而定。

HttpServletRequest request=(HttpServletRequest) arg0;//獲取request物件
HttpServletResponse response=(HttpServletResponse) arg1;//獲取response物件
HttpSession session=request.getSession();//獲取session物件

過濾操作程式碼......

chain.doFilter(request, response);//放行,通過了當前過濾器,遞交給下一個filter進行過濾

  (3)在web.xml中配置過濾器。這裡要謹記一條原則:在web.xml中,監聽器>過濾器>servlet。也就是說web.xml中監聽器配置在過濾器之前,過濾器配置在servlet之前,否則會出錯。

<filter>  
    <filter-name>loginFilter</filter-name>//過濾器名稱  
    <filter-class>com.ygj.control.loginFilter</filter-class>//過濾器類的包路徑
<init—param> //可選 
    <param—name>引數名</param-name>//過濾器初始化引數
    <param-value>引數值</param-value>  
</init—pamm>  
</filter> 
 
<filter-mapping>//過濾器對映  
    <filter-name>loginFilter</filter-name>  
<url—pattern>指定過濾器作用的物件</url-pattern>

 在配置中需要注意的有兩處:一是<filter-class>指明過濾器類所在的包路徑。二是<url-pattren>處定義過濾器作用的物件。一般有以下規則:

    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>

    如果一個過濾器需要過濾多種檔案,則可以配置多個<filter-mapping>,一個mapping定義一個url-pattern來定義過濾規則。

<filter>
      <filter-name>loginFilter</filter-name>
      <filter-class>com.ygj.control.loginFilter</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>loginFilter</filter-name>
      <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
  <filter-mapping>
      <filter-name>loginFilter</filter-name>
      <url-pattern>*.do</url-pattern>
  </filter-mapping>

例1:用過濾器實現登入驗證,沒登入則駁回訪問請求並重定向到登入頁面。

public void doFilter(ServletRequest arg0, ServletResponse arg1,
            FilterChain arg2) throws IOException, ServletException {
        
        HttpServletRequest request=(HttpServletRequest) arg0;
        HttpServletResponse response=(HttpServletResponse) arg1;
        HttpSession session=request.getSession();
        
        String path=request.getRequestURI();
        
        Integer uid=(Integer)session.getAttribute("userid");
        
        if(path.indexOf("/login.jsp")>-1){//登入頁面不過濾
            arg2.doFilter(arg0, arg1);//遞交給下一個過濾器
            return;
        }
        if(path.indexOf("/register.jsp")>-1){//註冊頁面不過濾
            arg2.doFilter(request, response);
            return;
        }
        
        if(uid!=null){//已經登入
            arg2.doFilter(request, response);//放行,遞交給下一個過濾器
            
        }else{
            response.sendRedirect("login.jsp");
        }

    }

 例2:設定字元編碼

public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
          HttpServletRequest request2=(HttpServletRequest) request;
          HttpServletResponse response2=(HttpServletResponse) response;
          
          request2.setCharacterEncoding("UTF-8");  
          response2.setCharacterEncoding("UTF-8"); 
          
          chain.doFilter(request, response); 

    }

 

作者:Roger_CoderLife

連結:https:blog.csdn.net/Roger_CoderLife/article/details/84333021

本文為Roger_CoderLife的原創文章,著作權歸作者所有,轉載請註明原文出處,歡迎轉載!