当前位置: 代码网 > it编程>编程语言>Java > Spring处理字段格式化的实战指南

Spring处理字段格式化的实战指南

2025年10月27日 Java 我要评论
一、整体架构:spring 类型转换体系spring 提供了两套互补的类型转换机制:模块用途特点core.convert 包下的 converter spi通用类型转换(如 long ↔ d

一、整体架构:spring 类型转换体系

spring 提供了两套互补的类型转换机制:

模块用途特点
core.convert 包下的 converter spi通用类型转换(如 longdate通用性强,不涉及字符串格式化或 locale
format 包下的 formatter spi客户端字段格式化(如 stringdate,带格式和语言)面向 ui 层,支持 locale,适合 web 应用

它们都由一个统一的服务接口管理:
conversionservice —— 是 spring 内部进行类型转换的核心接口。

关键点

  • converter:用于任意类型之间转换(后台逻辑用)。
  • formatter:专门用于 string 和目标类型之间转换(前端展示/提交用)。
  • 两者都被 conversionservice 管理,可共存。

二、核心概念:formatter spi

1. formatter<t> 接口

这是 spring 为“客户端字段格式化”设计的核心接口:

public interface formatter<t> extends printer<t>, parser<t> {
}

它由两个子接口组成:

(1) printer<t>:对象 → 字符串(用于显示)

string print(t fieldvalue, locale locale);
  • 把 java 对象(如 date)按指定语言环境(locale)格式化成字符串,用于页面展示。
  • 例如:new date()"2025-04-05"

(2) parser<t>:字符串 → 对象(用于解析请求)

t parse(string clientvalue, locale locale) throws parseexception;
  • 把用户提交的字符串(如表单输入)解析为 java 对象。
  • 例如:"2025-04-05"java.util.date

要求

  • 实现必须是 线程安全 的(因为会被多个请求共享)。
  • 解析失败应抛出 parseexception 或 illegalargumentexception。

2. 内置 formatter 实现(开箱即用)

spring 提供了一些常用的 formatter 实现:

formatter作用
numberstyleformatter格式化数字(支持千分位、小数点等)
currencystyleformatter显示货币(如 ¥1,234.00)
percentstyleformatter百分比显示(如 50%)
dateformattersimpledateformat 格式化日期

示例:dateformatter 实现了 print()parse(),使用 patternlocale 来格式化日期。

三、高级特性:注解驱动的格式化(annotation-driven formatting)

为了更方便地配置格式化规则,spring 支持通过 注解 + 工厂模式 来绑定格式化逻辑。

1. annotationformatterfactory<a extends annotation>

这个接口的作用是:将某个注解映射到具体的 printerparser

public interface annotationformatterfactory<a extends annotation> {
    set<class<?>> getfieldtypes();        // 支持哪些字段类型?
    printer<?> getprinter(a annotation, class<?> fieldtype);
    parser<?> getparser(a annotation, class<?> fieldtype);
}

示例:numberformatannotationformatterfactory

它处理 @numberformat 注解:

@numberformat(style = style.currency)
private bigdecimal price;
  • 当 spring 遇到这个字段时,会查找注册的 annotationformatterfactory
  • 找到后调用 getprinter() / getparser() 获取对应的格式化工厂
  • 最终使用 currencystyleformatter 来格式化金额

2. 常见格式化注解(在 org.springframework.format.annotation 包下)

注解用途
@numberformat数字格式化(支持 pattern 或 style)
@datetimeformat日期时间格式化(支持 iso 格式、自定义 pattern)

示例:

public class mymodel {
    @datetimeformat(iso = iso.date)  // 格式:yyyy-mm-dd
    private date birthdate;

    @numberformat(pattern = "#,###.00")
    private double salary;
}

这样就不需要在每个 controller 里手动写 new simpledateformat(...),而是统一管理。

四、注册机制 spi:如何让 spring 知道你的 formatter?

spring 提供了几个 spi 接口来注册格式化器。

1. formatterregistry(核心注册中心)

它是 converterregistry 的扩展,允许你注册:

void addformatterforfieldtype(class<?> fieldtype, formatter<?> formatter);
void addformatterforannotation(annotationformatterfactory<?> factory);

所有 formatter/converter 都要注册到这里才能生效。

2. formattingconversionservice(推荐实现类)

这是一个标准实现,实现了 conversionservice + formatterregistry,适合大多数场景。

你可以:

  • 编程式注册(java config)
  • 声明式注册(xml)

3. formatterregistrar(批量注册工具)

有时候你需要一次性注册多个 formatter(比如所有日期相关的),但直接注册不方便(比如类型擦除问题),这时可以用:

public interface formatterregistrar {
    void registerformatters(formatterregistry registry);
}

常见用途:

  • 注册 joda-time 所有格式化器
  • 设置全局日期格式
  • 批量注册 jsr-310 (java.time) 类型的 formatter

五、实战应用:如何配置全局日期格式?

默认情况下,未标注 @datetimeformatdate 字段会用 dateformat.short(如 4/5/25)格式化,这通常不符合中国习惯。

目标:设置全局日期格式为 yyyymmdd

方法一:java 配置(推荐)

@configuration
public class appconfig {

    @bean
    public formattingconversionservice conversionservice() {
        // 创建 conversionservice,但不注册默认 formatter
        defaultformattingconversionservice service = new defaultformattingconversionservice(false);

        // 保留 @numberformat 支持
        service.addformatterforfieldannotation(new numberformatannotationformatterfactory());

        // 设置全局日期格式:yyyymmdd
        dateformatterregistrar registrar = new dateformatterregistrar();
        registrar.setformatter(new dateformatter("yyyymmdd"));
        registrar.registerformatters(service);

        return service;
    }
}

方法二:xml 配置(传统项目)

<bean id="conversionservice" class="org.springframework.format.support.formattingconversionservicefactorybean">
    <property name="registerdefaultformatters" value="false"/>
    <property name="formatters">
        <set>
            <bean class="org.springframework.format.number.numberformatannotationformatterfactory"/>
        </set>
    </property>
    <property name="formatterregistrars">
        <set>
            <bean class="org.springframework.format.datetime.joda.jodatimeformatterregistrar">
                <property name="dateformatter">
                    <bean class="org.springframework.format.datetime.joda.datetimeformatterfactorybean">
                        <property name="pattern" value="yyyymmdd"/>
                    </bean>
                </property>
            </bean>
        </set>
    </property>
</bean>

六、总结:一句话理解全文

spring 的 formatter spi 是为 客户端环境(如 web 页面)设计的一套 基于 locale 的字符串 ↔ 对象 转换机制,相比通用的 converter,它更适合处理用户输入和输出的格式化需求,且支持注解驱动(如 @datetimeformat)、可集中配置、易于扩展。

七、常见问题解答(faq)

q1: formatter 和 propertyeditor 有什么区别?

  • propertyeditor 是 javabeans 规范的老技术,线程不安全,api 不够灵活。
  • formatter 是 spring 3 新引入的,线程安全、强类型、支持 locale,推荐替代 propertyeditor

q2: 在 spring mvc 中怎么启用这些 formatter?

只要把自定义的 formattingconversionservice 注入到 spring mvc 的配置中即可:

@configuration
@enablewebmvc
public class webconfig implements webmvcconfigurer {
    @override
    public void addformatters(formatterregistry registry) {
        registry.addformatter(new dateformatter("yyyymmdd"));
    }
}

或者使用 <mvc:annotation-driven conversion-service="conversionservice"/> xml 配置。

q3: jsr-310 时间类(localdate、localdatetime)支持吗?

支持!spring 会自动注册 java.time 类型的 formatter。你可以通过 datetimeformatterregistrar 控制其格式。

如果你正在开发 web 应用,尤其是需要处理表单提交、日期显示、货币格式等功能,那么这一套 formatter 机制就是你应该掌握的核心技能之一。

需要我根据你的具体场景(比如 spring boot 项目)给出一个完整的配置示例吗?

以上就是spring处理字段格式化的实战指南的详细内容,更多关于spring处理字段格式化的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com