1. 程式人生 > >servlet中Filter介面介紹

servlet中Filter介面介紹

      過濾器是指攔截請求,並對傳給被請求資源的ServletRequest 或 ServletResponse 進行處理的一個物件。過濾器可以用於登入、加密和解密、會話檢查等等。過濾器可以配置為攔截一個或多個資源。如果同一個資源或同一組資源中應用了多個過濾器,則呼叫順序有顯示顯得比較重要,這時候就需要部署描述符(web.xml)來控制其先後順序。

       filter過濾器中使用的介面包括Filter、FilterConfig和FilterChain。每個介面中包含若干方法,接下來我們按照filter的生命週期來介紹介面及中間對應的方法。

       過濾器類必須實現javax.servlet.Filter介面。這個介面為每個過濾器暴露3個生命週期方法,init、doFilter 和 destory。

package javax.servlet;

import java.io.IOException;

/**
 * A filter is an object that performs filtering tasks on either the request to
 * a resource (a servlet or static content), or on the response from a resource,
 * or both. <br>
 * @since Servlet 2.3
 */
public interface Filter {

    /**
     * Called by the web container to indicate to a filter that it is being
     * placed into service. The servlet container calls the init method exactly
     * once after instantiating the filter. The init method must complete
     * successfully before the filter is asked to do any filtering work. <br>
     * <br>
     * The web container cannot place the filter into service if the init method
     * either<br>
     * 1.Throws a ServletException <br>
     * 2.Does not return within a time period defined by the web container
     */
    public void init(FilterConfig filterConfig) throws ServletException;

    /**
     * The <code>doFilter</code> method of the Filter is called by the container
     * each time a request/response pair is passed through the chain due to a
     * client request for a resource at the end of the chain. The FilterChain
     * passed in to this method allows the Filter to pass on the request and
     * response to the next entity in the chain.
     * <p>
     * A typical implementation of this method would follow the following
     * pattern:- <br>
     * 1. Examine the request<br>
     * 2. Optionally wrap the request object with a custom implementation to
     * filter content or headers for input filtering <br>
     * 3. Optionally wrap the response object with a custom implementation to
     * filter content or headers for output filtering <br>
     * 4. a) <strong>Either</strong> invoke the next entity in the chain using
     * the FilterChain object (<code>chain.doFilter()</code>), <br>
     * 4. b) <strong>or</strong> not pass on the request/response pair to the
     * next entity in the filter chain to block the request processing<br>
     * 5. Directly set headers on the response after invocation of the next
     * entity in the filter chain.
     **/
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    /**
     * Called by the web container to indicate to a filter that it is being
     * taken out of service. This method is only called once all threads within
     * the filter's doFilter method have exited or after a timeout period has
     * passed. After the web container calls this method, it will not call the
     * doFilter method again on this instance of the filter. <br>
     * <br>
     * 
     * This method gives the filter an opportunity to clean up any resources
     * that are being held (for example, memory, file handles, threads) and make
     * sure that any persistent state is synchronized with the filter's current
     * state in memory.
     */
    public void destroy();

}

       當過濾器啟動服務的時候,比如應用程式啟動時,servlet容器就會呼叫init方法。換句話說,不用等到呼叫與被過濾器相關的資源之後,才呼叫init方法。這個方法只調用一次,並且應該包含該過濾器的初始化程式碼。

init方法的簽名如下:

void init(FilterConfig filterConfig)

注意:servlet容器給init方法傳遞了一個FilterConfig。

FilterConfig 介面

package javax.servlet;

import java.util.Enumeration;

/**
 * A filter configuration object used by a servlet container to pass information
 * to a filter during initialization.
 */
public interface FilterConfig {

    /**
     * Returns the filter-name of this filter as defined in the deployment
     * descriptor.
     */
    public String getFilterName();

    /**
     * Returns a reference to the {@link ServletContext} in which the caller is
     * executing.
     */
    public ServletContext getServletContext();

