多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > SpringMVC之類型轉換Converter

SpringMVC之類型轉換Converter

來源:程序員人生   發布時間:2015-01-16 08:12:44 閱讀次數:8274次

SpringMVC之類型轉換Converter

1.1     目錄

1.1      目錄

1.2      前言

1.3      Converter接口

1.4      ConversionService接口

1.5      ConverterFactory接口

1.6      GenericConverter接口

1.6.1     概述

1.6.2     ConditionalGenericConverter 接口

 

1.2     前言

       在以往我們需要SpringMVC為我們自動進行類型轉換的時候都是用的PropertyEditor。通過PropertyEditor的setAsText()方法我們可以實現字符串向特定類型的轉換。但是這里有1個限制是它只支持從String類型轉為其他類型。在Spring3中引入了1個Converter接口,它支持從1個Object轉為另外一個Object。除Converter接口以外,實現ConverterFactory接口和GenericConverter接口也能夠實現我們自己的類型轉換邏輯。

1.3     Converter接口

       我們先來看1下Converter接口的定義:

Java代碼 收藏代碼
  1. public interface Converter<S, T> {  
  2.      
  3.     T convert(S source);  
  4.    
  5. }  

 

       我們可以看到這個接口是使用了泛型的,第1個類型表示原類型,第2個類型表示目標類型,然后里面定義了1個convert方法,將原類型對象作為參數傳入進行轉換以后返回目標類型對象。當我們需要建立自己的converter的時候就能夠實現該接口。下面假定有這樣1個需求,有1個文章實體,在文章中是可以有附件的,而附件我們需要記錄它的要求地址、大小和文件名,所以這個時候文章應當是包括1個附件列表的。在實現的時候我們的附件是實時上傳的,上傳后由服務端返回對應的附件要求地址、大小和文件名,附件信息不直接寄存在數據庫中,而是作為文章的屬性1起寄存在Mongodb中。客戶端獲得到這些信息以后做1個簡單的展現,然后把它們封裝成特定格式的字符串作為隱藏域跟隨文章1起提交到服務端。在服務端我們就需要把這些字符串附件信息轉換為對應的List<Attachment>。所以這個時候我們就建立1個String[]到List<Attachment>的Converter。代碼以下:

Java代碼 收藏代碼
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.    
  4. import org.springframework.core.convert.converter.Converter;  
  5.    
  6. import com.tiantian.blog.model.Attachment;  
  7.    
  8. public class StringArrayToAttachmentList implements Converter<String[], List<Attachment>> {  
  9.    
  10.     @Override  
  11.     public List<Attachment> convert(String[] source) {  
  12.        if (source == null)  
  13.            return null;  
  14.        List<Attachment> attachs = new ArrayList<Attachment>(source.length);  
  15.        Attachment attach = null;  
  16.        for (String attachStr : source) {  
  17.            //這里假定我們的Attachment是以“name,requestUrl,size”的情勢拼接的。  
  18.            String[] attachInfos = attachStr.split(",");  
  19.            if (attachInfos.length != 3)//當按逗號分隔的數組長度不為3時就拋1個異常,說明非法操作了。  
  20.               throw new RuntimeException();  
  21.            String name = attachInfos[0];  
  22.            String requestUrl = attachInfos[1];  
  23.            int size;  
  24.            try {  
  25.               size = Integer.parseInt(attachInfos[2]);  
  26.            } catch (NumberFormatException e) {  
  27.               throw new RuntimeException();//這里也要拋1個異常。  
  28.            }  
  29.            attach = new Attachment(name, requestUrl, size);  
  30.            attachs.add(attach);  
  31.        }  
  32.        return attachs;  
  33.     }  
  34.    
  35. }  

 

 

1.4     ConversionService接口

       在定義好Converter以后,就是使用Converter了。為了統1調用Converter進行類型轉換,Spring為我們提供了1個ConversionService接口。通過實現這個接口我們可以實現自己的Converter調用邏輯。我們先來看1下ConversionService接口的定義:

