SpringMVC 提供的 Filter 类简介

2016-11-28 18:05:58   最后更新: 2016-11-28 18:05:58   访问数量:307




在 Web 应用中,请求的拦截是最常见的一个需求,例如常常需要进行用户权限的验证等等,这样的通用逻辑不应该陷入业务逻辑来处理,Spring 提供了 org.springframework.web.filter 包,定义了一系列过滤器,来提供请求的各种过滤功能

 

 

上图中可以看到 AbstractRequestLoggingFilter 是一个 abstract 类,他定义了一系列方法和两个 abstract 方法:

  1. protected abstract void beforeRequest(HttpServletRequest request, String message);
  2. protected abstract void afterRequest(HttpServletRequest request, String message);

 

顾名思义,分别用来在请求处理前执行一些操作,和在请求处理后执行一些操作

org.springframework.web.filter 包中有三个类继承于他:

  1. CommonsRequestLoggingFilter -- 在过滤前后分别打印出一段debug的信息
  2. ServletContextRequestLoggingFilter -- 在过滤前后分别向日志文件中写入一段日志信息,日志文件可由log4j.properties等指定
  3. Log4jNestedDiagnosticContextFilter -- 已废弃,将日志信息存储到NDC中,NDC采用了一个类似栈的机制来push和pot上下文信息,每一个线程都独立地储存上下文信息

 

html 的 form 表单只支持 GET 与 POST 操作,而其余的 DELETE、PUT 等 HTTP method 则并不支持

Spring3 提供了一个 Filter -- HiddenHttpMethodFilter,用来将指定的请求转换为标准的 http 方法,从而支持 GET、POST、PUT、DELETE 等请求

配置如下:

<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:

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

 

 

这样,一个 post 请求的表单就会自动变为 put 请求的表单了

 

HiddenHttpMethodFilter 源码解析

HiddenHttpMethodFilter 实现上述功能是通过复写父类 OncePerRequestFilter 的 doFilterInternal 方法实现的

@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String paramValue = request.getParameter(this.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); } }

 

 

可以看到,这个拦截器的工作就是将 name 为我们所配置的 methodParam 参数的表单的 HttpMethod 设置为 value 中所指定的值

 

Spring3 还提供了另一个修改 HTTP method 的拦截器,与 HiddenHttpMethodFilter 不同,HttpPutFormContentFilter 只处理 method 设置为 put 且 enctype 值为 application/x-www-form-urlencoded 的表单

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

 

 

比 HiddenHttpMethodFilter 方便的地方在于他不需要添加额外的 input 或 post 参数

 

ShallowEtagHeaderFilter 过滤器为 Spring 提供了对 ETag 的支持,所谓的 ETag 指的是被请求变量的实体值,是一个可以与Web资源关联的记号

每次服务器端响应一个请求都会在响应 Header 中添加 ETag 值:

ETag:"50b1c1d4f775c61:df3"

 

客户端在下一次请求时可以将上一次请求所收到的 ETag 值加入到请求 Header 中:

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

 

服务端通过对 If-None-Match 的校验,与重新计算的 ETag 值进行比较,如果 ETag 值没有变,那么就直接返回 304 状态,而不返回 body

使用 ETag 对节约带宽效果是很好的,但是由于每次都要计算 ETag,所以服务器性能并没有任何提升

 

源码解析

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); } }

 

 

Spring MVC中各个filter的用法 -- http://blog.csdn.net/qyp1314/article/details/42023725

 






技术帖      mvc      技术分享      http      java      filter      spring      request      springmvc      get      post      拦截器      put     


京ICP备15018585号