SpringMVC (12)_Data Formatting of Data Binding Process

       Preface: This article mainly introduces the concepts and usage of data formatting in the data binding process of SpringMVC .

This article focuses on the following issues:

  • SpringMVC's Data Formatting Architecture
  • Spring's built-in format converter

  • custom format converter

1. SpringMVC's data formatting architecture

1.1 Format Converter

       Provides implementation support for format conversion, and formats the input/output of attribute objects, which in essence still belongs to the category of "type conversion".


       There are two groups of four interfaces as follows:

 1. Printer interface

          Format display interface, print and display the T type object in a certain format according to the Locale information (that is, return the string form);

@FunctionalInterface
public interface Printer<T> {
	String print(T object, Locale locale);
}

 2. Parser interface

         Parse the interface, and parse the string into an object of type T according to the Locale information. If the parsing fails, a java.text.ParseException or IllegalArgumentException can be thrown.

@FunctionalInterface
public interface Parser<T> {
	T parse(String text, Locale locale) throws ParseException;
}

 3. Formatter interface

         Format the SPI interface, inherit the Printer and Parser interfaces, and complete the formatting and parsing functions of T type objects;

public interface Formatter<T> extends Printer<T>, Parser<T> {

}

 4. AnnotationFormatterFactory interface

         Annotation-driven field formatting factory for creating Printer and Parser for annotated object fields, that is, for formatting and parsing annotated object fields .

public interface AnnotationFormatterFactory<A extends Annotation> { // Recognized annotation types
	Set<Class<?>> getFieldTypes(); // A collection of field types that can be type-annotated by A
	Printer<?> getPrinter(A annotation, Class<?> fieldType); // Get Printer according to A annotation type and fieldType type
	Parser<?> getParser(A annotation, Class<?> fieldType); // Get Parser according to A annotation type and fieldType type
}

        This interface returns Printer and Parser for formatting and parsing field values ​​annotated by A-annotated types. For example, JodaDateTimeFormatAnnotationFormatterFactory can create corresponding Printer and Parser for the java.util.Date field type annotated with @DateTimeFormat for formatting and parsing.

 

1.2 Format Converter Registrar, Format Service

       Provides type converter registration support, runtime type conversion API support.


 It has two interfaces:

1.FormatterRegistry

        Format converter registrar for registering format converters (Formatter, Printer and Parser, AnnotationFormatterFactory);

public interface FormatterRegistry extends ConverterRegistry {

	// 添加格式化转换器(Spring3.1 新增API)
	void addFormatter(Formatter<?> formatter);

	// 为指定的字段类型添加格式化转换器
	void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);

	// 为指定的字段类型添加Printer 和Parser
	void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);

	// 添加注解驱动的字段格式化工厂AnnotationFormatterFactory
	void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);

}

 

2. FormattingConversionService

         继承自ConversionService,运行时类型转换和格式化服务接口,提供运行期类型转换和格式化的支持。该实现类扩展了 GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能。FormattingConversionService 拥有一个FormattingConversionServiceFactroyBean 工厂类,后者用于在 Spring 上下文中构造前者。

         FormattingConversionService内部实现如下图所示:


       FormattingConversionService内部实现如上所示,当调用convert方法时:

  1. 若是S类型----->String:调用私有的静态内部类PrinterConverter,其又调用相应的Printer 的实现进行格式化;
  2. 若是String----->T类型:调用私有的静态内部类ParserConverter,其又调用相应的Parser 的实现进行解析;
  3. 若是A 注解类型注解的S 类型----->String:调用私有的静态内部类AnnotationPrinterConverter,其又调用相应的AnnotationFormatterFactory的getPrinter 获取Printer 的实现进行格式化;

  4. 若是String----->A 注解类型注解的T 类型:调用私有的静态内部类AnnotationParserConverter,其又调用相应的AnnotationFormatterFactory的getParser 获取Parser 的实现进行解析。

        注:S类型表示源类型,T类型表示目标类型,A表示注解类型。

        此处可以可以看出之前的Converter SPI 完成任意Object 与Object 之间的类型转换,而Formatter SPI 完成任意Object与String之间的类型转换。

 

2. Spring内建的格式化转换器

类名

说明

DateFormatter

java.util.Date<---->String(实现日期的格式化/解析)

NumberFormatter

java.lang.Number<---->String(实现通用样式的格式化/解析)

CurrencyFormatter

java.lang.BigDecimal<---->String(实现货币样式的格式化/解析)

