后端——框架——视图层框架——spring mvc——过滤器 & 拦截器


1、拦截器

  拦截器是由Spring提供,类似Filter功能的类,它可以拦截DispatcherServlet分发的请求。

与Filter不同之处在于,Filter适用于所有Servlet,而拦截器(Interceptor)只适用于DispatcherServlet分发的请求。当同时有Filter,Interceptor存在的情况下,请求的执行链如下:

Filter chain---->DispatcherServlet的doService方法------>获取HandlerExecutionChain,执行HandlerInterceptor chain----->Controller中的handler方法。

使用拦截器有两个步骤:

  1. 自定义HandlerInterceptor接口的实现类,例如TestInterceptor。
  2. 注册HandlerInterceptor,注册的方式有两种,代码方式,在配置文件中配置。

编写HandlerInterceptor接口的实现类较为简单。只做练习的话,打印几条输出语句即可。

HandlerInterceptor有三个方法,

  1. preHandle:在Controller的handler方法之前执行,返回true时继续执行下一个Handler,若是最后一个Handler,则执行Controller中的方法。返回false时,表示请求终止,不会有任何后续。
  2. postHandle:在Controller的handler方法之后执行,当响应类型为数据流时,即直接向response对象的输出流写入数据时,例如调用response.getWriter.append方法,标注有@ResponseBody的handler。此方法不会执行。
  3. afterCompletion:在请求结束,响应关闭,线程资源被回收之后运行。

  注册有两种方式,

代码方式,示例如下:

public void addInterceptors(InterceptorRegistry registry) {
	// 调用InterceptorRegistry的addInterceptor方法
	// 拦截所有的请求,除login
	registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**").excludePathPatterns("/login");
}

  XML配置文件方式,示例如下:


	
	
	

2、过滤器

  本篇介绍mvc内置的过滤器。使用频率很低。

2.1   FormContent

  引用原著中的定义:

  the spring-web module provides FormContentFilter to intercept HTTP PUT, PATCH, and DELETE requests with a content type of application/x-www-form-urlencoded, read the from data from the body of request, and wrap the ServletRequest to make the form data available through the ServletRequest.getParameter*() family of methods

默认情况下,ServletRequest的getParameter*方法只能获取get和post请求类型中的参数。

添加FormContentFilter,它会适用于所有类型的请求。

使用步骤如下:

配置FormContentFilter拦截器拦截DispatcherSerlvet。代码如下:

// 添加过滤器
FilterRegistration.Dynamic filterRegistration = servletContext.addFilter("formContentFilter", new FormContentFilter());
// 配置请求的分发类型
EnumSet dispatchers = EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.FORWARD,DispatcherType.INCLUDE);
filterRegistration.addMappingForServletNames(dispatchers, true, "dispatcherServlet");

  编写任意的PUT,DELETE请求验证即可

2.2 ForwardedHeader

  引用原著中的定义:

ForwardedHeaderFilter is a Servlet filter that modifies the host, port, and scheme of the request, based on Forwarded headers, and then removes those headers

ForwardedHeaderFilter可以修改请求头中关于主机,端口,协议等信息。请求头中记录这些信息的属性有:

static {
	FORWARDED_HEADER_NAMES.add("Forwarded");
	FORWARDED_HEADER_NAMES.add("X-Forwarded-Host");
	FORWARDED_HEADER_NAMES.add("X-Forwarded-Port");
	FORWARDED_HEADER_NAMES.add("X-Forwarded-Proto");
	FORWARDED_HEADER_NAMES.add("X-Forwarded-Prefix");
	FORWARDED_HEADER_NAMES.add("X-Forwarded-Ssl");
}

  略。

2.3   ShallowEtagHeader

ShallowEtagHeaderFilter会根据响应的内容生成”shallow etag”,再次请求时,会将该值作为请求头中If-None-Match属性值,并与”shallow etag”的值进行比较,若二者相等返回304, Not Modified。相当于给请求添加缓存的功能。

使用步骤如下:

  1. 第一步,创建ShallowEtagHeaderFilter对象,
  2. 第二步,注册ShallowEtagHeaderFilter,拦截DispactherServlet,或者是URL地址都可以。
// ShallowEtagHeaderFilter
ShallowEtagHeaderFilter eTagHeader = new ShallowEtagHeaderFilter();
eTagHeader.setWriteWeakETag(true);
FilterRegistration.Dynamic shadowETagFilter = servletContext.addFilter("shadowETagFilter", eTagHeader);
shadowETagFilter.addMappingForServletNames(dispatchers, true, "dispatcherServlet");

  3. 第三步,验证。第一次请求时请求头中无If-None-Match属性,响应码为200。再次请求时,请求头中有If-None-Match属性值,浏览器中的响应码为304

// 调用request.getHeader方法
if-none-match: W/"0d2d08b5003a04494f5de83f30a514e17"
// 浏览器中查看
Status Code: 304

2.4  CorsFilter

  使用CorsFilter的步骤如下:

  第一步,配置过滤器。

CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
CorsFilter filter = new CorsFilter(source);

  第二步,Servlet添加过滤器。在web.xml中配置也是相同的

// 添加过滤器,filter为之前创建的CorsFilter
FilterRegistration.Dynamic filterRegistration = servletContext.addFilter("crosFilter", filter);
// 配置请求的分发类型
EnumSet dispatchers = EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.FORWARD, DispatcherType.INCLUDE);
// 过滤器拦截dispatcherServlet
filterRegistration.addMappingForServletNames(dispatchers, true, "dispatcherServlet");

相关