16、SpringMVC源码分析 - AbstractNamedValueMethodArgumentResolver
前言
AbstractNamedValueMethodArgumentResolver实现了HandlerMethodArgumentResolver,用于解析请求方法参数的值,可以解析@PathVariable、@RequestParam、@RequestHeader、@RequestAttribute、@CookieValue、@SessionAttribute、@MatrixVariable。
一、AbstractNamedValueMethodArgumentResolver
1、resolveArgument( )
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//获取参数的名称、默认值等信息
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
//参数名可能是表达式,解析出来
Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
//根据参数名获取参数值,由子类实现
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
//解析默认值
arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
}
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
//没有参数值,没有默认值,参数是必须的,则进入缺失值的处理
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
//对null值的处理,boolean类型赋值false,基本类型抛异常
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
}
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
//参数值为空字符串时,有默认值时,解析默认值
arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
}
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
//通过WebDataBinder的Converters将参数值类型转换成对应的类型
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());
}
// Check for null value after conversion of incoming argument value
if (arg == null && namedValueInfo.defaultValue == null &&
namedValueInfo.required && !nestedParameter.isOptional()) {
//值进行转换之后,对缺失值的处理
handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);
}
}
//已经解析出参数值,方法留给子类实现
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
二、PathVariableMethodArgumentResolver
用于解析@PathVariable
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
//获取uriTemplateVariables,在获取变量值
Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);
}
从request中获取uriTemplateVariables属性,在RequestMappingInfoHandlerMapping getHandler的时候解析出参数和值存入该属性中。
三、RequestParamMethodArgumentResolver
用于解析@RequestParam
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
if (servletRequest != null) {
//处理文件上传参数
Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
return mpArg;
}
}
Object arg = null;
MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
if (multipartRequest != null) {
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg = (files.size() == 1 ? files.get(0) : files);
}
}
if (arg == null) {
//通过request.getParameterValues获取参数值
String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
}
}
return arg;
}
四、RequestHeaderMethodArgumentResolver
用于解析@RequestHeader
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
//从request的headers中获取值
String[] headerValues = request.getHeaderValues(name);
if (headerValues != null) {
return (headerValues.length == 1 ? headerValues[0] : headerValues);
}
else {
return null;
}
}
五、RequestAttributeMethodArgumentResolver
用于解析@RequestAttribute
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request){
//从attributes中获取值,SCOPE_REQUEST域,request.getAttribute
return request.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
}
六、ServletCookieValueMethodArgumentResolver
用于解析@CookieValue
protected Object resolveName(String cookieName, MethodParameter parameter,
NativeWebRequest webRequest) throws Exception {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
Assert.state(servletRequest != null, "No HttpServletRequest");
//从Cookie里获取值
Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName);
if (Cookie.class.isAssignableFrom(parameter.getNestedParameterType())) {
return cookieValue;
}
else if (cookieValue != null) {
return this.urlPathHelper.decodeRequestString(servletRequest, cookieValue.getValue());
}
else {
return null;
}
}
七、SessionAttributeMethodArgumentResolver
用于解析@SessionAttribute
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) {
//从attributes中获取值,SCOPE_SESSION域,session.getAttribute
return request.getAttribute(name, RequestAttributes.SCOPE_SESSION);
}
八、MatrixVariableMethodArgumentResolver
用于解析@MatrixVariable
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
//获取路径参数
Map<String, MultiValueMap<String, String>> pathParameters = (Map<String, MultiValueMap<String, String>>)
request.getAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
if (CollectionUtils.isEmpty(pathParameters)) {
return null;
}
MatrixVariable ann = parameter.getParameterAnnotation(MatrixVariable.class);
Assert.state(ann != null, "No MatrixVariable annotation");
//路径变量名称
String pathVar = ann.pathVar();
List<String> paramValues = null;
if (!pathVar.equals(ValueConstants.DEFAULT_NONE)) {
if (pathParameters.containsKey(pathVar)) {
//根据变量名称和参数名称获取参数值
paramValues = pathParameters.get(pathVar).get(name);
}
}
else {
boolean found = false;
paramValues = new ArrayList<>();
//遍历路径变量名,匹配参数名称,获取参数值
for (MultiValueMap<String, String> params : pathParameters.values()) {
if (params.containsKey(name)) {
if (found) {
String paramType = parameter.getNestedParameterType().getName();
throw new ServletRequestBindingException(
"Found more than one match for URI path parameter '" + name +
"' for parameter type [" + paramType + "]. Use 'pathVar' attribute to disambiguate.");
}
paramValues.addAll(params.get(name));
found = true;
}
}
}
if (CollectionUtils.isEmpty(paramValues)) {
return null;
}
else if (paramValues.size() == 1) {
return paramValues.get(0);
}
else {
return paramValues;
}
}