美文网首页
spring类型转换器(三)

spring类型转换器(三)

作者: 立志java | 来源:发表于2020-08-31 08:17 被阅读0次

    spring类型转换器(三)

    格式化Formatter

    Converter用来将源数据类型转换目标数据类型,不过有时候一个数据类型会对应不同格式的字符串,如日期类型在不同国家显示的字符是不一样的,需要根据Locale进行转换,或者需要将日期类型转换为不同格式化的字符串,spring针对这种情况提供了Formatter接口来针对格式化进行处理。

    格式化Formatter其实也是一种Converter,只是两个互转类型之间,有一个固定是String类型,Formatter实现了不同格式的String类型与其他类型的类型互转

    Formatter主要针对的是Number类型和日期类型。Spring对这两种类型的子类和字符串之间的转换提供了格式化实现,下面以日期类型的转换为例说明。

    例子

    public static void main(String[] args) throws NoSuchFieldException {
            String today = "2018-12-04 12:21:32";
            DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
            Field longDateField = Person.class.getDeclaredField("longDate");
            Date longDate = (Date) conversionService.convert(today, new TypeDescriptor(longDateField));
            Field shortDateField = Person.class.getDeclaredField("shortDate");
            Date shortDate = (Date) conversionService.convert(today, new TypeDescriptor(shortDateField));
            Field localDateTimeField = Person.class.getDeclaredField("localDateTime");
            LocalDateTime localDateTime = (LocalDateTime) conversionService.convert(today, new TypeDescriptor(localDateTimeField));
            Field dateFormatField = Person.class.getDeclaredField("dateFormat");
            //日期到字符串的格式化转换,注意@DateTimeFormat注解一定要加在日期类型上,加在字符串类型上没有用
            String dateFormat = (String) conversionService.convert(LocalDateTime.now(), new TypeDescriptor(localDateTimeField), new TypeDescriptor(dateFormatField));
            System.out.println(dateFormat);
        }
        @Data
        static class Person{
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
            private Date longDate;
            @DateTimeFormat(pattern = "yyyy-MM-dd")
            private Date shortDate;
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
            private LocalDateTime localDateTime;
    
            private String dateFormat;
        }
    

    原理分析

    1. 首先需要明确的一点,格式化是完成指定类型和字符串类型的互转,那么就可以定性为使用Converter来完成,需要注册两个Converter,String到Class<?>和 Class<?>到String的转换,这样就可以借用Converter调用的壳子,内部的转换及格式化再具体实现
    2. 格式化功能的实现是通过两个接口来实现,通过Printer接口print()方法实现指定类型到字符串的转换,通过Parser接口parse()方法完成字符串到指定类型的转换。Formater接口继承了这两个接口
    3. 格式化可以转换为不同格式的字符串,并且可以用户自定义,那么就需要一个入口来让用户配置,所以提供了两个注解用于指定字段的格式类型
      • DateTimeFormat 指定日期格式的注解,通过指定pattern或者style实现指定不同的格式字符串
      • NumberFormat 指定数字格式的注解,通过指定pattern或者style实现指定不同的格式字符串。
    4. 那么通过什么来提供注解接入的入口呢,那就是AnnotationFormatterFactory<A extends Annotation>接口,这个接口集成了注解和Formater接口,将两者关联起来,然后注册到Converter中。同时这个接口的getFieldTypes()方法返回一个Set<Class<?>>,可以同时集成多个类型到字符串之间的转换。

    源码

    Formatter接口继承了Printer和Parser接口,一个用于将对象格式化为本地化的字符串,一个将字符串转换为对象。

    public interface Formatter<T> extends Printer<T>, Parser<T> {
    }
    public interface Printer<T> {
        String print(T object, Locale locale);
    }
    public interface Parser<T> {
        T parse(String text, Locale locale) throws ParseException;
    }
    

    AnnotationFormatterFactory集成了注解和Formatter。可以创建带有Annotation性质的Printer和Parser对象。

    public interface AnnotationFormatterFactory<A extends Annotation> {
        //支持多个类型到字符串之间的转换
        Set<Class<?>> getFieldTypes();
        //格式化
        Printer<?> getPrinter(A annotation, Class<?> fieldType);
        //反格式化
        Parser<?> getParser(A annotation, Class<?> fieldType);
    }
    

    在上章节的继承图中可以看到FormattingConversionService继承了GenericConversionService。同时实现了FormatterRegistry和ConverterRegistry接口

    FormatterRegistry扩展了ConverterRegistry接口,额外提供了注册Formatter、AnnotationFormatterFactory的功能

    public interface FormatterRegistry extends ConverterRegistry {
       void addFormatter(Formatter<?> formatter);
       void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
       void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);
       void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);
    }
    

    FormatterRegistrar接口用于批量注册Formatter的接口

    public interface FormatterRegistrar {
      //批量注册
       void registerFormatters(FormatterRegistry registry);
    }
    

    spring提供了FormattingConversionService的默认实现DefaultFormattingConversionService,使用的时候一般都是直接使用这个类。

    首先来看DefaultFormattingConversionService,在BeanFactory中只接收一个ConversionService变量,所以只能给spring容易配置一个ConversionService。那么到底应该用DefaultFormattingConversionService还是用DefaultConversionService?让我们来看DefaultFormattingConversionService中的实现

    public DefaultFormattingConversionService(StringValueResolver embeddedValueResolver, boolean registerDefaultFormatters) {
       setEmbeddedValueResolver(embeddedValueResolver);
        //注册DefaultConversionService中的默认转换器
       DefaultConversionService.addDefaultConverters(this);
       if (registerDefaultFormatters) {
          addDefaultFormatters(this);
       }
    }
    

    从源码可以看出,DefaultFormattingConversionService完全是对DefaultConversionService的扩展,在构造函数中调用了DefaultConversionService的addDefaultConverters完全拥有了DefaultConversionService所有的功能,所以只需要使用DefaultFormattingConversionService就可以

    DefaultFormattingConversionService创建完成之后除了添加Converters,还注册了一些Formatters,这些Formaters主要是spring提供的用于针对日期类型Number类型货币金额进行格式化转换

    public static void addDefaultFormatters(FormatterRegistry formatterRegistry) {
        //支持数字类型的字符串格式化转换
       formatterRegistry.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
        //支持对 货币金额 格式转换
       if (jsr354Present) {
          formatterRegistry.addFormatter(new CurrencyUnitFormatter());
          formatterRegistry.addFormatter(new MonetaryAmountFormatter());
          formatterRegistry.addFormatterForFieldAnnotation(new Jsr354NumberFormatAnnotationFormatterFactory());
       }
    
       if (jsr310Present) {
          //对java8的日期类型 字符串格式化转换   LocalDateTime
          new DateTimeFormatterRegistrar().registerFormatters(formatterRegistry);
       }
       if (jodaTimePresent) {
          //对joda格式的日期 字符串格式化转换
          new JodaTimeFormatterRegistrar().registerFormatters(formatterRegistry);
       } else {
           //对普通的Date 、Calendar、时间戳 字符串格式化转换
          new DateFormatterRegistrar().registerFormatters(formatterRegistry);
       }
    }
    

    Formater的注册和转换

    注册Formatter

    接下来分析下Formater的注册功能。通过上述分析我们可以知道,Formater实质上是Class<?>和String之间的互转,所以在注册的时候,只需要提供Class<?>、Printer和Parser。来看FormattingConversionService类中的实现

    //没有指定Class<?> 直接使用 Formater上的泛型作为和String互转的类型
    public void addFormatter(Formatter<?> formatter) {
       addFormatterForFieldType(getFieldType(formatter), formatter);
    }
    //formatter同时继承了 Printer和Parser接口
    public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) {
       addConverter(new PrinterConverter(fieldType, formatter, this));
       addConverter(new ParserConverter(fieldType, formatter, this));
    }
    //注册Converter
    public void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser) {
       addConverter(new PrinterConverter(fieldType, printer, this));
       addConverter(new ParserConverter(fieldType, parser, this));
    }
    

    可以看到的是注册Formater的过程,就是注册了一对Converter。注册Converter的过程已经在前文分析过,在这里我们来一起看下PrinterConverter和ParserConverter类。

    private static class PrinterConverter implements GenericConverter {
       private final Class<?> fieldType;
       private final TypeDescriptor printerObjectType;
       private final Printer printer;
       private final ConversionService conversionService;//this
       public PrinterConverter(Class<?> fieldType, Printer<?> printer, ConversionService conversionService) {
          this.fieldType = fieldType;
           //获取Printer上设置的泛型 即Class<?>
          this.printerObjectType = TypeDescriptor.valueOf(resolvePrinterObjectType(printer));
          this.printer = printer;
          this.conversionService = conversionService;//this
       }
    
       @Override //fieldType -> String 转换
       public Set<ConvertiblePair> getConvertibleTypes() {
          return Collections.singleton(new ConvertiblePair(this.fieldType, String.class));
       }
       @Override
       public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
          if (source == null) {
             return "";
          }//如果源数据类型和Printer支持的不一致,首先需要进行 源数据类型 -> Printer支持类型的转换
          if (!sourceType.isAssignableTo(this.printerObjectType)) {
             source = this.conversionService.convert(source, sourceType, this.printerObjectType);
          } //委托Printer 完成到 String类型的转换
          return this.printer.print(source, LocaleContextHolder.getLocale());
       }
    
       private Class<?> resolvePrinterObjectType(Printer<?> printer) {
          return GenericTypeResolver.resolveTypeArgument(printer.getClass(), Printer.class);
       }
    }
    

    可以看出PrinterConverter类型实现GenericConverter,用于实现传入类型到字符串的转换,具体的转换功能委托给参数Printer实现类对象实现。这里相当于是一个插件类保留。可以通过Printer实现任何类型到String类型的转换。

    再来看ParserConverter

    private static class ParserConverter implements GenericConverter {
       private final Class<?> fieldType;
       private final Parser<?> parser;
       private final ConversionService conversionService;
       public ParserConverter(Class<?> fieldType, Parser<?> parser, ConversionService conversionService) {
          this.fieldType = fieldType;
          this.parser = parser;
          this.conversionService = conversionService;//this
       }
       @Override //String -> fieldType 转换
       public Set<ConvertiblePair> getConvertibleTypes() {
          return Collections.singleton(new ConvertiblePair(String.class, this.fieldType));
       }
    
       @Override
       public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
          String text = (String) source;
          if (!StringUtils.hasText(text)) {
             return null;
          }
          Object result;
          try { //调用parser 将String类型转换为 Parser中声明的泛型
             result = this.parser.parse(text, LocaleContextHolder.getLocale());
          }
          //catch...
          if (result == null) {
             //throw ...
          }
          //如果通过Parser转换后的类型不是目标类型,调用相应的类型转换器继续转换
          TypeDescriptor resultType = TypeDescriptor.valueOf(result.getClass());
          if (!resultType.isAssignableTo(targetType)) {
             result = this.conversionService.convert(result, resultType, targetType);
          }
          return result;
       }
    }
    

    ParserConverter跟PrinterConverter实现了一个反方向的转换,至此注册通过一个Formater接口实现类,就可以完成Formater实现类中泛型到String类型之间的互转。

    例如注册 LocalDateTime的转换器,实现LocalDateTime和String类型的互转

    registry.addFormatterForFieldType(LocalDateTime.class, new TemporalAccessorPrinter(
        dtf == DateTimeFormatter.ISO_DATE_TIME ? DateTimeFormatter.ISO_LOCAL_DATE_TIME : dtf),
          new TemporalAccessorParser(LocalDateTime.class, dtf));
    

    可以看到使用一个类TemporalAccessorPrinter和TemporalAccessorParser,并都传入了一个参数DateTimeFormatter,众所周知LocalDateTime和String格式化就是通过DateTimeFormatter来实现。那么我们猜测TemporalAccessorParser其实就是对DateTimeFormatter的封装调用

    public final class TemporalAccessorPrinter implements Printer<TemporalAccessor> {
       private final DateTimeFormatter formatter;
       public TemporalAccessorPrinter(DateTimeFormatter formatter) {
          this.formatter = formatter;
       }
       @Override
       public String print(TemporalAccessor partial, Locale locale) {
           //调用formater的format转换为String
          return DateTimeContextHolder.getFormatter(this.formatter, locale).format(partial);
       }
    }
    

    可以看到TemporalAccessorPrinter就是调用的DateTimeFormatter完成格式化的,不过这里使用到了ThreadLocal,可以先不管,TemporalAccessorParser中同理也会使用DateTimeFormatter完成String到日期的转换

    public final class TemporalAccessorParser implements Parser<TemporalAccessor> {
       private final DateTimeFormatter formatter;
        //...
       @Override
       public TemporalAccessor parse(String text, Locale locale) throws ParseException {
          DateTimeFormatter formatterToUse = DateTimeContextHolder.getFormatter(this.formatter, locale);
          if (LocalDate.class == this.temporalAccessorType) {
             return LocalDate.parse(text, formatterToUse);
          } else if (LocalTime.class == this.temporalAccessorType) {
             return LocalTime.parse(text, formatterToUse);
          } else if (LocalDateTime.class == this.temporalAccessorType) {
             return LocalDateTime.parse(text, formatterToUse);
          }
          //...
       }
    }
    

    格式化转换

    Formatter的注册最终是注册了一对Converter,所以格式化转换完全就是Converter逻辑的实现,在前文已经分析过了,这里就不再赘述。

    AnnotationFormatterFactory的注册和转换

    注册

    分析完了Formatter的注册和转换过程,一起来看下FormatConversionService提供了另外一种注册。前文提到了可以通过在对象字段上声明一个注解,在注解中指定格式化后字符串格式。这个功能就是通过AnnotationFormatterFactory来实现的。来看FormatConversionService的addFormatterForFieldAnnotation()方法

    @Override
    public void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory) {
        //获取注册AnnotationFormatterFactory上的注解
       Class<? extends Annotation> annotationType =getAnnotationType(annotationFormatterFactory);
       if (this.embeddedValueResolver != null && annotationFormatterFactory instanceof EmbeddedValueResolverAware) {
          ((EmbeddedValueResolverAware) annotationFormatterFactory).setEmbeddedValueResolver(this.embeddedValueResolver);
       }
        //AnnotationFormatterFactory中定义的支持转换的Class<?>集合
       Set<Class<?>> fieldTypes = annotationFormatterFactory.getFieldTypes();
        //该集合中所有的类型都需要完成到String的互转,所以循环封装Converter并注册
       for (Class<?> fieldType : fieldTypes) {
           //注册 fieldType --> String 的类型转换器
          addConverter(new AnnotationPrinterConverter(annotationType, annotationFormatterFactory, fieldType));
           //注册 String --> fieldType 的类型转换器
          addConverter(new AnnotationParserConverter(annotationType, annotationFormatterFactory, fieldType));
       }
    }
    

    AnnotationFormatterFactory的注册,首先需要获取的就是AnnotationFormatterFactory泛型中的注解类型。然后通过getFieldTypes()获取所有声明的可以进行转换类型集合,然后循环注册了两个类型转换器AnnotationPrinterConverter和AnnotationParserConverter。那么来看一下AnnotationPrinterConverter到底如何完成可配置的类型转换的

    private class AnnotationPrinterConverter implements ConditionalGenericConverter {
       private final Class<? extends Annotation> annotationType; //注解类型
       private final AnnotationFormatterFactory annotationFormatterFactory;
       private final Class<?> fieldType;
       public AnnotationPrinterConverter(Class<? extends Annotation> annotationType,
             AnnotationFormatterFactory<?> annotationFormatterFactory, Class<?> fieldType) {
          this.annotationType = annotationType;
          this.annotationFormatterFactory = annotationFormatterFactory;
          this.fieldType = fieldType;
       }
       @Override
       public Set<ConvertiblePair> getConvertibleTypes() {
           //声明为 fieldType -> String 之间的转换
          return Collections.singleton(new ConvertiblePair(this.fieldType, String.class));
       }
       @Override
       public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
           //转换器生效的条件时 源数据类型上有该注解
          return sourceType.hasAnnotation(this.annotationType);
       }
       @Override
       public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {     //获取源数据类型上的注解
          Annotation ann = sourceType.getAnnotation(this.annotationType);
          if (ann == null) { //使用该转换器的前提是添加了相同的注解
             throw new IllegalStateException("");
          }
          AnnotationConverterKey converterKey = new AnnotationConverterKey(ann, sourceType.getObjectType());
          //将创建PrinterConverter缓存起来,避免每次重复创建
          GenericConverter converter = cachedPrinters.get(converterKey);
          if (converter == null) {
              //从annotationFormatterFactory中获取Printer
             Printer<?> printer = this.annotationFormatterFactory.getPrinter(
                   converterKey.getAnnotation(), converterKey.getFieldType());
              //在这个converter中又创建了PrinterConverter 
             converter = new PrinterConverter(this.fieldType, printer, FormattingConversionService.this);
             cachedPrinters.put(converterKey, converter);
          }
          //使用PrinterConverter 进行类型转换
          return converter.convert(source, sourceType, targetType);
       }
    }
    

    可以看到的是,AnnotationPrinterConverter实现了ConditionalGenericConverter接口,在matches()方法中声明了该转换器只会作用于Class<?>上有指定的注解的类型。在convert方法中最终创建了一个PrinterConverter对象,使用PrinterConverter完成格式化的功能,这个在上面已经分析过了。唯一的不同就是Printer的获取。使用annotationFormatterFactory获取printer,并将注解作为参数传递进去。所以可以我们可以实现AnnotationFormatterFactory的getPrinter()方法提供转换为字符串的功能即可,通过看以通过参数annotation获取用户配置的格式。实现格式的可配置。

    同样在AnnotationParserConverter中实现String到Class<?>的转换,调用AnnotationFormatterFactory获取Parser然后创建一个ParserConverter来实现类型转化。需要注意的是 注解只能添加在非String类型那一方上。

    private class AnnotationParserConverter implements ConditionalGenericConverter {
       private final Class<? extends Annotation> annotationType;
       private final AnnotationFormatterFactory annotationFormatterFactory;
       private final Class<?> fieldType;
        //此处省略...
    
       @Override//String 到fieldType的转换
       public Set<ConvertiblePair> getConvertibleTypes() {
          return Collections.singleton(new ConvertiblePair(String.class, fieldType));
       }
       @Override //注意这里用的是targetType 还是要非String类上声明注解
       public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
          return targetType.hasAnnotation(this.annotationType);
       }
       @Override
       public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
          Annotation ann = targetType.getAnnotation(this.annotationType);
          if (ann == null) {
             //throw ...
          }
          AnnotationConverterKey converterKey = new AnnotationConverterKey(ann, targetType.getObjectType());
          GenericConverter converter = cachedParsers.get(converterKey);
          if (converter == null) {
              //获取parser
             Parser<?> parser = this.annotationFormatterFactory.getParser(
                   converterKey.getAnnotation(), converterKey.getFieldType());
              //创建ParserConverter进行转换
             converter = new ParserConverter(this.fieldType, parser, FormattingConversionService.this);
             cachedParsers.put(converterKey, converter);
          }
          return converter.convert(source, sourceType, targetType);
       }
    }
    

    通过封装封装注册AnnotationPrinterConverter和AnnotationParserConverter,用户需要做的就只有是实现AnnotationFormatterFactory,在泛型中指定注解,然后实现了getPrinter()getParser()来实现Class<?>和String之间的转换,其他的调用直接走Converter流程。来看Date类型格式化的实现

    在DateFormatterRegistrar中,在注册Formatters之前,先注册了日期类型的一些converter,这里先不去管这个。最主要的是addFormatterForFieldAnnotation方法,通过这个方法完成对Formater的注册

    @Override
    public void registerFormatters(FormatterRegistry registry) {
       addDateConverters(registry);
        //注册Formater FormatterFactory
       registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
       if (this.dateFormatter != null) {
           //添加对非注解 Date类型转换
          registry.addFormatter(this.dateFormatter);
          registry.addFormatterForFieldType(Calendar.class, this.dateFormatter);
       }
    }
    

    来看下DateTimeFormatAnnotationFormatterFactory实现了AnnotationFormatterFactory。并指定注解为DateTimeFormat。

    public class DateTimeFormatAnnotationFormatterFactory  extends EmbeddedValueResolutionSupport
          implements AnnotationFormatterFactory<DateTimeFormat> {
    
       private static final Set<Class<?>> FIELD_TYPES;
    
       static {//定义支持的 格式化的类型,支持格式化 Date、Calendar、Long类型
          Set<Class<?>> fieldTypes = new HashSet<Class<?>>(4);
          fieldTypes.add(Date.class);
          fieldTypes.add(Calendar.class);
          fieldTypes.add(Long.class);
          FIELD_TYPES = Collections.unmodifiableSet(fieldTypes);
       }
       @Override //定义支持的 格式化的类型,支持格式化 Date、Calendar、Long类型
       public Set<Class<?>> getFieldTypes() {
          return FIELD_TYPES;
       }
       @Override
       public Printer<?> getPrinter(DateTimeFormat annotation, Class<?> fieldType) {
          return getFormatter(annotation, fieldType);
       }
       @Override
       public Parser<?> getParser(DateTimeFormat annotation, Class<?> fieldType) {
          return getFormatter(annotation, fieldType);
       }
       protected Formatter<Date> getFormatter(DateTimeFormat annotation, Class<?> fieldType) {
          DateFormatter formatter = new DateFormatter();
          //获取用户注解中写的格式
          formatter.setStylePattern(resolveEmbeddedValue(annotation.style()));
          formatter.setIso(annotation.iso()); //获取用户注解中写的格式
          formatter.setPattern(resolveEmbeddedValue(annotation.pattern())); //获取用户注解中写的格式
          return formatter;
       }
    }
    

    可以看到的是在getFieldType()声明了支持转换的有Date、Calendar、Long。可以看到getPrinter()getFormatter()方法返回了一个DateFormatter对象,并将用户配置的注解信息注入到这个DateFormatter对象中

    接下来就是最终的格式化实现就是这个DateFormatter对象了。大家想一下,一般针对Date类型的格式化都会用什么呢?想必大家都猜到了,没错就是SimpleDateFormat。在DateFormatter中就是创建了一个SimpleDateFormat来实现类型和字符串的转换的

    public class DateFormatter implements Formatter<Date> {
        //....此处省略
        @Override
        public String print(Date date, Locale locale) {
           return getDateFormat(locale).format(date);
        }
        @Override
        public Date parse(String text, Locale locale) throws ParseException {
           return getDateFormat(locale).parse(text);
        }
        protected DateFormat getDateFormat(Locale locale) {
           DateFormat dateFormat = createDateFormat(locale);
           if (this.timeZone != null) {
              dateFormat.setTimeZone(this.timeZone);
           }
           dateFormat.setLenient(this.lenient);
           return dateFormat;
        }
        //创建一个SimpleDateFormat,并使用 annotation传入的pattern
        private DateFormat createDateFormat(Locale locale) {
           if (StringUtils.hasLength(this.pattern)) {
              return new SimpleDateFormat(this.pattern, locale);
           }
           if (this.iso != null && this.iso != ISO.NONE) {
              String pattern = ISO_PATTERNS.get(this.iso);
              if (pattern == null) {
                 throw new IllegalStateException("Unsupported ISO format " + this.iso);
              }
              SimpleDateFormat format = new SimpleDateFormat(pattern);
              format.setTimeZone(UTC);
              return format;
           }
           if (StringUtils.hasLength(this.stylePattern)) {
              int dateStyle = getStylePatternForChar(0);
              int timeStyle = getStylePatternForChar(1);
              if (dateStyle != -1 && timeStyle != -1) {
                 return DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
              }
              if (dateStyle != -1) {
                 return DateFormat.getDateInstance(dateStyle, locale);
              }
              if (timeStyle != -1) {
                 return DateFormat.getTimeInstance(timeStyle, locale);
              }
              throw new IllegalStateException("Unsupported style pattern");
    
           }
           return DateFormat.getDateInstance(this.style, locale);
        }
    }
    

    至此就实现了Formatter的注册和使用。那么在spring中是如何使用的呢?

    spring中的使用

    <bean id="conversionService"    class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <converters>
            <set>
                <bean class="example.MyCustomConverter"/>
            </set>
        </converters>
        <formatters>
            <set>
                <bean class="example.MyCustomFormatters"/>
            </set>
        </formatters>
        <formatterRegistrars>
            <set>
            </set>
        </formatterRegistrars>
    </bean>
    

    没错就注册一个id为conversionService的FormattingConversionServiceFactoryBean对象。使用这个就可以了,不需要再注册ConversionServiceFactoryBean了。

    相关文章

      网友评论

          本文标题:spring类型转换器(三)

          本文链接:https://www.haomeiwen.com/subject/flassktx.html