Servlet之過濾器總結--Filter

            前言

                          我們知道實際開發中我們可能有這種需要:對於某個網站來說需要限制一些ip對該網站的訪

                     問。例如教育網站,通常我們只能訪問到它的首頁,至於教務管理的頁面,不在該教育網段範

                     圍的IP是不能訪問到的。

                          另外,在實際的項目中我們可能涉及到字符的轉碼,如果在每個頁面都去設置轉碼會十分的

                    麻煩,這時就可以使用Filter來解決了。

             Filter

                            Servlet過濾器Fileter是一個小型的web組件,它們通過攔截請求和響應,以便查看、提取或

                      以某種方式操作客戶端和服務器之間交換的數據,實現“過濾”的功能。Filter通常封裝了一些功

                      能的web組件,過濾器提供了一種面向對象的模塊化機制,將任務封裝到一個可插入的組件中,

                      Filter組件通過配置文件來聲明,並動態的代理。

                            簡單來說Servlet的Filter是:

                            ●  聲明式的:通過在web.xml配置文件中聲明,允許添加、刪除過濾器,而無需改動任何

                                 應用程序代碼或jsp頁面。

                           ●  靈活的:過濾器可用於客戶端的直接調用執行預處理和後期的處理工作,通過過濾鏈可

                                 以實現一些靈活的功能。

                           ●  可移植的:由於現今各個web容器都是以Servlet的規範進行設計的,因此Servlet過濾器

                                 同樣是跨容器的。

                           ●  可重用的:基於其可移植性和聲明式的配置方式,Filter是可重用的。

                            總的來說,Servlet的過濾器是通過一個配置文件來靈活的聲明的模塊化可重用組件。

                       過濾器動態的截獲傳入的請求和傳出的響應,在不修改程序代碼的情況下,透明的添加或刪除

                       他們。其獨立於任何平臺和web容器。

               Filter體系結構

                               如其名字所暗示的一樣,Servlet過濾器用於攔截傳入的請求和傳出的響應,並監視、修改

                         處理web工程中的數據流。過濾器是一個可插入的自由組件。

                               web資源可以不配置過濾器、也可以配置單個過濾器,也可以配置多個過濾器,形成一個

                         過濾器鏈。Filter接受用戶的請求,並決定將請求轉發給鏈中的下一個組件,或者終止請求

                         直接向客戶端返回一個響應。如果請求被轉發了,它將被傳遞給鏈中的下一個過濾器(以

                         web.xml過濾器的配置順序爲標準)。這個請求在通過過濾鏈並被服務器處理之後,一個響應

                         將以相反的順序通過該鏈發送回去。這樣,請求和響應都得到了處理。

                              Filter可以應用在客戶端和Servlet之間、servlet和serlvet或jsp之間,以及jsp之間。並且

                         可以通過配置信息,靈活的使用那個過濾器。

                Filter工作原理

                               基於Filter體系結構的描述,我們可以看出Filter的工作原理,簡單的通過一幅流程圖加以

                            演示:

                     

                              客戶端瀏覽器在訪問web服務器的某個具體資源的時候,經過過濾器1中code1代碼塊的相

                           關處理之後,將request請求傳遞給過濾鏈中的下一個過濾器2,(過濾鏈的順序以配置文件

                           中的順序爲基準)過濾器2處理完之後,request就傳遞的Servlet完成相應的邏輯。

                              返回響應的過程類似,只是過濾鏈的順序相反,這裏就不多說了。

                  Filter的創建過程

                                  在具體去實現FIlter之前,先去看看Filter的源碼,簡單的看看實現Filter需要做的事,從

                            源碼中可以看出,要編寫一個過濾器必須實現Filter接口。實現其接口規定的方法。

                                   ★  實現javax.servlet.Filter接口

                                   ★ 實現init方法,讀取過濾器的初始化參數

                                   ★ 實現doFilter方法,完成對請求或響應的過濾

                                   ★ 調用FilterChain接口對象的doFilter方法,向後續的過濾器傳遞請求或響應

                                  一個簡單的字符編碼處理的過濾器實現:

