2011-12-04 113 views
7

我有一個域模型,其中包含許多'元素',這些元素可以被渲染以顯示豐富的內容。有一些HTML文本,紡織文本,Flash對象等等。這些元素的基本特徵被封裝在AbstractElement中,其具有實現HTMLElementFlashElement等等。因此該模型有一個List<AbstractElement>來包含它可以擁有的所有元素。帶泛型的自動增長列表

編輯模型時,我希望用戶能夠動態添加元素,並在用戶提交表單時保存這些元素。所以我所擁有的是一種可通過JavaScript動態擴展的表單,其格式如下:

<form action=...> 
    <!-- Other attributes --> 
    <textarea name="object.elements[0].content"/> 
    <textarea name="object.elements[1].content"/> 
    <!-- Some elements are based on text, others on files --> 
    <input type="hidden" name="object.elements[2].file" value="somevalue"/> 
    <textarea name="object.elements[3].content"/> 
    <!-- Submit button --> 
</form> 

提交表單時出錯。這很明顯,爲什麼 - 在提交時,Spring試圖實例化列表中所需的元素。由於元素列表包含類型爲AbstractElement的抽象對象,因此Spring無法實例化新元素。

我該如何去讓Spring實例化正確類型的元素?可以在表單中添加類型信息,並使用一些ModelAttribute來完成它?這將如何工作?有什麼我可以在模型中自動做到這一點?

回答

1

我最終通過實現ModelAttribute來解決這個問題,該ModelAttribute通過解析原始表單數據來構造元素列表。通過使用HttpServletRequest對象解析原始表單數據,循環訪問參數映射並只需'手動'創建所需的對象。它可以重複使用,如果你把它放在輔助函數中,雖然我需要在每個控制器中使用ModelAttribute。

這不是理想的解決方案,但它有效。

1

聽起來您需要創建一個(或多個)客戶屬性編輯器,它們可以接受請求參數並將其轉換爲正確的類實例以添加到集合中。

Spring使用註冊到數據聯編程序中的PropertyEditor實例來綁定請求參數。如果PropertyEditor的默認設置無法確定正確的類型,則可以註冊您自己的編輯器來處理邏輯。

的過程在Spring文檔在此鏈接描述:

http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html

具體來說,請參閱如何註冊客戶屬性編輯器部分5.4.2.1。

您可以使用控制器的initBinder()方法(用@InitBinder註釋標識)中的WebDataBinder類的registerCustomEditor()方法註冊屬性編輯器。

+0

是不是PropertyEditor被設計爲處理單個文本值(如日期格式)到Java對象?我將如何添加額外的請求參數? – DCKing

+0

從你的問題來看,似乎最終用戶正在HTML表單上填充各種textareas並提交它。在提交時,我以爲你想以某種方式根據每個textarea的內容來確定要實例化的正確類型的對象。你可以使用PropertyEditor在一個字符串和任何類型的對象之間進行轉換,所以我認爲它適用於你。如果我沒有正確理解表單,請提供更多詳細信息,我會盡力提供幫助。 – khill

+0

正如您在示例表格中所看到的那樣,元素將具有「content」屬性並不一定。它可以有一個'文件'屬性。一個PropertyEditor不能聽那個。此外,不同類型的基於文本的內容不能根據字符串的內容來區分。 – DCKing

0

您可以嘗試通過創建一個ModelAttribute方法來實例化formObject,該方法將返回具體對象。 例如

@ModelAttribute("bindingObj") 
public AbstractObject initElementList() { 
    AbstractObject obj = new ConcreteObject(); 
    obj.setElements(new ArrayList<ConcreteElement>); 
    return obj; 
} 

@RequestMapping(...) 
public ModelAndView requestHandler(@ModelAttribute("bindingObj") AbstractObject) { 
    .... 
} 

Spring將首先調用initElementList並將結果添加到內部模型映射中。然後用這個值調用requestHandler。

這種方法的不足之處在於,你最終還是會引用具體的類。但是如果你有從你的基礎控制器派生的子類,那麼它可能會有所幫助。

+0

儘管我沒有在問題中提到它,但是解決方案在控制器之間輕鬆重複使用會有所幫助 - 還有更多的模型具有元素列表。在我看來,這是一個控制器非常具體的? – DCKing

+0

自定義PropertyEditor是一個選項,但我不知道如何解決編輯器中列表元素的具體類型。因爲每個控制器都知道它需要綁定到什麼列表元素,所以控制器可能是最好的選擇。 – praveenj