Java代碼 收藏代碼
  1. public interface ConversionService {  
  2.    
  3.     boolean canConvert(Class<?> sourceType, Class<?> targetType);  
  4.    
  5.     <T> T convert(Object source, Class<T> targetType);  
  6.      
  7.     boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);  
  8.    
  9.     Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);  
  10.    
  11. }  

 

       我們可以看到ConversionService接口里面定義了兩個canConvert方法和兩個convert方法,canConvert方法用于判斷當前的ConversionService是不是能夠對原類型和目標類型進行轉換,convert方法則是用于進行類型轉換的。上面出現的參數類型TypeDescriptor是對1種類型的封裝,里面包括該種類型的值、實際類型等等信息。

在定義了ConversionService以后我們就能夠把它定義為1個bean對象,然后指定<mvn:annotation-driven/>的conversion-service屬性為我們自己定義的ConversionService bean對象。如:

Xml代碼 收藏代碼
  1. <mvc:annotation-driven conversion-service="myConversionService"/>  
  2.   
  3. <bean id="myConversionService" class="com.tiantian.blog.web.converter.support.MyConversionService"/>  

 

       這樣當SpringMVC需要進行類型轉換的時候就會調用ConversionService的canConvert和convert方法進行類型轉換。

       1般而言我們在實現ConversionService接口的時候也會實現ConverterRegistry接口。使用ConverterRegistry可使我們對類型轉換器做1個統1的注冊。ConverterRegistry接口的定義以下:

Java代碼 收藏代碼
  1. public interface ConverterRegistry {  
  2.      
  3.     void addConverter(Converter<?, ?> converter);  
  4.    
  5.     void addConverter(GenericConverter converter);  
  6.    
  7.     void addConverterFactory(ConverterFactory<?, ?> converterFactory);  
  8.    
  9.     void removeConvertible(Class<?> sourceType, Class<?> targetType);  
  10.    
  11. }  

 

       正如前言所說的,要實現自己的類型轉換邏輯我們可以實現Converter接口、ConverterFactory接口和GenericConverter接口,ConverterRegistry接口就分別為這3種類型提供了對應的注冊方法,至于里面的邏輯就能夠發揮自己的設計能力進行設計實現了。

       對ConversionService,Spring已為我們提供了1個實現,它就是GenericConversionService,位于org.springframework.core.convert.support包下面,它實現了ConversionService接口和ConverterRegistry接口。但是不能直接把它作為SpringMVC的ConversionService,由于直接使用時不能往里面注冊類型轉換器。也就是說不能像下面這樣使用:

Xml代碼 收藏代碼
  1. <mvc:annotation-driven conversion-service="conversionService"/>  
  2.   
  3. <bean id="conversionService" class="org.springframework.core.convert.support.GenericConversionService"/>  

 

       為此我們必須對GenericConversionService做1些封裝,比如說我們可以在自己的ConversionService里面注入1個GenericConversionService,然后通過自己的ConversionService的屬性接收Converter并把它們注入到GenericConversionService中,以后所有關于ConversionService的方法邏輯都可以調用GenericConversionService對應的邏輯。依照這類思想我們的ConversionService大概是這樣的:

