Filter也稱之為過濾器,如下圖所示,瀏覽器在訪問web資源時折砸,如果服務(wù)器配置了過濾器,則該訪問在獲取到web資源之間會經(jīng)過過濾器沙峻,在訪問完后又會回到過濾器睦授,最后經(jīng)過服務(wù)器才返回瀏覽器。通過這種方法摔寨,我們可以實現(xiàn)權(quán)限訪問控制去枷、過濾敏感詞匯、壓縮響應(yīng)信息等一些高級功能是复。
1.Filter開發(fā)步驟
開發(fā)過濾器很簡單删顶,只需要經(jīng)過編寫java類,進(jìn)行相關(guān)配置淑廊,就可以使用了逗余。
1.1 編寫java類
Servlet API中提供了一個Filter接口,我們通過實現(xiàn)該接口重寫里面的方法就可以實現(xiàn)過濾器的功能。
import java.io.IOException;
import java.util.Enumeration;
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 HelloFilter implements Filter{
// 創(chuàng)建實例
public HelloFilter(){
System.out.println("1. 創(chuàng)建過濾器實例");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("2. 執(zhí)行過濾器初始化方法");
// 獲取過濾器在web.xml中配置的初始化參數(shù)
String encoding = filterConfig.getInitParameter("encoding");
System.out.println(encoding);
// 獲取過濾器在web.xml中配置的初始化參數(shù) 的名稱
Enumeration<String> enums = filterConfig.getInitParameterNames();
while (enums.hasMoreElements()){
// 獲取所有參數(shù)名稱:encoding蒋纬、path
String name = enums.nextElement();
// 獲取名稱對應(yīng)的值
String value = filterConfig.getInitParameter(name);
System.out.println(name + "\t" + value);
}
}
// 過濾器業(yè)務(wù)處理方法: 在請求到達(dá)servlet之前先進(jìn)入此方法處理公用的業(yè)務(wù)邏輯操作
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("3. 執(zhí)行過濾器業(yè)務(wù)處理方法");
// 放行 (去到Servlet)
// 如果有下一個過濾器猎荠,進(jìn)入下一個過濾器,否則就執(zhí)行訪問servlet
chain.doFilter(request, response);
System.out.println("5. Servlet處理完成蜀备,又回到過濾器");
}
@Override
public void destroy() {
System.out.println("6. 銷毀過濾器實例");
}
}
1.2 進(jìn)行相關(guān)配置
在web.xml中添加如下內(nèi)容:
<filter>
<!-- 過濾器名稱 -->
<filter-name>hello_filter</filter-name>
<!-- 過濾器對應(yīng)的實現(xiàn)類 -->
<filter-class>cn.itcast.a_filter_hello.HelloFilter</filter-class>
<!-- 過濾器初始化參數(shù) -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>path</param-name>
<param-value>c:/...</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hello_filter</filter-name>
<!-- 過濾器過濾模式关摇,/* 表示過濾所有資源 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
** 輔助servlet:**
public class ServletTest extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("I'm a test servlet!");
}
}
當(dāng)我們兩次訪問輔助測試servlet時效果如下:
2.FilterChain
即Filter鏈,在一個web應(yīng)用中碾阁,可以開發(fā)編寫多個Filter输虱,這些Filter組合起來稱之為一個Filter鏈。web服務(wù)器根據(jù)Filter在web.xml文件中的注冊順序脂凶,決定先調(diào)用哪個Filter宪睹,當(dāng)?shù)谝粋€Filter的doFilter方法被調(diào)用時愁茁,web服務(wù)器會創(chuàng)建一個代表Filter鏈的FilterChain對象傳遞給該方法。在doFilter方法中亭病,開發(fā)人員如果調(diào)用了FilterChain對象的doFilter方法鹅很,則web服務(wù)器會檢查FilterChain對象中是否還有filter,如果有罪帖,則調(diào)用第2個filter促煮,如果沒有,則調(diào)用目標(biāo)資源整袁。
3.Filter生命周期
通過上面實例菠齿, 可以看到在啟動tomcat服務(wù)器時就執(zhí)行了過濾器的構(gòu)造方法和初始化方法,在每次訪問servlet時都會進(jìn)入doFilter()方法坐昙,訪問完servlet方法后又會返回到doFilter()方法绳匀,而destroy()方法只在停止服務(wù)器時才會執(zhí)行一次。
下圖通過時序圖展示了有兩個過濾器的Filter執(zhí)行流程:
4.Filter映射
<filter-mapping>元素用于設(shè)置一個 Filter 所負(fù)責(zé)攔截的資源炸客。一個Filter攔截的資源可通過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑
<filter-name>子元素用于設(shè)置filter的注冊名稱疾棵。該值必須是在<filter>元素中聲明過的過濾器的名字
<filter-name>hello_filter</filter-name>
<url-pattern>設(shè)置 filter 所攔截的請求路徑(過濾器關(guān)聯(lián)的URL樣式)
<!-- 攔截指定的jsp -->
<url-pattern>/index.jsp</url-pattern>
<url-pattern>/list.jsp</url-pattern>
<!-- 攔截所有的jsp -->
<url-pattern>*.jsp</url-pattern>
<servlet-name>指定過濾器所攔截的Servlet名稱。
<!-- 3. 根據(jù)servlet的內(nèi)部名稱攔截 -->
<servlet-name>IndexServlet</servlet-name>
<!-- 攔截指定的servlet -->
<url-pattern>/index</url-pattern>
<dispatcher>指定過濾器所攔截的資源被 Servlet 容器調(diào)用的方式嚷量,可以是REQUEST,INCLUDE,FORWARD和ERROR之一陋桂,默認(rèn)REQUEST。用戶可以設(shè)置多個<dispatcher> 子元素用來指定 Filter 對資源的多種調(diào)用方式進(jìn)行攔截蝶溶。
<!-- 攔截直接訪問的請求或者重定向的資源 -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher> 子元素可以設(shè)置的值及其意義:
REQUEST:當(dāng)用戶直接訪問頁面時嗜历,Web容器將會調(diào)用過濾器。如果目標(biāo)資源是通過RequestDispatcher的include()或forward()方法訪問時抖所,那么該過濾器就不會被調(diào)用梨州。
INCLUDE:如果目標(biāo)資源是通過RequestDispatcher的include()方法訪問時,那么該過濾器將被調(diào)用田轧。除此之外暴匠,該過濾器不會被調(diào)用。
FORWARD:如果目標(biāo)資源是通過RequestDispatcher的forward()方法訪問時傻粘,那么該過濾器將被調(diào)用每窖,除此之外,該過濾器不會被調(diào)用弦悉。
ERROR:如果目標(biāo)資源是通過聲明式異常處理機(jī)制調(diào)用時窒典,那么該過濾器將被調(diào)用。除此之外稽莉,過濾器不會被調(diào)用瀑志。