首页 > 其他分享 >SpringMVC-解析对象

SpringMVC-解析对象

时间:2022-11-12 10:56:52浏览次数:39  
标签:解析 pv SpringMVC type request 对象 ex null parameter

如果参数是对象且没有注解,则参数由ServletModelAttributeMethodProcessor解析。解析如下参数:

@PostMapping("/userParam0")
@ResponseBody
public User handleUserByParam0(User user) {
	return user;
}

ModelAttributeMethodProcessor.supportsParameter(MethodParameter parameter)

public boolean supportsParameter(MethodParameter parameter) {
	return (parameter.hasParameterAnnotation(ModelAttribute.class) ||
			(this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));
}

如果参数有@ModelAttribute或者annotationNotRequired为true且参数类型不是简单类型。

BeanUtils.isSimpleProperty(Class<?> type)

public static boolean isSimpleProperty(Class<?> type) {
	Assert.notNull(type, "'type' must not be null");
	return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType()));
}

	public static boolean isSimpleValueType(Class<?> type) {
	return (Void.class != type && void.class != type &&
			(ClassUtils.isPrimitiveOrWrapper(type) ||
			Enum.class.isAssignableFrom(type) ||
			CharSequence.class.isAssignableFrom(type) ||
			Number.class.isAssignableFrom(type) ||
			Date.class.isAssignableFrom(type) ||
			Temporal.class.isAssignableFrom(type) ||
			URI.class == type ||
			URL.class == type ||
			Locale.class == type ||
			Class.class == type));
}

如果参数是以上类型或以上类型的数组则认为是简单类型。

ModelAttributeMethodProcessor.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 {

	Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
	Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");

	String name = ModelFactory.getNameForParameter(parameter);
	ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
	if (ann != null) {
		mavContainer.setBinding(name, ann.binding());
	}

	Object attribute = null;
	BindingResult bindingResult = null;

	if (mavContainer.containsAttribute(name)) {
		attribute = mavContainer.getModel().get(name);
	}
	else {
		// Create attribute instance
		try {
			attribute = createAttribute(name, parameter, binderFactory, webRequest);
		}
		catch (BindException ex) {
			if (isBindExceptionRequired(parameter)) {
				// No BindingResult parameter -> fail with BindException
				throw ex;
			}
			// Otherwise, expose null/empty value and associated BindingResult
			if (parameter.getParameterType() == Optional.class) {
				attribute = Optional.empty();
			}
			else {
				attribute = ex.getTarget();
			}
			bindingResult = ex.getBindingResult();
		}
	}

	if (bindingResult == null) {
		// Bean property binding and validation;
		// skipped in case of binding failure on construction.
		WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
		if (binder.getTarget() != null) {
			if (!mavContainer.isBindingDisabled(name)) {
				bindRequestParameters(binder, webRequest);
			}
			validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
				throw new BindException(binder.getBindingResult());
			}
		}
		// Value type adaptation, also covering java.util.Optional
		if (!parameter.getParameterType().isInstance(attribute)) {
			attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
		}
		bindingResult = binder.getBindingResult();
	}

	// Add resolved attribute and BindingResult at the end of the model
	Map<String, Object> bindingResultModel = bindingResult.getModel();
	mavContainer.removeAttributes(bindingResultModel);
	mavContainer.addAllAttributes(bindingResultModel);

	return attribute;
}

1、获取参数名,首先从@ModelAttribute获取value属性,如果没有获取参数名
2、如果ModelAndViewContainer有属性值则从ModelAndViewContainer获取
3、createAttribute创建属性值
4、如果bindingResult为null,bindRequestParameters绑定参数

ServletModelAttributeMethodProcessor.createAttribute(String attributeName, MethodParameter parameter,
WebDataBinderFactory binderFactory, NativeWebRequest request)