Java代碼 收藏代碼
  1. package com.tiantian.blog.web.converter.support;  
  2.    
  3. import java.util.Set;  
  4.    
  5. import javax.annotation.PostConstruct;  
  6.    
  7. import org.springframework.beans.factory.annotation.Autowired;  
  8. import org.springframework.core.convert.ConversionService;  
  9. import org.springframework.core.convert.TypeDescriptor;  
  10. import org.springframework.core.convert.converter.Converter;  
  11. import org.springframework.core.convert.converter.ConverterFactory;  
  12. import org.springframework.core.convert.converter.GenericConverter;  
  13. import org.springframework.core.convert.support.GenericConversionService;  
  14.    
  15. public class MyConversionService implements ConversionService {  
  16.    
  17.     @Autowired  
  18.     private GenericConversionService conversionService;  
  19.     private Set<?> converters;  
  20.      
  21.     @PostConstruct  
  22.     public void afterPropertiesSet() {  
  23.        if (converters != null) {  
  24.            for (Object converter : converters) {  
  25.               if (converter instanceof Converter<?, ?>) {  
  26.                   conversionService.addConverter((Converter<?, ?>)converter);  
  27.               } else if (converter instanceof ConverterFactory<?, ?>) {  
  28.                   conversionService.addConverterFactory((ConverterFactory<?, ?>)converter);  
  29.               } else if (converter instanceof GenericConverter) {  
  30.                   conversionService.addConverter((GenericConverter)converter);  
  31.               }  
  32.            }  
  33.        }  
  34.     }  
  35.      
  36.     @Override  
  37.     public boolean canConvert(Class<?> sourceType, Class<?> targetType) {  
  38.        return conversionService.canConvert(sourceType, targetType);  
  39.     }  
  40.    
  41.     @Override  
  42.     public boolean canConvert(TypeDescriptor sourceType,  
  43.            TypeDescriptor targetType) {  
  44.        return conversionService.canConvert(sourceType, targetType);  
  45.     }  
  46.    
  47.     @Override  
  48.     public <T> T convert(Object source, Class<T> targetType) {  
  49.        return conversionService.convert(source, targetType);  
  50.     }  
  51.    
  52.     @Override  
  53.     public Object convert(Object source, TypeDescriptor sourceType,  
  54.            TypeDescriptor targetType) {  
  55.        return conversionService.convert(source, sourceType, targetType);  
  56.     }  
  57.    
  58.     public Set<?> getConverters() {  
  59.        return converters;  
  60.     }  
  61.    
  62.     public void setConverters(Set<?> converters) {  
  63.        this.converters = converters;  
  64.     }  
  65.    
  66. }  

 

       在上面代碼中,通過converters屬性我們可以接收需要注冊的Converter、ConverterFactory和GenericConverter,在converters屬性設置完成以后afterPropertiesSet方法會被調用,在這個方法里面我們把接收到的converters都注冊到注入的GenericConversionService中了,以后關于ConversionService的其他操作都是通過這個GenericConversionService來完成的。這個時候我們的SpringMVC文件可以這樣配置:

Xml代碼 收藏代碼
  1. <mvc:annotation-driven conversion-service="conversionService"/>  
  2.   
  3. <bean id="genericConversionService" class="org.springframework.core.convert.support.GenericConversionService"/>  
  4.   
  5. <bean id="conversionService" class="com.tiantian.blog.web.converter.support.MyConversionService">  
  6.    <property name="converters">  
  7.        <set>  
  8.           <bean class="com.tiantian.blog.web.converter.StringArrayToAttachmentList"/>  
  9.        </set>  
  10.    </property>  
  11. </bean>  

 

       除以上這類使用GenericConversionService的思想以外,Spring已為我們提供了1個既可使用GenericConversionService,又可以注入Converter的類,那就是ConversionServiceFactoryBean。該類為我們提供了1個可以接收Converter的converters屬性,在它的內部有1個GenericConversionService對象的援用,在對象初始化完成以后它會new1個GenericConversionService對象,并往GenericConversionService中注冊converters屬性指定的Converter和Spring本身已實現了的默許Converter,以后每次返回的都是這個GenericConversionService對象。當使用ConversionServiceFactoryBean的時候我們的SpringMVC文件可以這樣配置:

