【Web请求处理】自定义对象参数解析原理

自定义对象参数解析原理

请求参数可以封装到自定义对象参数中

    @PostMapping("/saveuser")
    public Person saveUser(Person person) {
        return person;
    }

提交表单数据

<form action="/saveuser" method="post">
    姓名:<input name="userName" value="zhangsan"/>
    年龄:<input name="age" value="23"/>
    生日:<input name="birth" value="2021/6/10"/>
    宠物姓名:<input name="pet.name" value="小白"/>
    宠物年龄:<input name="pet.age" value="5"/>
    <input type="submit" value="提交"/>
</form>

在这里插入图片描述
这就是数据绑定,页面提交的请求数据,无论是GETPOST请求,都可以和对象属性进行绑定

自定义类型的参数,是使用ServletModelAttributeMethodProcessor这个参数处理器来封装POJO的。它会判断是否是简单类型

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

如果不是简单数据类型,而是自定义的参数类型,就会创建一个Web数据绑定器WebDataBinder,数据绑定器会将请求参数的值绑定到指定的JavaBean里面。而这个JavaBean就是调用createAttribute()方法创建的空对象attribute,这个空对象被binderFactory.createBinder()方法封装到了数据绑定器binder中。然后会利用底层的类型转换器,将请求过来的参数值转换成对象对应的属性类型,封装到对应的属性中。

@Override
	@Nullable
	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();
				}
				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;
	}

所以WebDataBinder就是利用converters将请求数据转成指定的数据类型,再次封装到JavaBean中
在这里插入图片描述
GenericConversionService在设置每一个值的时候,找它里面的所有converter,判断哪个converter可以将这个数据类型(request带来参数的字符串)转换到指定的类型(JavaBean属性对应的数据类型)
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值