spring有2種類型轉換器,一種是propertyEditor,一種是Converter.雖然都是類型轉換,但是還是有細微差別. 所以這裡以一個例子的形式來分析一下這2種類型轉換的使用場景和差別. 平常的應用中應該有很多這樣的情況,一個po中有一個欄位是status,這個status=0時代表成功
spring有2種類型轉換器,一種是propertyEditor,一種是Converter.雖然都是類型轉換,但是還是有細微差別.
所以這裡以一個例子的形式來分析一下這2種類型轉換的使用場景和差別.
平常的應用中應該有很多這樣的情況,一個po中有一個欄位是status,這個status=0時代表成功,status=1時代表失敗...雖然這個status可以定義為Integer的類型,但是有時候可能為了方便管理和更面向對象,直接定義了一個TypeStatus的類來表示這個status欄位.這個TypeStatus的實現可能如下,當然這隻是個demo不要當真:
public class TypeStatus { private Integer value; private String msg; public TypeStatus(Integer value, String msg) { this.value = value; this.msg = msg; } public static TypeStatus toBean(Integer value){ if(value==0){ return new TypeStatus(0,"成功"); }else if(value==1){ return new TypeStatus(1,"失敗"); }else{ return null; } } public Integer getValue() { return value; } public String getMsg() { return msg; } }
然後問題來了,雖然這樣封裝了一下後那個status欄位變得更生動了..但是我們從前端頁面中傳過來一個0,到controller中spring如何把0轉成一個TypeStatus類型呢?假設含有這個status欄位的po如下:
public class PoDemo { TypeStatus status; }
controller如下:
public class DemoController { public String testEditor(PoDemo po){ return "ok"; } }
從一種類型到另一個類型,這肯定需要用到類型轉換,我們先看第一種propertyEditor的實現,在controller中增加如下方法:
@InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(TypeStatus.class, "status", new TypeStatusEditor()); }
方法registerCustomEditor的第二個參數為欄位名,標識欄位名為status,類型為TypeStatus的屬性將會應用此類型轉換,如果我們的PoDemo有另一個欄位statusToo也為TypeStatus類型,那麼將不會應用此類型轉換.如果想把所有的TypeStatus類型欄位都應用此類型轉換,則第二個參數可以設置為null.
TypeStatusEditor的實現如下:
public class TypeStatusEditor extends PropertyEditorSupport { @Override public String getAsText() { TypeStatus ts = (TypeStatus) getValue(); return String.valueOf(ts.getValue()); } @Override public void setAsText(String text) throws IllegalArgumentException { TypeStatus ts = TypeStatus.toBean(Integer.parseInt(text)); setValue(ts); } }
PropertyEditor的使用此處不做討論.從代碼中也大體能看出實際是一個String到類型的過程,這個恰恰是propertyEditor和Converter的一個區別所在.PropertyEditor主要應用場景為String到類型的轉換.從Editor提供的get和set方法也可以看出,必經過String.一般前臺頁面傳過來的值大多是String類型,此時用PropertyEditor來轉換再合適不過了.
ProertyEditor是String到類型,這隻是一種特殊情況的轉換,而說到最通用的肯定是類型到類型.此時就是Converter的應用了.
還是PoDemo和Controller:
public class PoDemo { byte[] img; }
public class DemoController { public String testEditor(PoDemo po){ return "ok"; } }
比如我們向資料庫中存一個圖片,那麼資料庫中是以blob類型存儲的,而java類中對應的類型實際是byte[],那麼問題又來了,我前臺上傳一張圖片實際上以MultipartFile類型傳到Controller中的,spring如何將MultipartFile轉換成byte[]自動封裝成PoDemo類呢?此時PropertyEditor顯然不行了.這已經是類型到類型轉換,只能用Converter.
實現如下:
public class MultipartFileToByteArrayEditor implements Converter<CommonsMultipartFile,byte[]> { @Override public byte[] convert(CommonsMultipartFile source) { return source.getBytes(); } }
然後我們還需要在spring的配置文件中註冊一下:
<mvc:annotation-driven conversion-service="conversionService"> </mvc:annotation-driven> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="xx.xx.MultipartFileToByteArrayEditor"/> </list> </property> </bean>
這裡使用的系統提供的FormattingConversionServiceFactoryBean來註冊我們的類型轉換器類MultipartFileToByteArrayEditor,實際也可以用ConversionServiceFactoryBean來註冊.
都配置好後,spring就可以自動將MultipartFile轉換成byte[]並封裝成PoDemo了.
可能有人想到Converter實際上是包含PropertyEditor的,那麼如果2種轉換器都適用,那麼究竟會適用哪種呢?Spring預設是首先查找PropertyEditor,然後再查找Converter.
總結:PropertyEditor適用於String到類型,而Converter更加通用用於類型到類型.PropertyEditor優先順序更高.