一、问题引入

在做 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<StringNumber{

    @Override
    public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToNumber<T>(targetType);
    }

    private static final class StringToNumber<T extends Numberimplements Converter<StringT{

        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");
}
posted on 2021-12-01 11:02  格物致知_Tony  阅读(144)  评论(0编辑  收藏  举报