Spring Framework TypeConverter与ConversionService

好的,各位观众老爷们,欢迎来到“Spring转换变形记”现场!我是你们的老朋友,代码界的段子手——程序猿小李。今天,咱们不聊高深莫测的架构设计,也不谈云里雾里的微服务,咱们就来唠唠嗑,聊聊Spring Framework里那些看似不起眼,却能让你少加班的神奇小玩意儿:TypeConverter与ConversionService。

准备好了吗? 系好安全带,咱们的“变形记”要开始了!

第一幕:话说“类型不匹配”的那些糟心事儿

作为一名身经百战的程序员,你肯定遇到过这样的场景:

  • 前端传来一个String类型的“123”,你却想把它当成Integer来用,做个加减乘除啥的。
  • 数据库里存的是“2023-10-27”,而你的JavaBean里对应的字段却是LocalDate类型。
  • 配置文件里写的是“true”,你想把它转换成Boolean类型,控制程序的走向。

每当遇到这些情况,你的内心是不是这样的? 抓耳挠腮,恨不得把电脑砸了!

如果让你手动去处理这些类型转换,那简直就是噩梦!不仅代码冗余,而且容易出错。更可怕的是,每次遇到新的类型转换需求,你都得重新写一遍,简直就是重复劳动!

别担心,Spring Framework早就替你想好了!它提供了TypeConverter和ConversionService这两个利器,帮你轻松解决类型转换的问题。

第二幕:TypeConverter——“单刀赴会”的类型转换器

首先,我们来认识一下TypeConverter。你可以把它想象成一位身手矫健的“类型转换刺客”,专门负责处理单个类型之间的转换。

TypeConverter是个啥?

TypeConverter是一个接口,它定义了类型转换的基本行为。Spring Framework提供了很多默认的实现,比如:

  • SimpleTypeConverter: 一个简单的实现,可以转换一些常见的类型。
  • PropertyEditorRegistrySupport: 一个更强大的实现,可以注册自定义的PropertyEditor,实现更复杂的类型转换。

TypeConverter怎么用?

TypeConverter的使用非常简单,只需要调用它的convertIfNecessary()方法即可。

import org.springframework.beans.SimpleTypeConverter;

public class TypeConverterDemo {

    public static void main(String[] args) {
        SimpleTypeConverter converter = new SimpleTypeConverter();

        // String to Integer
        Integer intValue = converter.convertIfNecessary("123", Integer.class);
        System.out.println("String to Integer: " + intValue); // 输出:String to Integer: 123

        // String to Boolean
        Boolean booleanValue = converter.convertIfNecessary("true", Boolean.class);
        System.out.println("String to Boolean: " + booleanValue); // 输出:String to Boolean: true

        // String to LocalDate (需要PropertyEditor的支持)
        // 假设你注册了一个可以处理String到LocalDate转换的PropertyEditor
        // LocalDate localDate = converter.convertIfNecessary("2023-10-27", LocalDate.class);
        // System.out.println("String to LocalDate: " + localDate);
    }
}

看到没?只需要一行代码,就能搞定类型转换!简直不要太爽!

TypeConverter的局限性

虽然TypeConverter很方便,但它也有一些局限性:

  • 只能处理单个类型之间的转换。 如果你需要处理多个类型之间的转换,就需要创建多个TypeConverter实例。
  • 需要手动创建和配置。 在使用TypeConverter之前,你需要手动创建它的实例,并配置它支持哪些类型转换。
  • 扩展性有限。 如果你需要自定义类型转换逻辑,就需要实现PropertyEditor接口,并将其注册到TypeConverter中。

第三幕:ConversionService——“运筹帷幄”的类型转换服务

为了解决TypeConverter的局限性,Spring Framework推出了ConversionService。你可以把它想象成一个“类型转换指挥中心”,负责管理和协调所有的类型转换器。

ConversionService是个啥?

ConversionService是一个接口,它定义了类型转换服务的行为。Spring Framework提供了很多默认的实现,比如:

  • GenericConversionService: 一个通用的实现,可以注册自定义的Converter,实现更灵活的类型转换。

ConversionService怎么用?

ConversionService的使用也很简单,只需要调用它的convert()方法即可。

import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;

public class ConversionServiceDemo {

    public static void main(String[] args) {
        ConversionService conversionService = new DefaultConversionService();

        // String to Integer
        Integer intValue = conversionService.convert("123", Integer.class);
        System.out.println("String to Integer: " + intValue); // 输出:String to Integer: 123

        // String to Boolean
        Boolean booleanValue = conversionService.convert("true", Boolean.class);
        System.out.println("String to Boolean: " + booleanValue); // 输出:String to Boolean: true

        // String to LocalDate (需要注册Converter)
        // 假设你注册了一个可以处理String到LocalDate转换的Converter
        // LocalDate localDate = conversionService.convert("2023-10-27", LocalDate.class);
        // System.out.println("String to LocalDate: " + localDate);
    }
}

ConversionService的优势

相比于TypeConverter,ConversionService有以下优势:

  • 可以处理多个类型之间的转换。 ConversionService可以注册多个Converter,每个Converter负责处理一种类型之间的转换。
  • 自动发现和配置。 Spring Framework会自动发现和配置ConversionService,你只需要在配置文件中声明即可。
  • 扩展性强。 你可以自定义Converter,实现更复杂的类型转换逻辑。

