JavaWeb之Filter過濾器教程

什么是Filter過濾器灰羽?

Filter在Web開發(fā)中通常被稱為過濾器技矮,是一種用于攔截處理請求和響應的組件肢扯。它可以在請求到達目標資源之前進行攔截导梆,也可以對響應進行攔截。通過使用過濾器料按,可以對請求參數(shù)進行校驗、對響應內(nèi)容進行壓縮和加密等操作,從而提高系統(tǒng)的安全性婆殿、性能和可靠性。

過濾器可以串聯(lián)在處理請求的整個路徑中罩扇,對請求進行預處理和后處理婆芦。例如,可以過濾掉惡意請求喂饥、對請求參數(shù)進行統(tǒng)一格式化等消约。在處理響應時,可以統(tǒng)一設置響應頭员帮、對響應內(nèi)容進行壓縮等或粮。

  • Filter 過濾器它是 JavaWeb 的三大組件之一。
  • Filter 過濾器它是 JavaEE 的規(guī)范捞高。也就是接口
  • Servlet3.0可以用注解@WebFilter氯材,Servlet2.5可以使用xml文件配置。
  • Filter在配置時棠枉,和servlet一樣浓体,也可以配置通配符,例如 @WebFilter("*.do")表示攔截所有以.do結(jié)尾的請求

攔截請求常見的應用場景有: 1辈讶、權限檢查 2命浴、日記操作 3、事務管理 ……等等。

假設有一個admin目錄生闲,使用用戶登錄之后才可以訪問這個目錄下的資源媳溺。

思考:
我們知道,用戶登錄之后都會把用戶登錄的信息保存到 Session 域中碍讯。所以要檢查用戶是否登錄悬蔽,可以判斷 Session 中否包含有用戶登錄的信息即可!

<body>
  <%
    Object user = session.getAttribute("user");
    // 如果等于 null捉兴,說明還沒有登錄
    if (user == null) {
        request.getRequestDispatcher("/login.jsp").forward(request,response);
        return;
    }
  %>

<h2>這是info.jsp</h2>
</body>

結(jié)論:
這種在jsp頁面方式雖然能判斷用戶是否登錄限制資源訪問蝎困,但如果在html頁面下無法使用這種判斷方式,有了局限性倍啥,所以最好是使用Filte過濾器限制訪問禾乘。

Filter工作流程

Filter工作流程圖

Filter案例實操

Filter 過濾器的使用步驟:

1、編寫一個類去實現(xiàn) Filter 接口

2虽缕、實現(xiàn)過濾方法 doFilter()

3始藕、到 web.xml 中去配置 Filter 的攔截路徑

<body>
    這是登錄頁面。login.jsp 頁面 <br>
    <form action="http://localhost:8080/day05_cookie/login" method="get">
        用戶名:<input type="text" name="username"/> <br>
        密 碼:<input type="password" name="password"/> <br>
        <input type="submit" />
    </form>
</body>
public class AdminFilter implements Filter {
    public AdminFilter() {
        System.out.println("Filter實現(xiàn)類的構造器初始化操作...");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter過濾器初始化操作...");
    }

