Java 使用Play Framework 2使用动态创建的表单输入更新数据库
我有一个候选人模型和一堆其他模型,如学校、学位、技能、工作岗位等,它们与候选人模型有一对多的关系 我能够创建一个create表单(创建新候选表单的表单),该表单可以使用javascript/jquery动态创建表单字段。用户可以通过单击“添加其他按钮”添加更多输入字段。表单提交给控制器,所有数据都完美地添加到数据库中 这个问题在编辑表单中起作用。编辑表单与创建表单几乎相同,只是它在数据库的表单字段中预先填充了数据。当我将此表单提交到控制器中的更新函数时,它会错误地执行更新。当我返回到编辑表单查看它是否正常工作时,有一些带有空白值的随机输入字段,但数据确实得到了编辑 我对游戏框架相当陌生,可能做错了什么。我使用Codeigniter在PHP中做了类似的事情,效果很好。可能是因为Codeigniter不使用Ebean或JPA 下面是我写的一些代码,所以我的问题更容易理解。我只打算包括候选人模型和学校模型,因为其他模型与学校模型相似。此外,我还包含了生成动态表单字段的js代码 任何帮助都将不胜感激Java 使用Play Framework 2使用动态创建的表单输入更新数据库,java,javascript,jquery,playframework,ebean,Java,Javascript,Jquery,Playframework,Ebean,我有一个候选人模型和一堆其他模型,如学校、学位、技能、工作岗位等,它们与候选人模型有一对多的关系 我能够创建一个create表单(创建新候选表单的表单),该表单可以使用javascript/jquery动态创建表单字段。用户可以通过单击“添加其他按钮”添加更多输入字段。表单提交给控制器,所有数据都完美地添加到数据库中 这个问题在编辑表单中起作用。编辑表单与创建表单几乎相同,只是它在数据库的表单字段中预先填充了数据。当我将此表单提交到控制器中的更新函数时,它会错误地执行更新。当我返回到编辑表单查看
Candidate.java(model):
@Entity
public class Candidate extends Model {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
public String firstName;
public String lastName;
public boolean sponsorshipStatus;
public boolean proceedToInterview;
@Column(columnDefinition = "TEXT")
public String text;
@OneToMany(cascade = CascadeType.ALL)
public List<School> schools;
@OneToMany(cascade = CascadeType.ALL)
public List<Degree> degrees;
@OneToMany(cascade = CascadeType.ALL)
public List<Document> documents;
@OneToMany(cascade = CascadeType.ALL)
public List<JobPosition> jobPositions;
@OneToMany(cascade = CascadeType.ALL)
public List<Skill> skills;
/**
* Generic query helper for entity Candidate with id Long
*/
public static Model.Finder<Long, Candidate> find = new Model.Finder<Long, Candidate>(Long.class, Candidate.class);
public static Page<Candidate> page(int page, int pageSize, String sortBy, String order, String filter) {
return find.where()
.ilike("first_name", "%" + filter + "%")
.orderBy(sortBy + " " + order)
.findPagingList(pageSize)
.setFetchAhead(false).getPage(page);
}
}
School.java(model):
@Entity
public class School extends Model {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;
public String schoolName;
@ManyToOne
public Candidate candidate;
/**
* Generic query helper for entity Company with id Long
*/
public static Model.Finder<Long, School> find = new Model.Finder<Long, School>(
Long.class, School.class);
}
Application.java(controller):
public class Application extends Controller {
public static Result index() {
return ok(index.render("Your new application is ready."));
}
/*display a list of candiates*/
public static Result list(int page, String sortBy, String order, String filter) {
return ok(views.html.list.render(Candidate.page(page, 10, sortBy, order, filter), sortBy, order, filter));
}
/**
* Display the 'edit form' of a existing Candidate.
*
* @param id
* Id of the candidate to edit
*/
public static Result edit(Long id) {
Form<Candidate> candidateForm = form(Candidate.class).fill(Candidate.find.byId(id));
Candidate candidate = Candidate.find.byId(id);
return ok(views.html.editForm.render(id, candidateForm, candidate));
}
/**
* Handle the 'edit form' submission
*
* @param id
* Id of the computer to edit
*/
public static Result update(Long id) {
RequestBody request_body = request().body();
MultipartFormData body = request_body.asMultipartFormData();
// MultipartFormData FilePart object list
List<FilePart> files = body.getFiles();
List<Document> docs = new ArrayList<Document>();
for (FilePart file : files) {
String fileName = file.getFilename();
// Use Java.IO File class to move file in desired location
File f = file.getFile();
File nf = new File("\\\\WL-MSAMARITONI\\Images", fileName);
f.renameTo(nf);
Document doc;
doc = new Document();
doc.docName = fileName;
doc.filePath = nf.getAbsolutePath();
docs.add(doc);
}
Form<Candidate> candidateForm = form(Candidate.class).bindFromRequest();
Candidate updateCandidate = candidateForm.get();
updateCandidate.documents = docs;
/*while(updateCandidate.degrees.remove(null));
while(updateCandidate.jobPositions.remove(null));
while(updateCandidate.schools.remove(null));
while(updateCandidate.skills.remove(null));
while(updateCandidate.documents.remove(null));
*/
updateCandidate.update(id);
updateCandidate.save();
flash("success", "Candidate " + candidateForm.get().firstName + " has been created");
return redirect("/candidate/" + id);
}
/**
* Display the 'new candidate form'.
*/
public static Result create() {
Form<Candidate> candidateForm = form(Candidate.class);
return ok(views.html.createForm.render(candidateForm));
}
/**
* Handle the 'new candidate form' submission
*/
public static Result save() {
RequestBody request_body = request().body();
MultipartFormData body = request_body.asMultipartFormData();
// MultipartFormData FilePart object list
List<FilePart> files = body.getFiles();
List<Document> docs = new ArrayList<Document>();
for (FilePart file : files) {
String fileName = file.getFilename();
// Use Java.IO File class to move file in desired location
File f = file.getFile();
File nf = new File("\\\\WL-MSAMARITONI\\Images", fileName);
f.renameTo(nf);
Document doc;
doc = new Document();
doc.docName = fileName;
doc.filePath = nf.getAbsolutePath();
docs.add(doc);
}
Form<Candidate> candidateForm = form(Candidate.class).bindFromRequest();
Candidate newCandidate = candidateForm.get();
newCandidate.documents = docs;
newCandidate.save();
flash("success", "Computer " + candidateForm.get().firstName + " has been created");
return redirect("/candidates/new");
}
}
createForm.scala.html(view):
@(candidateForm: Form[Candidate])
@import helper._
@main("Create Candidate"){
<h1>Add a New Candidate</h1>
@form(routes.Application.save(), args= 'class -> "form-horizontal",'enctype -> "multipart/form-data") {
<div class="row">
<fieldset class="span6">
<legend>
<h3> Add Candidate Info</h3>
</legend>
@inputText(candidateForm("firstName"), '_label -> "First Name")
@inputText(candidateForm("lastName"), '_label -> "Last Name")
@checkbox(candidateForm("sponsorshipStatus"), '_label -> "Sponsorship Status")
@checkbox(candidateForm("proceedToInterview"), '_label -> "Proceed to Interview")
@textarea(candidateForm("text"), args = 'rows -> 3, 'cols -> 50, '_label -> "Notes")
</fieldset>
<fieldset class="span6">
<legend>
<h3>Add Schools</h3>
</legend>
<div id="schools" class="control-group">
<div class="school hidden_form_default">
<input id="chk_school" type="checkbox">
<input disabled="disabled" id="school" name="schools[].schoolName" placeholder="Enter School">
</div>
<div class="school">
<input id="chk_school_0" type="checkbox" value="1">
<input id="school_0" name="schools[0].schoolName" placeholder="Enter School" >
</div>
</div>
<button class="btn school_add_button">
Add Another
</button>
<button class="btn btn-danger school_delete_button">
Delete Checked
</button>
</fieldset>
</div>
<div class="row">
<fieldset class="span6">
<legend>
<h3>Add Degrees</h3>
</legend>
<div id="degrees" class="control-group">
<div class="degree hidden_form_default">
<input id="chk_degree" class="" type="checkbox" value="1">
<input id="degreeLevel" disabled="disabled" class="" name="degrees[].degreeLevel" placeholder="Degree Level" >
<input id="degreeFocus" disabled="disabled" class="" name="degrees[].degreeFocus" placeholder="Degree Focus" >
<input type="text" id="completedDate" disabled="disabled" class="datepicker input-small" name="degrees[].completedDate" placeholder="Completed" >
</div>
<div class= "degree">
<input id="chk_degree_0" class="" type="checkbox" value="1">
<input id="degreeLevel_0" class="" name="degrees[0].degreeLevel" placeholder="Degree Level" >
<input id="degreeFocus_0" class="" name="degrees[0].degreeFocus" placeholder="Degree Focus" >
<input type="text" id="completedDate_0" class="datepicker input-small" name="degrees[0].completedDate" placeholder="Completed" >
</div>
</div>
<button class="btn degree_add_button">
Add Another
</button>
<button class="btn btn-danger degree_delete_button">
Delete Checked
</button>
</fieldset>
<fieldset class="span6">
<legend>
<h3>Add Skills</h3>
</legend>
<div id="skills" class="control-group">
<div class="skill hidden_form_default">
<input id="chk_skill" type="checkbox">
<input disabled="disabled" id="skill" name="skills[].skill" class="clearMeFocus" placeholder="Enter skill">
</div>
<div class="skill">
<input id="chk_skill_0" type="checkbox" value="1">
<input id="skill_0" name="skills[0].skill" class="clearMeFocus" placeholder="Enter skill" >
</div>
</div>
<button class="btn skill_add_button">
Add Another
</button>
<button class="btn btn-danger skill_delete_button">
Delete Checked
</button>
</fieldset>
</div>
<div class="row">
<fieldset class="span6">
<legend>
<h3>Add Desired Positions</h3>
</legend>
<div id="positions" class="control-group">
<div class="position hidden_form_default">
<input id="chk_position" class="" type="checkbox" value="1">
<input id="position" disabled="disabled" class="" name="jobPositions[].position" placeholder="Enter Position" >
</div>
<input id="chk_position_0" class="" type="checkbox" value="1">
<input id="positionLevel_0" class="" name="jobPositions[0].position" placeholder="Enter Position" >
</div>
<button class="btn position_add_button">
Add Another
</button>
<button class="btn btn-danger position_delete_button">
Delete Checked
</button>
</fieldset>
<fieldset class="span6">
<legend>
<h3>Add Documents</h3>
</legend>
<div id="documents" class="control-group">
<div class="document hidden_form_default">
<input id="chk_document" type="checkbox">
<input type="file" disabled="disabled" id="document" name="documents[]">
</div>
<div class="document">
<input id="chk_document_0" type="checkbox" value="1">
<input id="document_0" type="file" name="documents[0]" >
</div>
</div>
<button class="btn document_add_button">
Add Another
</button>
<button class="btn btn-danger document_delete_button">
Delete Checked
</button>
</fieldset>
</div>
<button type="submit" class="btn btn-primary control">
Add Candidate
</button>
}
}
editForm.scala.html(view)
@(id: Long, candidateForm: Form[Candidate], candidate: Candidate)
@import helper._
@main("Edit Candidate") {
<h1>Edit Candidate</h1>
@form(routes.Application.update(id), args= 'class -> "form-horizontal",'enctype -> "multipart/form-data", 'id -> "updateForm") {
<div class="row">
<fieldset class="span6">
<legend>
<h3> Edit Candidate Info</h3>
</legend>
@inputText(candidateForm("firstName"), '_label -> "First Name")
@inputText(candidateForm("lastName"), '_label -> "Last Name")
@checkbox(candidateForm("sponsorshipStatus"), '_label -> "Sponsorship Status")
@checkbox(candidateForm("proceedToInterview"), '_label -> "Proceed to Interview")
@textarea(candidateForm("text"), args = 'rows -> 3, 'cols -> 50, '_label -> "Notes")
</fieldset>
<fieldset class="span6">
<legend>
<h3>Add Schools</h3>
</legend>
<div id="schools" class="control-group">
<div class="school hidden_form_default">
<input id="chk_school" type="checkbox">
<input disabled="disabled" id="school" name="schools[].schoolName" placeholder="Enter School">
</div>
@for(school <- candidate.schools) {
<div class="school">
<input id="chk_school_@school.id" type="checkbox" value="@school.id">
<input id="school_@school.id" name="schools[@school.id].schoolName" value="@school.schoolName" placeholder="Enter School" >
<input type="hidden" id="schoolId_@school.id" class="" name="schools[@school.id].id" value="@school.id">
</div>
}
<div class="school new_field_div">
<input id="chk_school_0" type="checkbox" value="1">
<input id="school_0" name="schools[0].schoolName" placeholder="Enter School" >
</div>
</div>
<button class="btn school_add_button">
Add Another
</button>
<button class="btn btn-danger school_delete_button">
Delete Checked
</button>
</fieldset>
</div>
<div class="row">
<fieldset class="span6">
<legend>
<h3>Add Degrees</h3>
</legend>
<div id="degrees" class="control-group">
<div class="degree hidden_form_default">
<input id="chk_degree" class="" type="checkbox" value="1">
<input id="degreeLevel" disabled="disabled" class="" name="degrees[].degreeLevel" placeholder="Degree Level" >
<input id="degreeFocus" disabled="disabled" class="" name="degrees[].degreeFocus" placeholder="Degree Focus" >
<input type="text" id="completedDate" disabled="disabled" class="datepicker input-small" name="degrees[].completedDate" placeholder="Completed" >
</div>
@for(degree <- candidate.degrees) {
<div class ="degree">
<input id="chk_degree_@degree.id" class="" type="checkbox" value="@degree.id">
<input id="degreeLevel_@degree.id" class="" name="degrees[@degree.id].degreeLevel" value="@degree.degreeLevel" placeholder="Degree Level" >
<input id="degreeFocus_@degree.id" class="" name="degrees[@degree.id].degreeFocus" value="@degree.degreeFocus" placeholder="Degree Focus" >
<input type="hidden" id="degreeId_@degree.id" class="" name="degrees[@degree.id].id" value="@degree.id">
<input type="text" id="completedDate_@degree.id" class="datepicker input-small" name="degrees[@degree.id].completedDate" value="@degree.completedDate" placeholder="Completed" >
</div>
}
<div class ="degree new_field_div">
<input id="chk_degree_0" class="" type="checkbox" value="1">
<input id="degreeLevel_0" class="" name="degrees[0].degreeLevel" placeholder="Degree Level" >
<input id="degreeFocus_0" class="" name="degrees[0].degreeFocus" placeholder="Degree Focus" >
<input type="text" id="completedDate_0" class="datepicker input-small" name="degrees[0].completedDate" placeholder="Completed" >
</div>
</div>
<button class="btn degree_add_button">
Add Another
</button>
<button class="btn btn-danger degree_delete_button">
Delete Checked
</button>
</fieldset>
<fieldset class="span6">
<legend>
<h3>Add Skills</h3>
</legend>
<div id="skills" class="control-group">
<div class="skill hidden_form_default">
<input id="chk_skill" type="checkbox">
<input disabled="disabled" id="skill" name="skills[].skill" class="clearMeFocus" placeholder="Enter skill">
</div>
@for(skill <- candidate.skills) {
<div class="skill">
<input id="chk_skill_@skill.id" type="checkbox" value="@skill.id">
<input id="skill_@skill.id" name="skills[@skill.id].skill" class="clearMeFocus" value="@skill.skill" placeholder="Enter skill" >
<input type="hidden" id="skillId_@skill.id" class="" name="skills[@skill.id].id" value="@skill.id">
</div>
}
<div class="skill new_field_div">
<input id="chk_skill_0" type="checkbox" value="1">
<input id="skill_0" name="skills[0].skill" class="clearMeFocus" placeholder="Enter skill" >
</div>
</div>
<button class="btn skill_add_button">
Add Another
</button>
<button class="btn btn-danger skill_delete_button">
Delete Checked
</button>
</fieldset>
</div>
<div class="row">
<fieldset class="span6">
<legend>
<h3>Add Desired Positions</h3>
</legend>
<div id="positions" class="control-group">
<div class="position hidden_form_default">
<input id="chk_position" class="" type="checkbox" value="1">
<input id="position" disabled="disabled" class="" name="jobPositions[].position" placeholder="Enter Position" >
</div>
@for(position <- candidate.jobPositions) {
<div class="position">
<input id="chk_position_@position.id" class="" type="checkbox" value="@position.id">
<input id="positionLevel_@position.id" class="" name="jobPositions[@position.id].position" value="@position.position" placeholder="Enter Position" >
<input type="hidden" id="positionId_@position.id" class="" name="jobPositions[@position.id].id" value="@position.id">
</div>
}
<div class="position new_field_div">
<input id="chk_position_0" class="" type="checkbox" value="1">
<input id="positionLevel_0" class="" name="jobPositions[0].position" placeholder="Enter Position" >
</div>
</div>
<button class="btn position_add_button">
Add Another
</button>
<button class="btn btn-danger position_delete_button">
Delete Checked
</button>
</fieldset>
<fieldset class="span6">
<legend>
<h3>Add Documents</h3>
</legend>
<div id="documents" class="control-group">
<div class="document hidden_form_default">
<input id="chk_document" type="checkbox">
<input type="file" disabled="disabled" id="document" name="documents[]">
</div>
@for(document <- candidate.documents) {
<div class="document">
<input id="chk_document_@document.id" type="checkbox" value="@document.id">
<input type="hidden" id="documentId_@document.id" class="" name="documents[@document.id].id" value="@document.id">
<p>@document.docName</p>
</div>
}
<div class="document new_field_div">
<input id="chk_document_0" type="checkbox" value="1">
<input id="document_0" type="file" name="documents[0]" >
</div>
</div>
<button class="btn document_add_button">
Add Another
</button>
<button class="btn btn-danger document_delete_button">
Delete Checked
</button>
</fieldset>
</div>
<div class="actions">
<input type="submit" value="Save this Candidate" class="btn primary">
or <a href="@routes.Application.list()" class="btn">Cancel</a>
</div>
}
}
main.js:
$(function () {
var delete_form_url = "/school/delete"
add_another_form_field('.school_add_button', '.school', '#schools', 'schoolName', '.school_delete_button', delete_form_url);
add_another_form_field('.degree_add_button', '.degree', '#degrees', 'degreeName', '.degree_delete_button', delete_form_url);
add_another_form_field('.skill_add_button', '.skill', '#skills', 'skillName', '.skill_delete_button', delete_form_url);
add_another_form_field('.position_add_button', '.position', '#positions', 'positionName', '.position_delete_button', delete_form_url);
add_another_form_field('.document_add_button', '.document', '#documents', 'documentName', '.document_delete_button', delete_form_url);
$('.datepicker').datepicker();
$("#updateForm").submit(function (event) {
$(".new_field_div").each(function () {
var isNull = false;
var new_field_inputs = $(this).find("input:text");
new_field_inputs.each(function (index, element) {
console.log($(element).val());
if ($(element).val()) {
isNull = false;
return false;
} else {
isNull = true;
}
});
if (isNull) {
$(this).remove();
}
});
});
});
function add_another_form_field(add_button_class, child_div_class, parent_element_id, field_name, delete_button_class, delete_form_url) {
var num = 1;
$(add_button_class).on("click", function (event) {
event.preventDefault();
var cloned_fields = $(child_div_class + ":first").clone();
console.log(cloned_fields);
cloned_fields.find('input,textarea,select').attr('id', function (i, val) {
if (val !== undefined) {
return val + '_' + num;
}
});
cloned_fields.find('label').attr('for', function (i, val) {
if (val !== undefined) {
return val + '_' + num;
}
});
cloned_fields.find('input,textarea,select').attr('name', function (i, val) {
if (val !== undefined) {
return val.replace(/\[\]/, "[" + num + "]");
}
});
cloned_fields.removeClass("hidden_form_default");
cloned_fields.addClass("new_field_div");
cloned_fields.find('input').prop('disabled', false);
cloned_fields.appendTo(parent_element_id);
num++;
// clear the new inputs on click
// clear input on focus
$(".clearMeFocus").focus(function () {
if ($(this).val() == $(this).attr("title")) {
clearMePrevious = $(this).val();
$(this).val("");
}
});
// if field is empty afterward, add text again
$(".clearMeFocus").blur(function () {
if ($(this).val() == "") {
$(this).val(clearMePrevious);
}
});
});
$(delete_button_class).click(function (event) {
event.preventDefault();
var form = $(this).parents('form');
var table_name = form.find('input[name="table_name"]').val();
$(child_div_class).find('input[type="checkbox"]:checked:enabled').each(function (index, child) {
table_row_id = $(child).val();
if (table_row_id) {
$.post(delete_form_url, {
table_name: table_name,
table_row_id: table_row_id
});
}
// delete from view
$(child).parents().remove(child_div_class);
});
});
}
Candidate.java(模型):
@实体
公共类候选扩展模型{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
公共长id;
公共字符串名;
公共字符串lastName;
公共赞助地位;
公共布尔过程交互;
@列(columnDefinition=“TEXT”)
公共字符串文本;
@OneToMany(级联=级联类型.ALL)
公立学校名单;
@OneToMany(级联=级联类型.ALL)
公开名单学位;
@OneToMany(级联=级联类型.ALL)
公开名单文件;
@OneToMany(级联=级联类型.ALL)
公开列出职位名单;
@OneToMany(级联=级联类型.ALL)
公开名单技能;
/**
*id为Long的实体候选的通用查询帮助程序
*/
公共静态Model.Finder=newmodel.Finder(Long.class,Candidate.class);
公共静态页面(整型页面、整型页面大小、字符串排序、字符串顺序、字符串筛选器){
返回find.where()
.ilike(“名字,“%”+过滤器+“%”)
.orderBy(排序方式+“”+订单)
.findPagingList(页面大小)
.setFetchAhead(false).getPage(第页);
}
}
School.java(模型):
@实体
公营学校扩展模式{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
公共长id;
公共字符串学名;
@许多酮
公众候选人;
/**
*id为Long的实体公司的通用查询帮助程序
*/
public static Model.Finder=new Model.Finder(
长时间上课,学校上课);
}
Application.java(控制器):
公共类应用程序扩展控制器{
公共静态结果索引(){
返回ok(index.render(“新应用程序准备就绪”);
}
/*显示糖果列表*/
公共静态结果列表(整型页面、字符串排序、字符串顺序、字符串筛选器){
返回ok(views.html.list.render(Candidate.page(page,10,sortBy,order,filter),sortBy,order,filter));
}
/**
*显示现有候选人的“编辑表单”。
*
*@param-id
*要编辑的候选人的Id
*/
公共静态结果编辑(长id){
表单candidateForm=表单(Candidate.class).fill(Candidate.find.byId(id));
候选对象=候选对象.find.byId(id);
返回ok(views.html.editForm.render(id,candidateForm,candidateForm));
}
/**
*处理“编辑表单”提交
*
*@param-id
*要编辑的计算机的Id
*/
公共静态结果更新(长id){
RequestBody request_body=request().body();
MultipartFormData body=请求_body.asMultipartFormData();
//MultipartFormData文件部件对象列表
List files=body.getFiles();
列表文档=新建ArrayList();
用于(文件部分文件:文件){
字符串fileName=file.getFilename();
//使用Java.IO File类将文件移动到所需位置
File f=File.getFile();
文件nf=新文件(“\\\\WL-MSAMARITONI\\Images”,文件名);
f、 重命名(nf);
文件文件;
doc=新文档();
doc.docName=文件名;
doc.filePath=nf.getAbsolutePath();
docs.add(doc);
}
Form candidateForm=Form(Candidate.class).bindFromRequest();
候选updateCandidate=candidateForm.get();
updateCandidate.documents=单据;
/*while(updateCandidate.degrees.remove(null));
while(updateCandidate.jobPositions.remove(null));
while(updateCandidate.schools.remove(null));
while(updateCandidate.skills.remove(null));
while(updateCandidate.documents.remove(null));
*/
updateCandidate.update(id);
updateCandidate.save();
flash(“成功”,“候选人”+candidateForm.get().firstName+“已创建”);
返回重定向(“/candidate/”+id);
}
/**
*显示“新候选人表格”。
*/
公共静态结果创建(){
表格candidateForm=表格(Candidate.class);
返回ok(views.html.createForm.render(candidateForm));
}
/**
*处理“新候选人表格”提交
*/
公共静态结果保存(){
RequestBody request_body=request().body();
MultipartFormData body=请求_body.asMultipartFormData();
//MultipartFormData文件部分对象