第四幕:Converter——“类型转换的灵魂”

Converter是ConversionService的核心组件,它负责实现具体的类型转换逻辑。

Converter是个啥?

Converter是一个接口,它定义了类型转换的行为。你需要实现这个接口,并编写自己的类型转换逻辑。

import org.springframework.core.convert.converter.Converter;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class StringToLocalDateConverter implements Converter<String, LocalDate> {

    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Override
    public LocalDate convert(String source) {
        if (source == null || source.isEmpty()) {
            return null;
        }
        return LocalDate.parse(source, formatter);
    }
}

如何注册Converter?

你可以通过以下几种方式注册Converter:

  • XML配置:
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.example.StringToLocalDateConverter"/>
        </set>
    </property>
</bean>
  • Java配置:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(stringToLocalDateConverter());
    }

    @Bean
    public Converter<String, LocalDate> stringToLocalDateConverter() {
        return new StringToLocalDateConverter();
    }
}
  • 注解: (Spring Boot 2.0+)
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

@Component
@ConfigurationPropertiesBinding
public class StringToLocalDateConverter implements Converter<String, LocalDate> {

    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Override
    public LocalDate convert(String source) {
        if (source == null || source.isEmpty()) {
            return null;
        }
        return LocalDate.parse(source, formatter);
    }
}

第五幕:TypeConverter vs ConversionService——“英雄莫问出处”

既然TypeConverter和ConversionService都能实现类型转换,那么我们应该选择哪个呢?

特性 TypeConverter ConversionService
适用场景 单个类型之间的简单转换 多个类型之间的复杂转换
配置方式 手动创建和配置 自动发现和配置
扩展性 有限,需要实现PropertyEditor接口 强,可以自定义Converter
使用方式 converter.convertIfNecessary(source, targetType) conversionService.convert(source, targetType)
Spring集成度 较低 较高

总结:

  • 如果你只需要处理单个类型之间的简单转换,并且不想引入过多的依赖,那么TypeConverter是一个不错的选择。
  • 如果你需要处理多个类型之间的复杂转换,并且希望利用Spring Framework的自动配置和扩展性,那么ConversionService是更好的选择。

第六幕:实战演练——“Show me the code!”

光说不练假把式,咱们来一个实战演练!

假设我们需要实现以下类型转换:

  • String to Integer
  • String to Boolean
  • String to LocalDate

我们可以使用ConversionService来实现:

  1. 创建Converter:
import org.springframework.core.convert.converter.Converter;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class StringToLocalDateConverter implements Converter<String, LocalDate> {

    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Override
    public LocalDate convert(String source) {
        if (source == null || source.isEmpty()) {
            return null;
        }
        return LocalDate.parse(source, formatter);
    }
}

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

@Component
public class StringToIntegerConverter implements Converter<String, Integer> {

    @Override
    public Integer convert(String source) {
        if (source == null || source.isEmpty()) {
            return null;
        }
        try {
            return Integer.parseInt(source);
        } catch (NumberFormatException e) {
            return null;
        }
    }
}

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

@Component
public class StringToBooleanConverter implements Converter<String, Boolean> {

    @Override
    public Boolean convert(String source) {
        if (source == null || source.isEmpty()) {
            return null;
        }
        return Boolean.parseBoolean(source);
    }
}
  1. 配置ConversionService: (使用Java配置)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToLocalDateConverter());
        registry.addConverter(new StringToIntegerConverter());
        registry.addConverter(new StringToBooleanConverter());
    }
}
  1. 使用ConversionService:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;

import java.time.LocalDate;

@Component
public class MyService {

    @Autowired
    private ConversionService conversionService;

    public void doSomething(String strInt, String strBoolean, String strDate) {
        Integer intValue = conversionService.convert(strInt, Integer.class);
        Boolean booleanValue = conversionService.convert(strBoolean, Boolean.class);
        LocalDate localDate = conversionService.convert(strDate, LocalDate.class);

        System.out.println("Integer: " + intValue);
        System.out.println("Boolean: " + booleanValue);
        System.out.println("LocalDate: " + localDate);
    }
}

第七幕:总结与展望——“路漫漫其修远兮”

好了,各位观众老爷们,今天的“Spring转换变形记”就到这里了。

我们从类型不匹配的烦恼开始,认识了TypeConverter和ConversionService这两个利器,学习了如何自定义Converter,并通过实战演练加深了理解。

希望通过今天的学习,你能够更加熟练地运用TypeConverter和ConversionService,告别手动类型转换的苦恼,写出更加优雅、高效的代码!

当然,类型转换的世界远不止这些。还有很多高级用法,比如:

  • 使用@NumberFormat@DateTimeFormat注解,简化类型转换的配置。
  • 利用Spring Data JPA的@Convert注解,实现数据库字段的类型转换。
  • 自定义Formatter,实现更灵活的类型格式化。

这些内容就留给各位观众老爷们自己去探索了。记住,学习永无止境,让我们一起在代码的海洋里遨游吧!

最后,祝大家编码愉快,永不加班!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注