1. 程式人生 > >Filter介紹,執行順序,例項

Filter介紹,執行順序,例項

Filter介紹

Filter可認為是Servlet的一種“變種”,它主要用於對使用者請求進行預處理,也可以對HttpServletResponse進行後處理,是個典型的處理鏈。它與Servlet的區別在於:它不能直接向用戶生成響應。完整的流程是:Filter對使用者請求進行預處理,接著將請求交給Servlet進行處理並生成響應,最後Filter再對伺服器響應進行後處理。

Filter有如下幾個用處。

  • 在HttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest。
  • 根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和資料。
  • 在HttpServletResponse到達客戶端之前,攔截HttpServletResponse。
  • 根據需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和資料。

Filter有如下幾個種類。

  • 使用者授權的Filter:Filter負責檢查使用者請求,根據請求過濾使用者非法請求。
  • 日誌Filter:詳細記錄某些特殊的使用者請求。
  • 負責解碼的Filter:包括對非標準編碼的請求解碼。
  • 能改變XML內容的XSLT Filter等。
  • Filter可負責攔截多個請求或響應;一個請求或響應也可被多個請求攔截。

建立一個Filter只需兩個步驟:

  • 建Filter處理類;
  • web.xml檔案中配置Filter。

下面先介紹一個簡單的記錄日誌的Filter,這個Filter負責攔截所有的使用者請求,並將請求的資訊記錄在日誌中。

LogFilter過濾器類

package com.ljq.servlet;

import java.io.IOException;

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

publicclass LogFilter implements Filter {
// FilterConfig可用於訪問Filter的配置資訊private FilterConfig config;

// 實現初始化方法publicvoid init(FilterConfig config) {
this.config = config;
}

// 實現銷燬方法publicvoid destroy() {
this.config =null;
}

// 執行過濾的核心方法publicvoid doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// ---------下面程式碼用於對使用者請求執行預處理---------
// 獲取ServletContext物件,用於記錄日誌 ServletContext context =this.config.getServletContext();
long before = System.currentTimeMillis();
System.out.println(
"開始過濾...");
// 將請求轉換成HttpServletRequest請求 HttpServletRequest hrequest = (HttpServletRequest) request;
// 記錄日誌 context.log("Filter已經截獲到使用者的請求地址: "+ hrequest.getServletPath());
// Filter只是鏈式處理,請求依然放行到目的地址 chain.doFilter(request, response);

// ---------下面程式碼用於對伺服器響應執行後處理---------long after = System.currentTimeMillis();
// 記錄日誌 context.log("過濾結束");
// 再次記錄日誌 context.log("請求被定位到"+ hrequest.getRequestURI() +"所花的時間為: "+ (after - before));
}

}

web.xml

<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><filter><filter-name>LogFilter</filter-name><filter-class>com.ljq.servlet.LogFilter</filter-class></filter><filter-mapping><filter-name>LogFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

上面程式實現了doFilter()方法,實現該方法就可實現對使用者請求進行預處理,也可實現對伺服器響應進行後處理——它們的分界線為是否呼叫了chain.doFilter(),執行該方法之前,即對使用者請求進行預處理;執行該方法之後,即對伺服器響應進行後處理。

在上面的請求Filter中,僅在日誌中記錄請求的URL,對所有的請求都執行chain.doFilter (request,reponse)方法,當Filter對請求過濾後,依然將請求傳送到目的地址。如果需要檢查許可權,可以在Filter中根據使用者請求 的HttpSession,判斷使用者許可權是否足夠。如果許可權不夠,直接呼叫重定向即可,無須呼叫chain.doFilter(request,reponse)方法。

下面是一個例項:

package com.ljq.servlet;

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.HttpSession;

publicclass AuthorityFilter implements Filter {
private FilterConfig config;

// 實現初始化方法publicvoid init(FilterConfig config) {
this.config = config;
}

// 實現銷燬方法publicvoid destroy() {
this.config =null;
}

// 執行過濾的核心方法publicvoid doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// 獲取該Filter的配置引數 String encoding = config.getInitParameter("encoding");
String login
= config.getInitParameter("login");

// 設定request編碼用的字符集 request.setCharacterEncoding(encoding);
HttpServletRequest req
= (HttpServletRequest) request;
HttpSession session
= req.getSession();
// 獲取客戶請求的路徑 String requestPath = req.getServletPath();


