2013-06-21 63 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("...") 
} 
)