過濾器原理及使用


 

過濾器

 

  Servlet過濾器可以對Servlet、JSP和HTML文件過濾。

  過濾器在實際開發中用得較多,是屬於較重點的內容。

 

Servlet過濾器的概念

  Servlet過濾器是在Java Servlet規范2.3中定義的,它能夠對Servlet容器的請求和響應對象進行檢查和修改。

  Servlet過濾器本身並不生成請求和響應對象,它只提供過濾作用。

  Servlet過濾器能夠在Servlet被調用之前檢查Request對象,修改Request Header和Request內容。

  在Servlet被調用之后檢查Response對象,修改Response Header和Response內容。

  Servlet過濾器負責過濾的Web組件可以是Servlet、JSP或HTML文件

 

Servlet過濾器的過濾過程

 

  過濾器的處理過程是一個鏈式的過程(FilterChain),即多個過濾器組成一個鏈,依次處理,最后交給過濾器之后的資源。

  其中鏈式過濾過程中也可以直接給出響應,即返回,而不是向后傳遞。

 

Filter接口

  所有的Servlet過濾器類都必須實現javax.servlet.Filter接口。

  這個接口含有3個過濾器類必須實現的方法:

  init(FilterConfig):這是Servlet過濾器的初始化方法,Servlet容器創建Servlet過濾器實例后將調用這個方法。

  在這個方法中可以讀取web.xml文件中Servlet過濾器的初始化參數。

  比如web.xml中聲明:

    <filter>
        <filter-name>MyFilter1</filter-name>
        <filter-class>com.mengdd.filter.MyFilter1</filter-class>
        <init-param>
            <param-name>hello</param-name>
            <param-value>world</param-value>
        </init-param>
        <init-param>
            <param-name>name</param-name>
            <param-value>zhang</param-value>
        </init-param>
    </filter>

  在MyFilter1中:

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        String paramValue1 = filterConfig.getInitParameter("hello");
        String paramValue2 = filterConfig.getInitParameter("name");

        ServletContext context = filterConfig.getServletContext();
    }

 

  注意:一旦一個過濾器啟動失敗,會導致整個Web應用啟動失敗。

 

  doFilter(ServletRequest, ServletResponse, FilterChain):這個方法完成實際的過濾操作。

  當客戶請求訪問與過濾器關聯的URL時,Servlet容器將先調用過濾器的doFilter方法

  FilterChain參數用於訪問后續過濾器。

  在這個方法中調用chain.doFilter()方法,用於調用過濾器鏈中后續過濾器的doFilter()方法,假如沒有后續過濾器,那么就把客戶請求傳給相應的Web組件。

  如果在這個方法中沒有調用chain.doFilter()方法,客戶請求不會到達所訪問的Web組件。

 

  destroy():Servlet容器在銷毀過濾器實例前調用該方法,在這個方法中可以釋放Servlet過濾器占用的資源。

 

過濾器的例子

  比如用戶登錄之后,將信息傳入session中,之后的其他頁面入口可能需要檢測是否存在session,以避免直接在地址欄輸入地址訪問頁面而造成的session中沒有用戶信息的情況,如果在每個Servlet或JSP前面都要判斷session中是否有相應屬性,會有很多的代碼重復,用過濾器可以很好地解決這個問題,如果不含登錄信息,即轉向到用戶登錄頁面。

package com.mengdd.filter;

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.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginFilter implements Filter {

    @Override
    public void destroy() {

        // 由Web容器調用
        // 在這里進行資源釋放
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("doFilter invoked!");

        HttpServletRequest req = (HttpServletRequest) request;
        HttpSession session = req.getSession();// 獲取請求的session,如果沒有,會創建一個新的session

        // 對不需要進行過濾的請求進行事先篩選操作
        String requestURI = req.getRequestURI();
        if (requestURI.endsWith("login.jsp")
                || requestURI.endsWith("LoginServlet")) {
            chain.doFilter(request, response);
            return;
        }

        if (null == session.getAttribute("username")) {

            // session中沒有用戶名屬性,說明是新的session,之前沒有登錄
            // 用過濾器完成了整個Web應用中未登錄情況的處理
            ((HttpServletResponse) response).sendRedirect("login.jsp");

            // 這里注意,由於本filter配置的<url-pattern>/*</url-pattern>是針對所有地址的
            // 所以請求發送到login.jsp頁面也會需要先經過此過濾器,造成重定向的遞歸重復調用
            // 所以需要對請求的URI進行判斷
        }
        else {
            // 按照過濾鏈繼續往下走
            chain.doFilter(request, response);
        }

    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        System.out.println("Filter init");
        // 過濾器是非常特殊的一個Servlet,它會在容器啟動的時候得到初始化
        // 過濾器的啟動失敗會導致Web應用啟動失敗

    }

}
LoginFilter.java

 

  過濾器的配置和Servlet的配置相似,只不過URL配置的是要過濾請求的URL:

    <!-- filter一般配置在所有的Servlet上面 -->
    <filter>
        <filter-name>LoginFilter</filter-name>
        <filter-class>com.mengdd.filter.LoginFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- /*表示所有地址,即所有請求都會被送到這個過濾器 -->

 

  可以做很多練習例子,比如可以創建一個NoteFilter過濾器,它可以拒絕列在黑名單上的客戶訪問留言簿。(黑名單通過過濾器參數設置)。  

  也可以利用Filter進行一些關鍵詞修改替換的工作。

 

串聯過濾器的例子

  幾點說明:

  1.串聯過濾器的順序是按照在web.xml中的配置順序為准的。

    <filter>
        <filter-name>MyFilter1</filter-name>
        <filter-class>com.mengdd.filter.MyFilter1</filter-class>
        <init-param>
            <param-name>hello</param-name>
            <param-value>world</param-value>
        </init-param>
        <init-param>
            <param-name>name</param-name>
            <param-value>zhang</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>MyFilter2</filter-name>
        <filter-class>com.mengdd.filter.MyFilter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter1</filter-name>
        <url-pattern>/InfoServlet</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>MyFilter2</filter-name>
        <url-pattern>/InfoServlet</url-pattern>
    </filter-mapping>
串聯過濾器配置

 

  2.在Servlet過濾器中能訪問application范圍內的共享數據:先調用FilterConfig的getServletContext()方法獲得ServletContext,再調用ServletContext的getAttribute()方法來獲得application范圍內的共享數據。

package com.mengdd.filter;

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;

public class MyFilter1 implements Filter {

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        System.out.println("MyFilter1 --> doFilter invoked!");
        System.out.println("MyFilter1 --> before chain.doFilter()");
        chain.doFilter(request, response);
        System.out.println("MyFilter1 --> after chain.doFilter()");

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        String paramValue1 = filterConfig.getInitParameter("hello");
        String paramValue2 = filterConfig.getInitParameter("name");

        ServletContext context = filterConfig.getServletContext();
    }

}
MyFilter1
package com.mengdd.filter;

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;

public class MyFilter2 implements Filter{

    @Override
    public void destroy() {
        
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        
        System.out.println("MyFilter2 --> doFilter invoked!");
        System.out.println("MyFilter2 --> before chain.doFilter()");
        chain.doFilter(request, response);
        System.out.println("MyFilter2 --> after chain.doFilter()"); 
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }

}
MyFilter2

 

 

參考資料

  聖思園張龍老師Java Web視頻教程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM