1、拦截器
拦截器是由Spring提供,类似Filter功能的类,它可以拦截DispatcherServlet分发的请求。
与Filter不同之处在于,Filter适用于所有Servlet,而拦截器(Interceptor)只适用于DispatcherServlet分发的请求。当同时有Filter,Interceptor存在的情况下,请求的执行链如下:
Filter chain---->DispatcherServlet的doService方法------>获取HandlerExecutionChain,执行HandlerInterceptor chain----->Controller中的handler方法。
使用拦截器有两个步骤:
- 自定义HandlerInterceptor接口的实现类,例如TestInterceptor。
- 注册HandlerInterceptor,注册的方式有两种,代码方式,在配置文件中配置。
编写HandlerInterceptor接口的实现类较为简单。只做练习的话,打印几条输出语句即可。
HandlerInterceptor有三个方法,
- preHandle:在Controller的handler方法之前执行,返回true时继续执行下一个Handler,若是最后一个Handler,则执行Controller中的方法。返回false时,表示请求终止,不会有任何后续。
- postHandle:在Controller的handler方法之后执行,当响应类型为数据流时,即直接向response对象的输出流写入数据时,例如调用response.getWriter.append方法,标注有@ResponseBody的handler。此方法不会执行。
- afterCompletion:在请求结束,响应关闭,线程资源被回收之后运行。
注册有两种方式,
代码方式,示例如下:
public void addInterceptors(InterceptorRegistry registry) { // 调用InterceptorRegistry的addInterceptor方法 // 拦截所有的请求,除login registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**").excludePathPatterns("/login"); }
XML配置文件方式,示例如下:
<mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/login"/> <bean class="interceptor.TestInterceptor"/> </mvc:interceptor>
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<DispatcherType> 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。相当于给请求添加缓存的功能。
使用步骤如下:
- 第一步,创建ShallowEtagHeaderFilter对象,
- 第二步,注册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<DispatcherType> dispatchers = EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.FORWARD, DispatcherType.INCLUDE); // 过滤器拦截dispatcherServlet filterRegistration.addMappingForServletNames(dispatchers, true, "dispatcherServlet");