SpringMVC data formatting, presentation look

7.3, the data is formatted
in such Web / client project, usually need to convert the data to a string for display in a format, so we can learn from the section data type conversion system central role not complete this requirement, therefore introducing Spring3 a format converter (formatter SPI) and formatting services API (FormattingConversionService) to support this demand. It is similar in function and PropertyEditor Spring, may alternatively be PropertyEditor parsing and formatting objects, and the fine-grained support field-level format / resolution.

 

Formatter SPI core logic conversion complete parsing and formatting, such as Web applications in client / project need to be parsed, the print / display object value using localized, such as in accordance Locale information java.util.Date ---- > java.lang.String print / show, java.lang.String ----> java.util.Date and so on.

 

The format conversion system is versatile Spring, its definition org.springframework.format package, not only in the Spring Web MVC scene.

 

7.3.1, architecture
1, format converter: providing implementation supports formatting conversion.

 


 

There are two groups of four interfaces as follows:

(1, Printer Interface: formatting a display interface, an object of type T to print the display (i.e., return a string) Locale information according to a certain format;

Java code  
Package org.springframework.format;  
public interface Printer <T> {  
    String Print (T Object, Locale the locale);   
}  
(2, Parser Interface: parsing interface string according to the object of type T Locale information analysis;

Java code  
Package org.springframework.format;  
public interface Parser <T> {  
    T the parse (String text, Locale the locale) throws a ParseException;  
}  
parsing may fail or an IllegalArgumentException is thrown to java.text.ParseException.

 

(3, Formatter Interface: SPI interface format, and the Parser interface inheritance Printer, complete parsing and formatting of objects of type T;

Java code  
Package org.springframework.format;  
public interface the Formatter <T> the extends Printer <T>, Parser <T> {  
}  
(. 4, AnnotationFormatterFactory Interface: annotation-driven chemical field format used to create the object field annotated Printer and Parser, namely for formatting and parsing annotated object fields.

Java code  
Package org.springframework.format;  
public interface AnnotationFormatterFactory <A {// the extends Annotation> type of annotation may identify ①  
    Set <Class <>> getFieldTypes () ;? // ② A can be annotated set of annotation types of field type  
    Printer getPrinter (A annotation, Class fieldType <?>) <?>; // ③ obtained according to A and the fieldType type of annotation types Printer  
    Parser the getParser (annotation A, Class fieldType <?>) <?>; // ④ The annotation A fieldType type and type acquisition Parser  
  
}  
returns the field value Parser Printer and formatting and parsing annotated a annotation types. As JodaDateTimeFormatAnnotationFormatterFactory Printer and can create a corresponding format and Parser to parse the field type java.util.Date @DateTimeFormat with annotations.

 

2, format converter registrar, formatting Services: Provides a type converter registered support type conversion API runtime support.

 

 

 


A There are two interfaces:

(1, FormatterRegistry: format converter is registered, for registering format converter (Formatter, Printer and Parser, AnnotationFormatterFactory);

 

 

Java code  
Package org.springframework.format;  
public interface FormatterRegistry the extends ConverterRegistry {  
    // add ① formatter converter (Spring3.1 add the API)  
    void addFormatter (the Formatter Formatter <?>);  
    // add to ② specified type field format converter  
    void addFormatterForFieldType (the fieldType Class, the formatter formatter <?> <?>);  
    // add Printer and ③ Parser field specifies the type of  
    void addFormatterForFieldType (Class fieldType, Printer printer , Parser <<?> <?>? > Parser);  
    // add annotations ④ driving field format chemical annotationFormatterFactory  
    void addFormatterForFieldAnnotation (  
                ? annotationFormatterFactory <the extends the annotation> annotationFormatterFactory);  
}   
(2, FormattingConversionService: inherited from ConversionService, run-time type conversion and formatting services interface, providing support for runtime type conversion and formatting.

 

 

Internal FormattingConversionService implemented as shown below:

 


We can see the internal FormattingConversionService realize shown above, when you call the convert method:

If the S type ⑴ -----> String: calling private static inner class PrinterConverter, which in turn calls the appropriate implementation of Printer format;

⑵ If String -----> T Type: call private static inner classes ParserConverter, which in turn calls the appropriate implementation Parser to parse;

A type of annotation ⑶ if annotation type S -----> String: calling private static inner class AnnotationPrinterConverter, which in turn calls the appropriate AnnotationFormatterFactory achieve getPrinter acquired Printer is formatted;

⑷ If String -----> A annotation type annotation type T: internal calls private static class AnnotationParserConverter, which in turn call the appropriate AnnotationFormatterFactory realization of getParser get Parser parse.

 

Legend: S type indicates the source type, T type indicates the type of target, A represents a type of annotation.

 

Here can be seen before completion Converter SPI type conversion between any Object and Object, and completed Formatter SPI type conversion between arbitrary Object String (i.e., formatting and parsing, and the like PropertyEditor).

 

7.3.2, Spring formatter converter built as follows:
Class Name

Explanation

DateFormatter

java.util.Date<---->String

Realization date formatting / parsing

NumberFormatter

java.lang.Number<---->String

Achieve universal formatting styles / parsing

CurrencyFormatter

java.lang.BigDecimal<---->String

The monetary formatting styles / parsing

PercentFormatter

java.lang.Number<---->String

Formatting styles to achieve a percentage / parsing

NumberFormatAnnotationFormatterFactory

@NumberFormat annotation types of digital field type <----> String

① specifying formatting / parsing format by @NumberFormat

② can format / parsing of numeric types: Short, Integer, Long, Float, Double, BigDecimal, BigInteger

JodaDateTimeFormatAnnotationFormatterFactory

@DateTimeFormat annotation type date field type <----> String

① specifying formatting / parsing format by @DateTimeFormat

② can format / resolution date type:

Date type (org.joda.time package) in Joda: LocalDate, LocalDateTime, LocalTime, ReadableInstant

java built-in date type: Date, Calendar, Long

 

classpath must have Joda-Time library, or can not format the date type

NumberFormatAnnotationFormatterFactory and JodaDateTimeFormatAnnotationFormatterFactory (if classpath provides Joda-Time Library) will be automatically registered if formatting service implementation DefaultFormattingConversionService.

 

7.3.3, the example
before example, we need to http://joda-time.sourceforge.net/ download Joda-Time library, this book uses is joda-time-2.1 version, will add the following jar package to the classpath :

Java code  
joda-time-2.1.jar  
 

 

7.3.3.1, type level parsing / formatting
a direct use Formatter SPI parsing / formatted

Java code  
// two, CurrencyFormatter: the formatting style currency / parsing  
the CurrencyFormatter CurrencyFormatter the CurrencyFormatter new new = ();  
currencyFormatter.setFractionDigits (2); // several reserved after the decimal point  
currencyFormatter.setRoundingMode (RoundingMode.CEILING); // round the mode (ceilling denotes rounding)  
  
// 1, with a currency symbol string "$ 123.125" into the BigDecimal ( "123.00")  
Assert.assertEquals (the BigDecimal new new ( "123.13"), currencyFormatter.parse ( "$ 123.125", Locale .US));  
// 2, the BigDecimal ( "123") format string "$ 123.00" display  
Assert.assertEquals ( "$ 123.00", currencyFormatter.print (new BigDecimal ( "123"), Locale.US)) ;  
Assert.assertEquals ( "¥ 123.00", currencyFormatter.print (new new the BigDecimal ( "123"), Locale.CHINA));  
Assert.assertEquals ( "¥ 123.00",   currencyFormatter.print(new BigDecimal("123"), Locale.JAPAN));  
           
parse method: string formatted according Locale information resolved to a BigDecimal type data;

print method: the data shown as BigDecimal type string data formatted according to Locale information.

 

Unlike Convert SPI, Formatter SPI can be resolved / formatted according localized (Locale) information.

 

Please refer to other test cases testNumber test methods and test methods cn.javass.chapter7.web.controller.support.formatter.InnerFormatterTest of testDate.

Java code  
@Test  
public void testWithDefaultFormattingConversionService () {  
    DefaultFormattingConversionService new new DefaultFormattingConversionService ConversionService = ();  
    // default does not automatically register any the Formatter  
    the CurrencyFormatter CurrencyFormatter the CurrencyFormatter new new = ();  
    currencyFormatter.setFractionDigits (2); // After several decimal places  
    currencyFormatter. setRoundingMode (RoundingMode.CEILING); // rounding mode (ceilling denotes rounding)  
    // Formatter SPI register achieve  
    conversionService.addFormatter (CurrencyFormatter);  
          
    // bind to ThreadLocal Locale information  
    automatically acquired as // internal FormattingConversionService Locale information, if not The default value is set Locale.getDefault ()  
    LocaleContextHolder.setLocale (Locale.US);  
    Assert.assertEquals("$1,234.13", conversionService.convert(new BigDecimal("1234.128"), String.class));  
    LocaleContextHolder.setLocale(null);  
      
        LocaleContextHolder.setLocale(Locale.CHINA);  
        Assert.assertEquals("¥1,234.13", conversionService.convert(new BigDecimal("1234.128"), String.class));  
    Assert.assertEquals(new BigDecimal("1234.13"), conversionService.convert("¥1,234.13", BigDecimal.class));  
    LocaleContextHolder.setLocale(null);}   
DefaultFormattingConversionService:带数据格式化功能的类型转换服务实现;

conversionService.addFormatter (): Formatter SPI register implemented;

conversionService.convert (new BigDecimal ( "1234.128"), String.class): BigDecimal type data format for a string type, where in accordance with "LocaleContextHolder.setLocale (locale)" localization information set format;

conversionService.convert ( "¥ 1,234.13", BigDecimal.class): Analytical data for the character string type data into BigDecimal, also here according to "LocaleContextHolder.setLocale (locale)" de-localization settings;

LocaleContextHolder.setLocale (locale): Set the localization information to ThreadLocal, for analyzing / Formatter SPI formatted according to the localization information;

 

Please refer to specific test Test method cn.javass.chapter7.web.controller.support.formatter.InnerFormatterTest of testWithDefaultFormattingConversionService.

 

Third, parsing custom Formatter / formatted

Here to parse / format PhoneNumberModel example.

 

(1, implemented defined Formatter SPI 

 

Java代码  
package cn.javass.chapter7.web.controller.support.formatter;  
//省略import  
public class PhoneNumberFormatter implements Formatter<PhoneNumberModel> {  
    Pattern pattern = Pattern.compile("^(\\d{3,4})-(\\d{7,8})$");  
    @Override  
    public String print(PhoneNumberModel phoneNumber, Locale locale) {//①格式化  
        if(phoneNumber == null) {  
            return "";  
        }  
        return new StringBuilder().append(phoneNumber.getAreaCode()).append("-")  
                                  .append(phoneNumber.getPhoneNumber()).toString();  
    }  
  
    @Override  
    public PhoneNumberModel parse (String text, Locale locale) throws ParseException {// ② resolved  
        IF {(StringUtils.hasLength (text)!)  
            // ① if source is null return null  
            return null;  
        }  
        Matcher Matcher = Pattern.matcher (text) ;  
        IF (matcher.matches ()) {  
            // If the match ② conversion  
            PhoneNumberModel new new PhoneNumberModel phoneNumber = ();  
            phoneNumber.setAreaCode (Matcher.group (. 1));  
            phoneNumber.setPhoneNumber (Matcher.group (2));  
            return phoneNumber;  
        } the else {  
            // If not ③ conversion fails  
            throw new IllegalArgumentException (String.format ( "type conversion failure, the format required [010-12345678], but the format is [% S]", text));  
        }  
    }  
}  
 similar Convert SPI achieved, but the methods herein will be appropriate incoming Locale locale, so you can parse / format data for different regions.

 

(2, test cases:

Java代码  
package cn.javass.chapter7.web.controller.support.formatter;  
//省略import  
public class CustomerFormatterTest {  
    @Test  
    public void test() {  
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();  
        conversionService.addFormatter(new PhoneNumberFormatter());  
  
        PhoneNumberModel phoneNumber = new PhoneNumberModel("010", "12345678");  
        Assert.assertEquals("010-12345678", conversionService.convert(phoneNumber, String.class));  
          
        Assert.assertEquals("010", conversionService.convert("010-12345678", PhoneNumberModel.class).getAreaCode());  
    }  
}  
Can parse String ---> PhoneNumberModel and formatting PhoneNumberModel ---> String by PhoneNumberFormatter.

 

This type of analytical grade / format we introduce finished, it can be seen from the test type level of the entire project is the same type of embodiment parsing / formatting logic.

 

Some students may need to implement different parsing / formatting logic in different classes of fields, such as the registration date field users need only model class, such as "2012-05-02" format parsing / formatting can be, and orders for the model under Order date field class may need, such as "2012-05-02 20:13:13" format for display.

 

Next, we learn about how to conduct field-level parsing / formatting it.

 

7.3.3.2, field-level analysis / formatting
a, using the built-in field-level annotation for analysis / format:

(1, test preparation model class:

Java code  
Package cn.javass.chapter7.model;  
public class FormatterModel {  
    @NumberFormat (= Style.NUMBER style, pattern = "#, ###")  
    Private int The totalCount;  
    @NumberFormat (style = Style.PERCENT)  
    Private Double Discount ;  
    @NumberFormat (style = Style.CURRENCY)  
    Private Double sumMoney;  
      
    @DateTimeFormat (ISO = ISO.DATE)   
    Private a Date registerDate;  
      
    @DateTimeFormat (pattern = "the mM-dd-YYYY HH: mm: SS")   
    Private orderDate, a Date;  
  
    / / getter omitted / setter  
}   
here we use the Spring field level parsing / formatting built two notes:

 

@Number: definition of digital correlation analysis / metadata format (universal styles currency style, style percentages), the following parameters:

    style: style specifies the type, which: Style.NUMBER (common style) Style.CURRENCY (currency style) Style.PERCENT (percent style), default Style.NUMBER;

    pattern: custom styles, such patter = "#, ###";

 

@DateTimeFormat: parsing related definitions date / format metadata, parameters are as follows:

    pattern: Specifies parsing / mode field formatted data, such as "yyyy-MM-dd HH: mm: ss"

iso: Specifies parsing / ISO model includes four fields formatted data: ISO.NONE (not used) ISO.DATE (yyyy-MM-dd) ISO.TIME (hh: mm: ss.SSSZ) ISO.DATE_TIME ( yyyy-mM-dd hh: mm: ss.SSSZ), default ISO.NONE;

    style: style specified for formatting mode, the default "SS", refer to the specific use org.joda.time.format.DateTimeFormat Joda-Time Library of the forStyle Javadoc;

Priority: pattern of greater than greater than iso style.

 

(2, test cases:

Java code  
@Test  
public void the Test () throws SecurityException, a NoSuchFieldException {  
    // default auto-enrollment support for @NumberFormat and @DateTimeFormat of  
    DefaultFormattingConversionService ConversionService =   
                                new new DefaultFormattingConversionService ();  
      
    // Prepare the test model objects  
    FormatterModel Model = new new FormatterModel ();  
    Model .setTotalCount (10000);  
    model.setDiscount (0.51);  
    model.setSumMoney (10000.13);  
    model.setRegisterDate (new new a Date (2012-1900,. 4,. 1));  
    model.setOrderDate (new new a Date (2012-1900,. 4, 1, 20, 18, 18));  
       
    // get the type information  
    TypeDescriptor descriptor =   
            a TypeDescriptor new new (FormatterModel.class.getDeclaredField ( "The totalCount"));          
    a TypeDescriptor stringDescriptor = TypeDescriptor.valueOf (String.class);  
          
    Assert.assertEquals ( "10,000", conversionService.convert (model.getTotalCount (), descriptor, stringDescriptor)) ;  
    Assert.assertEquals (model.getTotalCount (), conversionService.convert ( "10,000", stringDescriptor, descriptor));  
  
}  
 a TypeDescriptor: context has type information for Spring3 type conversion system to obtain type information (may contain classes, fields, the process parameter, attribute information); through a TypeDescriptor, we can obtain (classes, fields, methods, parameters, attributes) of various information such as the type of annotation information;

conversionService.convert (model.getTotalCount (), descriptor, stringDescriptor): The totalCount formatted as a string type, here will be formatted according to the annotation information totalCount field (obtained by the object descriptor);

conversionService.convert ( "10,000", stringDescriptor, descriptor): string "10,000" resolved to totalCount field type, here will be parsed according to the annotation information totalCount field (obtained by the object descriptor).

 

(3, annotation information by assigning different fields for different field-level fine grain Insights / Format

 

Java代码  
descriptor = new TypeDescriptor(FormatterModel.class.getDeclaredField("registerDate"));  
Assert.assertEquals("2012-05-01", conversionService.convert(model.getRegisterDate(), descriptor, stringDescriptor));  
Assert.assertEquals(model.getRegisterDate(), conversionService.convert("2012-05-01", stringDescriptor, descriptor));  
          
descriptor = new TypeDescriptor(FormatterModel.class.getDeclaredField("orderDate"));  
Assert.assertEquals("2012-05-01 20:18:18", conversionService.convert(model.getOrderDate(), descriptor, stringDescriptor));  
Assert.assertEquals(model.getOrderDate(), conversionService.convert("2012-05-01 20:18:18", stringDescriptor, descriptor));  
 As can be seen the test, we can achieve parsing / formatting control data field of fine-grained annotation mode, but must be used to specify the type of TypeDescriptor context information, i.e. the data field programming analysis / format troublesome.

 

Please refer to other test test test method cn.javass.chapter7.web.controller.support.formatter.InnerFieldFormatterTest of.

 

Second, custom annotations for field-level analysis / format:

Here to parse / format PhoneNumberModel field, for example.

(Note 1 type, defined parsing / formatted fields:

Java code  
Package cn.javass.chapter7.web.controller.support.formatter;  
// omitted Import  
@Target ({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})  
@Retention (RetentionPolicy.RUNTIME)  
public @interface the PhoneNumber {  
}  
 (2, AnnotationFormatterFactory achieve chemical annotation format:

Java code  
Package cn.javass.chapter7.web.controller.support.formatter;  
// omitted Import  
public class PhoneNumberFormatAnnotationFormatterFactory  
    the implements AnnotationFormatterFactory <the PhoneNumber> {// ① designation may parse / format type field annotation  
  
    private final Set <Class <? FieldTypes >>;  
    Private Final PhoneNumberFormatter Formatter;  
    public PhoneNumberFormatAnnotationFormatterFactory () {  
        the Set <Class <= >> the SET new new HashSet <Class <>> ();??  
        set.add (PhoneNumberModel.class);  
        this.fieldTypes = the SET;  
        the this .formatter = new PhoneNumberFormatter (); // formatter previously defined herein that implement  
    }  
    // ② designation may be parsed / set of formatted field type  
    @Override  
    the Set public <Class <>> getFieldTypes ()? {  
        return FieldTypes;  
    }  
    // ③ and annotative information acquired according to the parser type field  
    @Override  
    public Parser <> the getParser (the PhoneNumber Annotation, Class <> the fieldType?) {?  
        return Formatter;  
    }  
    // Get ④ the annotation information and field types formatter  
    @Override     
    public Printer getPrinter (the PhoneNumber annotation, the fieldType Class <?>) {<?>  
        return formatter;  
    }  
}   
AnnotationFormatterFactory be implemented according to obtain the corresponding field type information and annotations parser / formatter.

 

(3, modified FormatterModel add the following code:

Java code  
@PhoneNumber  
Private PhoneNumberModel phoneNumber;   
(. 4, test

Java code  
@Test  
ublic void the Test () throws SecurityException, a NoSuchFieldException {  
DefaultFormattingConversionService ConversionService =   
                                    new new DefaultFormattingConversionService (); // create a format service  
conversionService.addFormatterForFieldAnnotation (  
                new new PhoneNumberFormatAnnotationFormatterFactory ()); // add custom annotations format chemical plant  
      
FormatterModel model FormatterModel new new = ();  
a TypeDescriptor descriptor =   
        new new a TypeDescriptor (FormatterModel.class.getDeclaredField ( "phoneNumber"));  
a TypeDescriptor stringDescriptor = TypeDescriptor.valueOf (String.class);  
  
PhoneNumberModel value = (PhoneNumberModel) conversionService.convert("010-12345678", stringDescriptor, descriptor); //解析字符串"010-12345678"--> PhoneNumberModel  
model.setPhoneNumber(value);  
      
Assert.assertEquals("010-12345678", conversionService.convert(model.getPhoneNumber(), descriptor, stringDescriptor));//格式化PhoneNumberModel-->"010-12345678"  
   
 

As used herein DefaultFormattingConversionService of addFormatterForFieldAnnotation registered annotation formats chemical PhoneNumberFormatAnnotationFormatterFactory custom.

 

This programming format data / analytic we have done, it is quite cumbersome to use, then we will integrate it into Spring Web MVC environment.

7.3.4, Spring Web MVC environment is integrated into
a registered FormattingConversionService implementation and custom format converter:

 

Java code  
<the bean ID = "ConversionService"   
class = "org.springframework.format.support.FormattingConversionServiceFactoryBean">  
  <-! Omitted herein previously registered custom type converter ->  
  <Property name = "formatters">  
      <List >  
          <the bean class = "cn.javass.chapter7.web.controller.support.formatter.  
                                                  PhoneNumberFormatAnnotationFormatterFactory" />  
      </ List>  
  </ Property>  
</ the bean>  
 other configurations and as a prior learning 7.2.2.4.

 

Second, the example:

(1, a data object field analysis model / format:

 

Java code  
@RequestMapping (value = "/ format1")  
public String test1 (@ModelAttribute ( "Model") FormatterModel formatModel) {  
    return "the format / Success";  
}   
--------------- -
Disclaimer: this article is CSDN blogger "deep sea octopus" of the original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
Original link: https: //blog.csdn.net/jinwufeiyang/article/details/52006937

Guess you like

Origin www.cnblogs.com/45ddf4/p/12125700.html