Spring MVC中各個filter的用法

http://liuluo129.iteye.com/blog/1965268

過濾器相關類的結構

spring mvc的org.springframework.web.filter包下的Java文件以下:html


類的結構以下:web

AbstractRequestLoggingFilter及其子類 

  AbstractRequestLoggingFilter類定義了兩個方法beforeRequest和afterRequest分別用於設定過濾先後執行的操做,它有三個子類,分別是CommonsRequestLoggingFilter、ServletContextRequestLoggingFilter和Log4jNestedDiagnosticContextFilter,這三個子類分別實現了各自的beforeRequest和afterRequest。其中,CommonsRequestLoggingFilter在過濾先後分別打印出一段debug的信息;ServletContextRequestLoggingFilter在過濾先後分別向日志文件中寫入一段日誌信息,日誌文件可由log4j.properties等指定;Log4jNestedDiagnosticContextFilter則將日誌信息存儲到NDC中,NDC採用了一個相似棧的機制來push和pot上下文信息,每個線程都獨立地儲存上下文信息,好比說一個servlet就能夠針對 每個request建立對應的NDC,儲存客戶端地址等信息。spring

CharacterEncodingFilter

該過濾器是配置編碼格式的,在web.xml中設置以下:緩存

Xml代碼  收藏代碼
<filter>  
  <filter-name>springCharacterEncodingFilter</filter-name>  
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
  <init-param>  
     <param-name>forceEncoding</param-name>  
     <param-value>true</param-value>  
  </init-param>  
  <init-param>  
     <param-name>encoding</param-name>  
     <param-value>UTF-8</param-value>  
  </init-param>  
