2012-09-22 27 views
120

我正在尋找在MVC中綁定和轉換數據的最簡單最簡單的方法。如果可能的話,不用做任何xml配置。Spring MVC類型轉換:PropertyEditor或Converter?

到目前爲止,我一直在使用PropertyEditors像這樣:

public class CategoryEditor extends PropertyEditorSupport { 

    // Converts a String to a Category (when submitting form) 
    @Override 
    public void setAsText(String text) { 
     Category c = new Category(text); 
     this.setValue(c); 
    } 

    // Converts a Category to a String (when displaying form) 
    @Override 
    public String getAsText() { 
     Category c = (Category) this.getValue(); 
     return c.getName(); 
    } 

} 

... 
public class MyController { 

    @InitBinder 
    public void initBinder(WebDataBinder binder) { 
     binder.registerCustomEditor(Category.class, new CategoryEditor()); 
    } 

    ... 

} 

它很簡單:兩個轉換都在同一個類中定義,並且綁定是直截了當的。如果我想對所有控制器進行通用綁定,我仍然可以添加3 lines in my xml config


但春天3.x中引入了一個新的方式來做到這一點,利用Converters

在Spring容器中,該系統可以作爲一種替代 到屬性編輯器

所以我們假設我想使用轉換器,因爲它是「最新的替代品」。我會創造轉換器:

public class StringToCategory implements Converter<String, Category> { 

    @Override 
    public Category convert(String source) { 
     Category c = new Category(source); 
     return c; 
    } 

} 

public class CategoryToString implements Converter<Category, String> { 

    @Override 
    public String convert(Category source) { 
     return source.getName(); 
    } 

} 

第一個缺點:我得把兩個班。好處:不需要感謝通用性。

那麼,我該如何簡單綁定數據轉換器?

第二個缺點:我還沒有找到任何簡單的方法(註解或其他程序設施)做它的控制單元,完全不像。

我發現是乏味的,而不是簡單,只有一般的跨控制器綁定的唯一途徑:

  • XML config

    <bean id="conversionService" 
        class="org.springframework.context.support.ConversionServiceFactoryBean"> 
        <property name="converters"> 
         <set> 
          <bean class="somepackage.StringToCategory"/> 
          <bean class="somepackage.CategoryToString"/> 
         </set> 
        </property> 
    </bean> 
    
  • Java config只在春季3.1+):

    @EnableWebMvc 
    @Configuration 
    public class WebConfig extends WebMvcConfigurerAdapter { 
    
        @Override 
        protected void addFormatters(FormatterRegistry registry) { 
         registry.addConverter(new StringToCategory()); 
         registry.addConverter(new CategoryToString()); 
        } 
    
    } 
    

所有這些缺點,爲什麼使用轉換器?我錯過了什麼嗎?有沒有其他的技巧,我不知道?

我很想繼續使用屬性編輯器...綁定更容易,更快。

+0

注(我偶然也使用Spring 3.2.17):當使用有需要實際參考本conversionService豆: mauhiz

回答

50

所有這些缺點,爲什麼使用轉換器?我是否缺少 的東西?有沒有其他的技巧,我不知道?

不,我認爲你已經非常全面地描述了PropertyEditor和Converter,它們是如何聲明和註冊的。在我看來,PropertyEditors的範圍有限 - 它們幫助將String轉換爲一個類型,而這個字符串通常來自UI,因此使用@InitBinder註冊PropertyEditor並使用WebDataBinder是有道理的。

另一方面,轉換器更通用,它旨在用於系統中的任何轉換 - 而不僅僅是與UI相關的轉換(字符串轉換爲目標類型)。例如,Spring Integration廣泛使用轉換器將消息有效載荷轉換爲所需類型。

我認爲對於UI相關的流程PropertyEditors仍然適用,尤其是對於需要爲特定命令屬性進行自定義的情況。對於其他情況,我會採用Spring參考中的建議,而不是寫一個轉換器(例如,將Long ID轉換爲實體,例如,作爲示例)。

+5

