我想要实现的是这个示例应用: 〜\ 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离开。
由于
答案 0 :(得分:2)
嗯,我认为我使用JPA工作,我有点不确定你是想用JPA还是只用Ebean,但我认为你和其他人也可以通过Ebean移植它。 (如果你需要,我也可以做到,我猜;)
以下是我尝试使用JPA的内容:
play-2.1.0/samples/java/forms
play clean .. play compile .. play eclipse
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/default
和conf/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.sql
到evolutions/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); } } } } }
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> }
.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