</filter>  
<filter-mapping>  
   <filter-name>springCharacterEncodingFilter</filter-name>  
   <url-pattern>/*</url-pattern>  
</filter-mapping>  

HiddenHttpMethodFilter

html中form表單只支持GET與POST請求,而DELETE、PUT等method並不支持,spring3添加了一個過濾器,能夠將這些請求轉換爲標準的http方法,使得支持GET、POST、PUT與DELETE請求。能夠配置以下:tomcat

Xml代碼   收藏代碼
<filter>  
    <filter-name>HiddenHttpMethodFilter</filter-name>  
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>  
    <init-param>  
        <param-name>methodParam</param-name>  
        <param-value>_method_</param-value>  
    </init-param>  
</filter>  
<filter-mapping>  
    <filter-name>HiddenHttpMethodFilter</filter-name>  
    <url-pattern>/*</url-pattern>  
</filter-mapping>  

 

在頁面的form表單中設置method爲Post,並添加一個以下的隱藏域:服務器

  <input type="hidden" name="_method" value="put" />session

查看HiddenHttpMethodFilter源碼mvc

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {  
        String paramValue = request.getParameter(methodParam);  
        if("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {  
            String method = paramValue.toUpperCase(Locale.ENGLISH);  
            HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);  
            filterChain.doFilter(wrapper, response);  
        } else  
        {  
            filterChain.doFilter(request, response);  
        }  
}  

由源碼能夠看出,filter只對Post方法進行過濾,且須要添加參數名爲_method的隱藏域,也能夠設置其餘參數名,好比想設置爲_method_,能夠在HiddenHttpMethodFilter配置類中設置初始化參數: app

Xml代碼   收藏代碼
<filter>  
     <filter-name>HiddenHttpMethodFilter</filter-name>  
     <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>  
     <init-param>  
        <param-name>methodParam</param-name>  
        <param-value>_method_</param-value>  
     </init-param>  
</filter>   

HttpPutFormContentFilter

由HiddenHttpMethodFilter可知,html中的form的method值只能爲post或get,咱們能夠經過HiddenHttpMethodFilter獲取put表單中的參數鍵值對,而在Spring3中獲取put表單的參數鍵值對還有另外一種方法,即便用HttpPutFormContentFilter過濾器。post

HttpPutFormContentFilter過濾器的做爲就是獲取put表單的值,並將之傳遞到Controller中標註了method爲RequestMethod.put的方法中。

與HiddenHttpMethodFilter不一樣,在form中不用添加參數名爲_method的隱藏域,且method沒必要是post,直接寫成put,但該過濾器只能接受enctype值爲application/x-www-form-urlencoded的表單,也就是說,在使用該過濾器時,form表單的代碼必須以下:

<form action="" method="put" enctype="application/x-www-form-urlencoded">  

......  

</form>  

配置以下:

<filter>  
   <filter-name>httpPutFormcontentFilter</filter-name>  
   <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>  
</filter>  
<filter-mapping>  
   <filter-name>httpPutFormContentFilter</filter-name>  
   <url-pattern>/*</url-pattern>  
</filter-mapping>  

ShallowEtagHeaderFilter

ShallowEtagHeaderFilter是spring提供的支持ETag的一個過濾器,所謂ETag是指被請求變量的實體值,是一個能夠與Web資源關聯的記號,而Web資源能夠是一個Web頁,也能夠是JSON或XML文檔,服務器單獨負責判斷記號是什麼及其含義,並在HTTP響應頭中將其傳送到客戶端,如下是服務器端返回的格式:

ETag:"50b1c1d4f775c61:df3"  

客戶端的查詢更新格式是這樣的:

If-None-Match : W / "50b1c1d4f775c61:df3"  

   若是ETag沒改變,則返回狀態304而後不返回,這也和Last-Modified同樣。

   ShallowEtagHeaderFilter會將JSP等的內容緩存,生成MD5的key,而後在response中做爲Etage的header返回給客戶端。下次客戶端對相同的資源(或者說相同的url)發出請求時,客戶端會將以前生成的key做爲If-None-Match的值發送到server端。 Filter會客戶端傳來的值和服務器上的作比較,若是相同,則返回304;不然,將發送新的內容到客戶端。

查看ShallowEtagHeaderFilter的源碼以下:

 

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException{  
  ShallowEtagResponseWrapper responseWrapper = new ShallowEtagResponseWrapper(response, null);  
  filterChain.doFilter(request, responseWrapper);  
  // 由此可知,服務器仍會處理請求  
  byte[] body = responseWrapper.toByteArray();  
  int statusCode = responseWrapper.getStatusCode();  
   
  if (isEligibleForEtag(request, responseWrapper, statusCode, body)) {  
    String responseETag = generateETagHeaderValue(body);  
    response.setHeader(HEADER_ETAG, responseETag);  
   
    String requestETag = request.getHeader(HEADER_IF_NONE_MATCH);  
    if (responseETag.equals(requestETag)) {  
      if (this.logger.isTraceEnabled()) {  
        this.logger.trace("ETag [" + responseETag + "] equal to If-None-Match, sending 304");  
      }  
      response.setStatus(304);  
    }  
    else {  
      if (this.logger.isTraceEnabled()) {  
        this.logger.trace("ETag [" + responseETag + "] not equal to If-None-Match [" + requestETag + "], sending normal response");  
      }  
      copyBodyToResponse(body, response);  
    }  
  }  
  else {  
    if (this.logger.isTraceEnabled()) {  
      this.logger.trace("Response with status code [" + statusCode + "] not eligible for ETag");  
    }  
    copyBodyToResponse(body, response);  
  }  
}  

由源碼可知,ShallowEtagHeaderFilter只能根據結果判斷是否從新向客戶端發送數據,並不會不處理請求,所以節省帶寬,而不能提升服務器性能。

配置ShallowEtagHeaderFilter的代碼以下:

 

<filter>    
   <filter-name>shallowEtagHeaderFilter</filter-name>    
   <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</fliter-class>    
</filter>    
<filter-mapping>    
   <filter-name>shallowEtagHeaderFilter</filter-name>    
   <servlet-name>spring</servlet-name>    
</filter-mapping>  

RequestContextFilter

這是在Spring2.0時添加的類,經過LocaleContextHolder和RequestContextHolder把Http request對象基於LocalThread綁定到請求提供服務的線程上。如今通常使用DispatcherServlet這個中央分發器。如今RequestContextFilter過濾器主要用於第三方的Servlet,如JSF的FacesServlet。在Spring2.5以前都是使用該過濾器配置。配置以下:

 

<filter>    
    <filter-name>RequestContextFilter</filter-name>    
    <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>    
</filter>    
<filter-mapping>    
    <filter-name>RequestContextFilter</filter-name>    
    <servlet-name>Faces Servlet</servlet-name>    
</filter-mapping>  

DelegatingFilterProxy

該類其實並不能說是一個過濾器,它的原型是FilterToBeanProxy,即將Filter做爲spring的bean,由spring來管理。該類提供了在web.xml和application context之間的聯繫。

Proxy for a standard Servlet 2.3 Filter, delegating to a Spring-managed bean that implements the Filter interface. 

有如下幾個參數能夠設置:

(1) contextAttribute,使用委派Bean的範圍,其值必須從org.springframework.context.ApplicationContext.WebApplicationContext中取得,默認值是session;其餘可選的有request、globalSession和application

(2) targetFilterLifecycle,是否調用Filter的init和destroy方法,默認爲false。

(3)targetBeanName,被代理的過濾器的bean的名字,該bean的類必須實現Filter接口。

在web.xml中配置以下:

<filter>  
   <filter-name>testFilter</filter-name>  
   <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
   <init-param>  
      <param-name>targetBeanName</param-name>  
      <param-value>spring-bean-name</param-value>  
   </init-param>  
   <init-param>  
      <param-name>contextAttribute</param-name>  
     <param-value>session</param-value>  
   </init-param>  
   <init-param>  
      <param-name>targetFilterLifecycle</param-name>  
      <param-value>false</param-value>  
   </init-param>  
</filter>          
<filter-mapping>  
   <filter-name>testFilter</filter-name>  
   <url-pattern>/*</url-pattern>  
</filter-mapping>  

 testBean是被spring容器管理的對象,對象的類實現了Filter接口。或者能夠不用配置這個參數,這樣spring容器中全部實現了Filter接口的類都被代理,實際就是把Servlet容器中的filters同spring容器中的bean關聯起來,方便spring進行管理。

若是不配置DelegatingFilterProxy,則因爲filter比bean先加載,也就是spring會先加載filter指定的類到container中,這樣filter中注入的spring bean就爲null了。若是將filter中加入DelegatingFilterProxy類,"targetFilterLifecycle"指明做用於filter的全部生命週期。原理是,DelegatingFilterProxy類是一個代理類,全部的請求都會首先發到這個filter代理,而後再按照"filter-name"委派到spring中的這個bean。

此外,spring bean實現了Filter接口,但默認狀況下,是由spring容器來管理其生命週期的(不是由tomcat這種服務器容器來管理)。若是設置"targetFilterLifecycle"爲True,則spring來管理Filter.init()和Filter.destroy();若爲false,則這兩個方法失效。

在Spring Security中就是使用該類進行設置。即在web.xml中配置該過濾器,而後在spring security相關的配置中設置相應的過濾器bean。可是該類是spring-web包下的類,不屬於Spring Security類。

相關文章
相關標籤/搜索