2013-06-21 1 views
4

저는 Play Framework를 사용하고 있으며 컨트롤러 작업에서 양식으로 모델을 업데이트하는 일반적인 경우가 있습니다. 그러나 모델의 모든 속성을 포함하는 양식이있는 경우이 작업이 단지 작동하기 때문에 개념의 이해를위한 몇 가지 문제점을 알고 있습니다. 부분 양식 만있는 경우 (예 : 사용자 모델의 암호 만 편집하면이 메서드는 모델의 다른 속성을 null로 설정하기 때문에 모델을 파괴합니다. 그 문제에 대한 "공식적인"해결책이 있습니까? Play는 기존 속성 만 업데이트합니까?프레임 워크 처리 부분 양식

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

최근 프로젝트에서 이런 종류의 기능이 필요했으며 bindFromRequest() 메서드에 추가 매개 변수를 허용하기 위해 원래의 Play Form을 기반으로 한 Form 클래스를 다시 구현해야했습니다.

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

아이디어는 양식에 정의 된 필드를 수정하고 수정되지 않은 모델의 다른 필드를 유지하는 것입니다 :

예를 들어 코드를 촬영,이 같은 될 것입니다.

이 특정 바인딩을 허용하려면,이 같은 뭔가합니다 (bindFromRequest과 함께) bind(Map<String,String> data, String... allowedFields) 방법을 재정의 할 수 있습니다

대신 표준 재생 Form 클래스처럼 blankInstance()DataBinder을 만드는
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)); 
      } 
     } 
    } 

, 모델 인스턴스를 생성자 인수로 생성합니다.

+0

대단한 일반적인 접근 방식입니다.그러나 정확히 어디에 구현 했습니까? 특정 프로젝트 또는 Play 핵심에 직접 있습니까? bindFromRequest 메서드의 기존 매개 변수의 목적이 무엇인지 생각 해보시겠습니까? – linsenfips

+1

나는 play core Form 클래스를 확장하는 특정 프로젝트에서 CustomForm 클래스를 만들었습니다. 그래서이 부분적인 바인딩 기능이 필요할 때, 코어를 재생하는 대신 CustomForm 클래스를 사용해야합니다. 'data' 매개 변수는 요청의 데이터를 포함합니다 (재생 코어'Form.bindFromRequest() 소스를 살펴보고, 데이터 맵을 생성하여'bind()'메소드에 제공합니다). 'allowedFields'는 바인드 된 데이터를 제한하는 데 사용되는 선택적 매개 변수입니다 (Spring DataBinder 기능). – mguillermin

+0

나는 그것이 잘못되었지만 내가 원하는 바운드 데이터를 제한하지 않는다고 생각 하는가? – linsenfips

1

해결책이 있습니다. 내가하는 일은보다 서비스 지향적 인 응용 프로그램을 만드는 것입니다. 특정 작업에 대한 양식 및 모델을 만드는 곳 : updateUserPassword, updateUserEmail 등이 모델에서 이러한 간단한 방법을 구현합니다.

+0

그래, 맞아. 하지만 그때 수동으로 모든 작업을 수행해야합니다. hasFromRequest(). data(). get ("password")를 사용하여 특정 양식 데이터를 가져와 hasErrors 메소드가 더 이상 적용될 수 없으므로 유효성 검사를 수행해야합니다. – linsenfips

+0

양식에 맞는 모델을 작성하기 만하면됩니다. 암호 만 업데이트하는 경우 UpdateUserPassword 모델과 UpdateUserPasswordForm을 만듭니다. 그렇게하면 엔티티가 아니라 모델에 모든 유효성을 유지할 수 있습니다. –

+1

약간의 오버 헤드가 아닌가요? 모든 사례에 대해 모델을 만들면 속성이 겹칠 수 있으므로 많은 중복성이 발생합니다. – linsenfips

0

난 당신이 하나 개의 프로젝트에 모두 스칼라와 자바를 병합 할 수 있습니다 당신이 스칼라와 함께, 귀하의 양식을 스칼라 방향에서 살펴 본다 제안 어쩌면 예를 들어 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("...") 
} 
)