2013-06-21 38 views
4

我正在使用Play框架,并且我有通用用例来更新带有控制器操作中表单的模型。但是我有一些理解它背后的概念的问题,因为如果你有一个包含模型的所有属性的表单,那么这个工作就正常了。如果您只有部分表单,例如只编辑用户模型的密码,此方法破坏模型,因为它将模型的其他属性设置为null。 是否有任何“官方”解决方案?任何方式播放只更新现有的属性?玩框架处理部分表格

public static Result update(Long id) { 
    Model model = Model.findById(id); 
    Form<Model> filledForm = modelForm.bindFromRequest(); 
    if (filledForm.hasErrors()) { 
     return badRequest(edit.render(filledForm)); 
    } else { 
     model.update(); 
     flash("message", "Created new Model!"); 
     return ok(index.render()); 
    } 
} 

大概溶液中的事实以某种方式规定该bindFormRequest()方法可以与附加的参数来调用,像字符串或地图字符串?但我找不到那个目的。对此的一些洞察力也会很好。 非常感谢!

回答

7

在最近的项目中,我需要这种功能,我不得不重新实现Form类(基于原始Play表单),以允许bindFromRequest()方法的附加参数。

以你的代码为例,它会成为这样的:

Model model = Model.findById(id); 
Form<Model> filledForm = CustomForm.form(Model.class).bindFromRequest(model); 

的想法是只修改表单中定义的字段,并保持你的模型的其他字段不变。

要允许这种特异性结合,你有这样的事情重新定义bind(Map<String,String> data, String... allowedFields)方法(与bindFromRequest一起):

public Form<T> bind(T instance, Map<String,String> data, String... allowedFields) { 

    DataBinder dataBinder = null; 
    Map<String, String> objectData = data; 
    if(rootName == null) { 
     dataBinder = new DataBinder(instance); 
    } else { 
     dataBinder = new DataBinder(instance, rootName); 
     objectData = new HashMap<String,String>(); 
     for(String key: data.keySet()) { 
      if(key.startsWith(rootName + ".")) { 
       objectData.put(key.substring(rootName.length() + 1), data.get(key)); 
      } 
     } 
    } 

不是创建DataBinderblankInstance()为标准播放Form类做的,您可以使用模型实例作为构造函数参数来创建它。

+0

这是一个很好的通用方法。但是你究竟在哪里实现了它?在您的特定项目中还是直接在Play核心中?并且你有什么想法bindFromRequest方法的已经存在的参数的目的是什么? – linsenfips

+1

我在扩展Play核心Form类的特定项目中创建了一个CustomForm类。所以我只需要使用我的CustomForm类而不是Play核心的一个,当我需要这个部分绑定功能。 'data'参数包含来自请求的数据(查看Play核心'Form.bindFromRequest()'源代码,它构造一个数据Map并将其提供给'bind()'方法)。 'allowedFields'是一个可选参数,用于限制绑定数据(这是一个Spring DataBinder功能)。 – mguillermin

+0

我想我错了,但不限制我想要的绑定数据? – linsenfips

1

有一个解决方案。我会做的是做一个更加面向服务的应用程序。 如果您为特定操作创建表单和模型:updateUserPasswordupdateUserEmail等,并且在您的模型中实现这些简单方法。

+0

好吧,这是正确的,这将是一个解决方案。但之后我必须手动完成所有工作:使用bindFromRequest()。data()。get(“password”)获取特定的表单数据并执行验证,因为我猜hasErrors mehtod不能再应用了。 – linsenfips

+0

您所要做的就是创建适合您的表单的模型。如果您只更新密码,请创建UpdateUserPassword模型和UpdateUserPasswordForm。这样,您可以保留所有验证,但保留在您的模型上,而不是实体上。 –

+1

这不是一点点开销吗?为每种情况创建一个模型会导致大量冗余,因为属性可能会重叠。 – linsenfips

0

我建议你考虑看看Scala的方向,你可以在一个项目合并Scala和Java中,使用Scala的形式可能是tuple例如:

val someForm = Form(tuple("user_id" -> number, "password"->text)),然后从你的要求,你可以用它执行您的型号更新:

someForm.bindFromRequest.fold(
formWithErrors => { 
BadRequest 
}, 

data => { 
// update method takes two parameters user_id and password to update 
User.updatePassword(data._1,data._2) 
Ok("...") 
} 
)