Spring MVC中使用HandlerMethodArgumentResolver
策略接口来定义处理器方法参数解析器,@RequestHeader
使用的是RequestHeaderMapMethodArgumentResolver
和RequestHeaderMethodArgumentResolver
,接下来一起来深入了解一下其源码实现。
类结构
类解析
HandlerMethodArgumentResolver
和AbstractNamedValueMethodArgumentResolver
是解析策略的上层定义和抽象,关于这两个类可以参照《Spring 注解面面通 之 @CookieValue参数绑定源码解析》中的解析。
RequestHeaderMapMethodArgumentResolver
和RequestHeaderMethodArgumentResolver
则是用来针对不用类型的方法参数的解析。
1) RequestHeaderMapMethodArgumentResolver
实现了HandlerMethodArgumentResolver
的supportsParameter(...)
和resolveArgument(...)
方法。
RequestHeaderMapMethodArgumentResolver
相对比较简单,但在某些条件成立的情况下才会使用此类进行解析:
① 方法参数由@RequestHeader
注解注释。
② 方法参数类型必须是Map
类型。
package org.springframework.web.method.annotation;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* 解析用@RequestHeader注释的Map类型方法参数.
*
* 创建的Map包含所有请求头名称/值对.
* 方法参数类型可以是MultiValueMap,用于接收头的所有值,而不仅仅是第一个值.
*/
public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 方法参数检查.
* 方法参数由@RequestHeader注释.
* 方法参数类型必须是Map类型.
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.hasParameterAnnotation(RequestHeader.class) &&
Map.class.isAssignableFrom(parameter.getParameterType()));
}
/**
* 解析方法参数值.
*/
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 获取方法参数类型.
Class<?> paramType = parameter.getParameterType();
// 方法参数是MultiValueMap类型.
if (MultiValueMap.class.isAssignableFrom(paramType)) {
MultiValueMap<String, String> result;
// 方法参数是HttpHeaders类型.
if (HttpHeaders.class.isAssignableFrom(paramType)) {
result = new HttpHeaders();
}
else {
result = new LinkedMultiValueMap<>();
}
// 处理NativeWebRequest的所有头.
for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
String headerName = iterator.next();
String[] headerValues = webRequest.getHeaderValues(headerName);
if (headerValues != null) {
for (String headerValue : headerValues) {
result.add(headerName, headerValue);
}
}
}
return result;
}
// 方法参数是其他Map类型
else {
Map<String, String> result = new LinkedHashMap<>();
for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
String headerName = iterator.next();
String headerValue = webRequest.getHeader(headerName);
if (headerValue != null) {
result.put(headerName, headerValue);
}
}
return result;
}
}
}
2) RequestHeaderMethodArgumentResolver
继承自抽象AbstractNamedValueMethodArgumentResolver
(可以参照《Spring 注解面面通 之 @CookieValue参数绑定源码解析》)。
RequestHeaderMethodArgumentResolver
相对RequestHeaderMapMethodArgumentResolver
来说,,其在某些条件成立的情况下才会使用此类进行解析:
① 方法参数由@RequestHeader
注解注释。
② 方法参数类型不能为Map
类型。
package org.springframework.web.method.annotation;
import java.util.Map;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.context.request.NativeWebRequest;
/**
* 解析用@RequestHeader注释的方法参数,Map参数除外.
*
* @RequestHeader 用于从请求头解析的命名值.
* 当请求头不存在时,它有一个必需的标志和一个默认值.
*
* 调用WebDataBinder将类型转换应用于尚未与方法参数类型匹配的已解析请求头值.
*/
public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
/**
* @param beanFactory 用于解析默认值中${…}占位符和#{…}SpEL表达式的Bean工厂,
* 或如果默认值不应包含表达式,则返回null.
*/
public RequestHeaderMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
super(beanFactory);
}
/**
* 检查方法参数.
* 方法参数由@RequestHeader注释.
* 方法参数类型不为Map类型.
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.hasParameterAnnotation(RequestHeader.class) &&
!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()));
}
/**
* 创建NamedValueInfo.
*/
@Override
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
RequestHeader ann = parameter.getParameterAnnotation(RequestHeader.class);
Assert.state(ann != null, "No RequestHeader annotation");
return new RequestHeaderNamedValueInfo(ann);
}
/**
* 解析方法参数值.
*/
@Override
@Nullable
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
// 根据指定的名称获取请求头.
String[] headerValues = request.getHeaderValues(name);
if (headerValues != null) {
return (headerValues.length == 1 ? headerValues[0] : headerValues);
}
else {
return null;
}
}
/**
* 处理参数缺失异常.
*/
@Override
protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
throw new ServletRequestBindingException("Missing request header '" + name +
"' for method parameter of type " + parameter.getNestedParameterType().getSimpleName());
}
/**
* RequestHeaderNamedValueInfo.
*/
private static class RequestHeaderNamedValueInfo extends NamedValueInfo {
private RequestHeaderNamedValueInfo(RequestHeader annotation) {
super(annotation.name(), annotation.required(), annotation.defaultValue());
}
}
}
总结
@RequestHeader
是用来处理Web请求头中的信息,随着网站的多样和多元化,@RequestHeader
使用频率会越来越广泛。
若文中存在错误和不足,欢迎指正!