Java ---Filter過(guò)濾器

?????Filter可以視作是servlet的加強(qiáng)版董朝,主要用作對(duì)用戶的請(qǐng)求進(jìn)行預(yù)處理周偎,或者對(duì)返回給客戶端的結(jié)果進(jìn)行再次加工,是一個(gè)典型的鏈?zhǔn)教幚砟J健1酒?jiǎn)單介紹filter的基本使用方法蛮穿,主要涉及以下內(nèi)容:

  • Filter的背景知識(shí)
  • 使用Filter的流程
  • Filter的生命周期
  • 一個(gè)完整的實(shí)例

一、Filter的簡(jiǎn)單介紹
?????Filter在英文中是過(guò)濾器的意思宋舷,當(dāng)然在此處的使用也是完美的切合了它的意思绪撵,我們使用filter的主要目的就是完成一個(gè)過(guò)濾的作用∽r穑可以在一個(gè)請(qǐng)求到達(dá)servlet之前,將其截取進(jìn)行邏輯判斷幻碱,然后決定是否放行到請(qǐng)求的servlet绎狭。也可以在一個(gè)response到達(dá)客戶端之前,截取結(jié)果進(jìn)行邏輯判斷褥傍,然后決定是否允許返回給客戶端儡嘶。所以filter有如下幾個(gè)種類:

  • 用戶授權(quán)的filter:filter負(fù)責(zé)判斷用戶是否有權(quán)限請(qǐng)求該頁(yè)面,給予過(guò)濾判斷
  • 日志filter:截取某個(gè)用戶在本網(wǎng)站上的所有請(qǐng)求恍风,記錄軌跡
  • 負(fù)責(zé)解碼的filter:規(guī)定處理本次請(qǐng)求的解碼方式

最后需要注意的是蹦狂,一個(gè)filter過(guò)濾器可以加在多個(gè)servlet控制器上,當(dāng)然多個(gè)filter過(guò)濾器也是可以加在一個(gè)servlet控制器上的朋贬。由此也是可以看出來(lái)凯楔,我們使用filter往往是對(duì)一些公共的操作進(jìn)行處理,例如:判斷用戶權(quán)限锦募,解碼本次請(qǐng)求等摆屯,還比如,我們的web應(yīng)用中某些頁(yè)面是需要用戶登錄后才能訪問(wèn)的糠亩,以往我們都是在每個(gè)servlet頁(yè)面加上判斷控制虐骑,導(dǎo)致代碼冗余,有了filter赎线,我們可以定義一個(gè)實(shí)現(xiàn)了filter的過(guò)濾器廷没,讓需要判斷是否登錄的頁(yè)面都加上這么一個(gè)過(guò)濾器,可以大大降低代碼的冗余程度垂寥。

二颠黎、Filter的使用流程
?????在Java中如果想要自定義一個(gè)filter過(guò)濾器的話,需要繼承Javax.servlet.Filter接口矫废,這個(gè)接口中只有三個(gè)方法:

default void init(FilterConfig filterConfig)
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3)
default void destroy()

其中init和destroy方法是有默認(rèn)實(shí)現(xiàn)的盏缤,也就是我們不是必須重寫這兩個(gè)方法,但是doFilter 這個(gè)方法是一個(gè)核心的方法蓖扑,是我們必須要實(shí)現(xiàn)的唉铜。首先我們看init方法的作用,這個(gè)方法是用來(lái)初始化filter實(shí)例的律杠,也就是當(dāng)用戶請(qǐng)求了某個(gè)攔截器而此攔截器又匹配了某個(gè)過(guò)濾器潭流,此時(shí)web容器就會(huì)定位到該過(guò)濾器然后創(chuàng)建該filter類的實(shí)例對(duì)象并調(diào)用此實(shí)例的init方法竞惋,完成初始化工作。對(duì)于destroy方法毋庸置疑就是在過(guò)濾器執(zhí)行結(jié)束的時(shí)候調(diào)用灰嫉,主要完成對(duì)一些資源的釋放拆宛。下面主要看dofilter這個(gè)方法。
?????doFilter方法是filter接口中的核心方法讼撒,一旦創(chuàng)建完該過(guò)濾器的實(shí)例之后浑厚,會(huì)執(zhí)行dofilter方法,所有的過(guò)濾邏輯都是在此方法中進(jìn)行的根盒。主要有三個(gè)參數(shù)钳幅,第一個(gè)參數(shù)是一個(gè)ServletRequest對(duì)象,HttpServletRequest繼承于此接口炎滞,當(dāng)用戶請(qǐng)求某個(gè)攔截器的時(shí)候敢艰,檢測(cè)到此請(qǐng)求存在過(guò)濾器,于是會(huì)封裝好本次請(qǐng)求的相關(guān)數(shù)據(jù)册赛,傳遞給dofilter的ServletRequest參數(shù)钠导,ServletResponse參數(shù)的來(lái)源和ServletRequest是一樣的,都是由客戶端封裝過(guò)來(lái)的森瘪。至于第三個(gè)參數(shù)牡属,這是一個(gè)FilterChain處理鏈,詳細(xì)的介紹等說(shuō)明了web.xml中配置filter之后柜砾。
?????第一步如上湃望,創(chuàng)建一個(gè)繼承自filter接口的類,并實(shí)現(xiàn)其中的三個(gè)方法痰驱。第二步是在web.xml中配置該類用于過(guò)濾哪些攔截器证芭。web.xml代碼如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <!--定義filter-->
    <filter>
        <filter-name>isLogin</filter-name>
        <filter-class>Test_f.MyFilter</filter-class>
    </filter>

    <!--定義filter攔截的地址-->
    <filter-mapping>
        <filter-name>isLogin</filter-name>
        <url-pattern>/a</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>isLogin</filter-name>
        <url-pattern>/b</url-pattern>
    </filter-mapping>
