Playframework将列表发布到控制器

时间:2013-02-28 16:45:28

标签: jpa playframework ebean playframework-2.1 scala-template

我想要实现的是这个示例应用: 〜\ play-2.1.0 \ samples \ java \ forms

更新的最新代码:

我的question.scala.html看起来像:

@(questionForm: Form[Question])

@import helper._
@import helper.twitterBootstrap._



@answerField(field: Field, className: String = "answer") = {

<div class="twipsies well @className">
    <table>
        <tr>
            <td> @checkbox(field("addRight"),'_label -> "Add")</td>
            <td> @checkbox(field("editRight"),'_label -> "Edit")</td>
            <td> @checkbox(field("delRight"),'_label -> "Delete")</td>
            <td> @checkbox(field("viewRight"),'_label -> "View")</td>
        </tr>
    </table>
</div>

}


@if(questionForm.hasErrors) {
    <div class="alert-message error">
        <p><strong>Oops</strong> Please fix all errors</p>
    </div>
}

@helper.form(action = routes.Questions.submit, 'id -> "form") {

    <fieldset>

        @inputText(
            questionForm("name"),
            '_label -> "Name of a Right"
        )

        @inputText(
            questionForm("namex"),
            '_label -> "Name of a Right"
        )

        <div class="answers">

            @repeat(questionForm("answers"), min = 0) { answer =>
                @answerField(answer)
            }



            @**
            * Keep an hidden block that will be used as template for Javascript copy code
            * answer_template is only css style to make it hidden (look main.css and declare your own answer_template at bottom)
            **@
            @answerField(
                questionForm("answers"),
                className = "answer_template"
            )

            <div class="clearfix">
                <div class="input">
                    <a class="addAnswer btn success">Add </a>
                </div>
            </div>

        </div>
    </fieldset>

    <div class="actions">
        <input type="submit" class="btn primary" value="Insert">
    </div>

}

<script type="text/javascript" charset="utf-8">

        $('.removeAnswer').on('click', function(e) {
        var answers = $(this).parents('.answers');
        $(this).parents('.answer').remove();
        renumber(answers);
        });

        $('.addAnswer').on('click', function(e) {
        var answers = $(this).parents('.answers');
        var template = $('.answer_template', answers);
        template.before('<div class="clearfix answer">' + template.html() + '</div>');
        renumber(answers);
        });

        $('#form').submit(function() {
        $('.answer_template').remove()
        });

        // -- renumber fields
        // This is probably not the easiest way to do it. A jQuery plugin would help.

        var renumber = function(answers) {
        $('.answer').each(function(i) {
        $('input', this).each(function() {
        $(this).attr('name', $(this).attr('name').replace(/answers\[.+?\]/g, 'answers[' + i + ']'))
        });
        });
        }

</script>

...

问题模型:

package models;

import play.data.validation.Constraints;
import play.db.ebean.Model;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;


@Entity
public class Question extends Model {

@Id
public Long id;

@Constraints.Required
public String name;


@OneToMany(cascade = CascadeType.PERSIST, mappedBy = "question")
public List<Answer> answers;

public Question() {

}

public Question(String name) {
    this.name = name;

}
}

答案型号:

@Entity
public  class Answer extends Model {

@Id
public Long id;

public boolean addRight;
public boolean editRight;
public boolean delRight;
public boolean viewRight;

@ManyToOne
public Question question;

public Answer() {
}

public Answer(boolean addRight,boolean editRight,boolean delRight,boolean viewRight, 
Question question) {
    this.addRight = addRight;
    this.editRight = editRight;
    this.delRight = delRight;
    this.viewRight = viewRight;
    this.question = question;
}
}

最后控制器保存部分:

  public static Result submit() {
    Form<Question> filledForm = questionForm.bindFromRequest();

    if(filledForm.hasErrors()) {
        User user = User.findByUserName("samuel");
        return badRequest(question.render(filledForm));
    }
    else {
        // If we dont have any errors, we should be around here :)
        Question question = filledForm.get();
        // Since Answer needs reference to Question and with new Question
        // it cant get it loaded from DB we need to do little dirty trick here
        // in order to save new question id instantly to answers foreign_key
        // as question_id, otherwise it will be null
        System.out.println("-->" + question.answers.size() );
        if(question.answers != null) {
            ArrayList<Answer> answersCopy = new ArrayList<Answer>();
            Logger.trace("Size of Anwsers : " +answersCopy.size());
            for(Answer answer : question.answers) {
                answersCopy.add(new                  
   Answer(answer.addRight,answer.editRight,answer.delRight,answer.viewRight,question));
                System.out.println("##" + answer.addRight);
            }
            question.answers = answersCopy;
        }
        question.save();
        return ok("Nice, all saved!");

    }
}

使用上面的代码我没有得到任何例外但是......问题部分可以让Anwser离开。

由于

1 个答案:

答案 0 :(得分:2)

嗯,我认为我使用JPA工作,我有点不确定你是想用JPA还是只用Ebean,但我认为你和其他人也可以通过Ebean移植它。 (如果你需要,我也可以做到,我猜;)

以下是我尝试使用JPA的内容:

  • 打开终端(或cmd)并导航到名为play-2.1.0/samples/java/forms
  • 的项目
  • 然后(以防万一)运行以下命令:play clean .. play compile .. play eclipse
  • 去eclipse并将其导入(右键单击以打包资源管理器 - &gt;现有项目..)
  • 打开conf/application.conf并添加(或取消注释)这些行:
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
db.default.jndiName=DefaultDS
jpa.default=defaultPersistenceUnit
  • 创建conf/evolutions/defaultconf/META-INF
  • 的文件夹结构
  • 添加名为persistence.xml的文件,其中包含以下内容:
  

http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd”                版本= “2.0” &GT;

<persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <non-jta-data-source>DefaultDS</non-jta-data-source>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
    </properties>
</persistence-unit>
 </persistence>
  • 现在让我们为你的答案和问题模型创建表格,创建文件1.sqlevolutions/default,内容如下:
# --- !Ups

create table question (
  id                        bigint not null,
  name                      varchar(255),
  constraint pk_question primary key (id))
;

create table answer (
  id                        bigint not null,
  name                      varchar(255),
  question_id               bigint,
  constraint pk_answer primary key (id))
;

create sequence answer_seq start with 1000;
create sequence question_seq start with 1000;

alter table answer add constraint fk_answer_question_1 foreign key (question_id) references question (id) on delete restrict on update restrict;

# --- !Downs

SET REFERENTIAL_INTEGRITY FALSE;

drop table if exists question;
drop table if exists answer;

SET REFERENTIAL_INTEGRITY TRUE;

drop sequence if exists question_seq;
drop sequence if exists answer_seq;
  • 修改或添加以下模型:
package models;

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.ManyToOne; 

import play.data.validation.Constraints.Required;

@Entity 
@SequenceGenerator(name = "answer_seq", sequenceName = "answer_seq")
public class Answer {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "answer_seq")
public Long id;

@Required
public String name;

@ManyToOne
public Question question;

public Answer() { 
}

public Answer(String name, Question question) {   
      this.name = name;
      this.question = question;
}

}

...

package models;

import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import play.data.validation.Constraints.Required;
import play.db.jpa.*;

@Entity
@SequenceGenerator(name = "question_seq", sequenceName = "question_seq")
public class Question {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "question_seq")
public Long id;

@Required
public String name;

@Valid
@OneToMany(cascade = CascadeType.PERSIST, mappedBy = "question")
public List<Answer> answers;

public Question() {

}

public Question(String name) {
      this.name = name;
}

public void save() {

      JPA.em().persist(this);

      List<Question> allQuestions = JPA.em().createQuery("from Question order by name").getResultList();

      System.out.println("Number of questions: " + allQuestions.size());

      for(Question q : allQuestions) {

             System.out.println("Question --- id: " + q.id + ", name: " + q.name);

                if(q.answers != null) {

                   for(Answer a : q.answers) {
                           System.out.println("Answer --- id: " + a.id + ", name: " + a.name + " question_id: " + a.question.id);
                   }
             }
      }

}

}
  • 好的,现在模型OK让我们创建静态控制器和视图来测试它,从routes文件开始:
# Question
GET     /questions                  controllers.Questions.blank()
POST    /questions                  controllers.Questions.submit()
  • 然后添加以下控制器:
package controllers;

import static play.data.Form.form;
import java.util.ArrayList;
import models.Answer;
import models.Question;
import play.data.Form;
import play.db.jpa.Transactional;
import play.mvc.Controller;
import play.mvc.Result;
import views.html.question.*;

public class Questions extends Controller {

/**
* Defines a form wrapping the Question class.
*/ 
final static Form<Question> questionForm = form(Question.class);

/**
* Display a blank form.
*/ 
public static Result blank() {
    return ok(form.render(questionForm));
}

@Transactional
public static Result submit() {

Form<Question> filledForm = questionForm.bindFromRequest();

if(filledForm.hasErrors()) {
     return badRequest(form.render(filledForm));
} else {

// If we dont have any errors, we should be around here :)
Question question = filledForm.get();

// Since Answer needs reference to Question and with new Question
// it cant get it loaded from DB we need to do little dirty trick here
// in order to save new question id instantly to answers foreign_key
// as question_id, otherwise it will be null
if(question.answers != null) {
     ArrayList<Answer> answersCopy = new ArrayList<Answer>();
     for(Answer answer : question.answers) {
     answersCopy.add(new Answer(answer.name, question));
}
question.answers = answersCopy;
}
question.save();

// You can also use this test code to save data
// Question question = new Question("What is your favorite color?");
// question.answers = new ArrayList<Answer>();
// question.answers.add(new Answer("Blue", question));
// question.answers.add(new Answer("Red", question));
// question.save();

return ok("Nice, all saved!");

}
}

}
  • 好的,还有一个视图,在views.question创建它,将其命名为form.scala.html(顺便说一句,我重复使用了类似的代码,应用程序已经使用了联系人,但是它可以与你的模型一起使用。 )
@(questionForm: Form[Question])

@import helper._ 
@import helper.twitterBootstrap._

@title = {
     Add a new question 
}

@answerField(field: Field, className: String = "answer") = {
    @input(field, '_label -> "Answer", '_class -> className) { (id, name, value, _) =>
    <input type="text" name="@name" value="@value"> 
    <a class="removeAnswer btn danger">Remove</a>
} 
}

@main(title, nav = "question") {

@if(questionForm.hasErrors) {
    <div class="alert-message error">
        <p><strong>Oops</strong> Please fix all errors</p>
    </div>
}

@helper.form(action = routes.Questions.submit, 'id -> "form") {

<fieldset>
<legend>Fill a question with answers</legend>

@inputText(
    questionForm("name"), 
    '_label -> "Name of a question"
)

<div class="answers">

@repeat(questionForm("answers"), min = 0) { answer =>
     @answerField(answer("name"))
}

@**
* Keep an hidden block that will be used as template for Javascript copy code
* answer_template is only css style to make it hidden (look main.css and declare your own answer_template at bottom)
**@
@answerField(
    questionForm("answers[x].name"),
    className = "answer_template"
)

<div class="clearfix">
<div class="input">
    <a class="addAnswer btn success">Add answer</a>
</div>
</div>

</div>
</fieldset>

<div class="actions">
<input type="submit" class="btn primary" value="Insert">
<a href="@routes.Application.index" class="btn">Cancel</a>
</div>

}

<script type="text/javascript" charset="utf-8">

$('.removeAnswer').live('click', function(e) {
    var answers = $(this).parents('.answers');
    $(this).parents('.answer').remove();
    renumber(answers);
});

$('.addAnswer').live('click', function(e) {
    var answers = $(this).parents('.answers');
    var template = $('.answer_template', answers);
    template.before('<div class="clearfix answer">' + template.html() + '</div>');
    renumber(answers);
});

$('#form').submit(function() {
    $('.answer_template').remove()
});

// -- renumber fields
// This is probably not the easiest way to do it. A jQuery plugin would help.

var renumber = function(answers) {
$('.answer').each(function(i) {
    $('input', this).each(function() {
         $(this).attr('name', $(this).attr('name').replace(/answers\[.+?\]/g, 'answers[' + i + ']'))
         });
    });
}

</script>
}
  • 作为最后的调整,请检查main.css文件最后一行,您记得将其编辑为:
.phone_template, .profile_template, .answer_template {
     display: none;
}
  • 并添加main.scala.html这个:
<li class="@("active".when(nav == "question"))">
   <a href="@routes.Questions.blank()">Questions</a>
</li>
  • 现在,如果您还没有这样做,请转到浏览器,确认要运行的演变并导航到问题视图,然后尝试使用不同的问题和价值提交表单。

你应该在游戏的终端窗口看到结果(类似于我的下面),如果是这样的情况你刚刚成功保存了几个答案的新问题,你可以随意重复它 - 应该工作,因为新的id's总是生成。如果你想让你的表单也包含编辑等,我建议你检查JPA如何在play samples文件夹(computer-database-jpa)中使用,因为这个例子已经证明太大了;我可能会把它扔到github以后,晚安&amp;欢呼声。

Number of questions: 1
Question --- id: 50000, name: What is your favorite color?
Answer --- id: 50000, name: Blue question_id: 50000
Answer --- id: 50001, name: Red question_id: 50000