    /**
     * Returns a <code>String</code> containing the value of the named
     * initialization parameter, or <code>null</code> if the parameter does not
     * exist.
     */
    public String getInitParameter(String name);

    /**
     * Returns the names of the filter's initialization parameters as an
     * <code>Enumeration</code> of <code>String</code> objects, or an empty
     * <code>Enumeration</code> if the filter has no initialization parameters.
     */
    public Enumeration<String> getInitParameterNames();

}

      每次呼叫與過濾器相關的資源時,servlet容器都會呼叫Filter例項的doFilter方法。該方法會收到一個ServletRequest、ServletResponse和FilterChain。

doFilter方法的簽名如下:

public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)

      doFilter的實現可以訪問ServletRequest 和 ServletResponse。因此,可以在ServletRequest中新增屬性,或者在ServletResponse中新增一個標頭,甚至可以對ServletRequest 或 ServletResponse進行修復,改變它們的行為。

    doFilter方法實現中最後一行程式碼應該是呼叫FilterChain中的doFilter方法,

FilterChain.doFilter方法簽名為

public void doFilter(ServletRequest request, ServletResponse response)

      一個資源可以與多個過濾器關聯,FilterChain.doFilter( ) 通常會引發呼叫鏈中的下一個過濾器被呼叫。在鏈中的最後一個過濾器中呼叫FilterChain.doFilter( )會引發資源本身被呼叫。如果你沒有在 Filter.doFilter( )方法實現程式碼的最後呼叫FilterChain.doFilter( )方法,那麼程式的處理將會在這裡停止,並且不會呼叫請求。

注意,doFilter方法是FilterChain介面中唯一的方法,它與Filter中的doFilter方法不同。在FilterChain中,doFilter只有兩個引數,而不是三個。

Filter中最後一個生命週期方法是destory,其方法簽名為

void destroy()

這個方法在過濾器即將終止服務之前,由Servlet呼叫,一般發生在應用程式停止的時候。

Demo

package com.filter;

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

public class HttpFilter implements Filter {

	@Override
	public void destroy() {
		System.out.println("過濾器生命終止");
	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest)arg0;
		// 列印請求的URL
		System.out.println("filter1 " + req.getRequestURL());
		arg2.doFilter(arg0, arg1);
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		System.out.println("過濾器生命開始");
		
		String filterName = arg0.getFilterName();
		System.out.println("過濾器名為 " + filterName);
		
		// 遍歷過濾器中的引數和對應值
		Enumeration<String> initParas = arg0.getInitParameterNames();
		String paraName;
		String paraValue;
		while (initParas.hasMoreElements()) {
			paraName = initParas.nextElement();
			paraValue = arg0.getInitParameter(paraName);
			System.out.println(paraName + " = " + paraValue);
		}
	}
}

部署描述符web.xml中配置為
  <filter>
    <filter-name>httpFilter</filter-name>
    <filter-class>com.filter.HttpFilter</filter-class>
   	<init-param>
   		<param-name>creater</param-name>
   		<param-value>zhangqi</param-value>
   	</init-param>
   	<init-param>
   		<param-name>createrDate</param-name>
   		<param-value>2017-05-20</param-value>
   	</init-param>
  </filter>
  <filter-mapping>
    <filter-name>httpFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

伺服器啟動時,可以在控制檯中看到
過濾器生命開始
過濾器名為 httpFilter
creater = zhangqi
createrDate = 2017-05-20

說明,過濾器是在伺服器啟動時載入,且呼叫了init方法。

然後我們訪問下初始化頁面,控制檯可以看到

filter1 http://localhost:8080/servletDemo/
說明,這個請求被過濾器攔截,過濾器打印出了請求的URL。

最後,我們停止tomcat伺服器,控制檯可以看到

過濾器生命終止
說明,伺服器停止前,服務終止時,會呼叫destory方法,銷燬過濾器物件。