</web-app>

如上述的代碼,我們需要兩個(gè)操作担映,首先是定義一個(gè)filter废士,指定了該filter的name和相對(duì)應(yīng)的過(guò)濾器類。然后我們可以通過(guò)filter-mapping映射過(guò)濾器和URL蝇完,此處使用了兩個(gè)映射官硝,對(duì)該過(guò)濾器指定了對(duì)路徑名為/a和/b的請(qǐng)求進(jìn)行攔截。當(dāng)然這個(gè)url-pattern元素的值可以有以下三種形式短蜕,完全匹配(/a/b等)氢架,目錄匹配(/* 、 /abc/等)朋魔,擴(kuò)展名(.a岖研,*.b等)。
?????了解了配置filter的主要操作之后,我們回去看過(guò)濾器類孙援,我們說(shuō)init方法是在首次創(chuàng)建filter實(shí)例的時(shí)候害淤,用于執(zhí)行初始化操作的,其中有個(gè)參數(shù)FilterConfig 拓售,這是當(dāng)前filter的配置信息窥摄,其中方法如下:

String getFilterName();

ServletContext getServletContext();

String getInitParameter(String var1);

Enumeration<String> getInitParameterNames();

其實(shí)在創(chuàng)建filter實(shí)例的時(shí)候,web容器會(huì)將此實(shí)例對(duì)應(yīng)在web.xml中的配置信息讀取并封裝成一個(gè)FilterConfig 對(duì)象傳遞給init方法础淤,getFilterName方法就是我們?cè)趙eb.xml中配置的filter-name崭放,getServletContext會(huì)獲取當(dāng)前servlet的上下文,當(dāng)我們?cè)诙xfilter的時(shí)候使用<init-param>來(lái)定義一些初始化參數(shù)的時(shí)候值骇,就可以使用此方法來(lái)獲取這些初始化參數(shù)莹菱。getInitParameterNames方法用于獲取所有初始化參數(shù)的枚舉集合。這樣我們?cè)趇nit方法中就可以獲取這些配置參數(shù)吱瘩,初始化filter實(shí)例。
?????上面我們只定義了一個(gè)filter迹缀,如果我們對(duì)于一次請(qǐng)求需要執(zhí)行多個(gè)filter使碾,進(jìn)行過(guò)濾操作的話,web容器會(huì)在你請(qǐng)求某個(gè)URL的時(shí)候祝懂,在web.xml中找到所有匹配的filter票摇,按照注冊(cè)的順序以FilterChain 鏈的形式傳遞到方法doFilter的第三個(gè)參數(shù)中,而這個(gè)filterChain中只有一個(gè)方法:

void doFilter(ServletRequest var1, ServletResponse var2)

如果我們?cè)?void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) 方法中調(diào)用var3.doFilter(var1,var2)砚蓬,就代表此filter實(shí)例結(jié)束矢门,則web服務(wù)器會(huì)檢查FilterChain對(duì)象中是否還有filter對(duì)象(因?yàn)檫@是一個(gè)鏈,filter的數(shù)量是大于等于一的)灰蛙,如果沒(méi)有就會(huì)放行祟剔,直接調(diào)用目標(biāo)地址,如果還有filter對(duì)象摩梧,就會(huì)轉(zhuǎn)而執(zhí)行下一個(gè)filter物延。正是由于這樣的機(jī)制,我們才可以對(duì)于一個(gè)URL請(qǐng)求添加多個(gè)filter過(guò)濾器仅父。

三叛薯、一個(gè)簡(jiǎn)單的實(shí)例
下面通過(guò)一個(gè)簡(jiǎn)單的實(shí)例直觀的感受下filter過(guò)濾器的作用:

public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException{

        HttpServletRequest req = (HttpServletRequest)var1;
        HttpSession session = req.getSession();
        String state = (String)session.getAttribute("state");
        if(state.equals("1")){
            var3.doFilter(var1,var2);
        }else{
            HttpServletResponse response =  (HttpServletResponse)var2;
            response.sendRedirect("Error_page.html");
        }
    }
}
//web.xml
    <filter>
        <filter-name>isLogin</filter-name>
        <filter-class>Test_f.MyFilter</filter-class>
    </filter>

    <!--定義filter攔截的地址-->
    <filter-mapping>
        <filter-name>isLogin</filter-name>
        <url-pattern>/index.jsp</url-pattern>
    </filter-mapping>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title></title>
  </head>
  <body>
    <h1>這是index頁(yè)面</h1>
  </body>
</html>
//set.jsp
//為了使程序簡(jiǎn)單,我們采用手動(dòng)設(shè)置session
//在實(shí)際的項(xiàng)目中笙纤,當(dāng)用戶登錄之后自動(dòng)設(shè)置session
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title></title>
  </head>
  <body>
    <%pageContext.getSession().setAttribute("state","0");%>
  </body>
</html>

我們首先訪問(wèn)set.jsp頁(yè)面設(shè)置本次會(huì)話的session值耗溜,然后修改瀏覽器地址欄訪問(wèn)index.jsp頁(yè)面


這里寫圖片描述

敲下回車鍵,結(jié)果如下:

這里寫圖片描述

我們先看省容,敲下回車鍵之后抖拴,程序怎么執(zhí)行的,因?yàn)槲覀冊(cè)趙eb.xml中配置了MyFilter的攔截URL為index.jsp蓉冈,所以當(dāng)我們?cè)L問(wèn)index.jsp的時(shí)候城舞,會(huì)創(chuàng)建MyFilter 實(shí)例對(duì)象轩触,封裝配置信息到FilterConfig對(duì)象中,然后封裝request請(qǐng)求和response家夺,還有從web.xml 中讀取的FilterChain對(duì)象傳入MyFilter的doFilter方法中脱柱,我們?cè)谄渲蝎@取本次會(huì)話的session對(duì)象,取得其中的數(shù)據(jù)拉馋,如果為一放行榨为,否則跳轉(zhuǎn)到錯(cuò)誤頁(yè)面。此處的state的session值為0煌茴,我們?cè)趕et.jsp中設(shè)置的随闺,大家也可以在set.jsp頁(yè)面設(shè)置其值為1,這樣最終的結(jié)果會(huì)是這樣的:

這里寫圖片描述

上述的demo只是為了簡(jiǎn)單的演示蔓腐,其實(shí)使用filter可以完成大大的降低我們的代碼的冗余程度矩乐。這個(gè)例子是為了演示,所以很簡(jiǎn)單回论。

四散罕、Filter 的生命周期
?????當(dāng)用戶請(qǐng)求某個(gè)頁(yè)面時(shí)候,會(huì)到web.xml中匹配是否存在能夠匹配上此次請(qǐng)求的filter傀蓉,如果有封裝它的配置信息欧漱,F(xiàn)ilterChain鏈。然后調(diào)用init方法葬燎,完成初始化误甚,接著調(diào)用dofilter方法,處理核心邏輯谱净,當(dāng)此實(shí)例被銷毀的時(shí)候窑邦,會(huì)調(diào)用destroy方法。

本篇文章結(jié)束岳遥,如果有理解錯(cuò)誤奕翔,望大家指出!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末浩蓉,一起剝皮案震驚了整個(gè)濱河市派继,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捻艳,老刑警劉巖驾窟,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異认轨,居然都是意外死亡绅络,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)恩急,“玉大人杉畜,你說(shuō)我怎么就攤上這事≈怨В” “怎么了此叠?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)随珠。 經(jīng)常有香客問(wèn)我灭袁,道長(zhǎng),這世上最難降的妖魔是什么窗看? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任茸歧,我火速辦了婚禮,結(jié)果婚禮上显沈,老公的妹妹穿的比我還像新娘软瞎。我一直安慰自己,他們只是感情好拉讯,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布铜涉。 她就那樣靜靜地躺著,像睡著了一般遂唧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吊奢,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天盖彭,我揣著相機(jī)與錄音,去河邊找鬼页滚。 笑死召边,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的裹驰。 我是一名探鬼主播隧熙,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼幻林!你這毒婦竟也來(lái)了贞盯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沪饺,失蹤者是張志新(化名)和其女友劉穎躏敢,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體整葡,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡件余,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啼器。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旬渠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出端壳,到底是詐尸還是另有隱情告丢,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布更哄,位于F島的核電站芋齿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏成翩。R本人自食惡果不足惜觅捆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望麻敌。 院中可真熱鬧栅炒,春花似錦、人聲如沸术羔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)级历。三九已至释移,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寥殖,已是汗流浹背玩讳。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嚼贡,地道東北人熏纯。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像粤策,于是被迫代替她去往敵國(guó)和親樟澜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容