首页 > 其他分享 >SpringMVC-解析@RequestParam参数

SpringMVC-解析@RequestParam参数

时间:2022-11-11 21:56:44浏览次数:55  
标签:解析 name RequestParam SpringMVC namedValueInfo MethodParameter arg null parameter

InvocableHandlerMethod.invokeForRequest执行请求时会调用InvocableHandlerMethod.getMethodArgumentValues解析方法参数。

InvocableHandlerMethod.getMethodArgumentValues

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	MethodParameter[] parameters = getMethodParameters();
	if (ObjectUtils.isEmpty(parameters)) {
		return EMPTY_ARGS;
	}

	Object[] args = new Object[parameters.length];
	for (int i = 0; i < parameters.length; i++) {
		MethodParameter parameter = parameters[i];
		parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
		args[i] = findProvidedArgument(parameter, providedArgs);
		if (args[i] != null) {
			continue;
		}
		if (!this.resolvers.supportsParameter(parameter)) {
			throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
		}
		try {
			args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
		}
		catch (Exception ex) {
			// Leave stack trace for later, exception may actually be resolved and handled...
			if (logger.isDebugEnabled()) {
				String exMsg = ex.getMessage();
				if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
					logger.debug(formatArgumentError(parameter, exMsg));
				}
			}
			throw ex;
		}
	}
	return args;
}

获取handle方法的所有参数,遍历参数,调用resolvers.supportsParameter判断方法解析器是否支持解析参数,如果支持并缓存。不支持则抛出异常。resolvers.resolveArgument解析参数。

HandlerMethodArgumentResolverComposite.supportsParameter(MethodParameter parameter)

public boolean supportsParameter(MethodParameter parameter) {
	return getArgumentResolver(parameter) != null;
}

HandlerMethodArgumentResolverComposite.getArgumentResolver(MethodParameter parameter)

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
	HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
	if (result == null) {
		for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
			if (resolver.supportsParameter(parameter)) {
				result = resolver;
				this.argumentResolverCache.put(parameter, result);
				break;
			}
		}
	}
	return result;
}

遍历参数解析器,调用resolver.supportsParameter判断是否支持解析参数,如支持则加入argumentResolverCache,返回。如果没有支持解析参数的解析器则返回null。@RequestParam参数由RequestParamMethodArgumentResolver解析。

RequestParamMethodArgumentResolver.supportsParameter(MethodParameter parameter)

public boolean supportsParameter(MethodParameter parameter) {
	if (parameter.hasParameterAnnotation(RequestParam.class)) {
		if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
			RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
			return (requestParam != null && StringUtils.hasText(requestParam.name()));
		}
		else {
			return true;
		}
	}
	else {
		if (parameter.hasParameterAnnotation(RequestPart.class)) {
			return false;
		}
		parameter = parameter.nestedIfOptional();
		if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
			return true;
		}
		else if (this.useDefaultResolution) {
			return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
		}
		else {
			return false;
		}
	}
}

如果参数有@RequestParam注解则返回true。

AbstractNamedValueMethodArgumentResolver.resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)

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);
		}
		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 {
			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;
}

1、getNamedValueInfo获取参数名
2、resolveEmbeddedValuesAndExpressions解析参数名,参数可能有表达式或${}
3、resolveName解析参数值
4、如果没有获取到参数值,resolveEmbeddedValuesAndExpressions解析默认值,handleNullValue处理null值。
5、创建WebDataBinder,调用convertIfNecessary转换参数类型

AbstractNamedValueMethodArgumentResolver.getNamedValueInfo

private NamedValueInfo getNamedValueInfo(MethodParameter parameter) {
	NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter);
	if (namedValueInfo == null) {
		namedValueInfo = createNamedValueInfo(parameter);
		namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
		this.namedValueInfoCache.put(parameter, namedValueInfo);
	}
	return namedValueInfo;
}

createNamedValueInfo创建参数名。updateNamedValueInfo进行参数名判断和默认值设置。

RequestParamMethodArgumentResolver.createNamedValueInfo(MethodParameter parameter)

protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
	RequestParam ann = parameter.getParameterAnnotation(RequestParam.class);
	return (ann != null ? new RequestParamNamedValueInfo(ann) : new RequestParamNamedValueInfo());
}

