springMVC数据绑定流程
- springMVC框架将ServletRequest对象及方法的如参实例传递给WebDataBinderFactory石丽以创建DataBinder对象。
- DataBinder调用装配在springMVC上下文的ConversionService组件进行数据类型转换、数据格式化(类型转换和格式化是一起的一会来看源码),将Servlet中的请求信息填充到如参的对象中。
- 调用Validator组件对已经完成绑定了的请求消息的入参对象进行数据合法性校验,把最终生成数据绑定结果BindingData对象
- 如果在数据类型转换、格式化和校验的过程中出现错误的话,会把处理的结果放到BindingResult对象中,将它们赋给处理方法的响应入参。
运行路程
public final Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest request, WebDataBinderFactory binderFactory)
throws Exception {
String name = ModelFactory.getNameForParameter(parameter);
Object attribute = (mavContainer.containsAttribute(name)) ?
mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, request);
WebDataBinder binder = binderFactory.createBinder(request, attribute, name);
if (binder.getTarget() != null) {
bindRequestParameters(binder, request);
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors()) {
if (isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
}
// Add resolved attribute and BindingResult at the end of the model
Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return binder.getTarget();
}
10行,创建了一个WebDataBinder对象。传入了request,目标方法的参数,还有属性名(目标方法中没有加@ModelAttribute修饰,为目标方法如参类名第一个字母小写)。
12,13行,分别进行数据的绑定和校验。
来看一下创建的binder对象。
这个对象中就包括了数据的转换格式化(conversionService,从名字上就能看出来,包含了Formatting和Conversion),使用数据校验(validators)组件完成的数据效验,如果在数据转换格式化或者是娇艳过程中出现错误会把结果放在绑定结果(bindingResult)中。
那么类型转换是怎么用的conversionService
ConversionService converters =
java.lang.String -> java.lang.Boolean : org.springframework.core.convert.support.StringToBooleanConverter@343a5919
java.lang.String -> java.lang.Character : org.springframework.core.convert.support.StringToCharacterConverter@7018c855
java.lang.String -> java.lang.Enum : org.springframework.core.convert.support.StringToEnumConverterFactory@5efbc794
java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@14730670
java.lang.String -> java.time.Instant: org.springframework.format.datetime.standard.InstantFormatter@381724b3
java.lang.String -> java.util.Locale : org.springframework.core.convert.support.StringToLocaleConverter@913ac16
java.lang.String -> java.util.Properties : org.springframework.core.convert.support.StringToPropertiesConverter@7d0ad4f7
java.lang.String -> java.util.UUID : org.springframework.core.convert.support.StringToUUIDConverter@38289799
java.time.Instant -> java.lang.String : org.springframework.format.datetime.standard.InstantFormatter@381724b3
java.time.ZoneId -> java.util.TimeZone : org.springframework.core.convert.support.ZoneIdToTimeZoneConverter@1731f746
java.util.Calendar -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToLongConverter@84b6b20
java.util.Calendar -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToDateConverter@9f8e410
java.util.Date -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$DateToLongConverter@560357e6
java....
conversionService中内建了很多转换器,可以完成大多数java类型的转换工作。譬如、
java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@14730670
这个就完成了字符串和数字之间的转换。
完成数据的转换后,紧接着13行,进行格式化。