编辑现在我知道我的问题是由于this。该链接还提供了解决方案,但我似乎无法弄清楚如何在第二个列表中执行此操作。
我将首先向您展示我正在处理的代码结构。
这是Class MyForm:
public class MyForm extends ValidatorForm {
private List<ADTO> aDTOList;
// getters and setters for aDTOList below
public ADTO getADTO(int index) {
if (aDTOList == null) {
aDTOList = new ArrayList<ADTO>();
}
if (aDTOList.size() - 1 < index) {
while (aDTOList.size() - 1 < index) {
aDTOList.add(new ADTO());
}
}
return aDTOList.get(index);
}
@Override
protected ActionErrors execValidate(ActionMapping mapping, HttpServletRequest request) {
// BODY NOT SHOWN FOR PRIVACY
}
@Override
public void reset(ActionMapping mapping, HttpServletRequest request) {
super.reset(mapping, request);
this.aDTOList = new ArrayList<ADTO>();
}
}
这是ADTO课程:
public class ADTO {
private List<BDTO> bDTOList;
// getters and setters for bDTOList below
}
这是Class BDTO:
public class BDTO {
private String sample1;
private String sample2;
// getters and setters for sample1 and sample2 below
}
我通过这样做成功地在JSP中显示了aDTOList
的内容:
<logic:iterate id="ADTO" name="MyForm" property="aDTOList" indexId="idxRes">
<logic:iterate id="BDTO" name="ADTO" property="bDTOList" indexId="idxLine">
<html:hidden name="BDTO" property="sample1" indexed="true"/>
<html:hidden name="BDTO" property="sample2" indexed="true"/>
</logic:iterate>
</logic:iterate>
现在我的问题是每当我提交bDTOList
内部的形式aDTOList
将全部为null.aDTOList
与我显示的原始列表具有相同的大小,但唯一的区别是bDTOList
中aDTO
的所有元素都为null。如果aDTOList
的大小是2并且每个aDTOList
包含ADTO
,其大小也是2,那么bDTOList
的结构是这样的。
[[null, null],[null, null]]
因此我认为我的问题是我的表格中没有getBDTO
,但我不知道如何实现它。任何人都可以帮助我如何实现它?或者有没有其他方法用原始数据填充bDTOList
?
注意:我不能改变代码的结构和代码只是样本代码
经过几天的研究和修补我的代码后,我终于能够从JSP中检索出值并将其发送回表单。我将发布一个答案以供将来参考。感谢this website我能够知道我的问题的原因并最终找到解决方案。请参阅下面有关我如何解决问题的详细信息。
我发现问题是由于Commons BeanUtils中存在索引属性的问题,如果你使用java.util.List而不是Arrays,那么人们会在Request范围内的ActionForms中获得“index out of range”错误。这就是为什么需要在调用get(int)方法时生成列表的原因。每当调用reset方法时,您还需要重新初始化列表。为此,您需要将此代码粘贴到表单的重置方法中:
public void reset(ActionMapping actionMapping, HttpServletRequest httpServletRequest) {
aDTOList = ListUtils.lazyList(new java.util.ArrayList(), new Factory() {
public Object create() {
return buildADTOList();
}
});
}
private ADTO buildADTOList() {
ADTO aDTO = new ADTO();
List bDTOList = ListUtils.lazyList(new java.util.ArrayList(), new Factory() {
public Object create() {
return new BDTO();
}
});
aDTO.setBDTOList(bDTOList);
return aDTO;
}
现在,无论何时调用重置方法,您的列表都将重新生成其原始大小。接下来的问题是如何从JSP中检索值并将它们放回列表中。要做到这一点,您必须注意JSP标记的结果html名称属性的值必须采用这种格式aDTOList[0].bDTOList[0].sample1
。但是如果你使用标签(正如问题所使用的那样),生成的html的值将如下所示:示例:
<logic:iterate id="ADTO" name="MyForm" property="aDTOList" indexId="idxRes">
<logic:iterate id="BDTO" name="ADTO" property="bDTOList" indexId="idxLine">
<html:hidden name="BDTO" property="sample1" indexed="true"/>
<html:hidden name="BDTO" property="sample2" indexed="true"/>
</logic:iterate>
</logic:iterate>
这将导致:
<input type="hidden" name="BDTO[0].sample1" value="..."/>
<input type="hidden" name="BDTO[0].sample2" value="..."/>
<input type="hidden" name="BDTO[1].sample1" value="..."/>
<input type="hidden" name="BDTO[1].sample2" value="..."/>
<input type="hidden" name="BDTO[0].sample1" value="..."/>
<input type="hidden" name="BDTO[0].sample2" value="..."/>
<input type="hidden" name="BDTO[1].sample1" value="..."/>
<input type="hidden" name="BDTO[1].sample2" value="..."/>
结果不是aDTOList[0].bDTOList[0].sample1
格式,因此您需要使用<nested:iterate>
。
转换后的代码将是:
<nested:iterate property="aDTOList" indexId="idxRes">
<nested:iterate property="bDTOList" indexId="idxLine">
<nested:hidden property="sample1"/>
<nested:hidden property="sample2"/>
</nested:iterate>
</nested:iterate>
这将导致:
<input type="hidden" name="aDTOList[0].bDTOList[0].sample1" value="..."/>
<input type="hidden" name="aDTOList[0].bDTOList[0].sample2" value="..."/>
<input type="hidden" name="aDTOList[0].bDTOList[1].sample1" value="..."/>
<input type="hidden" name="aDTOList[0].bDTOList[1].sample2" value="..."/>
<input type="hidden" name="aDTOList[1].bDTOList[0].sample1" value="..."/>
<input type="hidden" name="aDTOList[1].bDTOList[0].sample2" value="..."/>
<input type="hidden" name="aDTOList[1].bDTOList[1].sample1" value="..."/>
<input type="hidden" name="aDTOList[1].bDTOList[1].sample2" value="..."/>
正如你所看到的那样是aDTOList[0].bDTOList[0].sample1
格式。
从中您可以从JSP检索嵌套列表的值并将其发送回表单。我希望这可以作为那些长期坚持解决这类问题的人的指南。
从您提供的链接,您正在使用Struts 1.以下是我在项目中的操作方法:
形成
与您的代码类似,在容器操作表单中声明一个List
。并且需要为列表添加一个额外的重要配置,需要覆盖reset
的ActionForm
方法以启动带有空对象的List
。 reset
代码如下:
// Form Class
....
// Declare the list
private List<DetailDto> details = new ArrayList<>();
....
// Reset Method
private Pattern detailParameterPattern = Pattern.compile("details\\[(\\d+)\\].*");
private static final int FIRST_GROUP_INDEX = 1;
@Override
public void reset(ActionMapping actionMapping, HttpServletRequest request) {
super.reset(actionMapping, request);
Enumeration<String> paramNames = request.getParameterNames();
int maxSize = 0;
boolean matched = false;
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
Matcher detailMatcher = detailParameterPattern.matcher(paramName);
if (detailMatcher.matches()) {
matched = true;
String index = detailMatcher.group(FIRST_GROUP_INDEX);
if (Integer.parseInt(index) > maxSize) {
maxSize = Integer.parseInt(index);
}
}
}
if (matched) {
for (int i = 0; i <= maxSize; i++) {
details.add(new DetailDto());
}
}
}
JSP
Struts indexed
标签有html
属性。使用JSTL forEach
标记,声明items
和变量,变量名称应该有点棘手,它应该与您在表单中声明的名称相同。代码如下所示:
<c:forEach items="${form.details}" varStatus="detailsStatus" var="details">
<tr>
<td class="resultCell">${detailsStatus.index+1}</td>
<td class="resultCell">
<html:checkbox name="details" property="checked" indexed="true" value="Y"/>
....
...
其他值映射由Struts框架自动完成。
这里的关键是你需要用对象而不是空的List
(或Array
)启动List
(或Array
),因为Struts不能为它创建对象。