咱們知道實際開發中咱們可能有這種須要:對於某個網站來講須要限制一些ip對該網站的訪html
問。例如教育網站,一般咱們只能訪問到它的首頁,至於教務管理的頁面,不在該教育網段範java
圍的IP是不能訪問到的。web
另外,在實際的項目中咱們可能涉及到字符的轉碼,若是在每一個頁面都去設置轉碼會十分的編程
麻煩,這時就可使用Filter來解決了。瀏覽器
Servlet過濾器Fileter是一個小型的web組件,它們經過攔截請求和響應,以便查看、提取或服務器
以某種方式操做客戶端和服務器之間交換的數據,實現「過濾」的功能。Filter一般封裝了一些功app
能的web組件,過濾器提供了一種面向對象的模塊化機制,將任務封裝到一個可插入的組件中,jsp
Filter組件經過配置文件來聲明,並動態的代理。ide
簡單來講Servlet的Filter是:模塊化
● 聲明式的:經過在web.xml配置文件中聲明,容許添加、刪除過濾器,而無需改動任何
應用程序代碼或jsp頁面。
● 靈活的:過濾器可用於客戶端的直接調用執行預處理和後期的處理工做,經過過濾鏈可
以實現一些靈活的功能。
● 可移植的:因爲現今各個web容器都是以Servlet的規範進行設計的,所以Servlet過濾器
一樣是跨容器的。
● 可重用的:基於其可移植性和聲明式的配置方式,Filter是可重用的。
總的來講,Servlet的過濾器是經過一個配置文件來靈活的聲明的模塊化可重用組件。
過濾器動態的截獲傳入的請求和傳出的響應,在不修改程序代碼的狀況下,透明的添加或刪除
他們。其獨立於任何平臺和web容器。
如其名字所暗示的同樣,Servlet過濾器用於攔截傳入的請求和傳出的響應,並監視、修改
處理web工程中的數據流。過濾器是一個可插入的自由組件。
web資源能夠不配置過濾器、也能夠配置單個過濾器,也能夠配置多個過濾器,造成一個
過濾器鏈。Filter接受用戶的請求,並決定將請求轉發給鏈中的下一個組件,或者終止請求
直接向客戶端返回一個響應。若是請求被轉發了,它將被傳遞給鏈中的下一個過濾器(以
web.xml過濾器的配置順序爲標準)。這個請求在經過過濾鏈並被服務器處理以後,一個響應
將以相反的順序經過該鏈發送回去。這樣,請求和響應都獲得了處理。
Filter能夠應用在客戶端和Servlet之間、servlet和serlvet或jsp之間,以及jsp之間。而且
能夠經過配置信息,靈活的使用那個過濾器。
基於Filter體系結構的描述,咱們能夠看出Filter的工做原理,簡單的經過一幅流程圖加以
演示:
客戶端瀏覽器在訪問web服務器的某個具體資源的時候,通過過濾器1中code1代碼塊的相
關處理以後,將request請求傳遞給過濾鏈中的下一個過濾器2,(過濾鏈的順序以配置文件
中的順序爲基準)過濾器2處理完以後,request就傳遞的Servlet完成相應的邏輯。
返回響應的過程相似,只是過濾鏈的順序相反,這裏就很少說了。
在具體去實現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是一個可插入的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配置詳解
由於這個匹配即屬於路徑映射,也屬於擴展映射,致使容器沒法判斷。
接下來筆者將演示一個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