一、问题引入
在做 Restful 案例的时候,我们在控制器方法入参位置写一个 Employee 类型的参数,SpringMVC 就能把表单中各项属性封装到参数中,这是怎么做到的呢?
//SpringMVC把表单提交的数据都封装到employee 对象中
@RequestMapping(value = "/emp", method = RequestMethod.POST)
public String addEmp(Employee employee) {
System.out.println("employee = " + employee);
employeeDao.save(employee);
//重定向到 emps 查询所有,然后在 list.jsp 显示
return "redirect:/emps";
}
SpringMVC 封装自定义类型对象的时候,JavaBean 要和页面提交的数据进行一一绑定,它是如何做到的呢?
既然要做到前端页面提交的值与 JavaBean 的属性进行绑定:
(1)页面提交的所有数据都是字符串;
(2)对于 Integer age,Date birth 这样的属性,需要做一定的转换操作:
employeName=zhangsan&age=18&gender=1
String age = reuqest.getParameter("age");
既然肯定会牵扯到以下操作:
1、数据类型转换:数据绑定期间的数据类型转换?String->Integer
2、数据格式化:数据绑定期间的数据格式化问题,比如提交的日期进行转换;
birth=2021-11-30 ---> Date 2021.11.30 2021/11/30 2021-11-30
3、数据校验:
我们提交的数据必须是合法的?
前端校验:JavaScript + 正则表达式
后端校验:重要的数据也必须进行校验:校验成功:数据合法;校验失败:提示错误;
二、数据绑定流程原理
① Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象;
② DataBinder 调用装配在 Spring MVC 上下文中的 ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中;
③ 调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果 BindingData 对象;
④ Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参;
Spring MVC 通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是 DataBinder,运行机制如下:
源码分析:
核心代码:
ModelAttributeMethodProcessor:
resolveArgument() 解析参数
bindRequestParameters(binder, request); 将页面提交的数据封装到 JavaBean 的属性中
------------------------------------------------
@Override
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) {
//将页面提交过来的数据封装到 JavaBean 的属性中
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();
}
三、通过debug调试流程
① 查看数据绑定流程,在Employee类的set方法上设置断点调试
WedDataBinder:
② Spring MVC 上下文中内建了很多转换器,可完成大多数 Java 类型的转换工作。
conversionService.converters= result = {LinkedHashMap@5127} size = 97 {GenericConverter$ConvertiblePair@5227} "java.lang.Number -> java.lang.Number" -> {GenericConversionService$ConvertersForPair@5228} "java.lang.Number -> java.lang.Number : org.springframework.core.convert.support.NumberToNumberConverterFactory@68161576" {GenericConverter$ConvertiblePair@5229} "java.lang.String -> java.lang.Number" -> {GenericConversionService$ConvertersForPair@5230} "java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@2d148610" {GenericConverter$ConvertiblePair@5231} "java.lang.Number -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5232} "java.lang.Number -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@3c1bc3fa" {GenericConverter$ConvertiblePair@5233} "java.lang.String -> java.lang.Character" -> {GenericConversionService$ConvertersForPair@5234} "java.lang.String -> java.lang.Character : org.springframework.core.convert.support.StringToCharacterConverter@1cf34886" {GenericConverter$ConvertiblePair@5235} "java.lang.Character -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5236} "java.lang.Character -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@441653cb" {GenericConverter$ConvertiblePair@5237} "java.lang.Number -> java.lang.Character" -> {GenericConversionService$ConvertersForPair@5238} "java.lang.Number -> java.lang.Character : org.springframework.core.convert.support.NumberToCharacterConverter@4d3b795f" {GenericConverter$ConvertiblePair@5239} "java.lang.Character -> java.lang.Number" -> {GenericConversionService$ConvertersForPair@5240} "java.lang.Character -> java.lang.Number : org.springframework.core.convert.support.CharacterToNumberFactory@2f5d6711" {GenericConverter$ConvertiblePair@5241} "java.lang.String -> java.lang.Boolean" -> {GenericConversionService$ConvertersForPair@5242} "java.lang.String -> java.lang.Boolean : org.springframework.core.convert.support.StringToBooleanConverter@296cad04" {GenericConverter$ConvertiblePair@5243} "java.lang.Boolean -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5244} "java.lang.Boolean -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@5f123be9" {GenericConverter$ConvertiblePair@5245} "java.lang.String -> java.lang.Enum" -> {GenericConversionService$ConvertersForPair@5246} "java.lang.String -> java.lang.Enum : org.springframework.core.convert.support.StringToEnumConverterFactory@497540d5" {GenericConverter$ConvertiblePair@5247} "java.lang.Enum -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5248} "java.lang.Enum -> java.lang.String : org.springframework.core.convert.support.EnumToStringConverter@dd4d305" {GenericConverter$ConvertiblePair@5249} "java.lang.String -> java.util.Locale" -> {GenericConversionService$ConvertersForPair@5250} "java.lang.String -> java.util.Locale : org.springframework.core.convert.support.StringToLocaleConverter@411c5b36" {GenericConverter$ConvertiblePair@5251} "java.util.Locale -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5252} "java.util.Locale -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@f1ffd8f" {GenericConverter$ConvertiblePair@5253} "java.lang.String -> java.util.Properties" -> {GenericConversionService$ConvertersForPair@5254} "java.lang.String -> java.util.Properties : org.springframework.core.convert.support.StringToPropertiesConverter@6c0f6751" {GenericConverter$ConvertiblePair@5255} "java.util.Properties -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5256} "java.util.Properties -> java.lang.String : org.springframework.core.convert.support.PropertiesToStringConverter@47e8dd2e" {GenericConverter$ConvertiblePair@5257} "java.lang.String -> java.util.UUID" -> {GenericConversionService$ConvertersForPair@5258} "java.lang.String -> java.util.UUID : org.springframework.core.convert.support.StringToUUIDConverter@640eeb0e" {GenericConverter$ConvertiblePair@5259} "java.util.UUID -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5260} "java.util.UUID -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@140d8185" {GenericConverter$ConvertiblePair@5261} "[Ljava.lang.Object; -> java.util.Collection" -> {GenericConversionService$ConvertersForPair@5262} "org.springframework.core.convert.support.ArrayToCollectionConverter@32f59ba" {GenericConverter$ConvertiblePair@5263} "java.util.Collection -> [Ljava.lang.Object;" -> {GenericConversionService$ConvertersForPair@5264} "org.springframework.core.convert.support.CollectionToArrayConverter@2aff55c" {GenericConverter$ConvertiblePair@5265} "[Ljava.lang.Object; -> [Ljava.lang.Object;" -> {GenericConversionService$ConvertersForPair@5266} "org.springframework.core.convert.support.ArrayToArrayConverter@116a289c" {GenericConverter$ConvertiblePair@5267} "java.util.Collection -> java.util.Collection" -> {GenericConversionService$ConvertersForPair@5268} "org.springframework.core.convert.support.CollectionToCollectionConverter@6913829d" {GenericConverter$ConvertiblePair@5269} "java.util.Map -> java.util.Map" -> {GenericConversionService$ConvertersForPair@5270} "org.springframework.core.convert.support.MapToMapConverter@1088e48c" {GenericConverter$ConvertiblePair@5271} "[Ljava.lang.Object; -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5272} "org.springframework.core.convert.support.ArrayToStringConverter@6d70f6d4" {GenericConverter$ConvertiblePair@5273} "java.lang.String -> [Ljava.lang.Object;" -> {GenericConversionService$ConvertersForPair@5274} "org.springframework.core.convert.support.StringToArrayConverter@2d1e0d2e" {GenericConverter$ConvertiblePair@5275} "[Ljava.lang.Object; -> java.lang.Object" -> {GenericConversionService$ConvertersForPair@5276} "org.springframework.core.convert.support.ArrayToObjectConverter@58ec757a" {GenericConverter$ConvertiblePair@5277} "java.lang.Object -> [Ljava.lang.Object;" -> {GenericConversionService$ConvertersForPair@5278} "org.springframework.core.convert.support.ObjectToArrayConverter@f17566f" {GenericConverter$ConvertiblePair@5279} "java.util.Collection -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5280} "org.springframework.core.convert.support.CollectionToStringConverter@65bbc70f" {GenericConverter$ConvertiblePair@5281} "java.lang.String -> java.util.Collection" -> {GenericConversionService$ConvertersForPair@5282} "org.springframework.core.convert.support.StringToCollectionConverter@3891c1eb" {GenericConverter$ConvertiblePair@5283} "java.util.Collection -> java.lang.Object" -> {GenericConversionService$ConvertersForPair@5284} "org.springframework.core.convert.support.CollectionToObjectConverter@3ed2426" {GenericConverter$ConvertiblePair@5285} "java.lang.Object -> java.util.Collection" -> {GenericConversionService$ConvertersForPair@5286} "org.springframework.core.convert.support.ObjectToCollectionConverter@36fcae1a" {GenericConverter$ConvertiblePair@5287} "java.nio.ByteBuffer -> java.lang.Object" -> {GenericConversionService$ConvertersForPair@5288} "org.springframework.core.convert.support.ByteBufferConverter@dc48475" {GenericConverter$ConvertiblePair@5289} "java.lang.Object -> java.nio.ByteBuffer" -> {GenericConversionService$ConvertersForPair@5290} "org.springframework.core.convert.support.ByteBufferConverter@dc48475" {GenericConverter$ConvertiblePair@5291} "java.time.ZoneId -> java.util.TimeZone" -> {GenericConversionService$ConvertersForPair@5292} "java.time.ZoneId -> java.util.TimeZone : org.springframework.core.convert.support.ZoneIdToTimeZoneConverter@3bec82bf" {GenericConverter$ConvertiblePair@5293} "java.time.ZonedDateTime -> java.util.Calendar" -> {GenericConversionService$ConvertersForPair@5294} "java.time.ZonedDateTime -> java.util.Calendar : org.springframework.core.convert.support.ZonedDateTimeToCalendarConverter@514a4df0" {GenericConverter$ConvertiblePair@5295} "java.lang.Object -> java.lang.Object" -> {GenericConversionService$ConvertersForPair@5296} "org.springframework.core.convert.support.IdToEntityConverter@295a5bd,org.springframework.core.convert.support.ObjectToObjectConverter@2b5b7eb6" {GenericConverter$ConvertiblePair@5297} "java.lang.Object -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5298} "org.springframework.core.convert.support.FallbackObjectToStringConverter@747de818" {GenericConverter$ConvertiblePair@5299} "java.lang.Object -> java.util.Optional" -> {GenericConversionService$ConvertersForPair@5300} "org.springframework.core.convert.support.ObjectToOptionalConverter@77db0eaa" {GenericConverter$ConvertiblePair@5301} "java.lang.Long -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5302} "@org.springframework.format.annotation.DateTimeFormat java.lang.Long -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@584ce5a1,@org.springframework.format.annotation.NumberFormat java.lang.Long -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5303} "java.lang.String -> java.lang.Long" -> {GenericConversionService$ConvertersForPair@5304} "java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.lang.Long: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@584ce5a1,java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Long: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5305} "java.math.BigInteger -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5306} "@org.springframework.format.annotation.NumberFormat java.math.BigInteger -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5307} "java.lang.String -> java.math.BigInteger" -> {GenericConversionService$ConvertersForPair@5308} "java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigInteger: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5309} "java.lang.Float -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5310} "@org.springframework.format.annotation.NumberFormat java.lang.Float -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5311} "java.lang.String -> java.lang.Float" -> {GenericConversionService$ConvertersForPair@5312} "java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Float: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5313} "java.lang.Double -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5314} "@org.springframework.format.annotation.NumberFormat java.lang.Double -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5315} "java.lang.String -> java.lang.Double" -> {GenericConversionService$ConvertersForPair@5316} "java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Double: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5317} "java.lang.Short -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5318} "@org.springframework.format.annotation.NumberFormat java.lang.Short -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5319} "java.lang.String -> java.lang.Short" -> {GenericConversionService$ConvertersForPair@5320} "java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Short: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5321} "java.lang.Integer -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5322} "@org.springframework.format.annotation.NumberFormat java.lang.Integer -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5323} "java.lang.String -> java.lang.Integer" -> {GenericConversionService$ConvertersForPair@5324} "java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Integer: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5325} "java.lang.Byte -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5326} "@org.springframework.format.annotation.NumberFormat java.lang.Byte -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5327} "java.lang.String -> java.lang.Byte" -> {GenericConversionService$ConvertersForPair@5328} "java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Byte: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5329} "java.math.BigDecimal -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5330} "@org.springframework.format.annotation.NumberFormat java.math.BigDecimal -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5331} "java.lang.String -> java.math.BigDecimal" -> {GenericConversionService$ConvertersForPair@5332} "java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigDecimal: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@28929ed0" {GenericConverter$ConvertiblePair@5333} "java.util.Date -> java.lang.Long" -> {GenericConversionService$ConvertersForPair@5334} "java.util.Date -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$DateToLongConverter@33349ef2,java.util.Date -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$DateToLongConverter@1cb56860" {GenericConverter$ConvertiblePair@5335} "java.util.Date -> java.util.Calendar" -> {GenericConversionService$ConvertersForPair@5336} "java.util.Date -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$DateToCalendarConverter@236be7ba,java.util.Date -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$DateToCalendarConverter@1f338919" {GenericConverter$ConvertiblePair@5337} "java.util.Calendar -> java.util.Date" -> {GenericConversionService$ConvertersForPair@5338} "java.util.Calendar -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToDateConverter@8675703,java.util.Calendar -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToDateConverter@3f26c807" {GenericConverter$ConvertiblePair@5339} "java.util.Calendar -> java.lang.Long" -> {GenericConversionService$ConvertersForPair@5340} "java.util.Calendar -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToLongConverter@438cbe6e,java.util.Calendar -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToLongConverter@40f48c47" {GenericConverter$ConvertiblePair@5341} "java.lang.Long -> java.util.Date" -> {GenericConversionService$ConvertersForPair@5342} "java.lang.Long -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$LongToDateConverter@72191415,java.lang.Long -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$LongToDateConverter@7bf68ca1" {GenericConverter$ConvertiblePair@5343} "java.lang.Long -> java.util.Calendar" -> {GenericConversionService$ConvertersForPair@5344} "java.lang.Long -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$LongToCalendarConverter@5daf227f,java.lang.Long -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$LongToCalendarConverter@39dd1b39" {GenericConverter$ConvertiblePair@5345} "java.time.LocalDateTime -> java.time.LocalDate" -> {GenericConversionService$ConvertersForPair@5346} "java.time.LocalDateTime -> java.time.LocalDate : org.springframework.format.datetime.standard.DateTimeConverters$LocalDateTimeToLocalDateConverter@3de19ab" {GenericConverter$ConvertiblePair@5347} "java.time.LocalDateTime -> java.time.LocalTime" -> {GenericConversionService$ConvertersForPair@5348} "java.time.LocalDateTime -> java.time.LocalTime : org.springframework.format.datetime.standard.DateTimeConverters$LocalDateTimeToLocalTimeConverter@4c021ef5" {GenericConverter$ConvertiblePair@5349} "java.time.ZonedDateTime -> java.time.LocalDate" -> {GenericConversionService$ConvertersForPair@5350} "java.time.ZonedDateTime -> java.time.LocalDate : org.springframework.format.datetime.standard.DateTimeConverters$ZonedDateTimeToLocalDateConverter@681a61d0" {GenericConverter$ConvertiblePair@5351} "java.time.ZonedDateTime -> java.time.LocalTime" -> {GenericConversionService$ConvertersForPair@5352} "java.time.ZonedDateTime -> java.time.LocalTime : org.springframework.format.datetime.standard.DateTimeConverters$ZonedDateTimeToLocalTimeConverter@39cfbb39" {GenericConverter$ConvertiblePair@5353} "java.time.ZonedDateTime -> java.time.LocalDateTime" -> {GenericConversionService$ConvertersForPair@5354} "java.time.ZonedDateTime -> java.time.LocalDateTime : org.springframework.format.datetime.standard.DateTimeConverters$ZonedDateTimeToLocalDateTimeConverter@4aaffeea" {GenericConverter$ConvertiblePair@5355} "java.time.ZonedDateTime -> java.time.OffsetDateTime" -> {GenericConversionService$ConvertersForPair@5356} "java.time.ZonedDateTime -> java.time.OffsetDateTime : org.springframework.format.datetime.standard.DateTimeConverters$ZonedDateTimeToOffsetDateTimeConverter@1686a4fc" {GenericConverter$ConvertiblePair@5357} "java.time.ZonedDateTime -> java.time.Instant" -> {GenericConversionService$ConvertersForPair@5358} "java.time.ZonedDateTime -> java.time.Instant : org.springframework.format.datetime.standard.DateTimeConverters$ZonedDateTimeToInstantConverter@2d29531d" {GenericConverter$ConvertiblePair@5359} "java.time.OffsetDateTime -> java.time.LocalDate" -> {GenericConversionService$ConvertersForPair@5360} "java.time.OffsetDateTime -> java.time.LocalDate : org.springframework.format.datetime.standard.DateTimeConverters$OffsetDateTimeToLocalDateConverter@69fb23f2" {GenericConverter$ConvertiblePair@5361} "java.time.OffsetDateTime -> java.time.LocalTime" -> {GenericConversionService$ConvertersForPair@5362} "java.time.OffsetDateTime -> java.time.LocalTime : org.springframework.format.datetime.standard.DateTimeConverters$OffsetDateTimeToLocalTimeConverter@5c16d889" {GenericConverter$ConvertiblePair@5363} "java.time.OffsetDateTime -> java.time.LocalDateTime" -> {GenericConversionService$ConvertersForPair@5364} "java.time.OffsetDateTime -> java.time.LocalDateTime : org.springframework.format.datetime.standard.DateTimeConverters$OffsetDateTimeToLocalDateTimeConverter@7f9426b3" {GenericConverter$ConvertiblePair@5365} "java.time.OffsetDateTime -> java.time.ZonedDateTime" -> {GenericConversionService$ConvertersForPair@5366} "java.time.OffsetDateTime -> java.time.ZonedDateTime : org.springframework.format.datetime.standard.DateTimeConverters$OffsetDateTimeToZonedDateTimeConverter@18c233e7" {GenericConverter$ConvertiblePair@5367} "java.time.OffsetDateTime -> java.time.Instant" -> {GenericConversionService$ConvertersForPair@5368} "java.time.OffsetDateTime -> java.time.Instant : org.springframework.format.datetime.standard.DateTimeConverters$OffsetDateTimeToInstantConverter@289667be" {GenericConverter$ConvertiblePair@5369} "java.util.Calendar -> java.time.ZonedDateTime" -> {GenericConversionService$ConvertersForPair@5370} "java.util.Calendar -> java.time.ZonedDateTime : org.springframework.format.datetime.standard.DateTimeConverters$CalendarToZonedDateTimeConverter@422e30b5" {GenericConverter$ConvertiblePair@5371} "java.util.Calendar -> java.time.OffsetDateTime" -> {GenericConversionService$ConvertersForPair@5372} "java.util.Calendar -> java.time.OffsetDateTime : org.springframework.format.datetime.standard.DateTimeConverters$CalendarToOffsetDateTimeConverter@1cd137fd" {GenericConverter$ConvertiblePair@5373} "java.util.Calendar -> java.time.LocalDate" -> {GenericConversionService$ConvertersForPair@5374} "java.util.Calendar -> java.time.LocalDate : org.springframework.format.datetime.standard.DateTimeConverters$CalendarToLocalDateConverter@1585728b" {GenericConverter$ConvertiblePair@5375} "java.util.Calendar -> java.time.LocalTime" -> {GenericConversionService$ConvertersForPair@5376} "java.util.Calendar -> java.time.LocalTime : org.springframework.format.datetime.standard.DateTimeConverters$CalendarToLocalTimeConverter@e355c12" {GenericConverter$ConvertiblePair@5377} "java.util.Calendar -> java.time.LocalDateTime" -> {GenericConversionService$ConvertersForPair@5378} "java.util.Calendar -> java.time.LocalDateTime : org.springframework.format.datetime.standard.DateTimeConverters$CalendarToLocalDateTimeConverter@3d2d7ef9" {GenericConverter$ConvertiblePair@5379} "java.util.Calendar -> java.time.Instant" -> {GenericConversionService$ConvertersForPair@5380} "java.util.Calendar -> java.time.Instant : org.springframework.format.datetime.standard.DateTimeConverters$CalendarToInstantConverter@2856c87e" {GenericConverter$ConvertiblePair@5381} "java.lang.Long -> java.time.Instant" -> {GenericConversionService$ConvertersForPair@5382} "java.lang.Long -> java.time.Instant : org.springframework.format.datetime.standard.DateTimeConverters$LongToInstantConverter@16f9f6d5" {GenericConverter$ConvertiblePair@5383} "java.time.Instant -> java.lang.Long" -> {GenericConversionService$ConvertersForPair@5384} "java.time.Instant -> java.lang.Long : org.springframework.format.datetime.standard.DateTimeConverters$InstantToLongConverter@3208fdd4" {GenericConverter$ConvertiblePair@5385} "java.time.LocalDate -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5386} "@org.springframework.format.annotation.DateTimeFormat java.time.LocalDate -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.time.LocalDate -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@7a0fb60c" {GenericConverter$ConvertiblePair@5387} "java.lang.String -> java.time.LocalDate" -> {GenericConversionService$ConvertersForPair@5388} "java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.LocalDate: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.lang.String -> java.time.LocalDate: org.springframework.format.datetime.standard.TemporalAccessorParser@2319a8c6" {GenericConverter$ConvertiblePair@5389} "java.time.LocalTime -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5390} "@org.springframework.format.annotation.DateTimeFormat java.time.LocalTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.time.LocalTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@560a172c" {GenericConverter$ConvertiblePair@5391} "java.lang.String -> java.time.LocalTime" -> {GenericConversionService$ConvertersForPair@5392} "java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.LocalTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.lang.String -> java.time.LocalTime: org.springframework.format.datetime.standard.TemporalAccessorParser@1670e060" {GenericConverter$ConvertiblePair@5393} "java.time.LocalDateTime -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5394} "@org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.time.LocalDateTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@11c88b74" {GenericConverter$ConvertiblePair@5395} "java.lang.String -> java.time.LocalDateTime" -> {GenericConversionService$ConvertersForPair@5396} "java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.lang.String -> java.time.LocalDateTime: org.springframework.format.datetime.standard.TemporalAccessorParser@7f794e13" {GenericConverter$ConvertiblePair@5397} "java.time.ZonedDateTime -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5398} "@org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.time.ZonedDateTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@794c95a7" {GenericConverter$ConvertiblePair@5399} "java.lang.String -> java.time.ZonedDateTime" -> {GenericConversionService$ConvertersForPair@5400} "java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.lang.String -> java.time.ZonedDateTime: org.springframework.format.datetime.standard.TemporalAccessorParser@68ae090e" {GenericConverter$ConvertiblePair@5401} "java.time.OffsetDateTime -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5402} "@org.springframework.format.annotation.DateTimeFormat java.time.OffsetDateTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.time.OffsetDateTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@3d68ac44" {GenericConverter$ConvertiblePair@5403} "java.lang.String -> java.time.OffsetDateTime" -> {GenericConversionService$ConvertersForPair@5404} "java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.OffsetDateTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.lang.String -> java.time.OffsetDateTime: org.springframework.format.datetime.standard.TemporalAccessorParser@854642c" {GenericConverter$ConvertiblePair@5405} "java.time.OffsetTime -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5406} "@org.springframework.format.annotation.DateTimeFormat java.time.OffsetTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.time.OffsetTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@15a8392c" {GenericConverter$ConvertiblePair@5407} "java.lang.String -> java.time.OffsetTime" -> {GenericConversionService$ConvertersForPair@5408} "java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.OffsetTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@648487da,java.lang.String -> java.time.OffsetTime: org.springframework.format.datetime.standard.TemporalAccessorParser@dd6b4ee" {GenericConverter$ConvertiblePair@5409} "java.time.Instant -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5410} "java.time.Instant -> java.lang.String : org.springframework.format.datetime.standard.InstantFormatter@7524339c" {GenericConverter$ConvertiblePair@5411} "java.lang.String -> java.time.Instant" -> {GenericConversionService$ConvertersForPair@5412} "java.lang.String -> java.time.Instant: org.springframework.format.datetime.standard.InstantFormatter@7524339c" {GenericConverter$ConvertiblePair@5413} "java.util.Calendar -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5414} "@org.springframework.format.annotation.DateTimeFormat java.util.Calendar -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@584ce5a1" {GenericConverter$ConvertiblePair@5415} "java.lang.String -> java.util.Calendar" -> {GenericConversionService$ConvertersForPair@5416} "java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Calendar: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@584ce5a1" {GenericConverter$ConvertiblePair@5417} "java.util.Date -> java.lang.String" -> {GenericConversionService$ConvertersForPair@5418} "@org.springframework.format.annotation.DateTimeFormat java.util.Date -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@584ce5a1" {GenericConverter$ConvertiblePair@5419} "java.lang.String -> java.util.Date" -> {GenericConversionService$ConvertersForPair@5420} "java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Date: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@584ce5a1"
③ WebDataBinder 核心类
WebDataBinder:数据绑定器负责数据绑定工作,负责数据绑定期间产生的类型转换、格式化、数据校验等问题
(1)ConversionService 组件进行数据类型转换、数据格式化工作;
(2)Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果 BindingData 对象;
(3)BindingResult 负责保存以及解析数据绑定期间数据校验产生的错误;
Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参;
四、SpringMVC 的类型转换器
ConversionService 组件:负责数据类型的转换以及格式化功能;
ConversionService有非常多的 convert,不同类型的转换和格式化用它自己的 converter;
Spring MVC 上下文中内建了很多转换器,可完成大多数 Java 类型的转换工作。
以 StringToNumberConverterFactory 为例分析:
{GenericConverter$ConvertiblePair@5229} "java.lang.String -> java.lang.Number" -> {GenericConversionService$ConvertersForPair@5230} "java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@2d148610"
查看:StringToNumberConverterFactory源码,在getConverter()方法中设置断点,在执行set方法(性别字段)前会调用该方法。
final class StringToNumberConverterFactory implements ConverterFactory<String, Number> {
@Override
public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToNumber<T>(targetType);
}
private static final class StringToNumber<T extends Number> implements Converter<String, T> {
private final Class<T> targetType;
public StringToNumber(Class<T> targetType) {
this.targetType = targetType;
}
@Override
public T convert(String source) {
if (source.length() == 0) {
return null;
}
return NumberUtils.parseNumber(source, this.targetType);
}
}
}
五、@InitBinder 注解(了解)
由 @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定
@InitBinder方法不能有返回值,它必须声明为void。
@InitBinder方法的参数通常是 WebDataBinder。
示例代码:
/**
由 @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。
WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定
@InitBinder方法不能有返回值,它必须声明为void。
@InitBinder方法的参数通常是 WebDataBinder
*/
@InitBinder
public void initBinder(WebDataBinder dataBinder){
dataBinder.setDisallowedFields("lastName");
}