SpringFramework核心技术三:Spring时间处理和类型转换

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 使用在(1)中,我们学习了蛮多的基本概念,在(2)中咱们看一下如何使用的问题。一、以编程方式使用ConversionService要以编程方式使用ConversionService实例,只需为其他bean注入一...

使用

在(1)中,我们学习了蛮多的基本概念,在(2)中咱们看一下如何使用的问题。


一、以编程方式使用ConversionService

要以编程方式使用ConversionService实例,只需为其他bean注入一个引用即可:

@Service
public class MyService {

    @Autowired
    public MyService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    public void doIt() {
        this.conversionService.convert(...)
    }
}

对于大多数用例,可以使用convert指定targetType的方法,但它不适用于更复杂的类型,如参数化元素的集合。如果你想转换List的Integer到List的String程序,例如,你需要提供的源和目标类型的正式定义。

幸运的是,TypeDescriptor提供了各种选项来简单明了:

DefaultConversionService cs = new DefaultConversionService();

List<Integer> input = ....
cs.convert(input,
    TypeDescriptor.forObject(input), // List<Integer> type descriptor
    TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));

请注意,DefaultConversionService自动注册转换器适用于大多数环境。这包括收集器,标转换器,也基本Object到String转换器。相同的转换器可以ConverterRegistry使用该类 上的静态 addDefaultConverters方法进行注册DefaultConversionService。

值类型转换器将被重新用于数组和集合,所以没有必要创建一个特定的转换器从转换Collection的S到 Collection的T,假设标准收集处理是适当的。

二、Spring字段格式

正如前一节所讨论的,core.convert是一种通用型转换系统。它提供统一的ConversionService API以及用于实现从一种类型到另一种类型的转换逻辑的强类型转换器SPI。Spring容器使用这个系统绑定bean属性值。另外,Spring表达式语言(SpEL)和DataBinder都使用这个系统来绑定字段值。例如,当使用SpEL需要强迫一个Short到一个Long完成的expression.setValue(Object bean, Object value)尝试,core.convert系统执行强制。

现在考虑典型客户端环境(如Web或桌面应用程序)的类型转换要求。在这样的环境中,您通常从String转换 为支持客户端回发过程,并返回String以支持视图呈现过程。另外,您经常需要本地化字符串值。更一般的core.convert Converter SPI没有直接解决这种格式化要求。为了直接解决它们,Spring 3引入了一个方便的Formatter SPI,为客户端环境提供了PropertyEditor的一个简单而强大的替代方案。

通常,在需要实现通用类型转换逻辑时使用Converter SPI; 例如,用于在java.util.Date和java.lang.Long之间进行转换。在客户端环境(如Web应用程序)中工作时需要使用Formatter SPI,并且需要解析和打印本地化的字段值。ConversionService为两个SPI提供统一的类型转换API。

1.格式化器SPI

格式化器SPI实现字段格式化逻辑很简单并且强类型化:

package org.springframework.format;

public interface Formatter<T> extends Printer<T>, Parser<T> {
}

Formatter从打印机和解析器构建块接口扩展而来:

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;
}

要创建自己的格式化程序,只需实现上面的格式化接口即可。例如,将T指定为要格式化的对象的类型 java.util.Date。实施print()操作以打印T的实例以在客户端区域设置中显示。实现parse()操作以从客户机语言环境返回的格式化表示中解析T的实例。如果解析尝试失败,则格式化程序应该抛出ParseException或IllegalArgumentException。注意确保您的Formatter实现是线程安全的。

format为方便起见,在子包中提供了几个格式化器实现。该number包提供了一个NumberFormatter,CurrencyFormatter并 使用a PercentFormatter来格式化java.lang.Number对象java.text.NumberFormat。该datetime包提供了一个用a DateFormatter来格式化java.util.Date对象java.text.DateFormat。该datetime.joda软件包提供基于Joda-Time库的综合日期时间格式化支持。

考虑DateFormatter作为一个示例Formatter实现:

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;
    }

}

2.注释驱动的格式

您将会看到,字段格式可以通过字段类型或注释进行配置。要将注释绑定到格式化程序,请实现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是您希望将格式逻辑与之关联的字段批注类型org.springframework.format.annotation.DateTimeFormat。已经 getFieldTypes()返回类型字段中的注释,可以使用上。已经 getPrinter()返回打印机打印的注释字段的值。已经 getParser()返回解析器解析一个clientValue一个注释字段。

下面的示例AnnotationFormatterFactory实现将@NumberFormat注释绑定到格式化程序。此注释允许指定数字样式或模式:

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();
            }
        }
    }
}

要触发格式化,只需使用@NumberFormat注释字段即可:

public class MyModel {

    @NumberFormat(style=Style.CURRENCY)
    private BigDecimal decimal;

}
  • 格式注释API
    org.springframework.format.annotation 包中存在可移植的格式注释API 。使用@NumberFormat格式化java.lang.Number字段。使用@DateTimeFormat格式化java.util.Date,java.util.Calendar,java.util.Long或Joda-Time字段。

以下示例使用@DateTimeFormatjava.util.Date格式化为ISO日期(yyyy-MM-dd):

public class MyModel {

    @DateTimeFormat(iso=ISO.DATE)
    private Date date;

}

3.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 addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);

    void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);

    void addFormatterForFieldType(Formatter<?> formatter);

    void addFormatterForAnnotation(AnnotationFormatterFactory<?, ?> factory);

}

如上所示,格式化程序可以通过fieldType或注释进行注册。