Xml代碼 收藏代碼
  1.    <mvc:annotation-driven conversion-service="conversionService"/>  
  2. <bean id="conversionService"  
  3.   class="org.springframework.context.support.ConversionServiceFactoryBean">  
  4.     <property name="converters">  
  5.         <list>  
  6.             <bean class="com.tiantian.blog.web.converter.StringArrayToAttachmentList"/>  
  7.         </list>  
  8.     </property>  
  9. </bean>  

 

 

       除ConversionServiceFactoryBean以外,Spring還為我們提供了1個FormattingConversionServiceFactoryBean。當使用FormattingConversionServiceFactoryBean的時候我們的SpringMVC配置文件的定義應當是這樣:

Xml代碼 收藏代碼
  1.     <mvc:annotation-driven conversion-service="conversionService"/>  
  2.    
  3.     <bean id="conversionService"  
  4.           class="org.springframework.format.support.FormattingConversionServiceFactoryBean">  
  5.           <property name="converters">  
  6.              <set>  
  7.                  <bean class="com.tiantian.blog.web.converter.StringArrayToAttachmentList"/>  
  8.              </set>  
  9.           </property>  
  10. </bean>  

 

       以上介紹的是SpringMVC自動進行類型轉換時需要我們做的操作。如果我們需要在程序里面手動的來進行類型轉換的話,我們也能夠往我們的程序里面注入1個ConversionService,然后通過ConversionService來進行相應的類型轉換操作,也能夠把Converter直接注入到我們的程序中。

1.5     ConverterFactory接口

       ConverterFactory的出現可讓我們統1管理1些相干聯的Converter。顧名思義,ConverterFactory就是產生Converter的1個工廠,確切ConverterFactory就是用來產生Converter的。我們先來看1下ConverterFactory接口的定義:

Java代碼 收藏代碼
  1. public interface ConverterFactory<S, R> {  
  2.      
  3.     <T extends R> Converter<S, T> getConverter(Class<T> targetType);  
  4.    
  5. }  

 

       我們可以看到ConverterFactory接口里面就定義了1個產生Converter的getConverter方法,參數是目標類型的class。我們可以看到ConverterFactory中1共用到了3個泛型,S、R、T,其中S表示原類型,R表示目標類型,T是類型R的1個子類。

斟酌這樣1種情況,我們有1個表示用戶狀態的枚舉類型UserStatus,如果要定義1個從String轉為UserStatus的Converter,根據之前Converter接口的說明,我們的StringToUserStatus大概是這個模樣:

Java代碼 收藏代碼
  1. public class StringToUserStatus implements Converter<String, UserStatus> {  
  2.   
  3.    @Override  
  4.    public UserStatus convert(String source) {  
  5.        if (source == null) {  
  6.           return null;  
  7.        }  
  8.        return UserStatus.valueOf(source);  
  9.    }  
  10.     
  11. }  

 

       如果這個時候有另外1個枚舉類型UserType,那末我們就需要定義另外1個從String轉為UserType的Converter――StringToUserType,那末我們的StringToUserType大概是這個模樣:

Java代碼 收藏代碼
  1. public class StringToUserType implements Converter<String, UserType> {  
  2.   
  3.    @Override  
  4.    public UserType convert(String source) {  
  5.        if (source == null) {  
  6.           return null;  
  7.        }  
  8.        return UserType.valueOf(source);  
  9.    }  
  10.     
  11. }  

 

       如果還有其他枚舉類型需要定義原類型為String的Converter的時候,我們還得像上面那樣定義對應的Converter。有了ConverterFactory以后,這1切都變得非常簡單,由于UserStatus、UserType等其他枚舉類型同屬于枚舉,所以這個時候我們就能夠統1定義1個從String到Enum的ConverterFactory,然后從中獲得對應的Converter進行convert操作。Spring官方已為我們實現了這么1個StringToEnumConverterFactory:

