зеркало из
https://github.com/iharh/notes.git
synced 2025-10-30 05:06:05 +02:00
207 строки
9.0 KiB
Plaintext
207 строки
9.0 KiB
Plaintext
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#format
|
||
|
||
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#format-Formatter-SPI
|
||
|
||
The Formatter SPI to implement field formatting logic is simple and strongly typed:
|
||
|
||
package org.springframework.format;
|
||
|
||
public interface Formatter<T> extends Printer<T>, Parser<T> {
|
||
}
|
||
|
||
public interface Printer<T> {
|
||
String print(T fieldValue, Locale locale);
|
||
}
|
||
|
||
import java.text.ParseException;
|
||
|
||
public interface Parser<T> {
|
||
T parse(String clientValue, Locale locale) throws ParseException;
|
||
}
|
||
|
||
To create your own Formatter, simply implement the Formatter interface above. Parameterize T to be the type of object you wish to format
|
||
Take care to ensure your Formatter implementation is thread-safe.
|
||
|
||
Several Formatter implementations are provided in format subpackages as a convenience.
|
||
The number package provides a NumberFormatter, CurrencyFormatter, and PercentFormatter to format java.lang.Number objects using a java.text.NumberFormat.
|
||
The datetime package provides a DateFormatter to format java.util.Date objects with a java.text.DateFormat.
|
||
The datetime.joda package provides comprehensive datetime formatting support based on the Joda Time library.
|
||
|
||
|
||
Consider DateFormatter as an example Formatter implementation:
|
||
|
||
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;
|
||
}
|
||
}
|
||
|
||
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#format-CustomFormatAnnotations
|
||
|
||
As you will see, field formatting can be configured by field type or annotation.
|
||
To bind an Annotation to a formatter, implement AnnotationFormatterFactory:
|
||
|
||
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);
|
||
}
|
||
|
||
Parameterize A to be the field annotationType you wish to associate formatting logic with
|
||
, for example org.springframework.format.annotation.DateTimeFormat.
|
||
Have getFieldTypes() return the types of fields the annotation may be used on.
|
||
Have getPrinter() return a Printer to print the value of an annotated field.
|
||
Have getParser() return a Parser to parse a clientValue for an annotated field.
|
||
|
||
|
||
The example AnnotationFormatterFactory implementation below binds the @NumberFormat Annotation to a formatter.
|
||
This annotation allows either a number style or pattern to be specified:
|
||
|
||
public final class NumberFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<NumberFormat> {
|
||
public Set<Class<?>> getFieldTypes() {
|
||
return new HashSet<Class<?>>(asList(new Class<?>[] {
|
||
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, simply annotate fields with @NumberFormat:
|
||
|
||
public class MyModel {
|
||
@NumberFormat(style=Style.CURRENCY)
|
||
private BigDecimal decimal;
|
||
}
|
||
|
||
A portable format annotation API exists in the org.springframework.format.annotation package.
|
||
Use @NumberFormat to format java.lang.Number fields.
|
||
Use @DateTimeFormat to format java.util.Date, java.util.Calendar, java.util.Long, or Joda Time fields.
|
||
|
||
The example below uses @DateTimeFormat to format a java.util.Date as a ISO Date (yyyy-MM-dd):
|
||
|
||
public class MyModel {
|
||
@DateTimeFormat(iso=ISO.DATE)
|
||
private Date date;
|
||
}
|
||
|
||
FormatterRegistrySPI
|
||
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#format-FormatterRegistry-SPI
|
||
|
||
The FormatterRegistry is an SPI for registering formatters and converters.
|
||
FormattingConversionService is an implementation of FormatterRegistry suitable for most environments.
|
||
This implementation may be configured programmatically or declaratively as a Spring bean using FormattingConversionServiceFactoryBean.
|
||
Because this implementation also implements ConversionService, it can be directly configured for use with Spring’s DataBinder
|
||
and the Spring Expression Language (SpEL).
|
||
|
||
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 by fieldType or annotation.
|
||
|
||
The FormatterRegistry SPI allows you to configure Formatting rules centrally, instead of duplicating such configuration across your Controllers.
|
||
For example, you might want to enforce that all Date fields are formatted a certain way, or fields with a specific annotation are formatted in a certain way.
|
||
With a shared FormatterRegistry, you define these rules once and they are applied whenever formatting is needed.
|
||
|
||
FormatterRegistrar SPI
|
||
The FormatterRegistrar is an SPI for registering formatters and converters through the FormatterRegistry:
|
||
|
||
package org.springframework.format;
|
||
|
||
public interface FormatterRegistrar {
|
||
void registerFormatters(FormatterRegistry registry);
|
||
}
|
||
|
||
A FormatterRegistrar is useful when registering multiple related converters and formatters for a given formatting category, such as Date formatting.
|
||
It can also be useful where declarative registration is insufficient.
|
||
For example when a formatter needs to be indexed under a specific field type different from its own <T> or when registering a Printer/Parser pair.
|
||
|
||
|
||
Configuring a global date & time format
|
||
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#format-configuring-formatting-globaldatetimeformat
|
||
|
||
By default, date and time fields that are not annotated with @DateTimeFormat are converted from strings using the DateFormat.SHORT style.
|
||
If you prefer, you can change this by defining your own global format.
|
||
|
||
You will need to ensure that Spring does not register default formatters, and instead you should register all formatters manually.
|
||
Use the org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar or org.springframework.format.datetime.DateFormatterRegistrar class depending on whether you use the Joda Time library.
|
||
|
||
For example, the following Java configuration will register a global ' `yyyyMMdd’ format. This example does not depend on the Joda Time library:
|
||
|
||
@Configuration
|
||
public class AppConfig {
|
||
@Bean
|
||
public FormattingConversionService conversionService() {
|
||
// Use the DefaultFormattingConversionService but do not register defaults
|
||
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);
|
||
|
||
// Ensure @NumberFormat is still supported
|
||
conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
|
||
|
||
// Register date conversion with a specific global format
|
||
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
|
||
registrar.setFormatter(new DateFormatter("yyyyMMdd"));
|
||
registrar.registerFormatters(conversionService);
|
||
|
||
return conversionService;
|
||
}
|
||
}
|
||
|
||
If you are using Spring MVC remember to explicitly configure the conversion service that is used.
|
||
For Java based @Configuration this means extending the WebMvcConfigurationSupport class and overriding the mvcConversionService() method.
|
||
For XML you should use the 'conversion-service' attribute of the mvc:annotation-driven element.
|
||
See "Conversion and Formatting" section for details.
|