PercentFormatter

java.lang.Number<---->String(实现百分数样式的格式化/解析)

NumberFormatAnnotationFormatterFactory

@NumberFormat注解类型的数字字段类型<---->String

①通过@NumberFormat指定格式化/解析格式

②可以格式化/解析的数字类型:Short、Integer、Long、Float、Double、BigDecimal、BigInteger

JodaDateTimeFormatAnnotationFormatterFactory

@DateTimeFormat注解类型的日期字段类型<---->String

          FormattingConversionServiceFactroyBean内部已经注册了NumberFormatAnnotationFormatterFactroy,JodaDateTimeFormatAnnotationFormatterFactroy。

3. 自定义格式转换器

      此处以解析/格式化AddressVo为例。字符串"江苏-南京" 格式化为 AddressVo:


 

1. 定义Formatter实现

public class AddressFormatter_ implements Formatter<AddressVo> {
    // 中文正则表达式
    Pattern pattern = Pattern.compile("^([\u4e00-\u9fa5]*)-([\u4e00-\u9fa5]*)$");
    
    @Override
    public String print(AddressVo address, Locale locale) {
        if(address == null) return "";
        return new StringBuilder().append(address.getProvince())
                                  .append("-")
                                  .append(address.getCity())
                                  .toString();
    }

    @Override
    public AddressVo parse(String text, Locale locale) throws ParseException {
        if(!StringUtils.hasLength(text)) return null;
        
        Matcher matcher = pattern.matcher(text);
        if(matcher.matches()) {
            String province = matcher.group(1); 
            String city     = matcher.group(2); 
            return new AddressVo(province, city);
        } else {
            throw new IllegalArgumentException();
        }
    }
}

 2. 定义解析/格式化字段的注解类型

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface AddressFormatter {

}

 3. 实现AnnotationFormatterFactory注解格式化工厂

public class AddressFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<AddressFormatter> {

    private final AddressFormatter_ formatter;
    
    public AddressFormatAnnotationFormatterFactory() {
        this.formatter = new AddressFormatter_();
    }
    
    //②指定可以被解析/格式化的字段类型集合
    @Override
    public Set<Class<?>> getFieldTypes() {
        Set<Class<?>> set = new HashSet<Class<?>>();
        set.add(AddressVo.class);
        return set;
    }
    
    @Override
    public Parser<?> getParser(AddressFormatter annotation, Class<?> fieldType) {
        return formatter;
    }

    @Override   
    public Printer<?> getPrinter(AddressFormatter annotation, Class<?> fieldType) {
        return formatter;
    }
}

 4. 对实体类添加注解

@AddressFormatter
private AddressVo address;

 5. 注册自定义转换器

<!-- 配置 ConversionService -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="formatters">
        <set>
            <bean class="com.wj.web.formatters.AddressFormatAnnotationFormatterFactory"></bean>
        </set>
    </property>
</bean>

 

4. 简述Spring內建常用格式化注解用法

1.@DateTimeFormat

        @DateTimeFormat 注解可对java.util.Date、java.util.Calendar、java.long.Long 时间类型进行标注:

  • pattern 属性:类型为字符串。指定解析/格式化字段数据的模式,如:”yyyy-MM-dd hh:mm:ss”;
  • iso 属性:类型为 DateTimeFormat.ISO。指定解析/格式化字段数据的ISO模式,包括四种:ISO.NONE(不使用)  默认、ISO.DATE(yyyy-MM-dd) 、ISO.TIME(hh:mm:ss.SSSZ)、ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ);
  • style 属性:字符串类型。通过样式指定日期时间的格式,由两位字符组成,第一位表示日期的格式,第二位表示时间的格式:S:短日期/时间格式、M:中日期/时间格式、L:长日期/时间格式、F:完整日期/时间格式、-:忽略日期或时间格式;

2. @NumberFormat

        可对类似数字类型的属性进行标注,它拥有两个互斥的属性:

  • style:类型为 NumberFormat.Style。用于指定– 样式类型,包括三种:Style.NUMBER(正常数字类型)、Style.CURRENCY(货币类型)、 Style.PERCENT(百分数类型);
  • pattern:类型为 String,自定义样式, 如patter="#,###";

3. 示例

@NumberFormat(pattern="#,####,####.#")
private double salary;
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date   birth;
 

 

代码下载来源:http://super-wangj.iteye.com/blog/2388430

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326271830&siteId=291194637