调试Spring MVC集合绑定

时间:2012-04-26 17:32:25

标签: forms debugging spring-mvc binding collections

我有一个非常简单的用户设置表单:

<form:form method="post" id="fm1" cssClass="fm-v clearfix" commandName="${commandName}" htmlEscape="true">
  <div class="row fl-controls-left">
    <spring:message code="screen.userSettings.label.timeZone.accesskey" var="timeZoneAccessKey" />
    <label for="timeZone" class="fl-label"><spring:message code="screen.userSettings.label.timeZone" /></label>
    <form:select id="timeZone" path="timeZone" accesskey="${timeZoneAccessKey}">
      <form:options items="${user.supportedTimeZones}" itemLabel="label" itemValue="id" />
    </form:select>

    <c:forEach items="${user.answers}" var="answer" varStatus="loop">
      <div class="row fl-controls-left">
        <form:select path="answers[${loop.index}].questionId">
          <option value="-1"><spring:message code="screen.userSettings.question.selectOne" /></option>
          <form:options items="${user.supportedQuestions}" itemLabel="question" itemValue="id" />
        </form:select>
        <form:input path="answers[${loop.index}].answer" size="30" autocomplete="false" htmlEscape="true" type="text" cssClass="required" cssErrorClass="error"/>
      </div>
    </c:forEach>
  </div>
</form:form>

基本上,您可以设置时区,并提供列表忘记密码问题的答案。绑定到此表单的模型对象基本上是这样的:

public class User implements Serializable {
    private static final long serialVersionUID = 8974875234954842283L;

    private List<Answer> answers;
    private List<Question> supportedQuestions;
    private List<TimeZone> supportedTimeZones;
    private String timeZone;

    public User() {
        credentials = new UsernamePasswordCredentials();
    }

    public List<Answer> getAnswers() {
        return answers;
    }

    public List<Question> getSupportedQuestions() {
        return supportedQuestions;
    }

    public List<TimeZone> getSupportedTimeZones() {
        return supportedTimeZones;
    }

    public String getTimeZone() {
        return timeZone;
    }

    public void setAnswers( List<Answer> answers ) {
        this.answers = answers;
    }

    public void setSupportedQuestions( List<Question> supportedQuestions ) {
        this.supportedQuestions = supportedQuestions;
    }

    public void setSupportedTimeZones( List<TimeZone> supportedTimeZones ) {
        this.supportedTimeZones = supportedTimeZones;
    }

    public void setTimeZone( String timeZone ) {
        this.timeZone = timeZone;
    }

    ...
}

表格显示得很好。它提供了一个下拉列表,显示了所有支持的时区,后面跟着几行问题/答案对,问题是包含所有支持问题的下拉列表。当我提交表单时,处理失败,因为List<Answer> answers未使用表单中的值进行更新。我的问题是双重的,首先,我做错了什么?其次,我将来如何处理这种类型的映射问题呢?

我尝试使用调试器逐步执行代码。使用表单中的值调用setTimeZone()方法,但setAnswers()方法不是。 setQuestionId()类的setAnswer()Answer方法也不是。{1}}或Request类。我查看了answer[x].questionId对象,它包含所有answer[x].answermap[ 'answers[4].questionId' -> 'cn=honeymoon,ou=questions,dc=company' 'answers[2].questionId' -> 'cn=honeymoon,ou=questions,dc=company' 'answers[0].questionId' -> 'cn=firstPet,ou=questions,dc=company' 'lt' -> 'LT-786e9b77-efbd-f302-062e-90364cc4634aZe1s2' 'answers[1].answer' -> 'qwer' 'answers[3].answer' -> 'poiu' 'submit' -> 'Save' 'answers[3].questionId' -> 'cn=honeymoon,ou=questions,dc=company' 'answers[1].questionId' -> 'cn=mothersMaiden,ou=questions,dc=company' 'answers[2].answer' -> 'zxcv' 'answers[4].answer' -> 'lkjh' 'timeZone' -> 'America/New_York' '_eventId' -> 'submit' 'answers[0].answer' -> 'asdf' ] 参数的键,但不确定值是什么。您建议如何追踪此类问题?

-------------------------- UPDATE -------------------- ------------

我刚从调试器中取出它:

answers

它是requestParameterMap中包含的内容。显然,它显示questionIdanswersetAnswers())都返回了值。为什么Spring没有在模型对象上调用setTimeZone()(请记住{{1}} 调用)?

1 个答案:

答案 0 :(得分:1)

这是viewState中绑定器的问题。看起来这应该有效:

<binder>
  <binding property="answers" />
  <binding property="timeZone" />
</binder>

因为answers是绑定模型对象的属性。但是,我实际上必须指定列表中元素的属性:

<binder>
  <binding property="answers[0].questionId" />
  <binding property="answers[0].answer" />
  <binding property="answers[1].questionId" />
  <binding property="answers[1].answer" />
  <binding property="answers[2].questionId" />
  <binding property="answers[2].answer" />
  <binding property="answers[3].questionId" />
  <binding property="answers[3].answer" />
  <binding property="answers[4].questionId" />
  <binding property="answers[4].answer" />
  <binding property="timeZone" />
</binder>

对我来说,这将有效(现在),因为我有一个固定大小的元素数量。必须包含列表中每个元素的每个属性都有点痛苦,但它确实有效。有bugs/feature requests提交此文件应该会更容易,但在那之前......