Java代碼 收藏代碼
  1. @SuppressWarnings("unchecked")  
  2. final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {  
  3.    
  4.     public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {  
  5.        return new StringToEnum(targetType);  
  6.     }  
  7.    
  8.     private class StringToEnum<T extends Enum> implements Converter<String, T> {  
  9.    
  10.        private final Class<T> enumType;  
  11.    
  12.        public StringToEnum(Class<T> enumType) {  
  13.            this.enumType = enumType;  
  14.        }  
  15.    
  16.        public T convert(String source) {  
  17.            if (source.length() == 0) {  
  18.               // It's an empty enum identifier: reset the enum value to null.  
  19.               return null;  
  20.            }  
  21.            return (T) Enum.valueOf(this.enumType, source.trim());  
  22.        }  
  23.     }  
  24.    
  25. }  

 

       這樣,如果是要進行String到UserStatus的轉換,我們就能夠通過StringToEnumConverterFactory實例的getConverter(UserStatus.class).convert(string)獲得到對應的UserStatus,如果是要轉換為UserType的話就是getConverter(UserType.class).convert(string)。這樣就非常方便,可以很好的支持擴大。

       對ConverterFactory我們也能夠把它當作ConvertionServiceFactoryBean的converters屬性進行注冊,在ConvertionServiceFactoryBean內部進行Converter注入的時候會根據converters屬性具體元素的具體類型進行不同的注冊,對FormattingConversionServiceFactoryBean也是一樣的方式進行注冊。所以如果我們自己定義了1個StringToEnumConverterFactory,我們可以這樣來進行注冊:

Xml代碼 收藏代碼
  1. <bean id="conversionService"  
  2.   class="org.springframework.context.support.ConversionServiceFactoryBean">  
  3.     <property name="converters">  
  4.         <list>  
  5.             <bean class="com.tiantian.blog.web.converter.StringArrayToAttachmentList"/>  
  6.             <bean class="com.tiantian.blog.web.converter.StringToEnumConverterFactory"/>  
  7.         </list>  
  8.     </property>  
  9. </bean>  

 

1.6     GenericConverter接口

1.6.1概述

GenericConverter接口是所有的Converter接口中最靈活也是最復雜的1個類型轉換接口。像我們之前介紹的Converter接口只支持從1個原類型轉換為1個目標類型;ConverterFactory接口只支持從1個原類型轉換為1個目標類型對應的子類型;而GenericConverter接口支持在多個不同的原類型和目標類型之間進行轉換,這也就是GenericConverter接口靈活和復雜的地方。

       我們先來看1下GenericConverter接口的定義:

Java代碼 收藏代碼
  1. public interface GenericConverter {  
  2.      
  3.     Set<ConvertiblePair> getConvertibleTypes();  
  4.    
  5.     Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);  
  6.    
  7.     public static final class ConvertiblePair {  
  8.    
  9.        private final Class<?> sourceType;  
  10.    
  11.        private final Class<?> targetType;  
  12.    
  13.        public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {  
  14.            Assert.notNull(sourceType, "Source type must not be null");  
  15.            Assert.notNull(targetType, "Target type must not be null");  
  16.            this.sourceType = sourceType;  
  17.            this.targetType = targetType;  
  18.        }  
  19.    
  20.        public Class<?> getSourceType() {  
  21.            return this.sourceType;  
  22.        }  
  23.    
  24.        public Class<?> getTargetType() {  
  25.            return this.targetType;  
  26.        }  
  27.     }  
  28.    
  29. }  

 

      我們可以看到GenericConverter接口中1共定義了兩個方法,getConvertibleTypes()和convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType)。getConvertibleTypes方法用于返回這個GenericConverter能夠轉換的原類型和目標類型的這么1個組合;convert方法則是用于進行類型轉換的,我們可以在這個方法里面實現我們自己的轉換邏輯。之所以說GenericConverter是最復雜的是由于它的轉換方法convert的參數類型TypeDescriptor是比較復雜的。TypeDescriptor對類型Type進行了1些封裝,包括value、Field及其對應的真實類型等等,具體的可以查看API。

       關于GenericConverter的使用,這里也舉1個例子。假定我們有1項需求是希望能通過user的id或username直接轉換為對應的user對象,那末我們就能夠針對id和username來建立1個GenericConverter。這里假定id是int型,而username是String型的,所以我們的GenericConverter可以這樣來寫:

