Spring动态(可扩展)列表形式
我在春季遇到动态表单问题。在我们的表单中,我们要指定一个标题, 并添加一些问题。我们有一个“添加”按钮来添加问题输入表单 jquery。
当需要时,我们的表格有一个问题字段。每次都会添加额外的字段 按下“添加”按钮。提交时似乎没有额外的字段 已提交(第一个由控制器收到)。为什么未发送额外字段收到?
我的代码大致基于 这个动态绑定列表示例。
我的模型由一个“Report”类组成,其中有一个 “标题”和“研究问题”列表。
下面是两个模型类的简短版本。 Roo 照顾所有的吸气剂和 setters
@Entity
@RooJavaBean
@RooEntity
public class Report{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@NotEmpty
private String title;
@OneToMany(mappedBy="report")
private List<Researchquestion> researchquestions;
}
@Entity
@RooJavaBean
@RooEntity
public class Researchquestion {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@NotEmpty
private String question;
}
这里是表单的 jspx
<div xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:form="http://www.springframework.org/tags/form"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:spring="http://www.springframework.org/tags"
version="2.0">
<jsp:output omit-xml-declaration="yes"/>
<spring:url value="/admin/report/appendquestion" var="insert_url"/>
<script type="text/javascript">
$(document).ready(function() {
var questionPosition = 0;
$("#addQuestionButton").click(function() {
questionPosition++;
$.get("${insert_url}", { fieldId: questionPosition},
function(data){
$("#insertAbove").before($(data));
});
});
});
</script>
<div class="list_overview_box span-19">
<spring:url value="/admin/report/" var="form_url"/>
<div class="list_overview_content">
<table>
<form:form action="${form_url}" method="post" modelAttribute="report">
<tr>
<th class="span-3">Veld</th>
<th>Waarde</th>
<th class="span-5">Errors</th>
</tr>
<!-- Title -->
<tr class="row">
<td class="vmiddle aleft">Title</td>
<td><form:input path="title" /></td>
<td></td>
</tr>
<!-- the "add" button -->
<tr class="row">
<td class="vmiddle aleft">Researchquestions</td>
<td colspan="2"><input type="button" id="addQuestionButton" value="Add question" /></td>
</tr>
<!-- First Researchquestion -->
<spring:bind path="researchquestions[0].question">
<tr class="row">
<td class="vmiddle aleft">Question 1</td>
<td><form:input path="${status.expression}" /></td>
<td></td>
</tr>
</spring:bind>
<!-- Save button, extra question's are added here -->
<tr id="insertAbove" class="row">
<spring:message code="button.save" var="form_submit"/>
<td colspan="3"><input id="proceed" type="submit" value="${form_submit}" /></td>
</tr>
</form:form>
</table>
</div>
</div>
</div>
下面是控制器在 jquery .get 请求后返回的页面 我的想法是我需要使用
就像上面的表单一样。 然而,当我这样做时,我收到错误:
java.lang.IllegalStateException:既不是 BindingResult 也不是普通的 bean 名称“researchquestions[1]”的目标对象可根据请求提供 属性
这里是我们控制器中相关的@ModelAttribute
<jsp:root version="2.0"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:tiles="http://tiles.apache.org/tags-tiles"
xmlns:form="http://www.springframework.org/tags/form"
xmlns:spring="http://www.springframework.org/tags"
xmlns:roo="urn:jsptagdir:/WEB-INF/tags" >
<tr class="row">
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<td class="vmiddle aleft">Question ${questionNumber +1}</td>
<td>
<form:input path="report.researchquestions[${questionNumber}].question" size="40" />
</td>
<td></td>
</tr>
</jsp:root>
和@requestmapping方法 @ModelAttribute 方法确保实例中的 List AutoPopulateList,我不太确定这是否是必需的。
如果我将 @RequestParam Map formdata
添加到 create()
(POST) 方法,那么 formdata 就会 包含 researchquestions[0].question
但不包含 researchquestions\[1\].question
或任何其他问题字段 按“添加”按钮后添加的
@ModelAttribute("report")
public Report getReport(Long id) {
Report result;
if(id != null){
result = Report.findReport(id);
} else{
result = new Report();
}
//Make sure the List in result is an AutoPopulatingList
List<Researchquestion> vragen = result.getResearchquestions();
if(vragen == null){
result.setResearchquestions(new AutoPopulatingList<Researchquestion>(Researchquestion.class));
} else if(!(vragen instanceof AutoPopulatingList)){
result.setResearchquestions(new AutoPopulatingList<Researchquestion>(
vragen, Researchquestion.class));
}
return result;
}
/**
* Aanmaken Report
* @param report
* @param result
* @param modelMap
* @return
*/
@RequestMapping(method = RequestMethod.POST)
public String create(@Valid @ModelAttribute("report") Report report,
BindingResult result, ModelMap modelMap) {
if (report == null) throw new InvalidBeanException("A report is required");
if (result.hasErrors()) {
modelMap.addAttribute("report", report);
return "admin/report/create";
}
report.persist();
//create questions
for(Researchquestion question : report.getResearchquestions()){
question.setProfielwerkstuk(report);
question.persist();
}
report.merge();
return "redirect:/admin/report";
}
@RequestMapping(value = "/appendquestion", method = RequestMethod.GET)
public String appendResearchquestionField(@RequestParam Integer fieldId, ModelMap modelMap){
modelMap.addAttribute("questionNumber", fieldId);
return "admin/report/appendquestion";
}
其他信息(根据 Ralph 的要求)
在 Spring 生成的 HTML 下方,researchquestions[0].question 默认采用以下形式:researchquestions[1]按“添加”按钮后将添加问题,
<tr class="row">
<td class="vmiddle aleft">Question 1</td>
<td>
<input id="researchquestions0.question" type="text" value=""
name="researchquestions[0].question">
</td>
<td></td>
</tr>
<tr class="row">
<td class="vmiddle aleft">Question 2</td>
<td>
<input id="researchquestions1.question" type="text" size="40" value="" name="researchquestions[1].question">
</td>
<td></td>
</tr>
位于实时 HTTP 标头的相关信息下方
我在“标题”字段中询问了“这是标题”,在“问题1”字段中询问了“这是第一个问题”,在“问题2”字段中询问了“这是第二个问题”(已添加)按“添加”按钮,
0].question 正在提交,但在 POST 请求中根本没有提交researchquestions[1].question。
Content-Type: application/x-www-form-urlencoded
Content-Length: 73
title=This+is+the+title&researchquestions%5B0%5D.question=This+is+the+first+question
很明显,researchquestions [ 第一个问题(默认形式)与后续问题的区别在于第一个问题使用
而后续问题则不使用。当我删除第一个问题的
标签时,researchquestions[0] 也不会提交。
正如我上面所解释的,在将
添加到appendquestion.jspx 时,我收到了 IllegalStateException。看来spring搜索对象researchquestions[1]
而不是 report.researchquestions[1]
java.lang.IllegalStateException:既不是 BindingResult 也不是普通的 bean 名称“researchquestions[1]”的目标对象可根据请求提供 属性
I am having problems with dynamic forms in spring. In our form we want to specify a title,
and add a number of questions. We have an "add" button to add question input form using
jquery.
Our form has one question field when it is requested. Extra fields are added every time
the "add" button is pressed. When submitting it seems that the extra fields are not being
submitted (the first one is received by the controller). Why are the extra fields not received being sent?
I roughly based my code on this dynamic binding list example.
My model consists of a class "Report" which has a
"title" and a list of "Researchquestion"s.
A short version of the two model classes is below. Roo takes care of all the getters and
setters
@Entity
@RooJavaBean
@RooEntity
public class Report{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@NotEmpty
private String title;
@OneToMany(mappedBy="report")
private List<Researchquestion> researchquestions;
}
@Entity
@RooJavaBean
@RooEntity
public class Researchquestion {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@NotEmpty
private String question;
}
Here the jspx for the form
<div xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:form="http://www.springframework.org/tags/form"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:spring="http://www.springframework.org/tags"
version="2.0">
<jsp:output omit-xml-declaration="yes"/>
<spring:url value="/admin/report/appendquestion" var="insert_url"/>
<script type="text/javascript">
$(document).ready(function() {
var questionPosition = 0;
$("#addQuestionButton").click(function() {
questionPosition++;
$.get("${insert_url}", { fieldId: questionPosition},
function(data){
$("#insertAbove").before($(data));
});
});
});
</script>
<div class="list_overview_box span-19">
<spring:url value="/admin/report/" var="form_url"/>
<div class="list_overview_content">
<table>
<form:form action="${form_url}" method="post" modelAttribute="report">
<tr>
<th class="span-3">Veld</th>
<th>Waarde</th>
<th class="span-5">Errors</th>
</tr>
<!-- Title -->
<tr class="row">
<td class="vmiddle aleft">Title</td>
<td><form:input path="title" /></td>
<td></td>
</tr>
<!-- the "add" button -->
<tr class="row">
<td class="vmiddle aleft">Researchquestions</td>
<td colspan="2"><input type="button" id="addQuestionButton" value="Add question" /></td>
</tr>
<!-- First Researchquestion -->
<spring:bind path="researchquestions[0].question">
<tr class="row">
<td class="vmiddle aleft">Question 1</td>
<td><form:input path="${status.expression}" /></td>
<td></td>
</tr>
</spring:bind>
<!-- Save button, extra question's are added here -->
<tr id="insertAbove" class="row">
<spring:message code="button.save" var="form_submit"/>
<td colspan="3"><input id="proceed" type="submit" value="${form_submit}" /></td>
</tr>
</form:form>
</table>
</div>
</div>
</div>
Below is the page the controller returns after the jquery .get request
I have the idea that I need to use <spring:bind>
just like in the form above.
When I do this however I get an error:
java.lang.IllegalStateException: Neither BindingResult nor plain
target object for bean name 'researchquestions[1]' available as request
attribute
appendquestion.jspx
<jsp:root version="2.0"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:tiles="http://tiles.apache.org/tags-tiles"
xmlns:form="http://www.springframework.org/tags/form"
xmlns:spring="http://www.springframework.org/tags"
xmlns:roo="urn:jsptagdir:/WEB-INF/tags" >
<tr class="row">
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<td class="vmiddle aleft">Question ${questionNumber +1}</td>
<td>
<form:input path="report.researchquestions[${questionNumber}].question" size="40" />
</td>
<td></td>
</tr>
</jsp:root>
Here the relevant @ModelAttribute and @requestmapping methods in our controller
The @ModelAttribute method makes sure that the List in an instance of
AutoPopulatingList, I am not really sure if this is required though.
If I add @RequestParam Map formdata
to the create()
(POST) method then the formdata does
contain researchquestions[0].question
but not researchquestions\[1\].question
or any other question fields
that have been added after pressing the "add" button
@ModelAttribute("report")
public Report getReport(Long id) {
Report result;
if(id != null){
result = Report.findReport(id);
} else{
result = new Report();
}
//Make sure the List in result is an AutoPopulatingList
List<Researchquestion> vragen = result.getResearchquestions();
if(vragen == null){
result.setResearchquestions(new AutoPopulatingList<Researchquestion>(Researchquestion.class));
} else if(!(vragen instanceof AutoPopulatingList)){
result.setResearchquestions(new AutoPopulatingList<Researchquestion>(
vragen, Researchquestion.class));
}
return result;
}
/**
* Aanmaken Report
* @param report
* @param result
* @param modelMap
* @return
*/
@RequestMapping(method = RequestMethod.POST)
public String create(@Valid @ModelAttribute("report") Report report,
BindingResult result, ModelMap modelMap) {
if (report == null) throw new InvalidBeanException("A report is required");
if (result.hasErrors()) {
modelMap.addAttribute("report", report);
return "admin/report/create";
}
report.persist();
//create questions
for(Researchquestion question : report.getResearchquestions()){
question.setProfielwerkstuk(report);
question.persist();
}
report.merge();
return "redirect:/admin/report";
}
@RequestMapping(value = "/appendquestion", method = RequestMethod.GET)
public String appendResearchquestionField(@RequestParam Integer fieldId, ModelMap modelMap){
modelMap.addAttribute("questionNumber", fieldId);
return "admin/report/appendquestion";
}
Additional info (as requested by Ralph)
Below the HTML that Spring generates, researchquestions[0].question is in the form by default, researchquestions[1].question is added after pressing the "add" button
<tr class="row">
<td class="vmiddle aleft">Question 1</td>
<td>
<input id="researchquestions0.question" type="text" value=""
name="researchquestions[0].question">
</td>
<td></td>
</tr>
<tr class="row">
<td class="vmiddle aleft">Question 2</td>
<td>
<input id="researchquestions1.question" type="text" size="40" value="" name="researchquestions[1].question">
</td>
<td></td>
</tr>
Below the relevant info from Live HTTP Headers
I intered "This is the title" in the "title" field, "This is the first question" in the "Question 1" field, and "This is the second question" in the "Question 2" field (which has been added by pressing the "add" button.
It is clear that researchquestions[0].question is being submitted, but researchquestions[1].question is not submitted at all in the POST request.
Content-Type: application/x-www-form-urlencoded
Content-Length: 73
title=This+is+the+title&researchquestions%5B0%5D.question=This+is+the+first+question
My suspicions
The difference between the first question (that is in the form by default) and the subsequent questions is that the first question uses <spring:bind>
and the subsequent ones do not. When I remove the <spring:bind>
tag for the first question, the researchquestions[0] is also not submitted.
As I explained above, I get an IllegalStateException when adding the <spring:bind>
to the appendquestion.jspx. It seems that spring searches for the object researchquestions[1]
instead of report.researchquestions[1]
java.lang.IllegalStateException: Neither BindingResult nor plain
target object for bean name 'researchquestions[1]' available as request
attribute
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我找到了表单未正确提交的原因。我在firebug中注意到以下HTML:
表单标签立即关闭,因此spring生成的HTML不正确。
看来这是因为表单位于表格内部,切换
和
标签解决了该问题。原始代码
工作版本
在
中,只允许使用与表相关的标签,例如
I found the reason why the form was not being submitted correctly. I noticed the following HTML in firebug:
The form tag is closed immediately, so the HTML generated by spring was not correct.
It appears that this was because the form was inside the table switching the
<table>
and<form:form>
tags fixed the issue.Original code
Working version
In a
<table>
it is only allowed to use table related tags such as<tr>
<th>
and<td>
. Which is probably why Spring immediately closed the<form>
tag.