|
对于最新的稳定版本,请使用 Spring Framework 6.2.7! |
Spring Field 格式设置
如上一节所述,core.convert是一个
通用型转换系统。它提供了一个统一的ConversionServiceAPI 作为
以及强类型ConverterSPI 用于实现一种类型的转换逻辑
到另一个。Spring 容器使用此系统来绑定 bean 属性值。在
此外,Spring 表达式语言 (SpEL) 和DataBinder使用此系统可以
bind 字段值。例如,当 SPEL 需要强制Short更改为Long自
完成expression.setValue(Object bean, Object value)尝试,则core.convert系统执行强制转换。
现在考虑典型客户端环境的类型转换要求,例如
Web 或桌面应用程序。在此类环境中,您通常从String支持客户端回发过程,以及返回到String以支持
View 渲染过程。此外,您经常需要本地化String值。越多
常规core.convert ConverterSPI 不满足此类格式要求
径直。为了直接解决这些问题,Spring 提供了一个方便的FormatterSPI 的
提供了一种简单而强大的替代方案PropertyEditor客户端的实现
环境。
通常,您可以使用ConverterSPI 当您需要实现通用型
conversion logic — 例如,用于在java.util.Date以及Long.
您可以使用Formatter当您在客户端环境(例如 Web
application),并且需要解析和打印本地化的字段值。这ConversionService为这两个 SPI 提供统一的类型转换 API。
这FormatterSPI 系列
这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为
display in client locale 中。实现parse()作来解析T从客户端区域设置返回的格式化表示形式。你Formatter应该抛出一个ParseException或IllegalArgumentException如果解析尝试失败。拿
确保您的Formatter实现是线程安全的。
这format子包提供了多个Formatter实现以方便使用。
这numberpackage 提供NumberStyleFormatter,CurrencyStyleFormatter和PercentStyleFormatter格式化Number使用java.text.NumberFormat.
这datetime包提供了一个DateFormatter格式化java.util.Date对象替换为
一个java.text.DateFormat.
以下内容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 Issues to contribute。
注释驱动的格式设置
字段格式可以按字段类型或注释进行配置。绑定
对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成为 FieldannotationType您希望与之关联的 格式化逻辑 — 例如org.springframework.format.annotation.DateTimeFormat. -
有
getFieldTypes()返回可以使用注释的字段类型。 -
有
getPrinter()返回一个Printer以打印带注释的字段的值。 -
有
getParser()返回一个Parser要解析clientValue对于带注释的字段。
以下示例AnnotationFormatterFactoryimplementation 将@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和@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和@NumberFormat.
|
基于样式的格式设置和解析依赖于区域设置敏感模式,这些模式可能会发生变化 取决于 Java 运行时。具体而言,依赖于日期、时间或 数字解析和格式化在运行时可能会遇到不兼容的行为更改 在 JDK 20 或更高版本上。 使用您控制的 ISO 标准化格式或具体模式允许 可靠的独立于系统和区域设置的日期、时间、 和数字值。 为 有关更多详细信息,请参阅 Spring Framework Wiki 中的使用 JDK 20 及更高版本进行日期和时间格式化页面。 |
这FormatterRegistrySPI 系列
这FormatterRegistry是用于注册格式化程序和转换器的 SPI。FormattingConversionService是FormatterRegistry适合
大多数环境。您可以以编程方式或声明方式配置此变体
作为 Spring bean 中,例如通过使用FormattingConversionServiceFactoryBean.因为这个
implementation 还实现ConversionService,可以直接配置
用于 Spring 的DataBinder和 Spring 表达式语言 (SpEL)。
下面的清单显示了FormatterRegistrySPI:
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);
}
如前面的清单所示,您可以按字段类型或注释注册格式化程序。
这FormatterRegistrySPI 允许您集中配置格式规则,而不是
在您的控制器之间复制此类配置。例如,您可能希望
强制所有日期字段都以某种方式格式化,或者强制字段具有特定的
annotation 以某种方式格式化。使用共享的FormatterRegistry,您可以定义
这些规则一次,每当需要格式化时都会应用它们。
这FormatterRegistrarSPI 系列
FormatterRegistrar是一个 SPI,用于通过
FormatterRegistry 的下面的清单显示了它的接口定义:
package org.springframework.format;
public interface FormatterRegistrar {
void registerFormatters(FormatterRegistry registry);
}
一个FormatterRegistrar在注册多个相关转换器时很有用,并且
给定格式类别的格式化程序,例如日期格式。它也可以是
在声明式注册不足时很有用 — 例如,当格式化程序
需要在与自身不同的特定字段类型下编制索引<T>或者
注册一个Printer/Parser双。下一节提供了有关
转换器和格式化程序注册。
在 Spring MVC 中配置格式
参见 Spring MVC 一章中的转换和格式化。