Converter接口
基本概念
在Spring框架中,
Converter接口是一个简单的策略接口,用于将一个对象类型转换为另一个对象类型。它在Spring的类型转换系统中使用,可以在多种情况下自动应用,例如处理HTTP请求参数、处理表单提交的数据、设置bean属性等注:仅针对
@RequestParam注解(匹配默认为形参的对象名,例如PayTypeEnum payTypeEnum为payTypeEnum,PayTypeEnum p为p),无法对@RequestBody注解对象生效
Spring默认提供了一些内置的Converter,用于常见的数据类型转换。例如,Spring可以自动将字符串转换为基本数据类型(如int、double、boolean等),以及一些常见的封装类型(如Integer、Double、Boolean等)
如果需要自定义类型转换,可以通过实现Converter接口来创建自己的转换器,并将其注册到Spring的ConversionService中。当Spring在数据绑定过程中遇到需要转换的类型时,它会使用自定义的转换器。
使用场景
- 处理HTTP请求参数:在Spring MVC中接收HTTP请求时,Spring会尝试将请求参数转换为控制器方法中声明的参数类型。如果需要将一个字符串参数转换为自定义对象,可以使用
Converter - 设置Bean属性:在Spring的IoC容器中,当设置bean的属性时,如果类型不匹配,Spring会尝试使用注册的
Converter进行类型转换 - 数据绑定:使用
DataBinder(非Web环境)或WebDataBinder(Web环境)用于将请求参数绑定到对象的属性上(数据绑定)。Converter可以用于自定义类型转换
源代码
Converter.java
package org.springframework.core.convert.converter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@FunctionalInterface
public interface Converter<S, T> {
@Nullable
T convert(S source);
default <U> Converter<S, U> andThen(Converter<? super T, ? extends U> after) {
Assert.notNull(after, "After Converter must not be null");
return (s) -> {
T initialResult = this.convert(s);
return initialResult != null ? after.convert(initialResult) : null;
};
}
}
convert():需要重写的方法,定义转换器逻辑andThen():提供默认的实现,可以通过使用此方式实现定义链式调用逻辑,最终通过返回的对象来使用convert()方法实现链式调用
示例代码
PayTypeEnum.java
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum PayTypeEnum {
/**
* 学生且周末
*/
STUDENT_WEEKEND(1, "studentWeekendStrategy"),
/**
* 学生但工作日
*/
student_working_day(2, "studentWorkdayStrategy"),
/**
* 非学生
*/
not_student(3, "notStudentStrategy");
/**
* 支付类型Code
*/
private final Integer payTypeCode;
/**
* 对应的策略(bean)名称
*/
private final String strategyName;
public static PayTypeEnum fromCode(int code) {
for (PayTypeEnum payType : PayTypeEnum.values()) {
if (payType.getPayTypeCode() == code) {
return payType;
}
}
throw new IllegalArgumentException("Invalid pay type code: " + code);
}
// 指定当前对象转换为JSON时所返回的值,可用于属性或者方法上
@JsonValue
public String getStrategyName() {
return strategyName;
}
}StringToPayTypeEnumConverter.java
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@Component
public class StringToPayTypeEnumConverter implements Converter<String, PayTypeEnum> {
/**
* 这里Converter<String, PayTypeEnum>
* 第一个参数必须为String,第二个参数为自定义转换的对象类型
* @param source 原始值
* @return 注入的对象
*/
@Override
public PayTypeEnum convert(String source) {
return PayTypeEnum.fromCode(Integer.parseInt(source));
}
}TestController.java
@GetMapping("/useStrategy")
public PayTypeEnum useStrategy(PayTypeEnum payTypeEnum) {
testService.useStrategy(payTypeEnum);
return payTypeEnum;
}当请求过来,SpringBoot会自动解析方法的请求体,当指定的对象与
@RequestParam匹配成功,自动触发自定义的Converter转换器http://localhost:8080/test/useStrategy?payTypeEnum=1注:Spring MVC默认会将对象转化为键与请求参数赋值的,这里自定义转换逻辑之后就不会自动给对象中的属性赋值了
链式调用
StringToIntegerConverter.java
import org.springframework.core.convert.converter.Converter;
public class StringToIntegerConverter implements Converter<String, Integer> {
@Override
public Integer convert(String source) {
System.out.println("将字符串数据转化为整型数据");
return Integer.parseInt(source);
}
}IntegerToStringConverter.java
import org.springframework.core.convert.converter.Converter;
public class IntegerToStringConverter implements Converter<Integer, String> {
@Override
public String convert(Integer source) {
System.out.println("将整型数据转化为字符串数据");
return String.valueOf(source);
}
}StringToStringConverter.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
public class StringToStringConverter implements Converter<String, String> {
/**
* 返回数据是Integer类型,相当于监听Integer类型
*/
@Autowired
private StringToIntegerConverter stringToIntegerConverter;
/**
* 由于SpringMVC为了适应处理,所以接受数据必须是字符串,这里接收不正确,无法触发
*/
@Autowired
private IntegerToStringConverter integerToStringConverter;
@Override
public String convert(String source) {
// andThen实现链式调用,从左到右顺序执行
Converter<String, String> resultConverter = stringToIntegerConverter.andThen(integerToStringConverter)
.andThen(stringToIntegerConverter).andThen(integerToStringConverter);
return resultConverter.convert(source);
// 不能使用自身的andThen方法,会形成递归导致栈溢出
// Converter<String, Integer> stringIntegerConverter = this.andThen(stringToIntegerConverter);
// Integer convert = stringIntegerConverter.convert(source);
// return String.valueOf(convert);
}
}ConverterConfig.java
import com.atguigu.boot.Converter.IntegerToStringConverter;
import com.atguigu.boot.Converter.StringToIntegerConverter;
import com.atguigu.boot.Converter.StringToStringConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
@Configuration
public class ConverterConfig {
@Bean
public Converter<String, Integer> stringToIntegerConverter() {
return new StringToIntegerConverter();
}
@Bean
public Converter<Integer, String> integerToStringConverter() {
return new IntegerToStringConverter();
}
@Bean
public Converter<String, String> stringToStringConverter() {
return new StringToStringConverter();
}
}TestController.java
@RequestMapping("/use")
public String test(String test) {
System.out.println(test);
return test;
}测试请求
localhost:8080/test/use?test=10打印结果
将字符串数据转化为整型数据 将整型数据转化为字符串数据 将字符串数据转化为整型数据 将整型数据转化为字符串数据 10