// 如果session範圍的user為null,即表明沒有登入
// 且使用者請求的既不是登入頁面,也不是處理登入的頁面if (session.getAttribute("user") ==null&&!requestPath.endsWith(login)) {
// forward到登入頁面 request.setAttribute("tip", "您還沒有登入");
request.getRequestDispatcher(login).forward(request, response);
}
// 放行請求else {
chain.doFilter(request, response);
}
}
}

上面Filter的doFilter方法裡2行斜體字程式碼用於獲取Filter的配置引數,而程式中粗體字程式碼則是此Filter的核心,①號程式碼 按配置引數設定了request編碼所用的字符集,接下來的粗體字程式碼判斷session範圍內是否有user屬性——沒有該屬性即認為沒有登入,如果既沒有登入,而且請求地址也不是登入頁,系統直接跳轉到登入頁面。

在web.xml檔案中配置該Filter,使用init-param元素為該Filter配置引數,init-param可接受如下兩個子元素:

param-name:指定引數名。

param-value:指定引數值。

該Filter的配置片段如下:

web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><!-- 定義Filter --><filter><filter-name>authority</filter-name><filter-class>com.ljq.servlet.AuthorityFilter</filter-class><!-- 下面3個init-param元素配置了3個引數 --><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><param-name>login</param-name><param-value>/login.jsp</param-value></init-param></filter><filter-mapping><filter-name>authority</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>


<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

上面配置片段中粗體字程式碼為該Filter指定了2個配置引數,指定login為/login.jsp,這表明:如果沒有登入該應用,普通使用者只能訪問/login.jsp。只有當用戶登入該應用後才可自由訪問其他頁面。

相關推薦

Filter介紹執行順序例項

Filter介紹Filter可認為是Servlet的一種“變種”,它主要用於對使用者請求進行預處理,也可以對HttpServletResponse進行後處理,是個典型的處理鏈。它與Servlet的區別在於:它不能直接向用戶生成響應。完整的流程是:Filter對使用者請求進行預處理,接著將請求交給Servlet

spring boot filter 配置多個時執行順序

在 spring boot 配置Filter過濾器 中簡單介紹了spring boot 中如何新增過濾器,有人問到如果配置多個怎麼控制,先經過哪個過濾器,後經過哪個過濾器。在web.xml中,我們知道,執行順序是誰在前邊執行誰。 在spring boot中的F

微信約戰炸金花棋牌平臺出租Java普通代碼塊構造代碼塊靜態代碼塊區別執行順序的代碼實例

屬性 java 對象 ... 沒有 每次 class string eat 除了說微信約戰炸金花棋牌平臺出租( h5.super-mans.com Q:2012035031)普通代碼塊,靜態代碼塊,構造代碼塊的執行順序外,還有靜態方法,靜態變量等,都放在一起的話,這個

第二種方式修改python unittest的執行順序使用猴子補丁

super 之前 ima out teardown 驗證 不同的 執行順序 鏈接 1、按照測試用例的上下順序,而不是按方法的名稱的字母順序來執行測試用例。 之前的文章鏈接 之前寫的,不是猴子補丁,而是要把Test用例的類名傳到run裏面去執行,與原生的使用有一點區

sql的執行順序外連線注意點