protected final Object createAttribute(String attributeName, MethodParameter parameter,
		WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {

	String value = getRequestValueForAttribute(attributeName, request);
	if (value != null) {
		Object attribute = createAttributeFromRequestValue(
				value, attributeName, parameter, binderFactory, request);
		if (attribute != null) {
			return attribute;
		}
	}

	return super.createAttribute(attributeName, parameter, binderFactory, request);
}

1、从request中获取属性值
2、如果存在属性值调用createAttributeFromRequestValue进行值的类型转换
3、否则调用父类createAttribute

ServletModelAttributeMethodProcessor.getRequestValueForAttribute(String attributeName, NativeWebRequest request)

protected String getRequestValueForAttribute(String attributeName, NativeWebRequest request) {
	Map<String, String> variables = getUriTemplateVariables(request);
	String variableValue = variables.get(attributeName);
	if (StringUtils.hasText(variableValue)) {
		return variableValue;
	}
	String parameterValue = request.getParameter(attributeName);
	if (StringUtils.hasText(parameterValue)) {
		return parameterValue;
	}
	return null;
}

1、从uri模板变量中获取属性值,存在则返回
2、通过属性名从request获取属性值

ModelAttributeMethodProcessor.createAttribute(String attributeName, MethodParameter parameter,
WebDataBinderFactory binderFactory, NativeWebRequest webRequest)

protected Object createAttribute(String attributeName, MethodParameter parameter,
		WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception {

	MethodParameter nestedParameter = parameter.nestedIfOptional();
	Class<?> clazz = nestedParameter.getNestedParameterType();

	Constructor<?> ctor = BeanUtils.getResolvableConstructor(clazz);
	Object attribute = constructAttribute(ctor, attributeName, parameter, binderFactory, webRequest);
	if (parameter != nestedParameter) {
		attribute = Optional.of(attribute);
	}
	return attribute;
}

1、BeanUtils.getResolvableConstructor解析参数类型构造函数
2、constructAttribute实例化对象

ServletModelAttributeMethodProcessor.bindRequestParameters(WebDataBinder binder, NativeWebRequest request)

	protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
	ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
	Assert.state(servletRequest != null, "No ServletRequest");
	ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
	servletBinder.bind(servletRequest);
}

ServletRequestDataBinder调用bind绑定参数值

ServletRequestDataBinder.bind(ServletRequest request)

public void bind(ServletRequest request) {
	MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
	MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
	if (multipartRequest != null) {
		bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
	}
	else if (StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/")) {
		HttpServletRequest httpServletRequest = WebUtils.getNativeRequest(request, HttpServletRequest.class);
		if (httpServletRequest != null) {
			StandardServletPartUtils.bindParts(httpServletRequest, mpvs, isBindEmptyMultipartFiles());
		}
	}
	addBindValues(mpvs, request);
	doBind(mpvs);
}

1、创建ServletRequestParameterPropertyValues将request中的参数值转成MutablePropertyValues
2、解析Multipart请求
3、addBindValues将uri模板变量加入MutablePropertyValues
4、doBind绑定参数值

WebDataBinder.doBind(MutablePropertyValues mpvs)

	protected void doBind(MutablePropertyValues mpvs) {
	checkFieldDefaults(mpvs);
	checkFieldMarkers(mpvs);
	adaptEmptyArrayIndices(mpvs);
	super.doBind(mpvs);
}

调用父类doBind。

DataBinder.doBind(MutablePropertyValues mpvs)

protected void doBind(MutablePropertyValues mpvs) {
	checkAllowedFields(mpvs);
	checkRequiredFields(mpvs);
	applyPropertyValues(mpvs);
}

applyPropertyValues填充参数值

AbstractPropertyAccessor.setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)

public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
		throws BeansException {

	List<PropertyAccessException> propertyAccessExceptions = null;
	List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
			((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));

	if (ignoreUnknown) {
		this.suppressNotWritablePropertyException = true;
	}
	try {
		for (PropertyValue pv : propertyValues) {
			// setPropertyValue may throw any BeansException, which won't be caught
			// here, if there is a critical failure such as no matching field.
			// We can attempt to deal only with less serious exceptions.
			try {
				setPropertyValue(pv);
			}
			catch (NotWritablePropertyException ex) {
				if (!ignoreUnknown) {
					throw ex;
				}
				// Otherwise, just ignore it and continue...
			}
			catch (NullValueInNestedPathException ex) {
				if (!ignoreInvalid) {
					throw ex;
				}
				// Otherwise, just ignore it and continue...
			}
			catch (PropertyAccessException ex) {
				if (propertyAccessExceptions == null) {
					propertyAccessExceptions = new ArrayList<>();
				}
				propertyAccessExceptions.add(ex);
			}
		}
	}
	finally {
		if (ignoreUnknown) {
			this.suppressNotWritablePropertyException = false;
		}
	}

	// If we encountered individual exceptions, throw the composite exception.
	if (propertyAccessExceptions != null) {
		PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
		throw new PropertyBatchUpdateException(paeArray);
	}
}

遍历参数列表,调用setPropertyValue设置参数值。

AbstractNestablePropertyAccessor.setPropertyValue(PropertyValue pv)

public void setPropertyValue(PropertyValue pv) throws BeansException {
	PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
	if (tokens == null) {
		String propertyName = pv.getName();
		AbstractNestablePropertyAccessor nestedPa;
		try {
			nestedPa = getPropertyAccessorForPropertyPath(propertyName);
		}
		catch (NotReadablePropertyException ex) {
			throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
					"Nested property in path '" + propertyName + "' does not exist", ex);
		}
		tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
		if (nestedPa == this) {
			pv.getOriginalPropertyValue().resolvedTokens = tokens;
		}
		nestedPa.setPropertyValue(tokens, pv);
	}
	else {
		setPropertyValue(tokens, pv);
	}
}