另一個好處是轉換器是無狀態的,每次註冊相同的屬性編輯器,而屬性編輯器是有狀態的,並創造了許多次,許多API調用來實現,我不認爲這將會對性能產生重大影響,但轉換器只是更乾淨更簡單。 –

+1

@Boris清潔,但是並不簡單,特別是對於初學者:你必須寫2轉換器類+在XML配置或Java配置中添加幾行。我正在談論Spring MVC表單提交/顯示,以及一般轉換(不僅是實體)。 –

7

最簡單的(假設你使用的是持久化框架),但不完美的方式是通過ConditionalGenericConverter接口將使用其元數據轉換實體來實現通用實體轉換器。例如,如果您使用的是JPA,則該轉換器可能會查看指定的類是否具有@Entity註釋,並使用@Id帶註釋的字段來提取信息並使用提供的字符串值自動執行查找作爲查找的Id。

public interface ConditionalGenericConverter extends GenericConverter { 
    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); 
} 

ConditionalGenericConverter是春天皈依API的「終極武器」,但正在執行一次,這將是能夠處理大多數實體convertions,節省開發時間 - 這是一個很大的安慰,當你只是指定實體類作爲參數的控制器,而且從不考慮實現一個新的轉換器(當然除了定製和非實體類型)。

+0

很好的解決方案只處理實體轉換,謝謝你的技巧。一開始不是很簡單,因爲你必須再寫一堂課,但從長遠來看,這是一件簡單而又時間緊迫的事情。 –

+0

順便說一句這樣的轉換器可以爲adher一些通用合同的任何類型來實現 - 另外一個例子:如果你的枚舉實現一些常用的反向查找界面 - 那麼你也將能夠實現一個通用的轉換器(這將是類似於http: //stackoverflow.com/questions/5178622/spring-custom-converter-for-all-enums) –

+0

@JeromeDalbert是的,它是一個有點困難的初學者做一些重量重的東西,但如果你有一個團隊的開發者會將它更簡單)PS它會變得乏味的形式,反正綁定) –

14
  1. 對於從字符串轉換到/使用格式化器(實施org.springframework.format.Formatter)代替轉換器。它有打印(...)解析(...)方法,所以你只需要一個類而不是兩個。 要註冊它們,使用FormattingConversionServiceFactoryBean,這可以兩個轉換器和格式化器寄存器,而不是ConversionServiceFactoryBean
  2. 新的格式化的東西有幾個額外的好處:
    • 格式化界面提供的Locale對象,在其打印(...)解析(...)方法,使您的字符串轉換可能是語言環境敏感
    • 除了預先註冊的格式化,FormattingConversionServiceFactoryBean配備了一些方便預先註冊AnnotationFormatterFactory對象,允許您指定附加格式p通過註釋參數。 例如: @RequestParam @DateTimeFormat(模式= 「MM-DD-YY」) LOCALDATE的baseDate ... 這不是很困難的創建自己的AnnotationFormatterFactory類,請參見Spring的NumberFormatAnnotationFormatterFactory舉個簡單的例子。 我認爲這消除了在控制器特定的格式化器/編輯器中的需要。對所有控制器使用一個ConversionService並通過註釋自定義格式。
  3. 我同意,如果您仍然需要一些控制器特定的字符串轉換,最簡單的方法仍然是使用自定義屬性編輯器。 (我試圖在我的@InitBinder方法中調用'binder.setConversionService(...)',但它失敗了,因爲binder對象帶有已設置的'global'轉換服務,看起來像每個控制器轉換在Spring 3中不鼓勵類)。
0

您可以通過將兩個轉換器實現爲靜態內部類來解決兩個獨立Converter類的需求。

public class FooConverter { 
    public static class BarToBaz implements Converter<Bar, Baz> { 
     @Override public Baz convert(Bar bar) { ... } 
    } 
    public static class BazToBar implements Converter<Baz, Bar> { 
     @Override public Bar convert(Baz baz) { ... } 
    } 
} 

你仍然需要單獨註冊他們兩個,但至少這減少了你需要的,如果你做任何更改修改文件的數量。