1. 程式人生 > >Servlet過濾器原理

Servlet過濾器原理

Servlet 過濾器原理

Servlet 過濾器是小型的 Web 元件,它們攔截請求和響應,
以便檢視、提取或以某種方式操作正在客戶機和伺服器之間交換的資料。
過濾器是通常封裝了一些功能的 Web 元件,這些功能雖然很重要,
但是對於處理客戶機請求或傳送響應來說不是決定性的。
典型的例子包括記錄關於請求和響應的資料、處理安全協議、

1.1宣告式的:過濾器通過 Web 部署描述符(web.xml)中的 XML 標籤來宣告。
   這樣允許新增和刪除過濾器,而無需改動任何應用程式程式碼或 JSP 頁面。

1.2動態的:過濾器在執行時由 Servlet 容器呼叫來攔截和處理請求和響應。

1.3靈活的:過濾器在 Web 處理環境中的應用很廣泛,涵蓋諸如日誌記錄和安全等許多最公共的輔助任務。
過濾器還是靈活的,因為它們可用於對來自客戶機的直接呼叫執行預處理和後期處理,
以及處理在防火牆之後的 Web 元件之間排程的請求。最後,可以將過濾器連結起來以提供必需的功能。

1.4模組化的:通過把應用程式處理邏輯封裝到單個類檔案中,過濾器從而定義了可容易地從請求/響應鏈中新增或刪除的模組化單元。

1.5可移植的:與 Java 平臺的其他許多方面一樣,Servlet 過濾器是跨平臺和跨容器可移植的,
從而進一步支援了 Servler 過濾器的模組化和可重用本質。

1.6可重用的:歸功於過濾器實現類的模組化設計,以及宣告式的過濾器配置方式,過濾器可以容易地跨越

1.7透明的:在請求/響應鏈中包括過濾器,這種設計是為了補充servlet 或 JSP 頁面提供的核心處理。
因而,過濾器可以根據需要新增或刪除,而不會破壞 servlet 或 JSP 頁面。

     
Servlet過濾器是Servlet的一種特殊用法,主要用來完成一些通用的操作。
比如編碼的過濾,判斷使用者的登陸狀態等等。
Servlet過濾器的適用場合:     
A.認證過濾   
B.登入和稽核過濾       
C.影象轉換過濾      
D.資料壓縮過濾       
E.加密過濾       
F.令牌過濾       
G.資源訪問觸發事件過濾        


Servlet過濾器介面的構成:     
所有的Servlet過濾器類都必須實現javax.servlet.Filter介面。
這個介面含有3個過濾器類必須實現的方法:        
init(FilterConfig cfg) 這是Servlet過濾器的初始化方法,性質等同與servlet的init方法。        
doFilter(ServletRequest,ServletResponse,FilterChain) 完成實際的過濾操作,當請求訪問過濾器關聯的URL時,Servlet容器將先呼叫過濾器的doFilter方法。
FilterChain引數用於訪問後續過濾器      
destroy() Servlet容器在銷燬過濾器例項前呼叫該方法,這個方法中可以釋放Servlet過濾器佔用的資源。性質等同與servlet的destory()方法。       

Servlet過濾器的建立步驟:     
A.實現javax.servlet.Filter介面的servlet類      
B.實現init方法,讀取過濾器的初始化函式       
C.實現doFilter方法,完成對請求或過濾的響應       
D.呼叫FilterChain介面物件的doFilter方法,向後續的過濾器傳遞請求或響應      
E.在web.xml中配置Filter         
2.使用過濾器處理中文問題       
當用使用者登陸頁面輸入帳號時,如果輸入是中文,後臺servlet再次輸出這個內容時,
可能就會是亂碼,這是因為serlvet中預設是以ISO-8859-1格式編碼的,
如果後臺有多個Servlet,多個引數,這樣就不合適,這個問題,
我們可以通過一個過濾器統一解決,使後臺的輸出輸出都支援中文!
將ISO-8859-1轉碼為GBK的那段程式碼!
       
3.使用過濾器認證使用者:    
每個過濾器也可以配置初始化引數,可以將不需要過濾的地址配置到這個Filter的配置引數中,
過濾時,如果請求地址在配置引數中,則放行,這樣就避免了在程式中硬編碼。
每個Filter中初始化時,都可以得到配置物件,在Filter中配置二個不需要過濾的地址,
一個是登陸頁面,一個是執行登陸認證的servlet;        
4.Servlet監聽器     
類似與Swing介面應用開發,Servlet也可以建立監聽器,以對Servlet容器,或Servlet中以象的事件做出反應。
Servlet監聽器主要有以下幾種:
ServletRequestListener ,
ServletRequestAttributeListener,       
HttpSessionActivationListener ,
HttpSessionBindingListener ,            
HttpSessionAttributeListener,
HttpSessionListener,            
ServletContextListener
...     
這些監聽器主要用來監聽session,request,application這三個物件裡存取資料的變化。
----------------------------------------------------------------------------------------------------
2.Servlet 過濾器體系結構

Servlet 過濾器用於攔截傳入的請求和/或傳出的響應,並監視、修改或以某種方式處理正在通過的資料流。
過濾器是自包含、模組化的元件,可以將它們新增到請求/響應鏈中,
或者在無需影響應用程式中其他 Web 元件的情況下刪除它們。
過濾器僅只是改動請求和響應的執行時處理,因而不應該將它們直接嵌入 Web 應用程式框架,
除非是通過 Servlet API 中良好定義的標準介面來實現。
當過濾器在 Servlet 2.3 規範中首次引入時,它們只能過濾 Web 客戶機和客戶機所訪問的指定 Web 資源之間的內容。
如果該資源然後將請求排程給其他 Web 資源,那就不能向幕後委託的任何請求應用過濾器。
Servlet 過濾器現在可以應用於 J2EE Web 環境中存在請求和響應物件的任何地方。
Servlet 過濾器可以應用在客戶機和 servlet 之間、servlet 和 servlet 或 JSP 頁面之間,
以及所包括的每個 JSP 頁面之間。它非常強大能力和靈活性!
----------------------------------------------------------------------------------------------------
3.1編寫實現類的程式
過濾器 API 包含 3 個簡單的介面,它們整潔地巢狀在
為了與我們的三步模式保持一致,過濾器必須運用三個方法,以便完全實現 Filter 介面:

init() :這個方法在容器例項化過濾器時被呼叫,它主要設計用於使過濾器為處理做準備。
該方法接受一個 FilterConfig 型別的物件作為輸入。

doFilter() :與 servlet 擁有一個 service() 方法(這個方法又呼叫 doPost() 或者 doGet() )來處理請求一樣,
過濾器擁有單個用於處理請求和響應的方法―― doFilter() 。
這個方法接受三個輸入引數:一個 ServletRequest 、 response 和一個 FilterChain 物件。
destroy() :
正如您想像的那樣,這個方法執行任何清理操作,這些操作可能需要在自動垃圾收集之前進行。
sample code list
 
SessionFilter.java
package net.pms.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
* @author jfish
* @since 2006.1.12
*/
public class SessionFilter implements Filter {

     public static boolean isContains(String container, String[] regx) {
           boolean result = false;

           for (int i = 0; i < regx.length; i++) {
                 if (container.indexOf(regx) != -1) {
                       return true;
                 }
           }
           return result;
     }

     public FilterConfig config;

     public void setFilterConfig(FilterConfig config) {
           this.config = config;
     }

     public FilterConfig getFilterConfig() {
           return config;
     }

     public void doFilter(ServletRequest request, ServletResponse response,
                 FilterChain chain) throws IOException, ServletException {

           HttpServletRequest httpreq = (HttpServletRequest) request;
           HttpServletResponse httpres = (HttpServletResponse) response;

           HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(
                       (HttpServletResponse) response);
           String logonStrings = config.getInitParameter("logonStrings");
           String includeStrings = config.getInitParameter("includeStrings");
           String redirectPath = httpreq.getContextPath()
                       + config.getInitParameter("redirectPath");
           String disabletestfilter = config.getInitParameter("disabletestfilter");

           if (disabletestfilter.toUpperCase().equals("Y")) {
                 chain.doFilter(request, response);
                 return;
           }
           String[] logonList = logonStrings.split(";");
           String[] includeList = includeStrings.split(";");
           Object user = httpreq.getSession().getAttribute("userinfo");
           if (user == null) {
                 if (!this.isContains(httpreq.getRequestURI(), includeList)) {
                       chain.doFilter(request, response);
                       return;
                 }
                 if (this.isContains(httpreq.getRequestURI(), logonList)) {
                       chain.doFilter(request, response);
                       return;
                 }
                 wrapper.sendRedirect(redirectPath);

           } else {
                 chain.doFilter(request, response);
           }
     }

     public void destroy() {
           this.config = null;
     }

     public void init(FilterConfig filterConfig) throws ServletException {
           this.config = filterConfig;
     }
}


3.2配置 Servlet 過濾器
在web.xml中:
        <filter>
           <filter-name>SessionFilter</filter-name>
           <filter-class>net.pms.web.filter.SessionFilter</filter-class>
           <init-param>
                 <param-name>logonStrings</param-name>
                 <param-value>login.jsp</param-value>
           </init-param>
           <init-param>
                 <param-name>includeStrings</param-name>
                 <param-value>.jsp;.html</param-value>
           </init-param>
           <init-param>
                 <param-name>redirectPath</param-name>
                 <param-value>/login.jsp</param-value>
           </init-param>
           <init-param>
                 <param-name>disabletestfilter</param-name>
                 <param-value>N</param-value>
           </init-param>
     </filter>
      <filter-mapping>
           <filter-name>SessionFilter</filter-name>
           <url-pattern>/*</url-pattern>
     </filter-mapping>
其中引數logonStrings,登陸頁面
includeStrings,過濾頁面引數
redirectPath,沒有登陸轉向頁面
disabletestfilter,過濾器是否有效。
----------------------------------------------------------------------------------------------------
4.1字符集過濾類:
package net.pms.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
*
* @author jfish
* @since 2006.1.12
*
*/
public class SetCharacterEncodingFilter implements Filter {


     protected String encoding = null;

     protected FilterConfig filterConfig = null;

     protected boolean ignore = true;

     public void destroy() {

           this.encoding = null;
           this.filterConfig = null;

     }

     public void doFilter(
           ServletRequest request,
           ServletResponse response,
           FilterChain chain)
           throws IOException, ServletException {

           // Conditionally select and set the character encoding to be used
           if (ignore || (request.getCharacterEncoding() == null)) {
                 String encoding = selectEncoding(request);
                 if (encoding != null)
                       request.setCharacterEncoding(encoding);
           }

           // Pass control on to the next filter
           chain.doFilter(request, response);

     }

     public void init(FilterConfig filterConfig) throws ServletException {

           this.filterConfig = filterConfig;
           this.encoding = filterConfig.getInitParameter("encoding");
           String value = filterConfig.getInitParameter("ignore");
           if (value == null)
                 this.ignore = true;
           else if (value.equalsIgnoreCase("true"))
                 this.ignore = true;
           else if (value.equalsIgnoreCase("yes"))
                 this.ignore = true;
           else
                 this.ignore = false;

     }

     protected String selectEncoding(ServletRequest request) {

           return (this.encoding);

     }

}
4.2
在web.xml中配置如下:
<filter>
    <filter-name>Set Character Encoding</filter-name>
    <filter-class>net.pms.web.filter.SetCharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>GBK</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>Set Character Encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
不過,在spring中帶有此過濾器
在web.xml中配置如下:
    <filter>
           <filter-name>encodingFilter</filter-name>
           <filter-class>
                 org.springframework.web.filter.CharacterEncodingFilter
           </filter-class>
           <init-param>
                 <param-name>encoding</param-name>
                 <param-value>GBK</param-value>
           </init-param>
           <init-param>
                 <param-name>forceEncoding</param-name>
                 <param-value>true</param-value>
           </init-param>
     </filter>
      <filter-mapping>
           <filter-name>encodingFilter</filter-name>
           <url-pattern>*.html</url-pattern>
     </filter-mapping>
     <filter-mapping>
           <filter-name>encodingFilter</filter-name>
           <url-pattern>*.jsp</url-pattern>
     </filter-mapping>