我是靠谱客的博主 如意乌龟,最近开发中收集的这篇文章主要介绍SpringMVC 坑路7 -> 数据格式化,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

数据格式化简介

Formatter SPI 简介

数据格式化架构

内建的格式化转换器

类型级别的解析/格式化

字段级别的解析/格式化

自定义注解进行字段级别的解析/格式化

数据格式化简介

  在 Web 项目中,通常需要将数据转换为具有某种格式的字符串进行展示,数据类型转换系统核心作用不是完成这个需求,因此 Spring3 引入了格式化转换器(Formatter SPI)和格式化服务 API(FormattingConversionService)从而支持这种需求。

Formatter SPI 简介

  Formatter SPI 核心是完成解析和格式化转换逻辑,在如 Web 项目中,需要解析、打印/展示本地化的对象值时使用,如根据 Locale 信息将 java.util.Date —> java.lang.String 打印/展示、java.lang.String —> java.util.Date 等。

  该格式化转换系统是 Spring 通用的,其定义在 org.springframework.format 包中,不仅仅在 Spring Web MVC 场景下用。

数据格式化架构

一、格式化转换器:提供格式化转换的实现支持。
二、格式化转换器注册器、格式化服务:提供类型转换器注册支持,运行时类型转换 API 支持。

数据格式化架构

一、格式化转换器:提供格式化转换的实现支持:

1.Printer 接口:格式化显示接口,将 T 类型的对象根据 Locale 信息以某种格式进行打印显示(即返回字符串形式);

package org.,springframework.format;
public interface Printer<T>{
    String print(T object,Locale locale);
}

2.Parser 接口:解析接口,根据 Locale 信息解析字符串到 T 类型的对象:

package org.springframework.format;
public interface Parser<T>{
    T parse(String text,Locale locale) throws ParseException;
}

3.Formatter 接口:格式化 SPI 接口,继承 Printer 和 Parser 接口,完成 T 类型对象的格式化和解析功能:

package org.springframework.format;
public interface Formatter<T> extends Printer<T>,Parser<T>{
}

4.AnnotationFormatterFactory 接口:注解驱动的字段格式化工厂,用于创建带注解的对象字段的 Printer 和 Parser,即用于格式化和解析带注解的对象字段。

package org.springframework.format;
public interface AnnotationFormatterFactory<A extends Annotation>{ // 可以识别的注解类型
    Set<Class<?>> getFieldTypes();// 可以被 A 注解类型注解的字段类型集合
    Printer<?> getPrinter(A annotation,Class<?> fieldType);// 根据 A 注解类型和 fieldType 类型获取 Printer
    Parser<?> getParser(A annotation,Class<?> fieldType);// 根据 A 注解类型和 fieldType 类型获取 Parser
}
二、格式化转换器注解器、格式化服务:提供类型转换器注册支持,运行时类型转换 API 支持

1、FormatterRegistry:格式化转换器注册器,用于注册格式化转换器(Formatter、Printer、Parser 和 AnnotationFormatterFactory)。
2、FormattingConversionService:继承自 ConversionService,运行时类型转换和格式化服务接口,提供运行期类型转换和格式化的支持。

内建的格式化转换器

类名说明
DateFormatterjava.util.Date <—-> String
实现日期的格式化/解析
NumberFormatterjava.util.Number <—-> String
实现通用样式的格式化/解析
CurrencyFormatterjava.util.BigDecimal <—-> String
实现货币样式的格式化/解析
PercentFormatterjava.util.Number <—-> String
实现百分数样式的格式化/解析
NumberFormatAnnotationFormatterFactory@NumberFormat 注解类型的数字字段类型 <—-> String
①通过@NumberFormat 指定格式化/解析格式
②可以格式化/解析的数字类型:Short、Integer、Long、Float、Double、BigDecimal、BigInteger
JodaDateTimeFormatAnnotationFormatterFactory@DateTimeFormat 注解类型的日期字段类型 <—-> String
①通过 @DataTimeFormat 指定格式化/解析格式
②可以格式化/解析的日期类型:joda 中的日期类型(org.joda.time 包中的):LocalDate、LocalDateTime、LocalTime、ReadableInstant,Java 内置的日期类型:Date、Calendar、Long。
classpath 中必须有 Joda-Time 类库,否则则无法格式化日期类型

内建的格式化转换器

  NumberFormatAnnotationFormatterFactory 和 JodaDateTimeFormatAnnotationFormatterFactory(如果 classpath 提供了 JodaTime 类库)在使用格式化服务实现 DefaultFormattingConversionService 时会自动注册。

类型级别的解析/格式化

1、直接使用 Formatter SPI

