6.6 formatting the Spring3 field, 6.6spring3
6.6Spring3 field formatting
As mentioned in the previous section, core. convert is a general type conversion system. It provides a unified ConversionServiceAPI and a strongly-typed Converter SPI to implement the type conversion logic. Spring containers use this system to bind bean property values. In addition, both SpEL and DataBinder use this system to bind field values. For example, when SpEL needs to convert a Short to a Long value to complete the expression. setValue (Objectbean, Object value) operation, the core. convert system will execute this forced conversion.
Consider the type conversion requirements of a typical customer environment (such as a web or desktop application. In this environment, you need to convert String to other types to support the customer's return process (Note: This is the process in which the user transmits the value to the server.In addition, you also need to convert it to String to support page rendering process (Note: The process in which the server transmits the value to the user). In addition, you usually need to localize the String value. The Converter SPI of the more general core. convert does not directly support such formatting requirements. To support it directly, Spring3 proposes a convenient FormatterSPI, which is used as an alternative to PropertyEditors and provides a simple and robust implementation for the customer environment.
In general, Converter SPI is used when you need to implement general type conversion logic, such as conversion between java. utils. Date and java. lang. Long types. When you are in a client environment, for example, in a web application, you need to parse the field value and output it in a localized format using FormatterSPI. ConversionService provides a unified type conversion API for the two SPI types.
FormatterSPI
Formatter SPI that implements the field formatting logic is simple and strongly typed:
package org.springframework.format;public interface Formatter<T> extends Printer<T>, Parser<T> {}
Formatter inherits the Printer and Parser interfaces, which are two building-blocks (components and interesting words)
public interface Printer<T> {String print(T object, Locale locale);}
import java.text.ParseException;public interface Parser<T> {T parse(String clientValue, Locale locale) throws ParseException;}
To create your own Formatter, you only need to implement the Formatter interface. The parameter T is the object type to be formatted, such as java. util. Date. The print () method is used to print a formatted and localized T instance locally. Implement the parse () method to convert formatted data of a client into a T instance. If a parsing operation fails, your Formatter should throw a ParseException or IllegalArgumentException. Ensure that your Formatter implementation is thread-safe.
For convenience, some Formatter implementations are provided in the format sub-package. The number package provides a NumberFormatter, CurrencyFormatter, and PercentFormatter. They use java. text. NumberFormat to format java. lang. Number objects. The datetime package provides a DateFormatter that uses java. text. DateFormat to format the java. util. Date object. The datetime. joda package provides comprehensive support for datetime formatting Based on the Joda Time library.
Consider an example of Formatter implementation class -- DateFormatter
package org.springframework.format.datetime;public final class DateFormatter implements Formatter<Date> {private String pattern;public DateFormatter(String pattern) {this.pattern = pattern;}public String print(Date date, Locale locale) {if(date == null) {return "";}return getDateFormat(locale).format(date);}public Date parse(String formatted, Locale locale) throws ParseException {if(formatted.length() == 0) {return null;}return getDateFormat(locale).parse(formatted);}protected DateFormat getDateFormat(Locale locale) {DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale);dateFormat.setLenient(false);return dateFormat;}}
The Spring team welcomes contributions from the Community to Formatter. You can contribute through http://jira.springframework.org.
Annotation-driven formatting
As you will see later, field formatting can be configured by field type or annotation. AnnotationFormatterFactory (Note: Associate A with the Printer and Parser generated by the Factory by.):
package org.springframework.format;public interface AnnotationFormatterFactory<A extends Annotation> {Set<Class<?>> getFieldTypes();Printer<?> getPrinter(A annotation, Class<?> fieldType);Parser<?> getParser(A annotation, Class<?> fieldType);}
Parameter A is the annotation type of the field to be associated with the formatting logic, such as org. springframework. format. annotation. DateTimeFormat. The getFieldTypes () method returns the field types that may be annotated. The getPrinter () method is used to return a Printer to output the value of the annotated field. The getParser () method returns a Parser to parse the annotated field into the value to be displayed on the client.
The following AnnotationFormatterFactory binds the @ NumberFormat annotation to a formatter. This annotation Allows defining a digital style (Style, such as CURRENCY, PERCENT) Or a digital format (Pattern, for example #,###):
public final class NumberFormatAnnotationFormatterFactory implementsAnnotationFormatterFactory<NumberFormat> {public Set<Class<?>> getFieldTypes() {return new HashSet<Class<?>>(asList(newClass<?>[] {Short.class, Integer.class, Long.class, Float.class,Double.class, BigDecimal.class, BigInteger.class}));}public Printer<Number> getPrinter(NumberFormat annotation,Class<?> fieldType) {return configureFormatterFrom(annotation, fieldType);}public Parser<Number> getParser(NumberFormat annotation,Class<?> fieldType) {return configureFormatterFrom(annotation, fieldType);}private Formatter<Number> configureFormatterFrom(NumberFormat annotation, Class<?> fieldType) {if (!annotation.pattern().isEmpty()) {return new NumberFormatter(annotation.pattern());} else {Style style = annotation.style();if (style == Style.PERCENT) {return new PercentFormatter();} else if (style == Style.CURRENCY) {return new CurrencyFormatter();} else {return new NumberFormatter();}}}}
To trigger formatting, you only need to add the @ NumberFormat annotation to the field:
public class MyModel {@NumberFormat(style=Style.CURRENCY)private BigDecimal decimal;}
Format annotation API
The org. springframework. format. annocation package contains a convenient API for formatting annotation. Use @ NumberFormat to format the java. lang. Number Field. Use @ DateTimeFormat to format the java. util. Date, java. util. Calendar, java. util. Long or Joda Time fields.
The following example uses @ DateTimeFormat to format java. util. Date to the ISO Date type (yyyy-MM-dd ):
public class MyModel {@DateTimeFormat(iso=ISO.DATE)private Date date;}
FormatterRegistry SPI
FormatterRegistry is an SPI for registering formatters and converters. FormattingConversionService is an implementation class of FormatterRegistry and is suitable for most environments. This implementation class can use FormattingConversionServiceFactoryBean for programmatic or declarative configuration to become a Spring Bean. Since this implementation also implements ConversionService, it can be directly configured and used with Spring DataBinder and SpEL.
Let's take a look at FormatterRegistry SPI:
package org.springframework.format;public interface FormatterRegistry extends ConverterRegistry {void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);void addFormatterForFieldType(Formatter<?> formatter);void addFormatterForAnnotation(AnnotationFormatterFactory<?, ?> factory);}
As shown above, Formatters can be registered through the field type or annotation.
FormatterRegistry SPI allows you to configure formatting rules in a centralized manner, instead of repeating such configurations in each Controller. For example, you may want to format all the Date fields in a certain way, or the fields with a certain annotation are also formatted in a certain way. With a shared FormatterRegistry, once you define rules, they can be applied to formatting at any time.
FormatterRegistrar SPI
FormatterRegistrar is an SPI, Which is used throughFormatterRegistryTo register formatters and converters.
package org.springframework.format;public interface FormatterRegistrar {void registerFormatters(FormatterRegistry registry);}
FormatterRegistrar is useful when multiple related converters and fomatters need to be registered for the specified formatting category, such as Date formatting.
Configure Formatting in Spring MVC
In Spring MVC applications, You can precisely configure a custom ConversionService instance and use it as the attribute of the annotation-driven element in an MVC namespace. This ConversionService can be used wherever type conversion is needed when the Controller data is bound. If ConversionService is not configured accurately, SpringMVC automatically registers a default formatters and converters to convert some common types, such as numbers and dates (Note: <mvc: annotation-driven> must be configured here.).
To rely on the Default Formatting rules, do not add additional configurations to your Spring MVC configuration XML file.
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"><mvc:annotation-driven /></beans>
By configuring such a row, the default formatters formatted for the Numbers and Date types are registered. Supports @ NumberFormat and @ DateTimeFormat annotations. If the jar package of Joda Time is available in classpath, it can also support the Joda Time formatting library.
To inject a ConversionSerivce instance that contains custom formatters and converters, we need to set the conversion-service attribute (annotation-driven in the mvc namespace ), then, specify custom converters, formatters, or FormatterRegistrars in the conversionService instance as the attributes of FormattingConversionServiceFactoryBean:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"><mvc:annotation-driven conversion-service="conversionService" /><bean id="conversionService"class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><set><bean class="org.example.MyConverter" /></set></property><property name="formatters"><set><bean class="org.example.MyFormatter" /><bean class="org.example.MyAnnotationFormatterFactory" /></set></property><property name="formatterRegistrars"><set><bean class="org.example.MyFormatterRegistrar" /></set></property></bean></beans>
Note: When you want to use FormatterRegistrars, read the "FormatterRegistrarSPI" section to obtain