Java代碼 收藏代碼
  1. public class UserGenericConverter implements GenericConverter {  
  2.    
  3.     @Autowired  
  4.     private UserService userService;  
  5.      
  6.     @Override  
  7.     public Object convert(Object source, TypeDescriptor sourceType,  
  8.            TypeDescriptor targetType) {  
  9.        if (source == null || sourceType == TypeDescriptor.NULL || targetType == TypeDescriptor.NULL) {  
  10.            return null;  
  11.        }  
  12.        User user = null;  
  13.        if (sourceType.getType() == Integer.class) {  
  14.            user = userService.findById((Integer) source);//根據id來查找user  
  15.        } else if (sourceType.getType() == String.class) {  
  16.            user = userService.find((String)source);//根據用戶名來查找user  
  17.        }  
  18.        return user;  
  19.     }  
  20.    
  21.     @Override  
  22.     public Set<ConvertiblePair> getConvertibleTypes() {  
  23.        Set<ConvertiblePair> pairs = new HashSet<ConvertiblePair>();  
  24.        pairs.add(new ConvertiblePair(Integer.class, User.class));  
  25.        pairs.add(new ConvertiblePair(String.class, User.class));  
  26.        return pairs;  
  27.     }  
  28.    
  29. }  

 

       我們可以看到在上面定義的UserGenericConverter中,我們在getConvertibleTypes方法中添加了兩組轉換的組合,Integer到User和String到User。然后我們給UserGenericConverter注入了1個UserService,在convert方法

中我們簡單的根據原類型是Integer還是String來判斷傳遞的原數據是id還是username,并利用UserService對應的方法返回相應的User對象。

       GenericConverter接口實現類的注冊方法跟Converter接口和ConverterFactory接口實現類的注冊方法是1樣的,這里就不再贅述了。

       雖然Converter接口、ConverterFactory接口和GenericConverter接口之間沒有任何的關系,但是Spring內部在注冊Converter實現類和ConverterFactory實現類時是先把它們轉換為GenericConverter,以后再統1對GenericConverter進行注冊

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 激情欧美成人久久综合小说 | 日本视频中文字幕一区二区 | 欧美最猛性xxxxx喷水 | 国产一区二区三区四区 | 亚洲春色在线观看 | 久久久久毛片成人精品 | 2020欧美极品hd18 | 欧美极品欧美日韩 | 五月天欧美激情午夜情 | 538亚洲欧美国产日韩在线精品 | 日一区二区 | 国产精品视频白浆免费视频 | 自拍偷自拍亚洲精品情侣 | 日本一级黄色 | 五月婷婷亚洲 | 福利四区 | free hd 性欧美 | 最近中文字幕完整在线看一 | 欧美第5页| 国产成人精品天堂 | 亚洲综合欧美日本另类激情 | 一区二区在线视频 | 精品国产一区二区三区在线 | aa大片| 午夜欧美精品久久久久久久久 | 欧美 日韩 国产在线 | 国产欧美一区二区三区视频在线观看 | 无夜精品久久久久久 | 亚洲国产欧美精品一区二区三区 | 一区二区三区毛片免费 | 国产1区2区三区不卡 | 欧美特黄a级高清免费看片 欧美特黄一级aa毛片 | 国产午夜视频在线观看第四页 | 91久久精品国产亚洲 | 69xx免费观看视频 | 在线观看精品福利片香蕉 | tom影院亚洲国产日本一区 | 国产v欧美v日本v精品 | 国产午夜人做人免费视频中文 | 看v片 | 亚洲视频 中文字幕 |