CurrencyFormatter cf = new CurrencyFormatter();
// 设置保留小数点后 2 位
cf.setFractionDigits(2);
// 四舍五入
cf.setRoundingMode(RoundingMode.HALF_UP);
cf.print(new BigDecimal("1234.567"),Locale.CHINA);

2、使用 DefaultFormattingConversionService

DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
// 默认不自动注册任何 Formatter
CurrentcyFormatter currencyFormatter = new CurrencyFormatter();
currencyForamtter.setFranctionDigits(2);// 保留小数点后几位
currencyFormatter.setRoundingMode(RoundingMode.HALF_UP);// 舍入模式(ceilling 表示四舍五入)
// 注册 Formatter SPI 实现
conversionService.addFormatter(currencyFormatter);
// 如果不设值默认是 Locale.getDefault();
LocaleContextHolder.setLocale(Locale.US);
字段级别的解析/格式化

  前面学习了类型级别的解析/格式化,从测试用力可以看出来类型级别的是对项目中的整个类型实施相同的解析/格式化逻辑。
  需要在不同的类的字段实施不同的解析/格式化逻辑,如用户模型类的注册日期字段只需要如“2017-02-06”格式进行解析/格式化即可,而订单模型类的下订单日期字段可能需要如“2013-06-06 00:00:00”格式进行展示。
这个就需要进行字段级别的解析/格式化了。

1:@Number:定义数字相关的解析/格式化元数据(通用样式、货币样式、百分数样式),参数如下:
(1)style:用于指定样式类型,包括三张:Style.NUMBER(通用样式)Style.CURRENCY(货币样式)Style.PERCENT(百分数样式),默认Style.NUMBER;
(2)pattern:自定义样式,如 pattern = “#,###”
2:@DateTimeFormat:定义日期相关的解析/格式化元数据,参数如下:

(1)pattern:指定解析/格式化字段数据的模式,如"yyyy-MM-dd HH:mm:ss"
(2)iso:自定解析/格式化字段数据的 ISO 模式,包括四种:ISO.NONE(不使用),ISO.DATE(yyyy-MM-dd),ISO.TIME(hh:mm:ss.SSSZ),ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ),默认 ISO.NONE;
(3)style:指定用于格式化的样式模式,默认"SS",具体使用请参考 Joda-Time 类库的 org.joda.time.format.DateTimeFormat 的forStyle 的 javadoc;

优先级:pattern > iso > style。

自定义注解进行字段级别的解析/格式化

1、定义解析/格式化字段的注解类型:

@Target({ElementType.METHOD,ElementType.FIELD,Element.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface PhoneNumber{
}

2、实现 AnnotationFormatterFactory 注解格式化工厂:

public class PhoneNumberFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<PhoneNumber>{ // 指定可以解析/格式化的字段注解类型
    private final Set<Class<?>> fieldTypes;
    private final PhoneNumberFormatter formatter;
    public PhoneNumberFormatAnnotationFormatterFactory(){
        Set<Class<?>> set = new HashSet<>();
        set.add(PhoneNumberModel.class);
        this.fieldTypes = set ;
        this.formatter = new PhoneNumberFormatter(); // 此处使用之前定义的 Formatter 实现
    }
    // 指定可以被解析/格式化的字段类型集合
    @Override
    public Set<Class<?>> getFieldTypes(){
        return fieldTypes;
    }
    // 根据注解信息和字段类型获取解析器
    @Override
    public Parser<?> getParser(PhoneNumber annotation,Class<?> fieldType){
        return formatter;
    }
    // 根据注解信息和字段类型获取格式化器
    @Override
    public Printer<?> getPrinter(PhoneNumber annotation,Class<?> fieldType){
        return formatter;
    }
}

自定义注解与 SpringMVC 集成

1、注册 FormattingConversionService 实现和自定义格式化转换器:

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="formatters">
        <list>
            <bean class="xx.formatter.PhoneNumberFormatAnnotationFormatterFactory"/>
        </list>
    </property>
</bean>

2、通过 ConfigurableWebBindingInitializer 注册 ConversionService

<bean id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
    <property name="conversionService" ref="conversionService"/>
</bean>

3、注册 ConfigurableWebBindingInitializer 到 RequestMappingHandlerAdapter

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="webBindingInitializer" ref="webBindingInitializer"/>
</bean>

配置自定义转换器

  如果使用的是 <mvc:annotation-drive> 的方式,那么上面的第2和第3步就不用做了,直接在 <mvc:annotation-drive> 里面配置 conversion-service 属性即可,示例:

<mvc:annotation-driven conversion-service="conversionService"/>

最后

以上就是如意乌龟为你收集整理的SpringMVC 坑路7 -> 数据格式化的全部内容,希望文章能够帮你解决SpringMVC 坑路7 -> 数据格式化所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部