获取@RequestParam注解并创建RequestParamNamedValueInfo。

RequestParamNamedValueInfo(RequestParam annotation)

public RequestParamNamedValueInfo(RequestParam annotation) {
		super(annotation.name(), annotation.required(), annotation.defaultValue());
	}

设置@RequestParam注解中的name到RequestParamNamedValueInfo。

AbstractNamedValueMethodArgumentResolver.updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info)

private NamedValueInfo updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info) {
	String name = info.name;
	if (info.name.isEmpty()) {
		name = parameter.getParameterName();
		if (name == null) {
			throw new IllegalArgumentException(
					"Name for argument of type [" + parameter.getNestedParameterType().getName() +
					"] not specified, and parameter name information not found in class file either.");
		}
	}
	String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue);
	return new NamedValueInfo(name, info.required, defaultValue);
}

如果NamedValueInfo中的name为null,即@RequestParam注解没有设置name属性,则获取方法参数名为name,name,required属性和默认值封装成NamedValueInfo。

RequestParamMethodArgumentResolver.resolveName(String name, MethodParameter parameter, NativeWebRequest request)

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) {
		String[] paramValues = request.getParameterValues(name);
		if (paramValues != null) {
			arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
		}
	}
	return arg;
}

1、MultipartResolutionDelegate.resolveMultipartArgument解析MultipartArgument,如果请求时文件上传,则进入这里进行解析。
2、 multipartRequest.getFiles获取MultipartFile集合,如果请求时文件上传,则进入这里
3、request.getParameterValues通过参数名获取请求中的参数值

标签:解析,name,RequestParam,SpringMVC,namedValueInfo,MethodParameter,arg,null,parameter
From: https://www.cnblogs.com/shigongp/p/16882040.html

相关文章

  • Linux开启DNS Server后解析外域受限问题
      CentOS7系统里起了一个DNSServer,一切顺利,针对本地域的各项解析都很成功,欢欣鼓舞。 在欢欣鼓舞时却发觉DNS服务器无法进行域外域名解析,查找原因发现除了本地定义的......
  • 快速掌握kafka原理解析
    ​简介​Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数......
  • 三环PE文件自行加载,并运行,解析PE结构,修复IAT,修复重定位表
    1//PELoad.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。2//34#include<iostream>5#include<windows.h>6#include<tchar.h>......
  • onps栈使用说明(2)——ping、域名解析等网络工具测试
    1.ping测试协议栈提供ping工具,其头文件为“net_tools/ping.h”,将其include进你的目标系统中即可使用这个工具。……#include"onps.h"#include"net_tools/ping.h"/......
  • 微信小程序经纬度转化为具体位置(逆地址解析)
    小程序wx.getLocation只能获取经纬度,这时候想要具体地址就需要借助第三方sdk(逆地址解析)我这边第三方以腾讯位置服务举例一.首先小程序需要申请wx.getLocation接口权......
  • Gson解析Json实例
          研究GSON花费了我一天的时间,期间出现了各种问题,第一次可以理解嘛,不过还好在安卓开发交流22群几位大神的帮助和我极大的耐心一下终于搞出来了,多谢几位大神,这里......
  • Android实战--解析稍复杂JSON数据DEMO
    废话不多说,直接上代码,布局文件:<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_wid......
  • 【MySQL(八)】一致性非锁定读 锁定读 解析
    一致性非锁定读与锁定读的区别主要针对的是读操作在加锁方式上的差别。这里先看下锁的分类吧。mysql的行锁分为读锁与写锁。读锁即S锁,也叫共享锁,当事务读取一行数据时,会尝试......
  • 【SpringMVC(三)】 HandlerAdapter
    HandlerAdapter在springmvc中是一个十分重要的角色。作用如下:1.负责直接调用控制器来处理请求;2.负责在调用控制器的前定制化处理request以及在调用后定制化处理response;3.隐......
  • Wireshark抓包工具解析HTTPS包
    转载来自:https://juejin.cn/post/7093132422150029325一、遇到的问题本学期的计算机网络课程需要使用到Wireshark抓包工具进行网络抓包实验,原本可以看到在该软件......