如果tokens为null,调用AbstractNestablePropertyAccessor.setPropertyValue设置属性值。否则调用setPropertyValue设置属性值。

AbstractNestablePropertyAccessor.setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv)

protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
	if (tokens.keys != null) {
		processKeyedProperty(tokens, pv);
	}
	else {
		processLocalProperty(tokens, pv);
	}
}

如果keys不为null调用processKeyedProperty否则调用processLocalProperty。

AbstractNestablePropertyAccessor.processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv)

private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
	PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
	if (ph == null || !ph.isWritable()) {
		if (pv.isOptional()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Ignoring optional value for property '" + tokens.actualName +
						"' - property not found on bean class [" + getRootClass().getName() + "]");
			}
			return;
		}
		if (this.suppressNotWritablePropertyException) {
			// Optimization for common ignoreUnknown=true scenario since the
			// exception would be caught and swallowed higher up anyway...
			return;
		}
		throw createNotWritablePropertyException(tokens.canonicalName);
	}

	Object oldValue = null;
	try {
		Object originalValue = pv.getValue();
		Object valueToApply = originalValue;
		if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
			if (pv.isConverted()) {
				valueToApply = pv.getConvertedValue();
			}
			else {
				if (isExtractOldValueForEditor() && ph.isReadable()) {
					try {
						oldValue = ph.getValue();
					}
					catch (Exception ex) {
						if (ex instanceof PrivilegedActionException) {
							ex = ((PrivilegedActionException) ex).getException();
						}
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read previous value of property '" +
									this.nestedPath + tokens.canonicalName + "'", ex);
						}
					}
				}
				valueToApply = convertForProperty(
						tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
			}
			pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
		}
		ph.setValue(valueToApply);
	}
	catch (TypeMismatchException ex) {
		throw ex;
	}
	catch (InvocationTargetException ex) {
		PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
				getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
		if (ex.getTargetException() instanceof ClassCastException) {
			throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
		}
		else {
			Throwable cause = ex.getTargetException();
			if (cause instanceof UndeclaredThrowableException) {
				// May happen e.g. with Groovy-generated methods
				cause = cause.getCause();
			}
			throw new MethodInvocationException(propertyChangeEvent, cause);
		}
	}
	catch (Exception ex) {
		PropertyChangeEvent pce = new PropertyChangeEvent(
				getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
		throw new MethodInvocationException(pce, ex);
	}
}

从PropertyValue中获取属性值类型转换后并设置。

标签:解析,pv,SpringMVC,type,request,对象,ex,null,parameter
From: https://www.cnblogs.com/shigongp/p/16882781.html

相关文章

  • 【JavaScript】Math对象知识全解
    文章目录​​前言​​​​常用属性​​​​常用方法​​​​实例参考​​前言除了简单的加减乘除,在某些长和开发者需要进行更为复杂的数学运算。JavaScript的Math对象提供了......
  • 10. 对象深拷贝问题
    首先,要知道基本数据保存在栈内存,对象数据保存在堆内存,对象地址(就是变量名)保存在栈内存,浅拷贝只会复制栈内存的内容,而深拷贝会复制栈和堆内存中的内容;所以深拷贝的对象有......
  • python 某猫投诉加密解析
    importhashlibimportjsonimportrandomimporttimeimportrequestssha256=hashlib.sha256()'''某猫投诉https://jiangsu.tousu.sina.com.cn/'''classBlackCatComplain......
  • 学Java· 从new说对象实例化
    概念了解想要知道内存中发生了什么,我们先来了解两个内存概念......
  • SpringMVC
    SpringMVC:学习视频-狂神说SpringMVC:视频链接SpringMVCssm:mybatis+Spring+SpringMVCMVC三层架构JavaSE:认真学习,老师带,入门快!JavaWeb:认真学习,老师带,入门快!......
  • SpringMVC-解析@RequestParam参数
    InvocableHandlerMethod.invokeForRequest执行请求时会调用InvocableHandlerMethod.getMethodArgumentValues解析方法参数。InvocableHandlerMethod.getMethodArgumentVal......
  • unity3d修改对象属性
    unity3d修改对象属性 #regionvoidloadWorkerModel(Vector3init_position,stringworker_name,stringBDID){GameObjectobj=(GameObject)......
  • 在ElasticSearch 5.x 中,为字段类型为nested的对象新增属性字段
    PUTindex_name/type/_mapping{"properties":{"nested类型字段名称":{"type":"nested","properties":{"......
  • Linux开启DNS Server后解析外域受限问题
      CentOS7系统里起了一个DNSServer,一切顺利,针对本地域的各项解析都很成功,欢欣鼓舞。 在欢欣鼓舞时却发觉DNS服务器无法进行域外域名解析,查找原因发现除了本地定义的......
  • 快速掌握kafka原理解析
    ​简介​Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数......