Issue with bindFromRequest in Play! Framework 2.3

流过昼夜 提交于 2020-01-29 11:36:05

问题


I'm trying to use the automatic binding feature of Play, without success. I'm developing in Java, on Eclipse 4.4 Luna.

Here is my form :

<h2>Create a new user</h2>
<form action="@routes.Backend.createUser()" method="post">
    First Name
    <input type="text" name="firstName" />
    Last Name
    <input type="text" name="lastName" />
    E-mail
    <input type="email" name="email" />
    PIN
    <input type="number" name="pin" />
    Status
    <input type="text" name="status" />
    Is guest?
    <input type="checkbox" name="isGuest" />

    <input type="submit" value="Create user" />
</form>

Here is my class "Users":

@Entity
public class Users extends Model {

// Database columns
@Id
public int userId;

public String firstName;
public String lastName;
public String email;
public int pin;
public String status;
public boolean isGuest;

}

And here is my controller:

public class Backend extends Controller {

  public static Result createUser() {
    Form<Users> form = Form.form(Users.class).bindFromRequest();
    if (form.hasErrors()) {
        // doSomething()
    } else {
        Users u = form.get();
        u.save();
    }

    // TESTING
    // Checking the content of the request
    DynamicForm requestData = Form.form().bindFromRequest();
    String firstName = requestData.get("firstName");
    String lastName = requestData.get("lastName");
    // Printing the content works, I am able to see the correct values
    System.out.println(firstName); // Bob
    System.out.println(lastName); // Smith
    // This somehow doesn't work...
    System.out.println(u.firstName); // NULL
    System.out.println(u.lastName); // NULL
    System.out.println(u.userId); // Correctly generated
    // END OF TESTING

    return redirect(routes.Backend.allUsers());
  }
}

I wonder why the automatic binding of values doesn't work. I have made sure that the fields name in my form correspond to the attributes names in the class, and this should be enough for the form binding to work, right?

I am using Eclipse Luna, and I turned off automatic project build (I do it manually from the console). I know that sometimes Eclipse can cause issues because of that auto-build feature. Note: This was the way to go, but I didn't clean the project using the activator command, as user Dmitri suggested. Also, you only have to do this once, as long as you don't turn on the automatic build feature in Eclipse.

I have tried restarting Eclipse and the application several times, without success...

EDIT: I tried using only String attributes for my Users class, since the requestData.get(String s) method returns a String. But still no success...

EDIT 2: I'm going to bind the values manually... If anyone have an idea, please post :)

EDIT 3: I've updated my code to follow the rules mentioned in the answer below

EDIT 4: I can't get autobinding working only when using my Postgresql 9.3 database. When I use in-memory database, everything works smoothly. Also, since there was no JDBC driver for Java 8 and postgresql 9.3, I'm using an older version of the driver (actually the driver is on PGSQL's website, but I couldn't get it working with Play). I will have to check what happens with another DB, then I'll report back here!

EDIT 5: I tried to create my custom data binder like this:

        Formatters.register(User.class, new Formatters.SimpleFormatter<User>() {
        @Override
        public User parse(String arg0, Locale arg1) throws ParseException {
            User u = new Model.Finder<Integer, User>(Integer.class, User.class).byId(Integer.parseInt(arg0));
            return u;
        }
        @Override
        public String print(User arg0, Locale arg1) {
            return "User : " + arg0.firstName;
        }
    });

... but it didn't work!

EDIT 6: User Dmitri has found a working solution: you have to compile the project outside of Eclipse. It seems that there is some incompatibilities between Eclipse's compilator and Play! Framework's compilator...


回答1:


I have been struggling with exactly the same problem: bindFromRequest returned nulls for "name" field. I did exactly the same what a guy in this Play for Java introduction video did: youtube.com/watch?v=bLrmnjPQsZc . But still no luck. I've been working on Windows 7 with JDK 1.8. IDE: Eclipse 4.4.0. And I run activator through cygwin.

This is what solved the problem for me:

  1. In Eclipse: Project -> Build Automatically - > turn off
  2. In cygwin: ./activator clean; ./activator compile; ./activator run;

After this, bindFromRequest binds name correctly and puts it into the database.




回答2:


Create getters/setters for your data model. It has solved my problem.




回答3:


In your code you have :

Users u = Form.form(Users.class).bindFromRequest().get(); 

Try with this instead :

Users user = new Users();
Form <Users> u = Form.form(Users.class).fill(user).bindFromRequest();

EDIT :

May be the problem is the input types you're using. Try to generate your form like this :

@form(routes.Backend.createUser()) {

            <label>First Name:</label> @inputText(userForm("first_name")) <br />
            <label>Last Name:</label> @inputText(userForm("first_name")) <br />
            <label>Email:</label> @inputText(userForm("email")) <br />
            <label>Pin:</label> @inputText(userForm("pin")) <br />
            <label>Status:</label> @inputText(userForm("status")) <br />
            <label>Is Guest:</label> @checkbox(userForm("is_guest")) <br />
            <input type="submit" value="Create user" />
    }

Then in User Entity : try to change all columns type to String

@Entity
public class Users extends Model {

// Database columns
@Id
public int user_id;

public String first_name;
public String last_name;
public String email;
public String pin;
public String status;
public String is_guest;

}

In your controller :

public class Backend extends Controller {

  public static Result createUser() {
    Form <Users> userForm = Form.form(Users.class).bindFromRequest();
    Users user = userForm .get();
    user.save();
}
}  



回答4:


There is absolutely no link between the binding and your database. Do not follow @blackbishop's advice telling you to change all the fields of your model to String. That's a very bad idea, if there are different types, there is a reason...

Moreover, Ebean (supposing you're using it) or JPA generate database column types according to your Java properties type. Why would you store a 0 or a 1 in a varchar column ?

Follow these rules :

  1. Use a singular name for your models (User instead of Users)
  2. Always use camel case for your properties, no underscores (firstName instead of first_name, lastName instead of last_name...)
  3. Check errors before getting the value after binding

That should give you this :

public static Result createUser() {
    Form<User> form = Form.form(User.class).bindFromRequest();
    if (form.hasErrors()) {
        // Do what you have to do (i.e. : redirect to the form with a flash message)
    }
    User u = form.get();
    u.save();
    return redirect(routes.Backend.allUsers());
}

By the way, in your testing lines, the user_id is correctly generated because you have no validation rules and this data comes from the database, not the form.




回答5:


I solved this by Adding Setters and Getters. If you have Entity/Model class you should add setters and getters. If you have FormData classes add setters and getters for it as well.

So when you call

Form<YourFormData> formData =       Form.form(YourFormData.class).bindFromRequest(); 
 YourFormData formData = formData.get(); 

Your formData will now have all the values set. Hope this helps!




回答6:


I know this post has an accepted answer but wanted to post my experience with this issue.

I had the same issue and performed all the steps mentioned in the answer above i.e. Eclipse build automatically and then clean and compile through the activator. However, this did not work. I tried many different ways and even created a project from scratch without creating any Eclipse dependencies. Still, it did not work.

Then, I looked at my model and decided to try by changing the case of my property names, and then voila! It worked!

Here is what my model looked like BEFORE:

public class Test {
 public String FirstName;
 public String LastName;}

Now, I changed it to look like this:

public class Test {
  public String firstName;
  public String lastName;}

Just wanted to point this out since it is not obvious and I am coming from .Net



来源:https://stackoverflow.com/questions/25365707/issue-with-bindfromrequest-in-play-framework-2-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!