Servlet過濾器簡介
Servlet過濾器實際上就是一個標準的java類,這個類通過實現Filter介面獲得過濾器的功能。它在jsp容器啟動的時候通過web.xml設定檔被系統載入。
Servlet過濾器在接收到使用者請求的時候被調用,當伺服器接收到使用者的請求的時候,依次調用配置好的過濾器,完成後將執行請求所要求的servlet,而servlet執行後的響應,則先通過配置好的過濾器後再發送給使用者。
過濾器的用途:
1、使用者認證和授權管理。
2、統計web應用的訪問量和訪問命中率,產生訪問報告。
3、實現web應用的Tlog功能。
4、實現資料壓縮功能。
5、對傳輸的資料進行加密。
6、實現xml檔案的XSLT的轉換。
一個servlet過濾器其實是一個java類,它的實現需要分為兩個部分,java類自身以及在web.xml檔案中的XML描述。對於filter介面,該介面由一對描述的生命週期的方法init(),destroy(),init方法在伺服器初始化過濾器的時候會調用,而destory方法在伺服器關閉的時候會調用,還有一個行為方法doFilter方法會在執行過濾操作的時候調用.
Servlet過濾器的配置
Servet過濾器需要通過web應用程式部署描述符檔案web.xml來部署到應用中。配置如下
複製代碼 代碼如下:
< filter>
<filter-name>Filtername</filter-name>
<filter-class>com.filter.Filter/class</filter-class>
<init-param>
<param-name>file</param-name>
<param-value>filename</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Filtername</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
下面是樣本:
使用過濾器解決中文編碼問題:
由於java的預設編碼方式是ISO-8859-1,而通常編寫中文應用程式的時候都是使用GB2312或gbk編碼方式。在這種情況下,應在頁面的首部通過<%@ page contentType="text/html;charset=gbk"%>命令來指定頁面的編碼方式。這樣中文頁面就可以正常地顯示了。但是如果頁面中村中表單。如一個input輸入框,如果訪問者在其中輸入中文,又提交到某個servlet進行處理的話,java會首先按ISO-5589-1的預設對這段文本進行編碼,然後交給servet處理,處理後的文本將還是以ISO-5589-1編碼方式村中,如果這個時候這個文本返回一個按GBK編碼來顯示的頁面,由於編碼格式的不同,很顯然得不到正確的顯示結果。
對於編碼方式的解決方案有很多種,這裡主要介紹用過濾器來解決中文編碼問題:
複製代碼 代碼如下:
public class CharacterEncodingFilter implements Filter {
private FilterConfig config;
private String encoding = "ISO8859_1";
public void destroy() {
config = null;
}
public void doFilter(ServletRequest request, ServletResponse response ,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding(encoding);
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
this.config = config;
String s = config.getInitParameter("encoding");
if(s!=null){
encoding = s;
}
}
}
然後在是XML的配置:
複製代碼 代碼如下:
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>com.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
最後是encoding.jsp的編寫?
複製代碼 代碼如下:
使用者名稱:<c:out value="${param.username}" default="none"></c:out><br>
密碼:<c:out value="${param.userpassword}" default="none"></c:out><br>
<form action="MyJsp.jsp" method="post">
使用者名稱:<input type="test" name="username"> <br>
密碼:<input type="password" name="userpassword"><br>
<input type="submit" value="提交">
</form>
啟動tomcat,訪問encoding.jsp,輸入“張山”就可以看到,經過過濾器後,頁面可以正常顯示伺服器傳出的資訊。。。
使用過濾器記錄使用者訪問日誌
對於有些項目,它對於使用者的每次訪問都要有詳細的記錄。那麼這是使用記錄日誌是一個非常好的解決方案,使用過濾器就可以很輕鬆地對每次使用者的訪問進行記錄。但是由於同一個訪問者在同一個時段訪問網站不同的頁面時,不能重複記錄日誌,否則日誌將會在很短的時間內塞滿伺服器的硬碟空間。於是這裡可以利用session對象來判斷使用者的每次會話,在一次會話中,過濾器只會記錄一次。
下面編寫LogFilter類,這個過濾器主要負責記錄使用者的訪問記錄:
複製代碼 代碼如下:
package com.filter;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.Date;
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.HttpSession;
import com.sun.org.apache.bcel.internal.generic.NEW;
public class LoginFilter implements Filter{
private FilterConfig config =null;
private String filename = null;
private String filtername = null;
public void destroy() {
this.config = null;
this.filename = null;
this.filtername = null;
}
public void doFilter(ServletRequest request , ServletResponse response,
FilterChain chain ) throws IOException, ServletException {
HttpServletRequest hRequest = (HttpServletRequest) request;
// 擷取session對象
HttpSession session = hRequest.getSession();
// 先判斷session中的LOGGED是否有值,如沒有則說明是新的請求
if(null==session.getAttribute("LOGGED")){
session.setAttribute("LOGGED", "yes"); // 設定LOGGED的值為yes,防止同一會話重複記錄
File file = new File(this.filename);
if(!file.exists())
file.createNewFile(); // 判斷檔案是否存在,如果不存在,就建立一個新的
/*
* 建立日誌記錄內容logContent包括訪問者的IP, 訪問的頁面URL和訪問的時間以及日誌過濾器的名字
*/
String logContent = hRequest.getRemoteHost()+"->"+hRequest.getRequestURI()+" Logged "+getTime()+" By s"+this.filtername+"\r\n";
RandomAccessFile rf = new RandomAccessFile(this.filename,"rw"); // 建立一個隨機檔案操作對象
rf.seek(rf.length()); // 將寫入指標指向檔案的尾部,rf.length()獲得檔案的長度,seek檔案長度這麼長得距離正好是檔案的尾部
rf.writeBytes(logContent); // 將日誌寫入到檔案中去
rf.close(); // 關閉檔案
}
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
this.config = config;
this.filename = this.config.getInitParameter("file");
this.filtername = this.config.getFilterName();
}
// 擷取時間
private String getTime(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
return sdf.format(new Date());
}
}
這裡利用session來限制同一個會話只會記錄一次日誌,而不管這個會話中的訪問者訪問了多少個頁面,在第一次訪問的時候,由於session的LOGGED是空的,所以這個時候記錄日誌並把LOGGED設定為yes,這樣第二次判斷的時候將不會執行記錄日誌。
然後在來配置XML:
複製代碼 代碼如下:
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.filter.LoginFilter</filter-class>
<init-param>
<param-name>file</param-name>
<param-value>D:/log.txt</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置好XML後,訪問跟目錄下地任何檔案,都會可以在D:/log.txt檔案中得到訪問者的記錄。