Spring中自定义类型转换器

本文介绍了如何在Spring框架中自定义类型转换器,包括实现Converter接口、处理日期转换细节、解决代码耦合问题,以及Spring内置日期转换器的使用。

目录

一、什么是类型转换器

二、自定义类型转化器

2.1 实现Converter接口

2.2 在Spring中注册

三、自定义类型转换器中的细节

3.1 解决代码的耦合

3.2 注册标签id值必须唯一

​3.3 Spring提供的日期转换器


一、什么是类型转换器

在Spring中类型转换器就是将配置文件中的字符串类型的数据,转换成对象中成员变量对应的数据类型,进而完成注入。其实在Spring中内置了类型转换器,那为什么还要去自定义类型转换器呢?

1)首先创建一个Person类,在这个类中有一个生日的属性,根据以往的经验,接下来在配置文件中对这两个属性进行注入

public class Person {
    private String name;
    private Date birthday;
    public void setName(String name) {
        this.name = name;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

2)配置文件为属性进行注入

<bean id="person" class="com.gl.demo.converter.Person">
    <property name="name" value="张三"></property>
    <property name="birthday" value="2002-01-01"></property>
</bean>

3)注入完成,接下来进行测试,按道理来说这里应该是会得到一个结果,但是程序报错了。仔细查看报错的原因,原来是Spring中不能将2002-01-01这个字符串转化为日期格式。这也就是为什么要自定义类型转换器的原因了。(其实Spring内置了日期的转换器,文末详说)

public void test() {
    ApplicationContext ctx =
            new ClassPathXmlApplicationContext("spring-config.xml");
    Person person = (Person) ctx.getBean("person");
    System.out.println(person);
}

二、自定义类型转化器

在Spring中为我们提供了自定义类型转换器的接口,我们只需要去实现这个接口即可。最后在Spring中注册这个接口就可以了。

2.1 实现Converter接口

实现这个接口的时候会发现这里有两个泛型,其中第一个是参数注入时的类型,第二个是需要转换的类型。实现接口方法的时候Spring会将配置文件中的注入数据通过source直接传递过来

// 这里的接口泛型有两个参数,一个是原来的类型,一个是转换后的类型
public class MyDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        // 在这个方法中写上具体的转换过程即可,其中这个source会将注入的参数传递过来
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = sdf.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

2.2 在Spring中注册

首先需要注册的话就要先创建MyDateConverter的对象,然后将创建好的对象告诉Spring即可

 <bean id="myConverter" class="com.gl.demo.converter.MyDateConverter"/>

这里Spring中提供了一个用于注册类型转化器的的bean标签,注意这个id值必须是conversionService不然就会报错,这是Spring的规定!

<bean id="myConverter" class="com.gl.demo.converter.MyDateConverter"/>

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <ref bean="myConverter"/>
        </set>
    </property>
</bean>

接下来再次进行试验,由于已经在Spring中将自定义的类型转换器进行了注册,所以现在是能够将值打印出来的。注意这里的打印值是调用了Java.Util包中的Date类的toString方法所以打印值会不一样,总的来说这里的转换是已经成功了

三、自定义类型转换器中的细节

3.1 解决代码的耦合

我们发现,在这个实现类中,日期的格式是写死了的,我们想要修改的时候只能是改代码,对于这种的解决方式大家应该已经想到了吧!那就是依赖注入

