Spring核心——數(shù)據(jù)的類型轉(zhuǎn)換

字符串到實體轉(zhuǎn)換一文中介紹了Spring核心框架中使用PropertyEditor將任何字符串轉(zhuǎn)換為數(shù)字、實體的方法。除了字符串到實體,Spring還提供了更加通用的功能在對象和對象之間進行數(shù)據(jù)轉(zhuǎn)換。

Converter<S, T>

Spring的類型轉(zhuǎn)換的基礎(chǔ)是Converter<S, T>(以下簡稱轉(zhuǎn)換器)接口:

packageorg.springframework.core.convert.converter;publicinterfaceConverter{Tconvert(S source);}

光是看他的結(jié)構(gòu)就很清晰的明白這個接口是要做什么。S表示Source(來源)、T表示Target(目標),所以這個接口的2個范型參數(shù)就是數(shù)據(jù)從S轉(zhuǎn)換為T,Converter::convert方法正是輸入一個“S”類型的實例,返回一個“T”類型的實例。

可以通過這個接口實現(xiàn)規(guī)范化、可復(fù)用的類型轉(zhuǎn)換功能。下面通過轉(zhuǎn)換器實現(xiàn)字符串到PC實體類相互轉(zhuǎn)換的過程。

Pc實體:

publicclassPCextendsDevice{String cpu;String graphic;String ram;//Getter & Setter ...}

在基類Device中通過反射實現(xiàn)字符串到實體類的轉(zhuǎn)換:

publicabstractclassDevice{publicvoidpares(String text){//字符串轉(zhuǎn)換為實體Field[] fields =this.getClass().getDeclaredFields();for(Field field : fields) {intbegIndex = text.indexOf(field.getName());intendIndex = text.indexOf(";", begIndex);String sub = text.substring(begIndex, endIndex), value = sub.split("=")[1];field.setAccessible(true);? ? field.set(this, value);}};publicStringvalue(){//實體轉(zhuǎn)換為字符串Field[] fields =this.getClass().getDeclaredFields();StringBuilder sb =newStringBuilder();for(Field field : fields) {sb.append(field.getName());sb.append("=");sb.append(field.get(this).toString());sb.append(";");}returnsb.toString();}}

然后聲明兩個轉(zhuǎn)換器的實現(xiàn)類:

publicclassString2PcConverterimplementsConverter{//字符串轉(zhuǎn)換為PC對象@OverridepublicPCconvert(String source){PC pc =newPC();pc.pares(source);returnpc;}}

publicclassPC2StringConverterimplementsConverter{//PC對象轉(zhuǎn)換為字符串@OverridepublicStringconvert(PC source){returnsource.value();}}

?最后使用這兩個轉(zhuǎn)換器:

publicclassConversionApp{voidsingletonConversion(){finalString text ="cpu=amd;ram=kingston;graphic=Navidia;";Converter string2Pc =newString2PcConverter();PC pc = string2Pc.convert(text);Converter pc2String =newPC2StringConverter();String string = pc2String.convert(pc);}}

以上就是Spring最基本的類型轉(zhuǎn)換功能——圍繞著轉(zhuǎn)換器(Converter<S, T>)接口實現(xiàn)數(shù)據(jù)類型轉(zhuǎn)換??吹竭@里可能有些碼友就要問了:這到底有什么用?直接用使用Device::pares和Device::value方法不就完事了?為什么還要引入轉(zhuǎn)換器兜一圈??!

如果系統(tǒng)僅僅只有1個或幾個類型轉(zhuǎn)換確實沒必要引入轉(zhuǎn)換器。但是業(yè)務(wù)總是繁雜多樣的,模塊與模塊之前也會存在數(shù)據(jù)結(jié)構(gòu)的差異,因此我們需要適配器(Adapter)、外觀(Facade)等模式來應(yīng)對變化多端的外部輸入而無需改動業(yè)務(wù)邏輯。實際上從更高的層次看,Converter接口就是Spring為類型轉(zhuǎn)換提供的一個適配器。后面會看到Spring已經(jīng)為程序的順利運行提供了大量的轉(zhuǎn)換器,即使在閱讀本文內(nèi)容之前不知道這些轉(zhuǎn)換器的存在,但Spring框架時時刻刻都在使用他們。

ConverterFactory<S, R>

轉(zhuǎn)換器只能對單一類型進行轉(zhuǎn)換,如果有大量相同類別的數(shù)據(jù)需要轉(zhuǎn)換可以使用ConverterFactory(一下簡稱轉(zhuǎn)換工廠):

publicinterfaceConverterFactory{? ? ConvertergetConverter(Class<T> targetType);}

ConverterFactory::getConverter是返回一個轉(zhuǎn)換器,這里范型標記“T”是“R”的子類??聪旅孓D(zhuǎn)換工廠的例子,他可以將字符串轉(zhuǎn)換成Device的子類:

publicclassString2DeviceConverterFactoryimplementsConverterFactory{publicConvertergetConverter(Class<T> targetType){returnnewString2DeviceConverter(targetType);}// Device的通用轉(zhuǎn)換器staticclassString2DeviceConverterimplementsConverter{privateClass klass;publicString2DeviceConverter(Class<? extends Device> klass){this.klass = klass;}publicTconvert(String source){Device device =null;device = klass.newInstance();device.pares(source);return(T) device;}}}

然后可以使用這個轉(zhuǎn)換工廠按照目標類型進行轉(zhuǎn)換:

publicclassConversionApp{voidfactoryConversion(){String2DeviceConverterFactory factory =newString2DeviceConverterFactory();Converter pcConverter = factory.getConverter(PC.class);//將字符串轉(zhuǎn)換為PCPC pc = pcConverter.convert("cpu=amd;ram=kingston;graphic=Navidia;");Converter phoneConverter = factory.getConverter(Phone.class);//將字符串轉(zhuǎn)換為PhonePhone phone = phoneConverter.convert("name=HUAWEIP20;cpu=Kirin970;ram=64G;");}}

Phone是另外一個繼承了Device的實體類:

publicclassPhoneextendsDevice{String name;String cpu;String ram;// Getter & Setter}

數(shù)據(jù)轉(zhuǎn)換服務(wù)

Spring已經(jīng)為數(shù)據(jù)轉(zhuǎn)換預(yù)設(shè)了大量的Converter,這些Converter可以通過ConversionService直接使用。ConversionService中包含了幾乎所有Java常規(guī)類型的數(shù)據(jù)格式轉(zhuǎn)換,看下面的案例。

publicclassConversionApp{ConversionAppregistConversionService(){ConfigurableApplicationContext ctx =newAnnotationConfigApplicationContext(ConversionConfig.class);// 獲取ConversionServiceConversionService service = ctx.getBean(ConversionService.class);// 字符串轉(zhuǎn)換為整型inti = service.convert("123456", Integer.class);// 字符串轉(zhuǎn)換為浮點floatf = service.convert("1234.56", Float.class);// 源生列表轉(zhuǎn)換為ListList list = service.convert(newint[] {1,2,3,4,5,6}, List.class);// 源生列表轉(zhuǎn)換為SetSet set = service.convert(newint[] {1,2,3,4,5,6}, Set.class);// 枚舉轉(zhuǎn)換Gender gender = service.convert("Male", Gender.class);// 使用自定義轉(zhuǎn)換器PC pc = service.convert("cpu=amd;ram=kingston;graphic=Navidia;", PC.class);// UUID轉(zhuǎn)換UUID uuid = service.convert("f51b4b95-0925-4ad0-8c62-4daf3ea7918f", UUID.class);// 字符串轉(zhuǎn)換為Optional<PC>Optional options = service.convert("cpu=amd;ram=kingston;graphic=Navidia;", Optional.class);// 使用TypeDescriptor描述進行轉(zhuǎn)換String source ="123456789";intresult = (int) service.convert(source, TypeDescriptor.valueOf(source.getClass()),TypeDescriptor.valueOf(Integer.class));_G.print(result);}enumGender {Male, Female, Other}}

除了上面的轉(zhuǎn)換,ConversionService還提供了其他轉(zhuǎn)換器,詳情請看org.springframework.core.convert.support.DefaultConversionService的JavaDoc文檔。

需要通過ConversionServiceFactoryBean來啟用ConversionService,下面的代碼是在@Configurable中向IoC容器添加ConversionServiceFactoryBean:

@ConfigurablepublicclassConversionConfig{@BeanpublicConversionServiceFactoryBeanConversionServiceFactoryBean(){ConversionServiceFactoryBean factoryBean =newConversionServiceFactoryBean();Set converters =newHashSet<>();// 添加自定義轉(zhuǎn)換器converters.add(newString2PcConverter());converters.add(newPC2StringConverter());factoryBean.setConverters(converters);returnfactoryBean;}}

也可以通過XML文件配置來引入ConversionService:

ConversionService在Spring MVC中的作用很大,可以全局注冊統(tǒng)一的類型轉(zhuǎn)換器。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容