Ihar Hancharenka 5dff80e88e first
2023-03-27 16:52:17 +03:00

207 строки
9.0 KiB
Plaintext
Исходник Ответственный История

Этот файл содержит неоднозначные символы Юникода

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 Springs 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.