select date(oi.pay_time) as event_date, count(distinct oi.device_id) as uv, count(*) as order_total, (select plat

一個頁面有多個script標籤時執行順序

JavaScript直譯器在執行指令碼時,是按塊執行的。通俗地說,就是瀏覽器在解析HTML文件流時,如果遇到一個script標籤,則JavaScript直譯器會等到這個程式碼塊都載入完成後,先對程式碼塊進行預編譯,然後再執行。執行完畢後,瀏覽器會繼續解析下面的HTML文件流,同時JavaSc

golang 全域性執行順序執行全域性變數執行init

package utils import "fmt" var Age int var Name string // Age Nane 是全域性變數 func init(){ fmt.Println("init 包的初始化 init()。。。") Age = 100

SQL 的執行順序記錄一下。

雖然看過,但是在專案中遇到一個SQL,要求給使用者按投票數排序,票數相等時按照先達到票數的時間排序,一開始竟然不會寫????後來從網上找了一圈 SQL UID,SUM(VOTE) AS VOTES FROM TABLE WHERE STAR=? GROUP BY UID ORDER BY VOTES D

異常處理 try...catch...finally 執行順序 以及對返回值得影響

異常處理 try...catch...finally 執行順序, 以及對返回值得影響 結論:1、不管有沒有出現異常,finally塊中程式碼都會執行;2、當try和catch中有return時,finally仍然會執行;3、finally是在return後面的表示式運算後執行的(此時並沒有返回運算後的值,而

JAVA 中 靜態方法非靜態方法構造方法 執行順序

一直不能理解java 中這三者的執行順序。@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

使用指令碼元素(執行順序noscript)

設定了src屬性的script元素不能含有任何內容。不能用同一個script元素既定義內嵌指令碼有引用外部指令碼。 <script src="simple.js"></script> 例子中的script元素儘管沒有任何內容,還是

try中有return語句執行return還是finally執行順序怎樣的

無論是否有異常發生,finally都會執行。 finally中常用來用清尾工作,如釋放連結等等。 示例程式碼如下: 執行到finally時,a的值為1,說明執行了一次return,確定返回值,

基於CentOS 6 系統創建邏輯卷LVM執行擴容縮減刪除等操作

靈活 硬盤 erl borde pan local lock 地址 擁有 基於CentOS 6 系統創建邏輯卷LVM,執行擴容,縮減,刪除等操作 2016-08-29 05:37:57 標簽:Linux LVM Fstab VG PV 原創作品,允許轉載,轉載時請務

分發系統expect遠程登錄執行命令傳遞參數

分發系統expect遠程登錄 執行命令自動退出 傳遞參數 分發系統:shell 上線腳本expect實現遠程傳輸文件,執行命令,系統上線等功能expect 腳本遠程登錄vim 1.expect#! /usr/bin/expectset host "192.168.91.129"

Centos環境下執行gulp顯示執行成功但找到不生成的壓縮文件

cat 大寫 div pip 沒有 span 找到 code root 舉例來說:以下是css文件夾下site.css文件為site.min.css,並且將生成的文件放在指定的目錄下 //壓縮站點css gulp.task(‘appallcss‘, funct

Libgdx Developer's Guide(Libgdx開發者手冊)-7(查詢日誌執行特定平臺程式碼的介面)

查詢 應用程式介面提供了豐富的方法來查詢執行時環境的屬性。 獲取應用型別 有時,對一些特殊案例來說,很有必要依賴於它所執行的平臺而編寫部分應用。Application.getApplicationType() 方法返回當前應用程式正在使用的平臺。  switch(Gdx

關於程序執行多程序和多執行緒的網路程式設計

程序執行緒網路 多工程式設計 : 可以有效的利用計算機資源,同時執行多個任務 程序 : 程序就是程式在計算機中一次執行的過程 程序和程式的區別: 程式是一個靜態檔案的描述,不佔計算機的系統資源 程序是一個動態的過程,佔有cpu記憶體等資源,有一定的生命週期 * 同一個程式的不同執行過程即為不同的程序

一行程式碼可以幹什麼執行之後這位程式設計師要跑路了

一款貪吃蛇遊戲,大概需要20行左右的程式碼,哪怕是一個最簡單的web頁面,也需要多行程式碼才能實現,但下面這位小夥子,卻成功的使用一行程式碼,刪除了公司的資料庫,甚至連備份檔案,都刪得乾乾淨淨,算是從刪庫到跑路的典型了。   一名叫Marco Marsala的程式設計師,是一

併發執行程序

一個是實力的體現,一個是商用的必須需求。 以往: windows: CreatThread(),_beginthred(),_beginthredexe() Linux: pthread_create() 建立執行緒 臨界區,互斥量。以往多執行緒程式碼不能跨平臺。 從C++11開始,C+

程序執行Event Loop(事件迴圈)Web Worker

執行緒,是程式執行流的最小單位。執行緒可與同屬一個程序的其他執行緒共享所擁有的全部資源,同一程序中的多個執行緒之間可以併發執行。執行緒有就緒,阻塞,執行三種基本狀態。 阮一峰大神針對程序和執行緒的類比,很是形象:計算機的核心CPU,是個工廠,時刻運轉著,工廠裡有很多個車間(程序),一個車間開工其他車間不能開