源码基于SpringMVC 5.2.7
HandlerMethodArgumentResolver是参数解析器的接口类,其主要有2个方法
boolean supportsParameter(MethodParameter parameter)
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
SpringMVC框架提供了很多参数解析,如下表所示
类型 | 支持的参数条件 | 备注 |
---|---|---|
org.springframework.web.method.annotation .RequestParamMethodArgumentResolver |
参数符合以下任一条件 1. 被@RequestParam注解且参数类型不是Map 2. 被@RequestParam注解且参数类型是Map且@RequestParam注解的name属性不为空 3. 没有注解@RequestParam且没有注解@RequestPart且参数是MultipartFile或part(与multipart requests相关) 4. 如果解析器作为默认解析器即useDefaultResolution为true且参数类型是简单类型 |
任一条件满足即支持 |
org.springframework.web.method.annotation .RequestParamMapMethodArgumentResolver |
参数包含注解@RequestParam且类型是Map及其子类且注解@RequestParam属性的name为空 |
|
org.springframework.web.servlet.mvc.method.annotation .PathVariableMethodArgumentResolver |
该解析支持符合以下条件任一条件的参数 1. 参数包含注解@PathVariable且参数类型不是Map及其子类 2. 参数包含注解@PathVariable且参数类型是Map及其子类且注解@PathVariable的value属性不为空 |
|
org.springframework.web.servlet.mvc.method.annotation .PathVariableMapMethodArgumentResolver |
参数包含注解@PathVariable且类型是Map及其子类且注解@PathVariable属性的name为空 |
|
org.springframework.web.servlet.mvc.method.annotation .MatrixVariableMethodArgumentResolver |
该解析支持符合以下条件任一条件的参数 1. 参数包含注解@MatrixVariable且参数类型不是Map及其子类 2. 参数包含注解@MatrixVariable且参数类型是Map及其子类且注解@MatrixVariable的value属性不为空 |
|
org.springframework.web.servlet.mvc.method.annotation .MatrixVariableMapMethodArgumentResolver |
参数包含注解@MatrixVariable且类型是Map及其子类且注解@MatrixVariable属性的name为空 |
|
org.springframework.web.servlet.mvc.method.annotation .ServletModelAttributeMethodProcessor |
参数符合以下任一条件 1. 参数有注解@ModuleAttribute 2. 属性annotationNotRequired为true且参数不是简单类型,简单类型包括 |
|
org.springframework.web.servlet.mvc.method.annotation .RequestResponseBodyMethodProcessor |
参数包含注解@RequestBody |
|
org.springframework.web.method.annotation .RequestHeaderMethodArgumentResolver |
参数包含注解@RequestHeader且参数类型不是Map及其子类 |
|
org.springframework.web.method.annotation .RequestHeaderMapMethodArgumentResolver |
参数包含注解@RequestHeader且类型是Map及其子类 |
|
org.springframework.web.servlet.mvc.method.annotation .ServletCookieValueMethodArgumentResolver |
参数包含注解@CookieValue |
|
org.springframework.web.method.annotation .ExpressionValueMethodArgumentResolver |
参数包含注解@Value |
|
org.springframework.web.servlet.mvc.method.annotation .SessionAttributeMethodArgumentResolver |
参数包含注解@SessionAttribute |
|
org.springframework.web.servlet.mvc.method.annotation .RequestAttributeMethodArgumentResolver |
参数包含注解@RequestAttribute |
|
org.springframework.web.servlet.mvc.method.annotation .ServletRequestMethodArgumentResolver |
参数类型是以下任何一种 1. org.springframework.web.context.request.WebRequest及其子类 2. javax.servlet.ServletRequest及其子类 3. org.springframework.web.multipart.MultipartRequest及其子类 4. javax.servlet.http.HttpSession及其子类 5. javax.servlet.http.PushBuilder及其子类 6. java.security.Principal及其子类 7. java.io.InputStream及其子类 8. java.io.Reader及其子类 9. org.springframework.http.HttpMethod 10. java.util.Locale 11. java.util.TimeZone 12. java.time.ZoneId |
|
org.springframework.web.servlet.mvc.method.annotation .ServletResponseMethodArgumentResolver |
参数类型是javax.servlet.ServletResponse及其子类或java.io.OutputStream及其子类或java.io.Writer及其子类 |
|
org.springframework.web.servlet.mvc.method.annotation .HttpEntityMethodProcessor |
参数类型是org.springframework.http.RequestEntity或者org.springframework.http.HttpEntity |
|
org.springframework.web.servlet.mvc.method.annotation .RedirectAttributesMethodArgumentResolver |
参数类型是org.springframework.web.servlet.mvc.support.RedirectAttributes及其子类 |
|
org.springframework.web.method.annotation .ModelMethodProcessor |
参数类型是org.springframework.ui.Model及其子类型 |
|
org.springframework.web.method.annotation .MapMethodProcessor |
参数类型是Map及其子类型且参数上没有任何注解 |
|
org.springframework.web.method.annotation .ErrorsMethodArgumentResolver |
参数类型是org.springframework.validation.Errors及其子类 |
|
org.springframework.web.method.annotation .SessionStatusMethodArgumentResolver |
参数类型是org.springframework.web.bind.support.SessionStatus |
|
org.springframework.web.servlet.mvc.method.annotation .UriComponentsBuilderMethodArgumentResolver |
参数类型是org.springframework.web.util.UriComponentsBuilder或者org.springframework.web.servlet.support.ServletUriComponentsBuilder |
AbstractNamedValueMethodArgumentResolver是一个抽象类,它是name-value型参数解析器的父类。name-value型不太好解释,像Request parameters、request headers、path variables就是name-value的例子。大概就是每个参数有name标记参数的名字、required标记参数是否必须、default value标记默认值,根据name从请求中解析参数的值。
主要成员属性
支持的参数条件
AbstractNamedValueMethodArgumentResolver是抽象类,支持的参数条件由其具体实现类指定
参数解析流程
AbstractNamedValueMethodArgumentResolver是抽象类,其控制name-value型参数解析的整体流程,有些细节或者数据获取需要各子类实现。name-value型参数解析器解析流程大致如下,需要子类实现的部分有备注:
1 获取NamedValueInfo信息namedValueInfo(name、required、default value)(由子类实现)
2 解析namedValueInfo中name的占位符以及SPEL表达式
3 解析name对应的值value(由子类实现)
4 如果value为null
4.1 如果namedValueInfo默认值不为空则取默认值
4.2 如果namedValueInfo默认值为空且namedValueInfo的isRequired为true执行value缺失逻辑-抛异常(vlaue确实逻辑可被子类覆盖)
4.3 空值处理:如果是Boolean取Boolean.False,其他基本类型则抛异常,其他不处理
5 使用WebDataBinder对value进行转换使其符合要解析的参数类型
6 对value解析后处理:默认不处理(可由子类覆盖)
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
... ...
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//笔者注:获取namedValueInfo信息,由子类实现
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
//笔者注:对name进行占位符、spel表达式解析返回真正的name
Object resolvedName = resolveStringValue(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
//笔者注:解析name对应的value,由子类实现
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
//笔者注: 如果没有解析出value,则进行默认值处理
if (namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
// 笔者注: 参数必传,则执行value缺失逻辑-可由子类覆盖
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
}
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
//笔者注: 使用DataBinder对value做类型转换,以符合参数的类型
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
}
catch (ConversionNotSupportedException ex) {
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
catch (TypeMismatchException ex) {
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
}
//笔者注:解析后处理,默认是不处理,可由子类覆盖
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
... ...
}
下面介绍AbstractNamedValueMethodArgumentResolver的具体实现类,因为解析流程是遵守上面解析逻辑的,只有需要子类实现部分不同,所以只对子类实现部分进行介绍
主要成员变量
支持的参数条件
参数符合以下任一条件
1. 被@RequestParam注解且参数类型不是Map
2. 被@RequestParam注解且参数类型是Map且@RequestParam注解的name属性不为空
3. 没有注解@RequestParam且没有注解@RequestPart且参数是MultipartFile或part(与multipart requests相关)
4. 如果解析器作为默认解析器即useDefaultResolution为true且参数类型是简单类型,其中简单类型包括:基本类型及其包装类型、Date、Number、Enum、CharSequence、URL、URI、Temporal、Locale、Class等
参数解析流程
同AbstractNamedValueMethodArgumentResolver。
a. 获取NamedValueInfo信息
返回RequestParamNamedValueInfo类型的对象,name、isRequired、defaultValue来自注解@RequestParam。如果没有@RequestParam注解则name为""、isRequired为false
b. 解析name对应的值value
1 如果参数类型是org.springframework.web.multipart.MultipartFile及其子类或者是MultipartFile类型的集合或数组,则从request解析MultipartFile对象
2 如果如果参数类型是javax.servlet.http.Part及其子类或者是Part类型的集合或数组,则从request解析Part对象
3 如果request是org.springframework.web.multipart.MultipartRequest,则取request第一个MultipartFile最为value
4 如果前面没有解析出value,则从request的parameterMap获取name对应的value
c. value缺失逻辑
根据参数类型不同抛不同类型的异常
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
implements UriComponentsContributor {
... ...
//笔者注:RequestParamMethodArgumentResolver重写父类方法,根据参数类型抛不同的异常
protected void handleMissingValue(String name, MethodParameter parameter, NativeWebRequest request)
throws Exception {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
if (servletRequest == null || !MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
throw new MultipartException("Current request is not a multipart request");
}
else {
throw new MissingServletRequestPartException(name);
}
}
else {
throw new MissingServletRequestParameterException(name,
parameter.getNestedParameterType().getSimpleName());
}
}
... ...
}
d. value解析后处理
RequestParamMethodArgumentResolver没有重写父类方法AbstractNamedValueMethodArgumentResolver#handleResolvedValue,保持父类逻辑即不处理
主要成员变量
无
支持的参数条件
该解析支持符合以下条件任一条件的参数
1. 参数包含注解@PathVariable且参数类型不是Map及其子类
2. 参数包含注解@PathVariable且参数类型是Map及其子类且注解@PathVariable的value属性不为空
参数解析流程
同AbstractNamedValueMethodArgumentResolver。
a. 获取NamedValueInfo信息
返回PathVariableNamedValueInfo类型对象,name、isRequired、defaultValue来自参数上的注解@PathVariable。
b. 解析name对应的值value
1 从request取出属性"org.springframework.web.servlet.HandlerMapping.uriTemplateVariables"。(该属性是在RequestMappingHandlerMapping匹配Handler阶段解析出uriTemplateVariables并且放在request中)
2 从uriTemplateVariables取得name对应value
c. value缺失逻辑
重写了父类方法,抛出异常org.springframework.web.bind.MissingPathVariableException
d. value解析后处理
PathVariableMethodArgumentResolver重写了父类方法AbstractNamedValueMethodArgumentResolver#handleResolvedValue。
将解析出来的name、value对放到request属性("org.springframework.web.servlet.View.pathVariables")中
public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
implements UriComponentsContributor {
... ...
//笔者注:重写了父类方法,将解析出来name-value添加到request的属性中
protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter,
@Nullable ModelAndViewContainer mavContainer, NativeWebRequest request) {
String key = View.PATH_VARIABLES;
int scope = RequestAttributes.SCOPE_REQUEST;
Map pathVars = (Map) request.getAttribute(key, scope);
if (pathVars == null) {
pathVars = new HashMap<>();
request.setAttribute(key, pathVars, scope);
}
//笔者注:将解析出来name-value添加到request的属性中
pathVars.put(name, arg);
}
... ...
}
主要成员变量
无
支持的参数条件
该解析支持符合以下条件任一条件的参数
1. 参数包含注解@MatrixVariable且参数类型不是Map及其子类
2. 参数包含注解@MatrixVariable且参数类型是Map及其子类且注解@MatrixVariable的value属性不为空
参数解析流程
同AbstractNamedValueMethodArgumentResolver。
a. 获取NamedValueInfo信息
返回MatrixVariableNamedValueInfo类型对象,name、isRequired、defaultValue来自注解@MatrixVariable。
b. 解析name对应的值value
1 从request取出属性"org.springframework.web.servlet.HandlerMapping.matrixVariables",类型是Map
2 如果@MatrixVariable指定了pathVar则从matrixVariables取pathVar对应的集合并从其中获取name对应的值,然后返回,否则进入3
3 依次遍历matrixVariables元素,从元素(MultiValueMap)中获取name对应的值,如果在多个元素中找到name则抛异常
c. value缺失逻辑
抛出异常org.springframework.web.bind.MissingMatrixVariableException
d. value解析后处理
未重写父类逻辑即不处理
主要成员变量
无
支持的参数条件
参数包含注解@RequestHeader且参数类型不是Map及其子类
参数解析流程
同AbstractNamedValueMethodArgumentResolver。
a. 获取NamedValueInfo信息
返回RequestHeaderNamedValueInfo类型对象,name、isRequired、defaultValue来自注解@RequestHeader。
b. 解析name对应的值value
从request headers中取出name对应的values
c. value缺失逻辑
抛出异常org.springframework.web.bind.MissingRequestHeaderException
d. value解析后处理
未重写父类逻辑
主要成员变量
支持的参数条件
参数包含注解@CookieValue
参数解析流程
同AbstractNamedValueMethodArgumentResolver。
a. 获取NamedValueInfo信息
返回CookieValueNamedValueInfo类型对象,name、isRequired、defaultValue来自注解@CookieValue。
b. 解析name对应的值value
1 从request cookies中取出name对应的Cookie
2 如果参数类型是Cookie则直接返回,否则返回Cookie的value
c. value缺失逻辑
抛出异常org.springframework.web.bind.MissingRequestCookieException
d. value解析后处理
未重写父类逻辑
主要成员变量
无
支持的参数条件
参数包含注解@Value
参数解析流程
同AbstractNamedValueMethodArgumentResolver。
a. 获取NamedValueInfo信息
返回ExpressionValueNamedValueInfo类型对象,name、isRequired、defaultValue来自注解@Value。
b. 解析name对应的值value
直接返回null。也就是说会走到默认值流程,即配置@Value时的value。如果value有placeholder,系统在启动的时候Spring会解析替换placeholder
public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
... ...
//笔者注:直接返回null,就是要走默认值流程,即@Value配置的placeholder解析出来的值
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
// No name to resolve
return null;
}
... ...
}
c. value缺失逻辑
抛出异常java.lang.UnsupportedOperationException
d. value解析后处理
未重写父类逻辑
主要成员变量
无
支持的参数条件
参数包含注解@SessionAttribute
参数解析流程
同AbstractNamedValueMethodArgumentResolver。
a. 获取NamedValueInfo信息
返回NamedValueInfo类型对象,name、isRequired、defaultValue来自注解@SessionAttribute。
b. 解析name对应的值value
从requst中取出name对应的SCOPE_SESSION作用域的属性
c. value缺失逻辑
抛出异常org.springframework.web.bind.ServletRequestBindingException
d. value解析后处理
未重写父类逻辑
主要成员变量
无
支持的参数条件
参数包含注解@RequestAttribute
参数解析流程
同AbstractNamedValueMethodArgumentResolver。
a. 获取NamedValueInfo信息
返回NamedValueInfo类型对象,name、isRequired、defaultValue来自注解@RequestAttribute。
b. 解析name对应的值value
从request中取出name对应的SCOPE_REQUEST作用域的属性
c. value缺失逻辑
抛出异常org.springframework.web.bind.ServletRequestBindingException
d. value解析后处理
未重写父类逻辑
主要成员变量
无
支持的参数条件
参数包含注解@RequestParam且类型是Map及其子类且注解@RequestParam属性的name为空
参数解析流程
1 如果参数类型是org.springframework.util.MultiValueMap子类,则
1.1 如果元素的类型是org.springframework.web.multipart.MultipartFile则从request中读取multiFileMap返回
1.2 如果元素的类型是javax.servlet.http.Part则从request读取parts对象,组建org.springframework.util.LinkedMultiValueMap类型对象返回
1.3 从request读取parameterMap,组建org.springframework.util.LinkedMultiValueMap类型对象返回
2 如果参数类型是Map及其子类
2.1 如果元素的类型是org.springframework.web.multipart.MultipartFile则从request中读取multiFileMap返回
2.2 如果元素的类型是javax.servlet.http.Part则从request读取parts对象,组建org.springframework.util.LinkedHashMap类型对象返回
2.3 从request读取parameterMap,组建org.springframework.util.LinkedHashMap类型对象返回
主要成员变量
无
支持的参数条件
参数包含注解@PathVariable且类型是Map及其子类且注解@PathVariable属性的name为空
参数解析流程
从request取出属性"org.springframework.web.servlet.HandlerMapping.uriTemplateVariables"。(该属性是在RequestMappingHandlerMapping匹配Handler阶段解析出uriTemplateVariables并且放在request中)
主要成员变量
无
支持的参数条件
参数包含注解@MatrixVariable且类型是Map及其子类且注解@MatrixVariable属性的name为空
参数解析流程
1 从request取出属性"org.springframework.web.servlet.HandlerMapping.matrixVariables",类型是Map
2 如果@MatrixVariable指定了pathVar则从matrixVariables取对应的值并加入到org.springframework.util.LinkedMultiValueMap对象,然后返回,否则进入3
3 依次遍历matrixVariables元素加入到org.springframework.util.LinkedMultiValueMap对象,并返回
AbstractMessageConverterMethodArgumentResolver是一个抽象类,它提供了一些工具方法从request body读取对象。
主要成员变量
readWithMessageConverters
1 读取request的请求头"Content-Type"
2 遍历messageConverters,如果找到能支持参数实际类型转换的元素,进入3,否则跳到4
3 如果有request body,则
3.1 执行RequestBodyAdvice中读取request body前处理(RequestResponseBodyAdviceChain#beforeBodyRead)
3.2 使用HttpMessageConverter读取并转换request body
3.3 执行RequestBodyAdvice中读取request body后处理(RequestResponseBodyAdviceChain#afterBodyRead)
4 如果没有request body 则
4.1 执行RequestBodyAdvice中关于空body的处理(RequestResponseBodyAdviceChain#handleEmptyBody)
5 如果读取到对象则返回该对象,否则抛异常HttpMediaTypeNotSupportedException
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
... ...
protected Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
MediaType contentType;
boolean noContentType = false;
try {
//笔者注:读取Content-Type
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
Class> contextClass = parameter.getContainingClass();
Class targetClass = (targetType instanceof Class ? (Class) targetType : null);
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = (Class) resolvableType.resolve();
}
HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
Object body = NO_VALUE;
EmptyBodyCheckingHttpInputMessage message;
try {
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
//笔者注:遍历messageConverters
for (HttpMessageConverter> converter : this.messageConverters) {
Class> converterType = (Class>) converter.getClass();
GenericHttpMessageConverter> genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter>) converter : null);
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
if (message.hasBody()) {
//笔者注:读取body之前执行RequstbodyAdvice的beforeBodyRead
HttpInputMessage msgToUse =
getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter) converter).read(targetClass, msgToUse));
//笔者注:读取body之后执行RequstbodyAdvice的afterBodyRead
body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
}
else {
//笔者注:没有request body则执行RequstbodyAdvice的handleEmptyBody
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
}
//笔者注:没有读取到对象,根据情况抛异常HttpMediaTypeNotSupportedException
if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
(noContentType && !message.hasBody())) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}
MediaType selectedContentType = contentType;
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(theBody, !traceOn);
return "Read \"" + selectedContentType + "\" to [" + formatted + "]";
});
return body;
}
... ...
}
主要成员变量
无
支持的参数条件
参数包含注解@RequestBody
参数解析流程
1. 从request的body中读取出对应类型的对象,参考AbstractMessageConverterMethodArgumentResolver
2. 对对象进行valid验证
3. 如果验证有错误且当前解析的参数后一个参数类型不是org.springframework.validation.Errors,则抛异常MethodArgumentNotValidException并结束解析流程,否则进入4
4. 将绑定结果添加到mavContainer属性中,属性名以"org.springframework.validation.BindingResult."开头
5. 返回对象
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
... ...
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
//笔者注:AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters读取参数类型的对象
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
//笔者注:数据检查
validateIfApplicable(binder, parameter);
//笔者注:绑定有错误且下一个参数不是Errors类型则抛异常
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
//笔者注:返回绑定后对象
return adaptArgumentIfNecessary(arg, parameter);
}
... ...
}
主要成员变量
无
支持的参数条件
参数类型是org.springframework.http.RequestEntity或者org.springframework.http.HttpEntity
参数解析流程
1 获取参数的实际类型(HttpEntity或RequestEntity泛型)
2 从request body中读取对象,参考AbstractMessageConverterMethodArgumentResolver
3 根据参数的类型创建RequestEntity或HttpEntity对象
public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor {
... ...
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)
throws IOException, HttpMediaTypeNotSupportedException {
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
Type paramType = getHttpEntityType(parameter);
if (paramType == null) {
throw new IllegalArgumentException("HttpEntity parameter '" + parameter.getParameterName() +
"' in method " + parameter.getMethod() + " is not parameterized");
}
//笔者注:AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters从request body中读取对象
Object body = readWithMessageConverters(webRequest, parameter, paramType);
if (RequestEntity.class == parameter.getParameterType()) {
return new RequestEntity<>(body, inputMessage.getHeaders(),
inputMessage.getMethod(), inputMessage.getURI());
}
else {
return new HttpEntity<>(body, inputMessage.getHeaders());
}
}
... ...
}
主要成员变量
无
支持的参数条件
参数符合以下任一条件
1. 参数包含注解@RequestPart
2. 参数不包含注解@RequestParam且参数类型org.springframework.web.multipart.MultipartFile及其子类或javax.servlet.http.Part及其子类
参数解析流程
1. 将request转为org.springframework.web.multipart.MultipartHttpServletRequest类型的对象,从其中读取MultipartFile或者Part元素。如果读取到则返回,否则进入2
2. 从request body中读取对象,参考AbstractMessageConverterMethodArgumentResolver
主要成员变量
无
支持的参数条件
参数包含注解@RequestHeader且类型是Map及其子类
参数解析流程
1 如果参数类型是HttpHeaders及其子类,创建HttpHeaders对象并从request header中取得所有header填充进去,返回HttpHeaders对象。否则进入2
2 如果参数类型是org.springframework.util.MultiValueMap及其子类,创建org.springframework.util.LinkedMultiValueMap对象并从request header中取得所有header填充进去,返回LinkedMultiValueMap对象。否则进入3
3 创建java.util.LinkedHashMap对象并从request header中取得所有header填充进去,返回LinkedHashMap对象
主要成员变量
无
支持的参数条件
参数类型是以下任何一种
1. org.springframework.web.context.request.WebRequest及其子类
2. javax.servlet.ServletRequest及其子类
3. org.springframework.web.multipart.MultipartRequest及其子类
4. javax.servlet.http.HttpSession及其子类
5. javax.servlet.http.PushBuilder及其子类
6. java.security.Principal及其子类
7. java.io.InputStream及其子类
8. java.io.Reader及其子类
9. org.springframework.http.HttpMethod
10. java.util.Locale
11. java.util.TimeZone
12. java.time.ZoneId
参数解析流程
1 如果参数类型是org.springframework.web.context.request.WebRequest及其子类、javax.servlet.ServletRequest及其子类或org.springframework.web.multipart.MultipartRequest及其子类,则将request转换得到对应的类型对象并返回
2 如果参数类型是javax.servlet.http.HttpSession及其子类则返回javax.servlet.http.HttpServletRequest#getSession()
3 如果参数类型是javax.servlet.http.PushBuilder及其子类则返回javax.servlet.http.HttpServletRequest#newPushBuilder
4 如果参数类型是java.io.InputStream及其子类则返回javax.servlet.ServletRequest#getInputStream
5 如果参数类型是java.io.Reader及其子类则返回javax.servlet.ServletRequest#getReader
6 如果参数类型是java.security.Principal及其子类则返回javax.servlet.http.HttpServletRequest#getUserPrincipal
7 解析并返回javax.servlet.http.HttpServletRequest#getMethod
8如果参数类型是java.util.Locale则使用工具方法org.springframework.web.servlet.support.RequestContextUtils#getLocale从request中解析并返回
9 如果参数类型是java.util.TimeZone则使用工具方法org.springframework.web.servlet.support.RequestContextUtils#getTimeZone从request中解析并返回
10 如果参数类型是java.time.ZoneId则使用工具方法org.springframework.web.servlet.support.RequestContextUtils#getTimeZone从request中解析并返回
主要成员变量
无
支持的参数条件
参数类型是javax.servlet.ServletResponse及其子类或java.io.OutputStream及其子类或java.io.Writer及其子类
参数解析流程
1 如果参数类型是javax.servlet.ServletResponse则返回response对象,否则进入2
2 如果参数类型是java.io.OutputStream则返回javax.servlet.ServletResponse#getOutputStream,否则进入3
3 如果参数类型是java.io.Writer则返回javax.servlet.ServletResponse#getWriter,否则抛异常
主要成员变量
无
支持的参数条件
参数类型是org.springframework.web.servlet.mvc.support.RedirectAttributes及其子类
参数解析流程
创建一个org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap对象返回
主要成员变量
无
支持的参数条件
参数类型是org.springframework.ui.Model及其子类型
参数解析流程
直接从mavContainer取ModelMap并返回
主要成员变量
无
支持的参数条件
参数类型是Map及其子类型且参数上没有任何注解
参数解析流程
直接从mavContainer取ModelMap并返回
支持的参数条件
参数类型是org.springframework.web.util.UriComponentsBuilder或者org.springframework.web.servlet.support.ServletUriComponentsBuilder
参数解析流程
根据request创建ServletUriComponentsBuilder对象,ServletUriComponentsBuilder的scheme、host、port从request设置,path从contextpath和servletpath拼接。
public class UriComponentsBuilderMethodArgumentResolver implements HandlerMethodArgumentResolver {
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
Assert.state(request != null, "No HttpServletRequest");
return ServletUriComponentsBuilder.fromServletMapping(request);
}
}
支撑的参数条件
参数类型是org.springframework.web.bind.support.SessionStatus
参数解析流程
直接读取mavContainer的属性sessionStatus即ModelAndViewContainer#getSessionStatus
支持的参数条件
参数类型是org.springframework.validation.Errors及其子类
参数解析流程
model中最后一个元素且该元素的key是以"org.springframework.validation.BindingResult."开头,否则抛异常。所以Errors类型参数必须紧跟着@ModuleAttribute、@RequestBody或@RequestPart后声明,否则modelMap中最后一个元素不满足条件。
支持的参数条件
参数符合以下任一条件
1. 参数有注解@ModuleAttribute
2. 属性annotationNotRequired为true且参数不是简单类型,简单类型包括
参数解析流程
ServletModelAttributeMethodProcessor是ModelAttributeMethodProcessor子类,解析的方法在ModelAttributeMethodProcessor#resolveArgument
1 根据注解@ModuleAttribute获取参数name(a. 注解中指定了name b. 根据类名生成)
2 如果mavContainer中已经有该name对应的对象则跳到4,否则进去3创建对象
3 创建对象obj
3.1 如果request包含该name的请求参数或者路径变量且能被转换为对应类型则返回转换后对象,否则进入3.2
3.2 获取类型的构造方法,如果构造方法没有参数,创建对象返回,否则进入3.3
3.3 取得构造方法的参数并分析参数的name(来源于注解@java.beans.ConstructorProperties或ParameterNameDiscoverer#getParameterNames(java.lang.reflect.Constructor>))
3.4 从request中取得name对应值转换为构造方法的参数类型,使用构造方法创建对象返回
4 从request获取参数绑定到对象obj中的属性:WebRequestDataBinder#bind
5 返回绑定后的obj