public class MyDateConverter implements Converter<String, Date> {
    // 在这里添加一个属性,并给上setter方法就可了
    private String dateName;
    public void setDateName(String dateName) {
        this.dateName = dateName;
    }
    @Override
    public Date convert(String source) {
        SimpleDateFormat sdf = new SimpleDateFormat(dateName);
        Date date = null;
        try {
            date = sdf.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

修改了代码的格式之后,接下来就是需要在配置文件中注入数据了,其他的配置文件不用修改

<bean id="myConverter" class="com.gl.demo.converter.MyDateConverter">
    <property name="dateName" value="yyyy-MM-dd"/>
</bean>

3.2 注册标签id值必须唯一

这个细节已经在2.2中说明了

3.3 Spring提供的日期转换器

其实Spring是提供了日期转化器的,但是由于提供的格式我们平常使用的比较少,这也就相当于没有提供。这里只需要将日期格式改成反斜线的方式即可

<bean id="person" class="com.gl.demo.converter.Person">
    <property name="name" value="李四"></property>
    <property name="birthday" value="2002/01/01"></property>
</bean>

 这里为了避免干扰,将之前的配置文件全部都注释了,并且将名字修改了,最后运行看结果

这里发现没有报错,说明了Spring确实是含有日期转换器的 

<think>我们正在讨论如何在Spring框架中创建并注册自定义类型转换器到ConversionService。根据用户的问题和之前的引用,我们可以总结如下: 用户之前遇到了自定义转换器实例化失败的问题,现在希望了解如何正确创建和注册自定义类型转换器。引用[1]提供了关于ConversionService的基本信息:它是一个无状态对象,在应用程序启动时实例化,并在整个容器中共享。如果没有注册自定义的ConversionService,Spring会使用基于PropertyEditor的旧系统。 引用[2]虽然讲的是自定义消息转换器(用于HTTP消息转换),但注册方式类似,都是通过声明一个Bean来加入Spring容器。引用[3]提到@Required注解已被弃用,推荐使用构造函数注入,这提示我们在自定义转换器时,如果需要依赖其他Bean,应使用构造函数注入。 现在,我们将详细说明创建和注册自定义类型转换器的步骤: ### 步骤1:创建自定义转换器类 自定义转换器需要实现Spring的`Converter`接口(通常使用`Converter<S, T>`),其中S是源类型,T是目标类型。 例如,假设我们需要将字符串转换为自定义的`Money`对象: ```java package com.example.converter; import org.springframework.core.convert.converter.Converter; public class StringToMoneyConverter implements Converter<String, Money> { @Override public Money convert(String source) { // 解析字符串,例如"100.00 USD" -> Money对象 String[] parts = source.split(" "); double amount = Double.parseDouble(parts[0]); String currency = parts[1]; return new Money(amount, currency); } } ``` 注意:转换器类应该是线程安全的,避免使用可变状态。 ### 步骤2:注册自定义转换器到ConversionService #### 方式1:使用Java配置(推荐) 在配置类中,定义一个`ConversionServiceFactoryBean`的Bean,并将自定义转换器添加到其转换器集合中。 ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.ConversionService; import org.springframework.format.support.FormattingConversionServiceFactoryBean; import java.util.Set; @Configuration public class AppConfig { @Bean public ConversionService conversionService() { FormattingConversionServiceFactoryBean factory = new FormattingConversionServiceFactoryBean(); // 添加自定义转换器 factory.setConverters(getConverters()); // 初始化 factory.afterPropertiesSet(); return factory.getObject(); } private Set<?> getConverters() { return Set.of(new StringToMoneyConverter()); } } ``` #### 方式2:使用XML配置 在Spring XML配置文件中,声明`ConversionServiceFactoryBean`并添加自定义转换器: ```xml <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.example.converter.StringToMoneyConverter"/> </set> </property> </bean> ``` ### 步骤3:使用自定义转换器 一旦注册,Spring框架在执行类型转换时会自动使用这个转换器。例如,在控制器中,当接收一个字符串参数并需要转换为`Money`对象时: ```java @RestController public class PaymentController { @GetMapping("/pay") public String processPayment(@RequestParam("amount") Money money) { // 由于注册了StringToMoneyConverter,Spring会自动将字符串参数转换为Money对象 return "Payment processed: " + money; } } ``` ### 注意事项 1. **转换器依赖注入**:如果转换器需要依赖其他Bean(如服务类),可以通过构造函数注入: ```java public class StringToMoneyConverter implements Converter<String, Money> { private final CurrencyService currencyService; // 使用构造函数注入 public StringToMoneyConverter(CurrencyService currencyService) { this.currencyService = currencyService; } @Override public Money convert(String source) { // 使用currencyService进行转换 } } ``` 然后在配置中,将转换器声明为一个Bean,并注入依赖: ```java @Bean public StringToMoneyConverter stringToMoneyConverter(CurrencyService currencyService) { return new StringToMoneyConverter(currencyService); } // 然后在conversionService中引用这个Bean @Bean public ConversionService conversionService(StringToMoneyConverter stringToMoneyConverter) { FormattingConversionServiceFactoryBean factory = new FormattingConversionServiceFactoryBean(); factory.setConverters(Set.of(stringToMoneyConverter)); factory.afterPropertiesSet(); return factory.getObject(); } ``` 2. **多个转换器**:可以同时注册多个转换器Spring会按需使用最匹配的转换器。 3. **Spring Boot自动配置**:在Spring Boot中,默认已经创建了一个`ConversionService`,你只需要通过`@Bean`提供自定义转换器Spring Boot会自动将它们添加到默认的`ConversionService`中。但是,如果使用`FormattingConversionService`,则需要像上面一样显式配置。 ### 总结 创建自定义类型转换器需要: 1. 实现`Converter<S, T>`接口。 2. 通过配置类或XML将转换器注册到`ConversionService`。 3. 确保`ConversionService`的Bean被Spring容器管理。 这样,Spring在需要类型转换时就会自动使用你的转换器。 §§相关问题§§ 1. Spring Boot中如何自动注册自定义类型转换器? 2. 如何为自定义转换器编写单元测试? 3. Spring MVC中类型转换和格式化有什么区别? [^1]: ConversionService是一个无状态对象,旨在在应用程序启动时实例化,然后在多个线程之间共享。 [^2]: 自定义消息转化器,只需要在@Configuration的类中添加消息转化器的@bean加入到Spring容器,就会被Spring Boot自动加入到容器中。 [^3]: 从Spring Framework 5.1开始,@Required注释被正式弃用,支持为所需的设置使用构造函数注入。</think>### 如何在 Spring 中创建并注册自定义类型转换器到 ConversionService 以下是创建和注册自定义类型转换器的完整步骤,基于 Spring 框架的最佳实践: #### 1. 创建自定义转换器类 实现 `Converter<S, T>` 接口,定义类型转换逻辑: ```java import org.springframework.core.convert.converter.Converter; public class TranslationConvert implements Converter<String, CustomObject> { // 可选:注入依赖服务 private final DictionaryService dictionaryService; // 推荐使用构造函数注入 public TranslationConvert(DictionaryService dictionaryService) { this.dictionaryService = dictionaryService; } @Override public CustomObject convert(String source) { // 实现转换逻辑,例如: String translated = dictionaryService.translate(source); return new CustomObject(translated); } } ``` **关键点**: - 必须实现 `Converter<S, T>` 接口 - 建议提供无参构造函数或显式依赖注入 - 确保线程安全性(无共享可变状态) #### 2. 注册转换器到 ConversionService ##### 方式 1:Java 配置(推荐) ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.format.support.FormattingConversionServiceFactoryBean; @Configuration public class AppConfig { @Bean public FormattingConversionServiceFactoryBean conversionService( TranslationConvert translationConvert) { FormattingConversionServiceFactoryBean factory = new FormattingConversionServiceFactoryBean(); factory.setConverters(Set.of(translationConvert)); return factory; } @Bean public TranslationConvert translationConvert(DictionaryService dictionaryService) { return new TranslationConvert(dictionaryService); } } ``` ##### 方式 2:XML 配置 ```xml <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.example.TranslationConvert"> <constructor-arg ref="dictionaryService"/> </bean> </set> </property> </bean> ``` #### 3. 在应用中使用转换器 Spring 会自动在需要类型转换的场景使用注册的转换器: ```java // 在控制器中自动转换请求参数 @GetMapping("/translate") public ResponseEntity<?> handleRequest(@RequestParam("input") CustomObject obj) { // obj 已通过 TranslationConvert 自动转换 return ResponseEntity.ok(obj); } // 手动使用 ConversionService @Service public class TranslationService { private final ConversionService conversionService; public TranslationService(ConversionService conversionService) { this.conversionService = conversionService; } public CustomObject manualConvert(String input) { return conversionService.convert(input, CustomObject.class); } } ``` #### 关键注意事项 1. **依赖注入**:如果转换器需要其他 Bean,使用构造函数注入(推荐)或 setter 注入 2. **Bean 命名**:ConversionService 的 Bean ID 必须是 `conversionService` 3. **初始化顺序**:确保依赖 Bean 在转换器之前初始化 4. **作用范围**:转换器应设计为无状态线程安全对象 5. **Spring Boot 简化**:在 Boot 应用中只需声明 `@Bean`,Boot 会自动注册到默认 ConversionService #### 调试技巧 如果遇到实例化问题: ```properties # application.properties logging.level.org.springframework.beans=DEBUG logging.level.org.springframework.core.convert=TRACE ``` 这会显示转换器注册和使用的详细日志,帮助定位问题[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值