Проблема с bindFromRequest в Play! Framework 2.3
Я пытаюсь использовать функцию автоматической привязки Play, но безуспешно. Я занимаюсь разработкой на Java, на Eclipse 4.4 Luna.
Вот моя форма:
<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>
Вот мой класс "Пользователи":
@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;
}
А вот и мой контроллер:
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());
}
}
Интересно, почему не работает автоматическое связывание значений? Я убедился, что имена полей в моей форме соответствуют именам атрибутов в классе, и этого должно быть достаточно для работы привязки формы, верно?
Я использую Eclipse Luna, и я отключил автоматическую сборку проекта (я делаю это вручную из консоли). Я знаю, что иногда Eclipse может вызывать проблемы из-за этой функции автоматической сборки. Примечание: это был путь, но я не чистил проект с помощью команды активатора, как предложил Дмитрий. Кроме того, вам нужно сделать это только один раз, если вы не включили функцию автоматической сборки в Eclipse.
Я попытался перезапустить Eclipse и приложение несколько раз, но безуспешно...
РЕДАКТИРОВАТЬ: я пытался использовать только атрибуты String для моего класса Users, так как метод requestData.get(String s) возвращает String. Но все равно безуспешно...
РЕДАКТИРОВАТЬ 2: Я собираюсь связать значения вручную... Если у кого-нибудь есть идея, пожалуйста, напишите:)
РЕДАКТИРОВАТЬ 3: я обновил свой код, чтобы следовать правилам, упомянутым в ответе ниже
РЕДАКТИРОВАТЬ 4: Я не могу заставить работать автосвязывание только при использовании моей базы данных Postgresql 9.3. Когда я использую базу данных в памяти, все работает гладко. Кроме того, поскольку не было драйвера JDBC для Java 8 и postgresql 9.3, я использую более старую версию драйвера (на самом деле драйвер есть на сайте PGSQL, но я не смог заставить его работать с Play). Мне нужно будет проверить, что происходит с другой БД, и я сообщу здесь!
РЕДАКТИРОВАТЬ 5: Я пытался создать свой пользовательский связыватель данных, как это:
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;
}
});
... но это не сработало!
РЕДАКТИРОВАТЬ 6: Пользователь Дмитрий нашел рабочее решение: вы должны скомпилировать проект вне Eclipse. Кажется, что есть некоторая несовместимость между компилятором Eclipse и Play! Компилятор фреймворка...
6 ответов
Я боролся с точно такой же проблемой: bindFromRequest вернул нули для поля "имя". Я сделал то же самое, что сделал парень из этого вводного видео о Play для Java: youtube.com/watch?v=bLrmnjPQsZc . Но все равно не повезло. Я работал над Windows 7 с JDK 1.8. IDE: Eclipse 4.4.0. И я запускаю активатор через Cygwin.
Вот что решило проблему для меня:
- В Eclipse: Проект -> Автоматическая сборка -> отключить
- В cygwin: ./activator clean; ./activator compile; ./activator run;
После этого bindFromRequest правильно связывает имя и помещает его в базу данных.
Создать геттеры / сеттеры для вашей модели данных. Это решило мою проблему.
В вашем коде у вас есть:
Users u = Form.form(Users.class).bindFromRequest().get();
Попробуйте с этим вместо этого:
Users user = new Users();
Form <Users> u = Form.form(Users.class).fill(user).bindFromRequest();
РЕДАКТИРОВАТЬ:
Может быть, проблема в том, какие типы ввода вы используете. Попробуйте создать свою форму следующим образом:
@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" />
}
Затем в User Entity
: попробуйте изменить все типы столбцов на 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;
}
В вашем контроллере:
public class Backend extends Controller {
public static Result createUser() {
Form <Users> userForm = Form.form(Users.class).bindFromRequest();
Users user = userForm .get();
user.save();
}
}
Я решил это, добавив сеттеры и геттеры. Если у вас есть класс Entity/Model, вы должны добавить сеттеры и геттеры. Если у вас есть классы FormData, добавьте для него и сеттеры, и геттеры.
Поэтому, когда вы звоните
Form<YourFormData> formData = Form.form(YourFormData.class).bindFromRequest();
YourFormData formData = formData.get();
Ваши formData теперь будут иметь все установленные значения. Надеюсь это поможет!
Нет абсолютно никакой связи между привязкой и вашей базой данных. Не следуйте совету @blackbishop, который подсказывает вам изменить все поля вашей модели на String. Это очень плохая идея, если есть разные типы, есть причина...
Более того, Ebean (предположим, вы используете его) или JPA генерируют типы столбцов базы данных в соответствии с вашим типом свойств Java. Зачем вам хранить 0 или 1 в столбце varchar?
Следуйте этим правилам:
- Используйте единственное имя для ваших моделей (
User
вместоUsers
) - Всегда используйте верблюжий регистр для своих свойств, без подчеркивания (firstName вместо first_name, lastName вместо last_name...)
- Проверьте ошибки до получения значения после привязки
Это должно дать вам это:
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());
}
Кстати, в ваших тестовых линиях user_id
правильно генерируется, потому что у вас нет правил проверки, и эти данные поступают из базы данных, а не из формы.
Я знаю, что у этого сообщения есть принятый ответ, но хотел бы поделиться своим опытом с этой проблемой.
У меня была та же проблема, и я выполнил все шаги, упомянутые в ответе выше, т.е. Eclipse build автоматически, а затем очистил и скомпилировал через активатор. Однако это не сработало. Я пробовал много разных способов и даже создал проект с нуля, не создавая никаких зависимостей Eclipse. Тем не менее, это не сработало.
Затем я посмотрел на свою модель и решил попробовать, изменив регистр имен своих свойств, а затем вуаля! Это сработало!
Вот как выглядела моя модель ДО:
public class Test {
public String FirstName;
public String LastName;}
Теперь я изменил это так:
public class Test {
public String firstName;
public String lastName;}
Просто хотел указать на это, так как это не очевидно, и я исхожу из.Net