Retrieve the values of a nested list from JSP and send it back to form

大兔子大兔子 提交于 2019-12-08 07:55:32

问题


EDIT Now I know my problem is due to this. The link also provided solutions but I can't seem to figure out how to do it in the 2nd list.

I will first show you the code structure I am working on.

Here is 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>();
    }


}

Here is Class ADTO:

public class ADTO {
    private List<BDTO> bDTOList;
    // getters and setters for bDTOList below

}

Here is Class BDTO:

public class BDTO {
    private String sample1;
    private String sample2;
    // getters and setters for sample1 and sample2 below

}

I have successfully displayed the contents of aDTOList in the JSP by doing this:

<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>

Now my problem is whenever I submit the form bDTOList that is inside aDTOList will become all null.aDTOList has the same size as the original list I have displayed but the only difference is that all elements of bDTOList in a aDTO is null. The structure of the aDTOList is like this if the size of aDTOList is 2 and each ADTO contains bDTOList which also has the size of 2.

[[null, null],[null, null]]

Thus I think my problem is I do not have getBDTO in my form, but I don't know how to implement it. Can anyone help me on how to implement it? Or is there any other means of populating bDTOList with the original data?

NOTE: I CAN'T CHANGE THE STRUCTURE OF THE CODES AND THE CODES ARE JUST SAMPLE CODES


回答1:


After days of research and tinkering my code I finally was able to retrieve back the values from the JSP and send it back to form. I will just post an answer for future reference. Thanks to this website I was able to know the cause of my problem and eventually made a solution to solve it. Refer below on the details on how I solved my problem.

I found out that the problem is due to an issue in Commons BeanUtils with indexed properties if you use java.util.List rather than Arrays is that people then get "index out of range" errors with ActionForms that are in Request scope. That is why growing the list when the get(int) method is called is needed to be done. Also you need to reinitialize the list whenever the reset method is called. To do this you need to paste this code in the reset method of the form:

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;
}

Now your whenever the reset method is called your list will regrow to its original size. The next problem is now how to retrieve back the values from the JSP and place them back in the list. To do this you have to take note of that the value of the resulting html name attribute of your JSP tag must be in this format aDTOList[0].bDTOList[0].sample1. But if you use tag (just as the question was using), the value of the resulting html will look like this: Example:

<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>

This will result into:

<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="..."/>

The result is not in aDTOList[0].bDTOList[0].sample1 format thus you need to use <nested:iterate>.
The converted code will be:

<nested:iterate property="aDTOList" indexId="idxRes">
    <nested:iterate property="bDTOList" indexId="idxLine">
        <nested:hidden property="sample1"/>
        <nested:hidden property="sample2"/>
    </nested:iterate>
</nested:iterate>

This will result to:

<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="..."/>

As you can see it is in aDTOList[0].bDTOList[0].sample1 format.

And from that you can retrieve the values of a nested list from JSP and send it back to form. I hope this will serve as a guide for those people that have been stuck for days solving this kind of problem.




回答2:


From the link you provided, you are using Struts 1. Here is how I do it in my project:

Form
Similar to your code, declare a List in the container action form. And need one additional important configuration for the list, need to override the reset method of ActionForm to initiate the List with empty objects. The reset code is like below:

// 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
There is a indexed attribute of Struts html tags. With JSTL forEach tag, declare the items and variable, the variable name should be little tricky that it should be same as the name you declared in form. The code looks like below:

<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"/>
....
...

The others value mapping are done automatically by Struts framework.
The key here is that you need to initiate the List(Or Array) with objects instead of empty List(Or Array), because Struts cannot create object for it.



来源:https://stackoverflow.com/questions/55272358/retrieve-the-values-of-a-nested-list-from-jsp-and-send-it-back-to-form

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!