package com.kiritor.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;  public class EncodeFilter implements Filter{     //定義替換後的字符集,從過濾器的配置參數中讀取     String newCharSet;     public void destroy(){     }     public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException      {         //處理請求字符集         request.setCharacterEncoding(newCharSet);                  //傳遞給下一個過濾器。這裏沒有下一個,作爲過濾器的規則和良好的編程習慣,應該加上         chain.doFilter(request,response);          //處理響應字符集         response.setContentType("text/html;charset="+newCharSet);     }          public void init(FilterConfig filterConfig)throws ServletException      {         //從過濾器的配置中獲得初始化參數,如果沒有就使用默認值         if(filterConfig.getInitParameter("newcharset")!=null)         {             newCharSet = filterConfig.getInitParameter("newcharset");         }         else             newCharSet = "GB2312";     } }
                           這裏對於過濾器對請求和響應的具體"過濾"過程,筆者就不多提了。

                Filter的配置

                                Filter是一個可插入的web組件,必須在web.xml文件中配置纔有效,那麼Filter是如何

                           配置的呢?針對上述字符編碼的Filter,配置信息如下:                 

 <!-- 指定過濾器的名字,初始化參數等信息 -->   <filter>     <display-name>EncodeFilter</display-name>     <filter-name>EncodeFilter</filter-name>     <filter-class>com.kiritor.filter.EncodeFilter</filter-class>   </filter>   <!-- 指定過濾器的URL關聯/*表示所有的 -->   <filter-mapping>     <filter-name>EncodeFilter</filter-name>     <url-pattern>/*</url-pattern>   </filter-mapping>
                                 url-pattern配置詳解
                            在web.xml文件中,以下語法用於定義映射:

                               l 以”/’開頭和以”/*”結尾的是用來做路徑映射的。

                               l 以前綴”*.”開頭的是用來做擴展映射的。

                               l “/” 是用來定義default servlet映射的。

                               l 剩下的都是用來定義詳細映射的。比如: /aa/bb/cc.action

                               所以,爲什麼定義”/*.action”這樣一個看起來很正常的匹配會錯?

                           因爲這個匹配即屬於路徑映射,也屬於擴展映射,導致容器無法判斷。

                Filter編程實例演示:

                               接下來筆者將演示一個IP過濾器,過濾掉某個具體的ip,並將客戶端的訪問記錄做

                           一個日誌文件記錄。實際的過程如下:

                               這裏筆者保留了字符處理的Filter,打印信息,以便更好的理解過濾鏈的執行情況。

                               編寫IP過濾器:IPFilter

package com.kiritor.filter;  import java.io.IOException; import java.net.InetAddress;  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 com.kiritor.logUtil.LogUtil;  /**  * Servlet Filter implementation class IPFilter  */ public class IPFilter implements Filter {      /**      * Default constructor.       */     private String ip;     private FilterConfig config;     public IPFilter() {         // TODO Auto-generated constructor stub     }      /**      * @see Filter#destroy()      */     public void destroy() {         // TODO Auto-generated method stub     }      /**      * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)      */     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {         HttpServletRequest req= (HttpServletRequest)request;         HttpServletResponse res = (HttpServletResponse)response;         // 獲取客戶請求lP         /*下面那條註釋語句得到的是IPV6地址,          * 客戶端和服務器在同一臺機子上是得不到ipv4地址的**/         //String remoteIP = request.getRemoteAddr();         //以這種方式獲取IPv4地址         InetAddress inet = InetAddress.getLocalHost();         LogUtil.logRecord(inet.getHostAddress());         //System.out.println(remoteIP);         if (inet.getHostAddress().equals("192.168.0.3")){                          req.getRequestDispatcher("ipErr.jsp").forward(request, response);                      } else {             chain.doFilter(request, response);// 調用過濾鏈上的下一個過濾器         }         System.out.println("IPFilter處理");         chain.doFilter(request, response);     }      /**      * @see Filter#init(FilterConfig)      */     public void init(FilterConfig fConfig) throws ServletException {         //從過濾器的配置中獲得初始化參數,如果沒有就使用默認值         this.config = fConfig;         if(fConfig.getInitParameter("ipinfo")!=null)         {             ip = fConfig.getInitParameter("ipinfo");         }         else             ip = "192.168.0.3";     }  }   
                        接下來進行配置:

        

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">   <display-name>Servlet_Filter</display-name>   <welcome-file-list>     <welcome-file>index.html</welcome-file>     <welcome-file>index.htm</welcome-file>     <welcome-file>index.jsp</welcome-file>     <welcome-file>default.html</welcome-file>     <welcome-file>default.htm</welcome-file>     <welcome-file>default.jsp</welcome-file>   </welcome-file-list>   <filter>     <display-name>EncodeFilter</display-name>     <filter-name>EncodeFilter</filter-name>     <filter-class>com.kiritor.filter.EncodeFilter</filter-class>     <init-param>         <param-name>newcharset</param-name>         <param-value>gb2312</param-value>     </init-param>   </filter>   <filter-mapping>     <filter-name>EncodeFilter</filter-name>     <url-pattern>/*</url-pattern>   </filter-mapping>   <filter>     <display-name>IPFilter</display-name>     <filter-name>IPFilter</filter-name>     <filter-class>com.kiritor.filter.IPFilter</filter-class>     <init-param>         <param-name>ipinfo</param-name>         <param-value>192.168.0.3</param-value>     </init-param>   </filter>   <filter-mapping>     <filter-name>IPFilter</filter-name>     <url-pattern>/*</url-pattern>   </filter-mapping> </web-app>
                               接下來簡單的日誌文件操作: 
package com.kiritor.logUtil;  import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date;  import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest;  /**  * @author Kiritor  * 2013-6-15 上午8:21:19  * 功能:實現IP訪問的日誌記錄  */ public  class LogUtil {    public static void logRecord(String ip)    {        try{            FileOutputStream out = new FileOutputStream("D:\\log.txt",true);                        Date date = new Date();            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd a  hh:mm:ss");            String str = f.format(date);                        String runningMsg = str+"--->\r\n"+                  ip +"登錄"                     +"\r\n";            out.write(runningMsg.getBytes());            out.close();                    }catch(Exception e){            e.printStackTrace();        }    } } 
                           ok,我們看看實際的運行效果吧!
         

                           日誌文檔信息記錄如下:        

2013-06-15 上午  08:56:59---> 192.168.0.3登錄 2013-06-15 上午  09:00:08---> 192.168.0.3登錄 
                              好了,對於Servlet過濾器的學習就到這個地方了,當然上述實例只是Filter的簡單運用

                      十分的靈活與方便。

                       參考文檔:

                        http://www.ibm.com/developerworks/cn/java/j-pj2ee10/index.html

                                                                                                                                     By      Kiritor

                                                                                                                                     2013 /06 /15


                   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章