過濾器(Filter)
過濾器實際上就是對web資源進行攔截,做一些處理后再交給下一個過濾器或servlet處理
通常都是用來攔截request進行處理的,也可以對返回的進行攔截處理
大概流程圖如下
應用場景
自動登錄
統一設置編碼格式
訪問權限控制
敏感字符過濾等
創建Filter
在Servlet中我們一般都會對request和中的字符集編碼進行配置,如果Servlet過多字符集編碼發生變化時修改起碼會很麻煩,這些通用的字符集編碼配置等工作我們可以放到Filter中來實現。
下面我們來創建一個處理字符集編碼的Filter。
右鍵包名—>new ---->Filter
輸入過濾器名稱,跟創建Servlet一樣,這里我們直接使用 @ 注解,不再去web,xml中進行配置了。
創建完成后默認代碼,可以看到,實現了Filter接口,實現了3個方法。3個方法的作用已經在注釋中寫清楚了。
package filter;
import javax.servlet.*;
import javax.servlet..;
import java.io.;
@( = “”)
public class Filter {
public void destroy() {
/銷毀時調用/
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
/*過濾方法 主要是對request和response進行一些處理,然后交給下一個過濾器或Servlet處理*/
chain.doFilter(req, resp);//交給下一個過濾器或servlet處理
}
public void init(FilterConfig config) throws ServletException {
/*初始化方法 接收一個FilterConfig類型的參數 該參數是對Filter的一些配置*/
}
配置Filter
可配置的屬性有這些
常用配置項
配置要攔截的資源
以指定資源匹配。例如"/index.jsp"以目錄匹配。例如"/servlet/*"以后綴名匹配,例如"*.jsp"通配符,攔截所有web資源。"/*"
** **
配置初始化參數,跟Servlet配置一樣
例如
initParams = {
@WebInitParam(name = "key",value = "value")
}
**
配置攔截的類型,可配置多個。默認為.REQUEST**
例如
dispatcherTypes = {DispatcherType.ASYNC,DispatcherType.ERROR}
其中是個枚舉類型,有下面幾個值
FORWARD,//轉發的
INCLUDE,//包含在頁面的
REQUEST,//請求的
ASYNC,//異步的
ERROR;//出錯的
下面我們來對 代碼進行一下修改
package filter;
import javax.servlet.*;
import javax.servlet..;
import javax.servlet..;
import java.io.;
@( = “”,
= "/",/通配符()表示對所有的web資源進行攔截/
= {
@(name = “charset”, value = “utf-8”)/這里可以放一些初始化的參數/
})
public class Filter {
private String ;
private String charset;
public void destroy() {
/*銷毀時調用*/
System.out.println(filterName + "銷毀");
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
/*過濾方法 主要是對request和response進行一些處理,然后交給下一個過濾器或Servlet處理*/
System.out.println(filterName + "doFilter()");
req.setCharacterEncoding(charset);
resp.setCharacterEncoding(charset);
chain.doFilter(req, resp);
}

public void init(FilterConfig config) throws ServletException {
/*初始化方法 接收一個FilterConfig類型的參數 該參數是對Filter的一些配置*/
filterName = config.getFilterName();
charset = config.getInitParameter("charset");
System.out.println("過濾器名稱:" + filterName);
System.out.println("字符集編碼:" + charset);
}
這樣一個簡單的字符集編碼處理的過濾器就完成了
我們看看執行打印的結果
需要注意的是
過濾器是在服務器啟動時就會創建的,只會創建一個實例,常駐內存,也就是說服務器一啟動就會執行Filter的init( config)方法.
當Filter被移除或服務器正常關閉時,會執行destroy方法
多個Filter的執行順序
在我們的請求到達Servle之間是可以經過多個Filter的,一般來說,建議Filter之間不要有關聯,各自處理各自的邏輯即可。這樣,我們也無需關心執行順序問題。
如果一定要確保執行順序,就要對配置進行修改了,執行順序如下
在web.xml中,filter執行順序跟的順序有關,先聲明的先執行使用注解配置的話,filter的執行順序跟名稱的字母順序有關,例如AFilter會比BFilter先執行如果既有在web.xml中聲明的Filter,也有通過注解配置的Filter,那么會優先執行web.xml中配置的Filter
我們寫個小例子看一下
新建3個Filter,加上之前的一共四個
其中和是通過注解聲明的
注解配置
@WebFilter(filterName = "CharsetFilter", urlPatterns = "/*",/*通配符(*)表示對所有的web資源進行攔截*/ initParams = { @WebInitParam(name = "charset", value = "utf-8")/*這里可以放一些初始化的參數*/ })
ABFilter
@WebFilter(filterName = "ABFilter",urlPatterns = "/*")
AFilter和BFilter是在web.xml配置的。
執行順序跟的順序無關
的順序才決定執行順序
AFilter filter.AFilter BFilter filter.BFilter <!--這里BFilter在AFilter之前--> <filter-mapping> <filter-name>BFilter</filter-name> <url-pattern>/filter.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>AFilter</filter-name> <url-pattern>/filter.jsp</url-pattern> </filter-mapping>
每個Filter添加了打印語句,如下
以為例
package filter;
import javax.servlet.*;
import javax.servlet..;
import java.io.;
@( = “”, = “/*”)
public class Filter {
private String ;
public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { System.out.println(filterName + " doFilter()"); chain.doFilter(req, resp); } public void init(FilterConfig config) throws ServletException { filterName= config.getFilterName(); System.out.println("過濾器名稱:" + filterName +" init"); }
下面我們來訪問filter.jsp看看打印結果
可以看到,執行結果符合預期。
BFilter和AFilter是在web.xml中聲明的,且BFilter的在前,故BFilter在AFilter之前執行。
和是通過注解聲明的,故他倆在BFilter和AFilter之后執行,但是的名稱以A開頭,故在之前執行
訪問權限控制小例子##
下面我們寫一個訪問控制權限控制的小例子。
我們在瀏覽一些網站經常有這個情況,沒有登錄時是不允許我們訪其主頁的,只有登錄過后才能訪問。
下面我們就用Filter簡單實現一下。
需求分析
登錄時將登錄的賬號密碼保存到cookie中,下次訪問時攜帶賬號和密碼,過濾器中進行校驗用戶沒有登錄直接訪問主頁時,要跳轉到登錄頁面登錄過濾器不對登錄頁面進行過濾
我們先來看一下項目結構
這里主要看一下的代碼
我們在中對非登錄頁面的其他jsp都會進行過濾,判斷cookie中是否攜帶了account和pwd。
如果有這兩個數據表示之前登錄過,那么對數據進行校驗,正確的話就進行下一個操作。
否則的話,跳轉到登錄界面
package filter;
import javax.servlet.*;
import javax.servlet..;
import javax.servlet.http.Cookie;
import javax.servlet.http.;
import javax.servlet.http.;
import java.io.;
@( = “”, = “*.jsp”, = {})
public class Filter {
public void destroy() {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { System.out.println("LoginFilter doFilter"); HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String url = request.getRequestURI(); System.out.println("請求的url:" + url); /*登錄頁面不需要過濾*/ int idx = url.lastIndexOf("/"); String endWith = url.substring(idx + 1); if (!endWith.equals("login.jsp")) { /*不是登錄頁面 進行攔截處理*/ System.out.println("不是登錄頁面,進行攔截處理"); if (!isLogin(request)) { System.out.println("沒有登錄過或者賬號密碼錯誤,跳轉到登錄界面"); response.sendRedirect("login.jsp"); } else { System.out.println("已經登錄,進行下一步"); chain.doFilter(req, resp); } } else { System.out.println("是登錄頁面,不進行攔截處理"); chain.doFilter(req, resp); } } private boolean isLogin(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); String account = ""; String pwd = ""; if (cookies != null && cookies.length > 0) { for (Cookie cookie : cookies) { if (cookie.getName().equals("account")) { account = cookie.getValue(); } else if (cookie.getName().equals("pwd")) { pwd = cookie.getValue(); } } } if (account.equals("") || pwd.equals("")) { return false; } else if (account.equals("yzq") && pwd.equals("123")) { return true; } return false; } public void init(FilterConfig config) throws ServletException { System.out.println("LoginFilter init"); }
執行效果
可以看到,我們在沒有登錄的情況下直接去訪問index.jsp頁面時會自動跳轉到登錄頁面,在登錄成功后,再次直接訪問index頁面則可以訪問。
下面是demo
訪問控制demo
如果你覺得本文對你有幫助,麻煩動動手指頂一下,可以幫助到更多的開發者,如果文中有什么錯誤的地方,還望指正,轉載請注明轉自喻志強的博客 ,謝謝!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。