簡體   English   中英

spring-mvc中抽象類的數據綁定

[英]Data binding of an abstract class in spring-mvc

我已經通過Spring文檔和源代碼,仍然沒有找到我的問題的答案。

我在我的域模型中有這些類,並希望在spring-mvc中將它們用作后備表單對象。


public abstract class Credentials {
  private Long     id;
  ....
}
public class UserPasswordCredentials extends Credentials {
  private String            username;
  private String            password;
  ....
}
public class UserAccount {
  private Long              id;
  private String            name;
  private Credentials       credentials;
  ....
}

我的控制器:


@Controller
public class UserAccountController
{
  @RequestMapping(value = "/saveAccount", method = RequestMethod.POST)
  public @ResponseBody Long saveAccount(@Valid UserAccount account)
  {
    //persist in DB
    return account.id;
  }

  @RequestMapping(value = "/listAccounts", method = RequestMethod.GET)
  public String listAccounts()
  {
    //get all accounts from DB
    return "views/list_accounts";
  }
  ....
}

在UI上,我有不同憑據類型的動態表單。 我的POST請求通常如下所示:


name                    name
credentials_type        user_name
credentials.password    password
credentials.username    username

如果我嘗試向服務器提交請求,則拋出以下異常:


org.springframework.beans.NullValueInNestedPathException: Invalid property 'credentials' of bean class [*.*.domain.UserAccount]: Could not instantiate property type [*.*.domain.Credentials] to auto-grow nested property path: java.lang.InstantiationException
    org.springframework.beans.BeanWrapperImpl.newValue(BeanWrapperImpl.java:628)

我最初的想法是使用@ModelAttribute


    @ModelAttribute
    public PublisherAccount prepareUserAccountBean(@RequestParam("credentials_type") String credentialsType){
      UserAccount userAccount = new PublisherAccount();
      Class credClass = //figure out correct credentials class;
      userAccount.setCredentials(BeanUtils.instantiate(credClass));
      return userAccount;
    }

這種方法的問題在於,在任何其他方法(如listAccounts )之前調用prepareUserAccountBean方法也是不合適的。

一個強大的解決方案是將prepareUserAccountBeansaveUserAccount到單獨的Controller。 聽起來不對:我希望所有與用戶相關的操作都駐留在同一個控制器類中。

有什么簡單的解決 我可以以某種方式利用DataBinder,PropertyEditor或WebArgumentResolver嗎?

謝謝!!!!!

我看不到任何簡單而優雅的解決方案。 也許是因為問題不是如何在Spring MVC中綁定抽象類的數據,而是:為什么首先在表單對象中使用抽象類? 我想你不應該。

從表單發送到控制器的對象稱為“表單(支持)對象”,原因如下:對象屬性應反映表單字段。 如果您的表單包含用戶名和密碼字段,那么您的類中應該有用戶名和密碼屬性。

因此credentials應具有UserPasswordCredentials類型。 這將跳過您的“抽象實例化嘗試”錯誤。 兩個解決方案:

  • 建議:將UserAccount.credentials的類型從Credentials更改為UserPasswordCredentials。 我的意思是,除UserPasswordCredentials外,UserAccount可能具有哪些憑據? 更重要的是,我敢打賭,您的數據庫userAccounts具有存儲為憑據的用戶名和密碼,因此您也可以直接在UserAccount中使用UserPasswordCredentials類型。 最后,Spring建議使用“現有業務對象作為命令或表單對象”( 請參閱doc ),因此修改UserAccount將是最佳選擇。
  • 不推薦:按原樣保留UserAccount,然后創建UserAccountForm類。 此類與UserAccount具有相同的屬性,但UserAccountForm.credentials具有UserPasswordCredentials類型。 然后在列出/保存時,一個類(例如UserAccountService)進行轉換。 此解決方案涉及一些代碼重復,因此只有在您有充分理由(您無法更改的遺留實體等)時才使用它。

我不確定,但您應該在控制器上使用ViewModel類而不是Domain Objects。 然后,在saveAccount方法中,您將驗證此ViewModel,如果一切正常,您將其映射到您的域模型並保留它。

通過這樣做,你有另一個優勢。 如果您將任何其他屬性添加到您的域UserAccount類,例如: private bool isAdmin 如果您的Web用戶向您發送一個帶有isAdmin = true的POST參數,該參數將綁定到用戶域類並保持不變。

嗯,這就是我的方式:

public class NewUserAccount {
    private String name;
    private String username;
    private String password;
}  

@RequestMapping(value = "/saveAccount", method = RequestMethod.POST)
public @ResponseBody Long saveAccount(@Valid NewUserAccount account)
{
    //...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM