• Spring MVC中各个filter的用法


    转载自:http://liuluo129.iteye.com/blog/1965268


    过滤器相关类的结构

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


    类的结构如下:

    AbstractRequestLoggingFilter及其子类 

      AbstractRequestLoggingFilter类定义了两个方法beforeRequest和afterRequest分别用于设定过滤前后执行的操作,它有三个子类,分别是CommonsRequestLoggingFilter、ServletContextRequestLoggingFilter和Log4jNestedDiagnosticContextFilter,这三个子类分别实现了各自的beforeRequest和afterRequest。其中,CommonsRequestLoggingFilter在过滤前后分别打印出一段debug的信息;ServletContextRequestLoggingFilter在过滤前后分别向日志文件中写入一段日志信息,日志文件可由log4j.properties等指定;Log4jNestedDiagnosticContextFilter则将日志信息存储到NDC中,NDC采用了一个类似栈的机制来push和pot上下文信息,每一个线程都独立地储存上下文信息,比如说一个servlet就可以针对 每一个request创建对应的NDC,储存客户端地址等信息。

    CharacterEncodingFilter

    该过滤器是配置编码格式的,在web.xml中设置如下:

    Xml代码  收藏代码
    1. <filter>  
    2.   <filter-name>springCharacterEncodingFilter</filter-name>  
    3.   <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
    4.   <init-param>  
    5.      <param-name>forceEncoding</param-name>  
    6.      <param-value>true</param-value>  
    7.   </init-param>  
    8.   <init-param>  
    9.      <param-name>encoding</param-name>  
    10.      <param-value>UTF-8</param-value>  
    11.   </init-param>  
    12. </filter>  
    13. <filter-mapping>  
    14.    <filter-name>springCharacterEncodingFilter</filter-name>  
    15.    <url-pattern>/*</url-pattern>  
    16. </filter-mapping>  

     HiddenHttpMethodFilter

    html中form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,spring3添加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求。可以配置如下:

    Xml代码  收藏代码
    1. <filter>  
    2.     <filter-name>HiddenHttpMethodFilter</filter-name>  
    3.     <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>  
    4.     <init-param>  
    5.         <param-name>methodParam</param-name>  
    6.         <param-value>_method_</param-value>  
    7.     </init-param>  
    8. </filter>  
    9. <filter-mapping>  
    10.     <filter-name>HiddenHttpMethodFilter</filter-name>  
    11.     <url-pattern>/*</url-pattern>  
    12. </filter-mapping>  

     在页面的form表单中设置method为Post,并添加一个如下的隐藏域:

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

    查看HiddenHttpMethodFilter源码

    Java代码  收藏代码
    1. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {  
    2.         String paramValue = request.getParameter(methodParam);  
    3.         if("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {  
    4.             String method = paramValue.toUpperCase(Locale.ENGLISH);  
    5.             HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);  
    6.             filterChain.doFilter(wrapper, response);  
    7.         } else  
    8.         {  
    9.             filterChain.doFilter(request, response);  
    10.         }  
    11. }  

         由源码可以看出,filter只对Post方法进行过滤,且需要添加参数名为_method的隐藏域,也可以设置其他参数名,比如想设置为_method_,可以在HiddenHttpMethodFilter配置类中设置初始化参数: 

    Xml代码  收藏代码
    1. <filter>  
    2.      <filter-name>HiddenHttpMethodFilter</filter-name>  
    3.      <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>  
    4.      <init-param>  
    5.         <param-name>methodParam</param-name>  
    6.         <param-value>_method_</param-value>  
    7.      </init-param>  
    8. </filter>   

     HttpPutFormContentFilter

    由HiddenHttpMethodFilter可知,html中的form的method值只能为post或get,我们可以通过HiddenHttpMethodFilter获取put表单中的参数键值对,而在Spring3中获取put表单的参数键值对还有另一种方法,即使用HttpPutFormContentFilter过滤器。

    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>  

    配置如下:

     

    Xml代码  收藏代码
    1. <filter>  
    2.    <filter-name>httpPutFormcontentFilter</filter-name>  
    3.    <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>  
    4. </filter>  
    5. <filter-mapping>  
    6.    <filter-name>httpPutFormContentFilter</filter-name>  
    7.    <url-pattern>/*</url-pattern>  
    8. </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的源码如下:

     

    Java代码  收藏代码
    1. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException{  
    2.   ShallowEtagResponseWrapper responseWrapper = new ShallowEtagResponseWrapper(response, null);  
    3.   filterChain.doFilter(request, responseWrapper);  
    4.   // 由此可知,服务器仍会处理请求  
    5.   byte[] body = responseWrapper.toByteArray();  
    6.   int statusCode = responseWrapper.getStatusCode();  
    7.    
    8.   if (isEligibleForEtag(request, responseWrapper, statusCode, body)) {  
    9.     String responseETag = generateETagHeaderValue(body);  
    10.     response.setHeader(HEADER_ETAG, responseETag);  
    11.    
    12.     String requestETag = request.getHeader(HEADER_IF_NONE_MATCH);  
    13.     if (responseETag.equals(requestETag)) {  
    14.       if (this.logger.isTraceEnabled()) {  
    15.         this.logger.trace("ETag [" + responseETag + "] equal to If-None-Match, sending 304");  
    16.       }  
    17.       response.setStatus(304);  
    18.     }  
    19.     else {  
    20.       if (this.logger.isTraceEnabled()) {  
    21.         this.logger.trace("ETag [" + responseETag + "] not equal to If-None-Match [" + requestETag + "], sending normal response");  
    22.       }  
    23.       copyBodyToResponse(body, response);  
    24.     }  
    25.   }  
    26.   else {  
    27.     if (this.logger.isTraceEnabled()) {  
    28.       this.logger.trace("Response with status code [" + statusCode + "] not eligible for ETag");  
    29.     }  
    30.     copyBodyToResponse(body, response);  
    31.   }  
    32. }  

    由源码可知,ShallowEtagHeaderFilter只能根据结果判断是否重新向客户端发送数据,并不会不处理请求,因此节省带宽,而不能提高服务器性能。

    配置ShallowEtagHeaderFilter的代码如下:

     

    Xml代码  收藏代码
    1. <filter>    
    2.    <filter-name>shallowEtagHeaderFilter</filter-name>    
    3.    <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</fliter-class>    
    4. </filter>    
    5. <filter-mapping>    
    6.    <filter-name>shallowEtagHeaderFilter</filter-name>    
    7.    <servlet-name>spring</servlet-name>    
    8. </filter-mapping>  

     

    RequestContextFilter

    这是在Spring2.0时添加的类,通过LocaleContextHolder和RequestContextHolder把Http request对象基于LocalThread绑定到请求提供服务的线程上。现在一般使用DispatcherServlet这个中央分发器。现在RequestContextFilter过滤器主要用于第三方的Servlet,如JSF的FacesServlet。在Spring2.5之前都是使用该过滤器配置。配置如下:

     

    Xml代码  收藏代码
    1. <filter>    
    2.     <filter-name>RequestContextFilter</filter-name>    
    3.     <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>    
    4. </filter>    
    5. <filter-mapping>    
    6.     <filter-name>RequestContextFilter</filter-name>    
    7.     <servlet-name>Faces Servlet</servlet-name>    
    8. </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中配置如下:

    Xml代码  收藏代码
    1. <filter>  
    2.    <filter-name>testFilter</filter-name>  
    3.    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
    4.    <init-param>  
    5.       <param-name>targetBeanName</param-name>  
    6.       <param-value>spring-bean-name</param-value>  
    7.    </init-param>  
    8.    <init-param>  
    9.       <param-name>contextAttribute</param-name>  
    10.      <param-value>session</param-value>  
    11.    </init-param>  
    12.    <init-param>  
    13.       <param-name>targetFilterLifecycle</param-name>  
    14.       <param-value>false</param-value>  
    15.    </init-param>  
    16. </filter>          
    17. <filter-mapping>  
    18.    <filter-name>testFilter</filter-name>  
    19.    <url-pattern>/*</url-pattern>  
    20. </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类。


  • 相关阅读:
    如何检测和删除通过pip安装的Python包?
    tensorflow使用keras
    ubuntu18.04安装tensorflow2.0
    python pip版本的安装与管理
    leetcode 377. 组合总和 Ⅳ
    little tips
    NYOJ 104-最大和
    NYOJ 44-子串和
    NYOJ 15-括号匹配(二)
    leetCode 32. Longest Valid Parentheses
  • 原文地址:https://www.cnblogs.com/ycpanda/p/3637300.html
Copyright © 2020-2023  润新知