spring-mvc中抽象类的数据绑定

Den*_* K. 14 java data-binding binding spring 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;
  ....
}
Run Code Online (Sandbox Code Playgroud)

我的控制器:


@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";
  }
  ....
}
Run Code Online (Sandbox Code Playgroud)

在UI上,我有不同凭据类型的动态表单.我的POST请求通常如下所示:


name                    name
credentials_type        user_name
credentials.password    password
credentials.username    username
Run Code Online (Sandbox Code Playgroud)

如果我尝试向服务器提交请求,则抛出以下异常:


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)

Run Code Online (Sandbox Code Playgroud)

我最初的想法是使用 @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;
    }
Run Code Online (Sandbox Code Playgroud)

这种方法的问题是prepareUserAccountBean方法在任何其他方法(如listAccounts)之前被调用,这是不合适的.

一个强大的解决方案是移出两个prepareUserAccountBeansaveUserAccount转移到单独的控制器.听起来不对:我希望所有与用户相关的操作都驻留在同一个控制器类中.

有什么简单的解决 我可以以某种方式利用DataBinder,PropertyEditor或WebArgumentResolver吗?

谢谢!!!!!

goe*_*ing -1

我不确定,但您应该在控制器上使用 ViewModel 类而不是域对象。然后,在 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)
{
    //...
}
Run Code Online (Sandbox Code Playgroud)