一、Coverter接口,将S型转换成T型
@FunctionalInterface public interface Converter<S, T> { /** * Convert the source object of type {@code S} to target type {@code T}. * @param source the source object to convert, which must be an instance of {@code S} (never {@code null}) * @return the converted object, which must be an instance of {@code T} (potentially {@code null}) * @throws IllegalArgumentException if the source cannot be converted to the desired target type */ @Nullable T convert(S source); }
下面写个Demo把String转换成Date
(1)编写类型转换器DateConverter
public class DateConverter implements Converter<String,Date>{ @Override public Date convert(String source) { SimpleDateFormat sdf=new SimpleDateFormat("yyyy-dd-mm"); Date date=null; if(StringUtils.isEmpty(source)) { return null; } try { date= sdf.parse(source); } catch (ParseException e) { e.printStackTrace(); } return date; } }
(2)把类型转换器添加到spring中,可以在配置类中添加,也可以添加在DefaultConversionService中,Spring启动之后自动加载该类
@Configuration public class WebConfiguration { @Bean public GenericConversionService getGenericConversionService(@Autowired GenericConversionService conversionService) { conversionService.addConverter(new DateConverter()); System.out.println("类型转换已加入!"); return conversionService; } }
(3)Controller
@Controller public class HelloController { @RequestMapping("/test") @ResponseBody public String hello( String date) { return "===="+date; } }
启动SpringBoot之后访问测试
二、ConverterFactory
ConverterFactory就是管理继承或者实现同一接口的converter,就是一个工厂(类似于代理,就是一个统一管理同一类型的converter)。
public interface ConverterFactory<S, R> { <T extends R> Converter<S, T> getConverter(Class<T> targetType); }
(1)spring为我们提供了StringToNumberConverterFactory、StringToEnumConverterFactory。当浏览器传参String类型的数字时,我们就可以用int、float等进行接受。枚举也类似。以StringToNumberConverterFactory为列:
final class StringToNumberConverterFactory implements ConverterFactory<String, Number> { @Override public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) { return new StringToNumber<>(targetType); } private static final class StringToNumber<T extends Number> implements Converter<String, T> { private final Class<T> targetType; public StringToNumber(Class<T> targetType) { this.targetType = targetType; } @Override public T convert(String source) { if (source.isEmpty()) { return null; } return NumberUtils.parseNumber(source, this.targetType); } } }
(2)NumberUtils工具类中根据传进来targetType类型完成转换
@SuppressWarnings("unchecked") public static <T extends Number> T parseNumber(String text, Class<T> targetClass) { Assert.notNull(text, "Text must not be null"); Assert.notNull(targetClass, "Target class must not be null"); String trimmed = StringUtils.trimAllWhitespace(text); if (Byte.class == targetClass) { return (T) (isHexNumber(trimmed) ? Byte.decode(trimmed) : Byte.valueOf(trimmed)); } else if (Short.class == targetClass) { return (T) (isHexNumber(trimmed) ? Short.decode(trimmed) : Short.valueOf(trimmed)); } else if (Integer.class == targetClass) { return (T) (isHexNumber(trimmed) ? Integer.decode(trimmed) : Integer.valueOf(trimmed)); } else if (Long.class == targetClass) { return (T) (isHexNumber(trimmed) ? Long.decode(trimmed) : Long.valueOf(trimmed)); } else if (BigInteger.class == targetClass) { return (T) (isHexNumber(trimmed) ? decodeBigInteger(trimmed) : new BigInteger(trimmed)); } else if (Float.class == targetClass) { return (T) Float.valueOf(trimmed); } else if (Double.class == targetClass) { return (T) Double.valueOf(trimmed); } else if (BigDecimal.class == targetClass || Number.class == targetClass) { return (T) new BigDecimal(trimmed); } else { throw new IllegalArgumentException( "Cannot convert String [" + text + "] to target class [" + targetClass.getName() + "]"); } }
(3)当然也可以自定义ConverterFactory,一定要把其添加到spring中,负责无效,添加如下,可以在GenericConverterService\DefaultConverterService中添加
@Configuration public class WebConfiguration { @Bean public GenericConversionService getDefaultConversionService(@Autowired GenericConversionService conversionService) { conversionService.addConverter(new TestConverterFactory()); System.out.println("类型转换已加入!"); return conversionService; } }
三、GenericConverter(多对多的转换)
GenericConverter接口是所有的Converter接口中最灵活也是最复杂的一个类型转换接口。像我们之前介绍的Converter接口只支持从一个原类型转换为一个目标类型;ConverterFactory接口只支持从一个原类型转换为一个目标类型对应的子类型;而GenericConverter接口支持在多个不同的原类型和目标类型之间进行转换,这也就是GenericConverter接口灵活和复杂的地方。