此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
弹簧字段格式
如上一节所述,core.convert
是一个
通用型转换系统。它提供了一个统一的ConversionService
API 作为
以及强类型的Converter
SPI 用于实现从一种类型实现转换逻辑
给另一个。Spring 容器使用此系统来绑定 bean 属性值。在
此外,Spring 表达式语言 (SpEL) 和DataBinder
使用此系统
绑定字段值。例如,当 SpEL 需要强制Short
设置为Long
自
完成一个expression.setValue(Object bean, Object value)
尝试,则core.convert
系统执行强制。
现在考虑典型客户端环境的类型转换要求,例如
Web 或桌面应用程序。在此类环境中,您通常从String
支持客户端回发过程,以及返回String
以支持
视图渲染过程。此外,您经常需要进行本地化String
值。更多
常规core.convert
Converter
SPI 不满足此类格式要求
径直。为了直接解决它们,Spring 提供了一个方便的Formatter
SPI 该
提供了一个简单而强大的替代方案PropertyEditor
客户端的实现
环境。
通常,您可以使用Converter
SPI 当您需要实现通用类型时
转换逻辑 — 例如,用于在java.util.Date
和Long
.
您可以使用Formatter
在客户端环境(例如 Web
application),需要解析和打印本地化字段值。这ConversionService
为两个 SPI 提供统一的类型转换 API。
这Formatter
SPI
这Formatter
实现字段格式化逻辑的 SPI 是简单且强类型的。这
以下列表显示了Formatter
接口定义:
package org.springframework.format;
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
Formatter
从Printer
和Parser
构建块接口。这
以下列表显示了这两个接口的定义:
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;
}
创建您自己的Formatter
,实现Formatter
前面显示的界面。
参数化T
设置为要格式化的对象类型 - 例如,java.util.Date
.实现print()
作以打印T
为
显示在客户端区域设置中。实现parse()
作来解析T
从客户端区域设置返回的格式化表示形式。你Formatter
应该抛出一个ParseException
或IllegalArgumentException
如果解析尝试失败。拿
注意确保您的Formatter
实现是线程安全的。
这format
子包提供了几个Formatter
为了方便起见。
这number
package 提供NumberStyleFormatter
,CurrencyStyleFormatter
和PercentStyleFormatter
格式化Number
使用java.text.NumberFormat
.
这datetime
package 提供了一个DateFormatter
格式化java.util.Date
对象与
一个java.text.DateFormat
,以及DurationFormatter
格式化Duration
对象
在@DurationFormat.Style
枚举(请参阅格式注释 API)。
以下内容DateFormatter
就是一个例子Formatter
实现:
-
Java
-
Kotlin
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;
}
}
class DateFormatter(private val pattern: String) : Formatter<Date> {
override fun print(date: Date, locale: Locale)
= getDateFormat(locale).format(date)
@Throws(ParseException::class)
override fun parse(formatted: String, locale: Locale)
= getDateFormat(locale).parse(formatted)
protected fun getDateFormat(locale: Locale): DateFormat {
val dateFormat = SimpleDateFormat(this.pattern, locale)
dateFormat.isLenient = false
return dateFormat
}
}
Spring 团队欢迎社区驱动Formatter
贡献。请参阅 GitHub 问题进行贡献。
注释驱动的格式
字段格式可以按字段类型或注释进行配置。绑定
对Formatter
实现AnnotationFormatterFactory
.以下内容
列表中显示了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);
}
要创建实现,请执行以下作:
-
参数化
A
成为领域annotationType
您希望与之关联 格式化逻辑 — 例如org.springframework.format.annotation.DateTimeFormat
. -
有
getFieldTypes()
返回可以使用注释的字段类型。 -
有
getPrinter()
返回一个Printer
以打印带注释的字段的值。 -
有
getParser()
返回一个Parser
解析clientValue
对于带注释的字段。
以下示例AnnotationFormatterFactory
实现绑定了@NumberFormat
注释到格式化程序中,以指定数字样式或模式:
-
Java
-
Kotlin
public final class NumberFormatAnnotationFormatterFactory
implements AnnotationFormatterFactory<NumberFormat> {
private static final Set<Class<?>> FIELD_TYPES = Set.of(Short.class,
Integer.class, Long.class, Float.class, Double.class,
BigDecimal.class, BigInteger.class);
public Set<Class<?>> getFieldTypes() {
return FIELD_TYPES;
}
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 NumberStyleFormatter(annotation.pattern());
}
// else
return switch(annotation.style()) {
case Style.PERCENT -> new PercentStyleFormatter();
case Style.CURRENCY -> new CurrencyStyleFormatter();
default -> new NumberStyleFormatter();
};
}
}
class NumberFormatAnnotationFormatterFactory : AnnotationFormatterFactory<NumberFormat> {
override fun getFieldTypes(): Set<Class<*>> {
return setOf(Short::class.java, Int::class.java, Long::class.java, Float::class.java, Double::class.java, BigDecimal::class.java, BigInteger::class.java)
}
override fun getPrinter(annotation: NumberFormat, fieldType: Class<*>): Printer<Number> {
return configureFormatterFrom(annotation, fieldType)
}
override fun getParser(annotation: NumberFormat, fieldType: Class<*>): Parser<Number> {
return configureFormatterFrom(annotation, fieldType)
}
private fun configureFormatterFrom(annotation: NumberFormat, fieldType: Class<*>): Formatter<Number> {
return if (annotation.pattern.isNotEmpty()) {
NumberStyleFormatter(annotation.pattern)
} else {
val style = annotation.style
when {
style === NumberFormat.Style.PERCENT -> PercentStyleFormatter()
style === NumberFormat.Style.CURRENCY -> CurrencyStyleFormatter()
else -> NumberStyleFormatter()
}
}
}
}
要触发格式设置,您可以使用@NumberFormat
,如下所示
示例显示:
-
Java
-
Kotlin
public class MyModel {
@NumberFormat(style=Style.CURRENCY)
private BigDecimal decimal;
}
class MyModel(
@field:NumberFormat(style = Style.CURRENCY) private val decimal: BigDecimal
)
格式注释 API
可移植格式注释 API 存在于org.springframework.format.annotation
包。您可以使用@NumberFormat
格式化Number
字段,例如Double
和Long
,@DurationFormat
格式化Duration
ISO-8601 和简化样式中的字段,
和@DateTimeFormat
设置字段的格式,例如java.util.Date
,java.util.Calendar
,
和Long
(对于毫秒时间戳)以及 JSR-310java.time
类型。
以下示例使用@DateTimeFormat
格式化java.util.Date
作为 ISO 日期
(yyyy-MM-dd):
-
Java
-
Kotlin
public class MyModel {
@DateTimeFormat(iso=ISO.DATE)
private Date date;
}
class MyModel(
@DateTimeFormat(iso=ISO.DATE) private val date: Date
)
有关更多详细信息,请参阅 javadoc@DateTimeFormat
,@DurationFormat
和@NumberFormat
.
基于样式的格式和解析依赖于区域设置敏感模式,这些模式可能会发生变化 取决于 Java 运行时。具体而言,依赖于日期、时间或 数字解析和格式化在运行时可能会遇到不兼容的行为变化 在 JDK 20 或更高版本上。 使用 ISO 标准化格式或您控制的具体模式允许 可靠的独立于系统和语言环境的日期、时间、 和数字值。 为 有关更多详细信息,请参阅 Spring Framework wiki 中的 JDK 20 及更高版本的日期和时间格式化页面。 |
这FormatterRegistry
SPI
这FormatterRegistry
是用于注册格式化器和转换器的 SPI。FormattingConversionService
是FormatterRegistry
适合人群
大多数环境。您可以通过编程或声明方式配置此变体
作为 Spring bean,例如,通过使用FormattingConversionServiceFactoryBean
.因为这个
实现也实现ConversionService
,可以直接配置
与 Spring 的DataBinder
和 Spring 表达式语言 (SpEL)。
以下列表显示了FormatterRegistry
SPI:
package org.springframework.format;
public interface FormatterRegistry extends ConverterRegistry {
void addPrinter(Printer<?> printer);
void addParser(Parser<?> parser);
void addFormatter(Formatter<?> formatter);
void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);
void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);
}
如前面的列表所示,您可以按字段类型或注释注册格式化程序。
这FormatterRegistry
SPI 允许您集中配置格式规则,而不是
在控制器之间复制此类配置。例如,您可能想要
强制所有日期字段都以特定方式格式化,或者将字段设置为特定的
注释以某种方式格式化。使用共享的FormatterRegistry
,则定义
这些规则一次,并在需要格式化时应用它们。
这FormatterRegistrar
SPI
FormatterRegistrar
是一个 SPI,用于通过
FormatterRegistry 中。以下列表显示了其接口定义:
package org.springframework.format;
public interface FormatterRegistrar {
void registerFormatters(FormatterRegistry registry);
}
一个FormatterRegistrar
在注册多个相关转换器时很有用,并且
给定格式类别的格式化程序,例如日期格式。也可以是
在声明性注册不足的情况下很有用,例如,当格式化程序
需要在与其自身不同的特定字段类型下建立索引<T>
或者当
注册一个Printer
/Parser
双。下一节将提供有关
转换器和格式化程序注册。
在 Spring MVC 中配置格式
请参阅 Spring MVC 章节中的转换和格式化。