Проблема с bindFromRequest в игре! Фреймворк 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 и приложение несколько раз, но безуспешно...

EDIT: я пытался использовать только атрибуты String для своего класса Users, так как метод requestData.get(String s) возвращает String. Но пока безуспешно...

РЕДАКТИРОВАТЬ 2: я собираюсь связать значения вручную... Если у кого-то есть идея, напишите :)

EDIT 3: я обновил свой код, чтобы следовать правилам, упомянутым в ответе ниже.

EDIT 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;
        }
    });

... но это не сработало!

EDIT 6: Пользователь Дмитрий нашел рабочее решение: вам нужно скомпилировать проект вне Eclipse. Похоже, что есть некоторая несовместимость между компилятором Eclipse и Play! Компилятор фреймворка...


person Danish Ashfaq    schedule 18.08.2014    source источник
comment
Вы получаете какую-либо ошибку?   -  person blackbishop    schedule 18.08.2014
comment
Абсолютно никаких ошибок... Я знаю, что все остальное работает, так как я могу вручную привязать значения и создать экземпляр моего объекта Users, затем сохранить его и получить, но эта функция автоматической привязки определенно не работает для меня...   -  person Danish Ashfaq    schedule 18.08.2014


Ответы (6)


Я боролся с точно такой же проблемой: bindFromRequest возвращал нули для поля «имя». Я сделал то же самое, что и парень из вводного видео Play for Java: youtube.com/watch?v=bLrmnjPQsZc . Но все равно не повезло. Я работаю над Windows 7 с JDK 1.8. IDE: Затмение 4.4.0. Активатор запускаю через cygwin.

Вот что решило проблему для меня:

  1. В Eclipse: Project -> Build Automatically -> отключить
  2. В cygwin: ./активатор чистый; ./активатор компилируется; ./запустить активатор;

После этого bindFromRequest правильно связывает имя и помещает его в базу данных.

person Dmitri Lihhatsov    schedule 04.09.2014
comment
Я пытался создать свой пользовательский связыватель данных, но он все еще не работал, так что в основном я все еще борюсь с проблемой... Я собирался вернуться к простому SQL для всех своих запросов! Но теперь я собираюсь попробовать это прямо сейчас и сообщить здесь! - person Danish Ashfaq; 05.09.2014
comment
Невероятно, это сработало! Значит, это было связано с «Затмением»… верно? Не могли бы вы объяснить, что на самом деле произошло? Большое спасибо! :) - person Danish Ashfaq; 05.09.2014
comment
Нет проблем :) Я подозреваю, что это связано с расширениями ebean, которые появляются после компиляции. Eclipse видит новые изменения и снова компилируется, что приводит к путанице в коде. - person Dmitri Lihhatsov; 05.09.2014
comment
Это очень вероятно. Пользователи IntelliJ IDEA не сообщали о такой проблеме... Я не знаю, было ли отправлено сообщение об ошибке, кому сообщить об ошибке (Eclipse или Play?) и стоит ли вообще его подавать. В любом случае, большое спасибо за помощь, я бы сам не узнал! - person Danish Ashfaq; 07.09.2014
comment
...Вау... сногсшибательно... Итак, проблема с Eclipse IDE - person MADHAIYAN M; 05.11.2014

Создайте геттеры/сеттеры для вашей модели данных. Это решило мою проблему.

person abbas    schedule 19.09.2015
comment
На самом деле это правильный ответ. Ошибка возникает из-за того, что компилятор scala добавляет геттеры и сеттеры по умолчанию, которые не создаются при его компиляции с помощью eclipse. - person Tom; 25.09.2016
comment
Даже сегодня я считаю, что это правильный ответ, у меня была точно такая же проблема. Создание геттеров и сеттеров решает проблему. - person Ilhicas; 23.01.2017

В вашем коде у вас есть:

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();
}
}  
person blackbishop    schedule 18.08.2014
comment
В конце я использую метод .get(), который должен возвращать объект типа Users. Это именно то, что сделано в Play! Видео о платформе для разработчиков Java: youtube.com/watch?v=bLrmnjPQsZc - person Danish Ashfaq; 18.08.2014
comment
Что такое userForm в вашем коде? Я проверил документацию по игре, но в ней ничего нет... Я просто знаю, что это параметр, передаваемый шаблону, например @(userForm: Form[Users]), но что это такое? - person Danish Ashfaq; 19.08.2014
comment
перейдите по этой ссылке: playframework.com/documentation/2.2.x/ScalaForms - person blackbishop; 19.08.2014
comment
Итак, я предположил, что это простая форма Form‹Users› userForm = Form.form(Users.class); который я передал в свой шаблон. И я все еще не могу заставить работать автопривязку... Сгенерированная форма в порядке, все в порядке, когда я вручную проверяю значения. - person Danish Ashfaq; 19.08.2014
comment
вот хороший сообщение - person blackbishop; 19.08.2014
comment
Спасибо за информацию. Мне удалось заставить автопривязку работать над другим тестовым проектом, точно следуя инструкциям в видеоуроке. Я думаю, что моя проблема может быть связана с тем, что у меня более сложная база данных, чем более простая, используемая в примере. Я думаю, что на данный момент я собираюсь связать значения вручную, и я посмотрю на это позже. Спасибо за вашу помощь :) - person Danish Ashfaq; 19.08.2014

Между привязкой и вашей базой данных нет абсолютно никакой связи. Не следуйте совету @blackbishop, который говорит вам изменить все поля вашей модели на String. Это очень плохая идея, если есть разные типы, есть причина...

Кроме того, Ebean (предположим, что вы его используете) или JPA генерируют типы столбцов базы данных в соответствии с вашим типом свойств Java. Зачем хранить 0 или 1 в столбце varchar?

Следуйте этим правилам:

  1. Используйте единственное имя для своих моделей (User вместо Users)
  2. Всегда используйте верблюжий регистр для своих свойств, без подчеркивания (firstName вместо first_name, lastName вместо last_name...)
  3. Проверяйте ошибки перед получением значения после привязки

Это должно дать вам следующее:

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 генерируется правильно, потому что у вас нет правил проверки, и эти данные поступают из базы данных, а не из формы.

person c4k    schedule 20.08.2014
comment
Я всегда использовал эти правила, но для этого проекта, если я назову свою модель User, имя базы данных будет user, которое является зарезервированным именем SQL... В любом случае, я попробую использовать camelCase и отчитаюсь. Спасибо! - person Danish Ashfaq; 20.08.2014
comment
Я пробовал с camelCase... безуспешно. Я действительно понятия не имею, что происходит, я все еще получаю тот же результат:/ - person Danish Ashfaq; 20.08.2014
comment
Что меня действительно беспокоит, так это то, что если я печатаю содержимое формы (form.toString()), я получаю это: Form(of=class models.system.Users, data={firstName=Bob, lastName=Smith, pin=567, isGuest=on, [email protected], status=active}, value=Some(models.system.Users@5d482b), errors={}), что ясно показывает, что метод form.get() у меня не работает... - person Danish Ashfaq; 20.08.2014
comment
Чтобы user было зарезервированным словом в MySQL, просто используйте @Table(name = "users") в своем классе модели. Что вставляется в базу данных после отправки формы? - person c4k; 20.08.2014
comment
Да, я буду использовать аннотацию @Table, это лучшее решение. После отправки формы вставляется ноль. У меня может быть зацепка: проверьте мое редактирование! - person Danish Ashfaq; 20.08.2014

Я решил это, добавив сеттеры и геттеры. Если у вас есть класс Entity/Model, вы должны добавить сеттеры и геттеры. Если у вас есть классы FormData, добавьте для него сеттеры и геттеры.

Поэтому, когда вы звоните

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

Теперь в ваших formData будут установлены все значения. Надеюсь это поможет!

person Shirish Singh    schedule 23.06.2016

Я знаю, что этот пост имеет принятый ответ, но хотел опубликовать свой опыт решения этой проблемы.

У меня была такая же проблема, и я выполнил все шаги, упомянутые в ответе выше, т.е. автоматически собрал Eclipse, а затем очистил и скомпилировал через активатор. Однако это не сработало. Я пробовал много разных способов и даже создал проект с нуля, не создавая никаких зависимостей от Eclipse. Тем не менее, это не сработало.

Затем я посмотрел на свою модель и решил попробовать, изменив регистр имен свойств, и вуаля! Это сработало!

Вот как моя модель выглядела ДО:

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

Теперь я изменил его, чтобы он выглядел так:

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

Просто хотел указать на это, так как это неочевидно, и я исхожу из .Net.

person dotnetster    schedule 05.12.2014