好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Springboot强大的类型转换功能,你必须要掌握

环境:Springboot2.4.11

Spring3引入了一个core.convert包,它提供了一个通用类型转换系统。系统定义一个SPI来实现类型转换逻辑,定义一个API来在运行时执行类型转换。在Spring容器中,你可以使用此系统作为PropertyEditor实现的替代方案,将外部化的bean属性值字符串转换为所需的属性类型。你还可以在应用程序中需要进行类型转换的任何位置使用公共API。

Converter SPI

实现类型转换逻辑的SPI是简单且强类型的,如以下接口定义所示:

packageorg.springframework.core. convert .converter; public interfaceConverter { T convert (Ssource); }

要创建自己的转换器,需要实现converter接口,并将S参数化为要转换的类型,将T参数化为要转换的类型。如果需要将S的集合或数组转换为T的集合或集合,还可以透明地应用这样的转换器,前提是同时注册了委托数组或集合转换器(默认情况下,DefaultConversionService会这样做)。

对于每个转换调用,保证源参数source不为null。如果转换失败,转换器可能会抛出任何未检查的异常。具体来说,它应该抛出IllegalArgumentException以报告无效的源值。注意确保转换器实现是线程安全的。

为了方便起见,core.convert.support包中提供了几种转换器实现。其中包括从字符串到数字和其他常见类型的转换器。下表显示了StringToInteger类,它是典型的转换器实现:

packageorg.springframework.core. convert .support; finalclassStringToIntegerimplementsConverter Integer >{ public Integer convert (Stringsource){ return Integer .valueOf(source); } }

使用ConverterFactory

当需要集中整个类层次结构的转换逻辑时(例如,从字符串转换为枚举对象时),可以实现ConverterFactory,如下例所示:

packageorg.springframework.core. convert .converter; public interfaceConverterFactory { Converter getConverter(Class targetType); }

将S参数化为要转换的类型,将R参数化为定义可转换为的类范围的基类型。然后实现getConverter(类 ),其中T是R的一个子类。

以StringToEnumConverterFactory为例:

packageorg.springframework.core. convert .support; finalclassStringToEnumConverterFactoryimplementsConverterFactory { public Converter getConverter(Class targetType){ return newStringToEnumConverter(targetType); } privatefinalclassStringToEnumConverter implementsConverter { privateClass enumType; public StringToEnumConverter(Class enumType){ this.enumType=enumType; } public T convert (Stringsource){ return (T)Enum.valueOf(this.enumType,source.trim()); } } }

自定义类型转换

现在需要将接受的字符串转换为Users对象

public classUsers{ privateString name ; private Integer age; }

接口

@GetMapping( "/convert2" ) public Objectconvert2(Usersusers){ return users; }

调用接口


如上,通过get方式users的参数通过逗号分割。接下来就是写类型转换器了。

@SuppressWarnings({ "rawtypes" , "unchecked" }) public classUsersConverterFactoryimplementsConverterFactory { @Override public Converter getConverter(Class targetType){ return newStringToUsersConverter(); } privatefinalclassStringToUsersConverter implementsConverter { public Users convert (Stringsource){ if(source== null ||source.trim().length()==0){ return null ; } Users user =newUsers(); //下面做简单处理,不做校验 String[] values =source.split( "," ); user .setName( values [0]); user .setAge( Integer .parseInt( values [1])); return user ; } } }

注册类型转换器

@Configuration public classWebConfigimplementsWebMvcConfigurer{ @Override public voidaddFormatters(FormatterRegistryregistry){ registry.addConverterFactory(newUsersConverterFactory()); } }

编程方式使用类型转换器

要以编程方式使用ConversionService实例,可以像对任何其他bean一样向其注入引用。以下示例显示了如何执行此操作:

我们使用系统内置的类型转换器:字符串类型转枚举类型

public enumPayStatus{ START,PROCESS,COMPLETE } @RestController @RequestMapping( "/users" ) public classUsersController{ @Resource privateConversionServicecs; @GetMapping( "/convert" ) public Object convert (Stringstatus){ booleancanConvert=cs.canConvert(String.class,PayStatus.class); return canConvert?cs. convert (status,PayStatus.class): "UNKNOW" ; } }

先判断是否能够转换,其实就是判断有没有从source到target的类型转换器存在。

类型转换的实现原理

以自定义类型转换器为例

SpringMVC在进行接口调用是会执行相应的参数解析,确定了参数解析器后会执行转换服务。

查找参数解析器

查找合适的HandlerMethodArgumentResolver

public classInvocableHandlerMethodextendsHandlerMethod{ protectedObject[]getMethodArgumentValues(...)throwsException{ //查找合适的参数解析器(本例应用的是ServletModelAttributeMethodProcessor) if(!this.resolvers.supportsParameter(parameter)){ thrownewIllegalStateException(formatArgumentError(parameter, "Nosuitableresolver" )); } try{ args[i]=this.resolvers.resolveArgument(parameter,mavContainer,request,this.dataBinderFactory); } } }

解析参数

执行

public classModelAttributeMethodProcessorimplementsHandlerMethodArgumentResolver{ public finalObjectresolveArgument(...){ attribute=createAttribute( name ,parameter,binderFactory,webRequest); } } public classServletModelAttributeMethodProcessorextendsModelAttributeMethodProcessor{ protectedfinalObjectcreateAttribute(StringattributeName,MethodParameterparameter,WebDataBinderFactorybinderFactory,NativeWebRequestrequest)throwsException{ //这里得到的是原始值 Stringvalue=getRequestValueForAttribute(attributeName,request); if(value!= null ){ Objectattribute=createAttributeFromRequestValue(value,attributeName,parameter,binderFactory,request); if(attribute!= null ){ return attribute; } } return super.createAttribute(attributeName,parameter,binderFactory,request); } protectedObjectcreateAttributeFromRequestValue(StringsourceValue,StringattributeName,MethodParameterparameter,WebDataBinderFactorybinderFactory,NativeWebRequestrequest)throwsException{ DataBinderbinder=binderFactory.createBinder(request, null ,attributeName); //ConversionService对象是在容器启动的时候就初始化好的 //在WebMvcAutoConfiguration#mvcConversionService方法中初始化。 ConversionServiceconversionService=binder.getConversionService(); if(conversionService!= null ){ TypeDescriptorsource=TypeDescriptor.valueOf(String.class); TypeDescriptortarget=newTypeDescriptor(parameter); //判断是否有合适的类型转换器 if(conversionService.canConvert(source,target)){ //此方法中进行类型的转换 return binder.convertIfNecessary(sourceValue,parameter.getParameterType(),parameter); } } return null ; } }

原文链接:https://HdhCmsTesttoutiao测试数据/a7015115159660200486/

查看更多关于Springboot强大的类型转换功能,你必须要掌握的详细内容...

  阅读:61次