FormatterRegistry SPI允许您集中配置格式化规则,而不是在控制器中复制这种配置。例如,您可能希望强制所有日期字段以特定方式格式化,或者使用特定批注的字段以特定方式格式化。通过共享的FormatterRegistry,您可以定义这些规则一次,并在需要格式化时应用这些规则。

4.FormatterRegistrar SPI

FormatterRegistrar是一个用于通过FormatterRegistry注册格式化器和转换器的SPI:

package org.springframework.format;

public interface FormatterRegistrar {

    void registerFormatters(FormatterRegistry registry);

}

FormatterRegistrar在为给定格式类别(例如日期格式)注册多个相关转换器和格式化程序时非常有用。在声明性注册不足的情况下,它也很有用。例如,格式化程序需要在与其自己的不同的特定字段类型下或在注册打印机/解析器对时进行索引。下一节提供了有关转换器和格式化程序注册的更多信息。

三、配置全球日期和时间格式

默认情况下,不使用注释的日期和时间字段@DateTimeFormat使用DateFormat.SHORT样式从字符串转换。如果你愿意,你可以通过定义你自己的全局格式来改变它。

您需要确保Spring不会注册默认格式化程序,而应该手动注册所有格式化程序。根据您是否使用Joda-Time库,使用 org.springframework.format.datetime.joda.JodaTimeFormatterRegistrarororg.springframework.format.datetime.DateFormatterRegistrarclass

例如,以下Java配置将注册全局“yyyyMMdd”格式。这个例子不依赖于Joda-Time库:

@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;
    }
}

如果你更喜欢基于XML的配置,你可以使用a FormattingConversionServiceFactoryBean。这是同一个例子,这次使用乔达时间:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd>

    <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>
</beans>

乔达时提供单独的不同类型来表示date,time和date-time 的值。的dateFormatter,timeFormatter和dateTimeFormatter的性质 JodaTimeFormatterRegistrar,应使用来配置不同的格式为每种类型。在DateTimeFormatterFactoryBean提供了一个方便的方法来创建格式化。

如果您使用Spring MVC,请记住明确配置使用的转换服务。对于基于Java的@Configuration这意味着扩展 WebMvcConfigurationSupport类和重写mvcConversionService()方法。对于XML,您应该使用元素的’conversion-service’属性 mvc:annotation-driven。有关详细信息,请参阅转换和格式。

目录
相关文章
|
15天前
|
Java 测试技术 Spring
【SpringFramework】Spring整合JUnit
本文简述Spring整合JUnit单元测试组件的通用方法,可以简化Spring框架测试。
56 14
|
30天前
|
XML Java 数据格式
【SpringFramework】Spring初体验
Spring是一款由Rod Johnson创立的主流Java EE轻量级开源框架,它旨在简化Java企业级项目开发,提供一站式轻量级解决方案,取代复杂的EJB。Spring的核心功能包括IoC(控制反转)和AOP(面向切面编程),并支持非侵入式开发、组件化和容器管理。这篇文章简要描述相关知识点和初始springframework。
111 60
【SpringFramework】Spring初体验
|
22天前
|
XML Java 数据格式
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
108 69
|
20天前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
49 21
|
13天前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
15天前
|
SQL Java 关系型数据库
【SpringFramework】Spring事务
本文简述Spring中数据库及事务相关衍伸知识点。
42 9
|
3月前
|
存储 Java API
简单两步,Spring Boot 写死的定时任务也能动态设置:技术干货分享
【10月更文挑战第4天】在Spring Boot开发中,定时任务通常通过@Scheduled注解来实现,这种方式简单直接,但存在一个显著的限制:任务的执行时间或频率在编译时就已经确定,无法在运行时动态调整。然而,在实际工作中,我们往往需要根据业务需求或外部条件的变化来动态调整定时任务的执行计划。本文将分享一个简单两步的解决方案,让你的Spring Boot应用中的定时任务也能动态设置,从而满足更灵活的业务需求。
245 4
|
4月前
|
存储 缓存 Java
在Spring Boot中使用缓存的技术解析
通过利用Spring Boot中的缓存支持,开发者可以轻松地实现高效和可扩展的缓存策略,进而提升应用的性能和用户体验。Spring Boot的声明式缓存抽象和对多种缓存技术的支持,使得集成和使用缓存变得前所未有的简单。无论是在开发新应用还是优化现有应用,合理地使用缓存都是提高性能的有效手段。
65 1
|
4月前
|
前端开发 安全 Java
技术进阶:使用Spring MVC构建适应未来的响应式Web应用
【9月更文挑战第2天】随着移动设备的普及,响应式设计至关重要。Spring MVC作为强大的Java Web框架,助力开发者创建适应多屏的应用。本文推荐使用Thymeleaf整合视图,通过简洁的HTML代码提高前端灵活性;采用`@ResponseBody`与`Callable`实现异步处理,优化应用响应速度;运用`@ControllerAdvice`统一异常管理,保持代码整洁;借助Jackson简化JSON处理;利用Spring Security增强安全性;并强调测试的重要性。遵循这些实践,将大幅提升开发效率和应用质量。
79 7
|
4月前
|
JavaScript 前端开发 Java
【颠覆传统】Spring框架如何用WebSocket技术重塑实时通信格局?揭秘背后的故事与技术细节!
【9月更文挑战第4天】随着Web应用对实时交互需求的增长,传统的HTTP模型已无法满足现代应用的要求,特别是在需要持续、双向通信的场景下。WebSocket协议由此诞生,提供全双工通信渠道,使服务器与客户端能实时互发消息。作为Java开发中最受欢迎的框架之一,Spring通过其WebSocket模块支持这一协议,简化了WebSocket在Spring应用中的集成。
66 0