    /**
     * doFilter():專門用于攔截請求氮趋,過濾響應
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        var httpServletRequest = (HttpServletRequest) servletRequest;
        var session = httpServletRequest.getSession();
        var user = session.getAttribute("user");
        if (user == null) {
            //如果等于null,則沒有登錄成功
            servletRequest.getRequestDispatcher(File.separator + "login.jsp").forward(servletRequest,servletResponse);
        } else {
            //登錄成功伍派,放行當前請求和響應
            filterChain.doFilter(servletRequest,servletResponse);
        }
    }

    @Override
    public void destroy() {
        System.out.println("Filter過濾器銷毀操作...");
    }
}
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        var username = req.getAttribute("username");
        var password= req.getAttribute("password");
        if ("admin".equals(username) && "123456".equals(password)) {
            req.getSession().setAttribute("user",username);
            resp.getWriter().write("登錄成功");
        } else {
            req.getRequestDispatcher(File.separatorChar + "login.jsp").forward(req,resp);
        }
    }
}
<!-- 配置Filter過濾器 -->
<filter>
    <!-- Filter實現(xiàn)類的別名 -->
    <filter-name>adminFilter</filter-name>
    <!-- Filter實現(xiàn)類的全類名 -->
    <filter-class>com.evan.java.AdminFilter</filter-class>
</filter>
<!-- 映射當前請求到Filter實現(xiàn)類 -->
<filter-mapping>
    <!-- 當前請求的攔截路徑到哪個Filter使用 -->
    <filter-name>adminFilter</filter-name>
    <!-- 配置攔截路徑:
            / 表示請求地址是 http://ip:port/工程路徑/  映射到當前工程模塊的web目錄
            /admin/* 表示請求地址是 http:ip:port/工程路徑/admin/*
         -->
    <url-pattern>/admin/*</url-pattern>
</filter-mapping>

<!-- 配置servlet訪問 -->
<servlet>
    <servlet-name>loginServlet</servlet-name>
    <servlet-class>com.evan.java.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>loginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
</servlet-mapping>

結(jié)論:
當login.jsp登錄成功時當前請求執(zhí)行目標資源,F(xiàn)ilter檢查滿足規(guī)則則會放行剩胁,繼續(xù)執(zhí)行下一個操作诉植;當?shù)卿浭∪?zhí)行當前請求的目標資源時會被攔截跳轉(zhuǎn)到login.jsp

Filter生命周期

public class AdminFilter implements Filter {
    public AdminFilter() {
        System.out.println("1.Filter實現(xiàn)類的構造器初始化操作...");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("2.Filter過濾器初始化操作...");
    }

    /**
     * doFilter():專門用于攔截請求,過濾響應
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("3.doFilter執(zhí)行請求和響應的攔截操作...");
    }

    @Override
    public void destroy() {
        System.out.println("4.Filter過濾器銷毀操作...");
    }
}

Filter聲明周期的執(zhí)行過程:

  1. 執(zhí)行FIlter實現(xiàn)類的構造器
  2. 執(zhí)行Filter初始化方法
  3. 執(zhí)行Filter的doFilter攔截方法
  4. 執(zhí)行FIlter的銷毀方法
    步驟1和2是在web工程啟動時執(zhí)行昵观,后續(xù)web工程沒有關閉倍踪,再次執(zhí)行Filter操作會執(zhí)行步驟3,步驟3在每次攔截到請求時執(zhí)行索昂,步驟4在工程停止時執(zhí)行。

FilterConfig類

FilterConfig 類見名知義扩借,它是 Filter 過濾器的配置文件類椒惨。
Tomcat 每次創(chuàng)建 Filter對象的時候,也會同時創(chuàng)建一個 FilterConfig 類潮罪,這里包含了 Filter 配置文件的配置信息康谆。
FilterConfig 類的作用是獲取 filter 過濾器的配置內(nèi)容 :
1、獲取 Filter 的名稱 filter-name 的內(nèi)容

2嫉到、獲取在 Filter 中配置的 init-param 初始化參數(shù)

3沃暗、獲取 ServletContext 對象

public class AdminFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter過濾器初始化操作...");
        //獲取Filter的名稱filter-name的內(nèi)容
        System.out.println("filter-name值:" + filterConfig.getFilterName());
        //獲取web.xml中配置的init-param初始化參數(shù)
        System.out.println("初始化參數(shù)username的值是:" + filterConfig.getInitParameter("username"));
        //獲取ServletContext對象
        System.out.println("ServletContext對象:" + filterConfig.getServletContext());
    }
}
<!-- 配置Filter過濾器 -->
<filter>
    <!-- Filter實現(xiàn)類的別名 -->
    <filter-name>adminFilter</filter-name>
    <!-- Filter實現(xiàn)類的全類名 -->
    <filter-class>com.evan.java.AdminFilter</filter-class>
    <!-- 配置Filter初始化參數(shù)值 -->
    <init-param>
        <param-name>username</param-name>
        <param-value>admin</param-value>
    </init-param>
</filter>
<!-- 映射當前請求到Filter實現(xiàn)類 -->
<filter-mapping>
    <!-- 當前請求的攔截路徑到哪個Filter使用 -->
    <filter-name>adminFilter</filter-name>
    <!-- 配置攔截路徑:
            / 表示請求地址是 http://ip:port/工程路徑/  映射到當前工程模塊的web目錄
            /admin/* 表示請求地址是 http:ip:port/工程路徑/admin/* 映射到當前工程模塊的web目錄下的admin目錄
         -->
    <url-pattern>/admin/*</url-pattern>
</filter-mapping>

FilterChain 過濾器鏈

Filter: 過濾器 。
Chain :鏈何恶,鏈條孽锥。
FilterChain就是過濾器鏈條。


FilterChain工作流程圖
多個FilterChain執(zhí)行的特點:

1、所有Filter和目標資源默認都執(zhí)行在同一個線程中惜辑。
2唬涧、多個Filter共同執(zhí)行的時候,它們都使用同一個Request對象盛撑。

FilterChain.doFilter方法的作用:

1碎节、執(zhí)行下一個Filter過濾器(如果有Filter)
2、執(zhí)行目標資源(下一步?jīng)]有Filter執(zhí)行目標資源)
在多個Filter過濾器執(zhí)行的時候抵卫,他們執(zhí)行的優(yōu)先順序是由他們在web.xml中配置從上而下的順序決定狮荔。

案例實操
//Filter1實現(xiàn)類
public class Filter1 implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter1 前置代碼");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("Filter1 后置代碼");
    }
}

//Filter2實現(xiàn)類
public class Filter2 implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter2 前置代碼");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("Filter2 后置代碼");
    }
}
<filter>
    <filter-name>filter1</filter-name>
    <filter-class>com.evan.java.Filter1</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter1</filter-name>
    <url-pattern>/filterTest.jsp</url-pattern>
</filter-mapping>

<filter>
    <filter-name>filter2</filter-name>
    <filter-class>com.evan.java.Filter2</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>/filterTest.jsp</url-pattern>
</filter-mapping>

FilterChain的執(zhí)行結(jié)果:
Filter1 前置代碼
Filter1的線程:http-nio-8080-exec-3
Filter2 前置代碼
Filter2的線程:http-nio-8080-exec-3
filterText.jsp
Filter2 后置代碼
Filter1 后置代碼

FIilterChain的執(zhí)行順序:
先執(zhí)行Filter鏈的所有前置代碼以及doFIlter的攔截方法,然后執(zhí)行Filter鏈的所有后置代碼介粘;同時它們的都是在一個線程中按照web.xml中的filter配置的先后順序執(zhí)行殖氏。
如果采取的是注解的方式進行配置,那么過濾器鏈的攔截順序是按照全類名的先后順序排序的碗短。
如果采取的是xml的方式進行配置受葛,那么按照配置的先后順序進行排序。

Filter 的攔截路徑

  • 精確匹配
    <url-pattern>/target.jsp</url-pattern>
    以上配置的路徑偎谁,表示請求地址必須為:http://ip:port/工程路徑/target.jsp
  • 目錄匹配
    <url-pattern>/admin/*</url-pattern>
    以上配置的路徑总滩,表示請求地址必須為:http://ip:port/工程路徑/admin/*
  • 后綴名匹配
    <url-pattern>*.html</url-pattern>
    以上配置的路徑,表示請求地址必須以.html 結(jié)尾才會攔截到
    <url-pattern>*.do</url-pattern>
    以上配置的路徑巡雨,表示請求地址必須以.do 結(jié)尾才會攔截到
    <url-pattern>*.action</url-pattern>
    以上配置的路徑闰渔,表示請求地址必須以.action 結(jié)尾才會攔截到

結(jié)論:
Filter 過濾器它只關心請求的地址是否匹配,不關心請求的資源是否存在n硗8越А!

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末正蛙,一起剝皮案震驚了整個濱河市督弓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乒验,老刑警劉巖愚隧,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锻全,居然都是意外死亡狂塘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門鳄厌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荞胡,“玉大人,你說我怎么就攤上這事了嚎±崞” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長窖梁。 經(jīng)常有香客問我赘风,道長,這世上最難降的妖魔是什么纵刘? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任邀窃,我火速辦了婚禮,結(jié)果婚禮上假哎,老公的妹妹穿的比我還像新娘瞬捕。我一直安慰自己,他們只是感情好舵抹,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布肪虎。 她就那樣靜靜地躺著,像睡著了一般惧蛹。 火紅的嫁衣襯著肌膚如雪扇救。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天香嗓,我揣著相機與錄音迅腔,去河邊找鬼。 笑死靠娱,一個胖子當著我的面吹牛沧烈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播像云,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锌雀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了迅诬?” 一聲冷哼從身側(cè)響起腋逆,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侈贷,沒想到半個月后闲礼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡铐维,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了慎菲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嫁蛇。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖露该,靈堂內(nèi)的尸體忽然破棺而出睬棚,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布抑党,位于F島的核電站包警,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏底靠。R本人自食惡果不足惜害晦,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望暑中。 院中可真熱鬧壹瘟,春花似錦、人聲如沸鳄逾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雕凹。三九已至殴俱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枚抵,已是汗流浹背线欲。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俄精,地道東北人询筏。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像竖慧,于是被迫代替她去往敵國和親嫌套。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

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