简体   繁体   中英

Play Framework 2: How to correctly construct objects from various sources in the controller and then validate them?

For this example, the user wishes to create a blog post for their site. Form submission is handled through AJAX. The POST request is handled by the createPost method in the controller. The method extracts the json data and combines it with the users session data to construct the appropriate Post object. It then validates the data and returns an appropriate response.

The Post model is as follows:

@Entity
public Post extends model {
  @Id
  public Long id;
  @Required
  public User author;
  @Required
  public String title;
  @Required
  public String body;
}

The controller method is as follows:

@BodyParser.Of(BodyParser.Json.class)
public static Result createPost() {
  JsonNode json = request().body().asJson();
  Post post = new Post();

  post.author = User.findbyId(request().username());
  post.title = json.findPath("title").textValue();
  post.body = json.findPath("body").textValue();

  Form<Post> filledForm = Form.form(Post.class).bind(Json.toJson(post));

  if (filledForm.hasErrors())
    return badRequest(filledForm.errorsAsJson());

  // save post

  return ok();  
}

Now, this method works, however, there must be a better way of doing it rather than taking the json request, extracting it into an object and then converting that object back into json so that it can be bound to the form. Any ideas?

The common way to do it is using bindFromRequest in the controller side.

public static Result savePost() {
    Form<Post> postForm= form(Post .class).bindFromRequest();
    if(postForm.hasErrors()) {
        Logger.error("Form has errors: " + postForm.errorsAsJson());
        return badRequest(filledForm.render(postForm));
   }
   Post post=postForm.get();
   post.save()
   ....
}

For a full example you can checkout the forms sample .

And the AJAX post could be something like that:

function postUrl(form){
    var postData = new FormData($(form)[0])
    var formURL = $(form).attr("action");
    var request=$.ajax({
        url : formURL, type: "POST", data : $(form).serialize(),
    });
    request.done(function(data) {
    //Whatever  
    });
}

It's a commonly discussed issue in Play that form classes shouldn't really be domain classes. Only works in simple cases.

One alternative is to create a form-data class and bind that. The form-data class can contain data from many different models. Then have code that loads your domain object (Post) a copy fields from form-data object. I use code-generation for the form-data to domain-object code. YMMV.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM