从请求和登录用户绑定表单



我又来了一个关于Play2.0的问题:-)。

我有一个模型叫Task。此任务包含一个名为 createdBy 的字段。此字段必须填充已登录的用户。

我的字段声明如下所示:

@ManyToOne
@Constraints.Required
public User createdBy;

我呈现一个表单,登录用户可以在其中从下拉框中输入描述优先级。提交表单后,我调用我的save()方法。在保存方法中,我有以下代码:

Form<Task> taskForm = form(Task.class).bindFromRequest();
if (taskForm.hasErrors()) {
    return badRequest(views.html.tasks.taskCreate.render(taskForm));
}
taskForm.get().save();

显然,Task永远不会保存,因为字段createdBy不包含任何(有效)用户。对用户的唯一引用是我在会话中保存他的唯一 CODE 而不是主键。

只有当我删除必需约束并将用户后填充到保存的任务时,我才能让它工作。一定有更好的方法将表单和用户绑定在一起,对吧?

Play2.0 想要你做的是区分你的"数据库模型"和你的"表单 bean"。我也认为应该有一个更好的解决方案。但另一方面,它很干净。所以你应该做的是:

  1. 例如,创建一个名为TaskForm的"表单豆"。此类仅包含表单中显示的字段,并具有正确的批注和验证。
  2. TaskForm中创建一个返回TasktoTask(User user)方法。
  3. 将控制器中的代码更改为:

    Form<TaskForm> taskForm = form(TaskForm.class).bindFromRequest();
    if (taskForm.hasErrors()) {
      return badRequest(views.html.tasks.taskCreate.render(taskForm));
    }
    taskForm.get().toTask(user).save();
    
  4. 将注释/验证保留在"模型类"Task中,但将它们视为数据库验证,而不是表单验证。

编辑:

  • 一些额外的解释:我在Play组上就这个验证/绑定问题进行了几次讨论:讨论1,讨论2。据我了解,Play 开发人员的想法是使用 Form 类进行绑定/验证。此 Form 类包装现有类。我认为他们的想法没有错,这个包装的类是表单的 1 对 1 表示。唯一的问题是,Scala语言使这比Java语言容易得多。在Java中,你必须创建大量的"表单表示类",而在Scala中,你可以使用"mapping"和"case classes"之类的东西(参见ScalaForms)。所以我完全同意你在评论中的观点,即为一个不同的属性编写一个新的"表单 bean"可能不值得,你宁愿在一个地方进行验证。但这就是它的设计方式。我希望他们要么自己更改 API,要么其他人仔细查看并提交拉取请求。但是现在,这就是框架希望你进行绑定/验证的方式。

  • 例:

    public class Task extends Model {
        @Constraints.Required
        public String description;
        @Constraints.Required
        public Integer priority;
        @ManyToOne
        @Constraints.Required
        public User createdBy;
        public Task() {
        }
        public Task(final TaskForm taskForm, final Long userCode) {
            description = taskForm.description;
            userCode = taskForm.userCode;
            createdBy = User.findByCode(userCode);
        }
    }
    public class TaskForm {
        @Constraints.Required
        public String description;
        @Constraints.Required
        public Integer priority;
        public toTask(final Long userCode) {
            return new Task(this, userCode);
        }
    }
    public class Tasks extends Controller {
        public static Result save() {
            Form<TaskForm> taskForm = form(TaskForm.class).bindFromRequest();
            if (taskForm.hasErrors()) {
                return badRequest(views.html.tasks.taskCreate.render(taskForm));
            }
            taskForm.get().toTask(session("userCode")).save();
        }
    }
    

从模型中删除所需的注释,并通过两个步骤绑定新任务:

Form<Task> taskForm = form(Task.class).bindFromRequest();
if (taskForm.hasErrors()) {
    return badRequest(views.html.tasks.taskCreate.render(taskForm));
}
Task newTask = taskForm.get();
newTask.createdBy = someObjectOfUserModel;
newTask.save();
return ok("New user added");

最新更新