2017-08-01 72 views
1

我有一種情況,用戶可以動態地向表單添加行,然後通過單擊Submit按鈕來提交這些記錄。爲了更好的可視化,請參閱此處的演示 - http://formvalidation.io/examples/adding-dynamic-field/#adding-fields-with-same-names。問題是Spring沒有將請求綁定到我的Request類。Spring Boot:可以動態添加行的表單的提交

<form id="surveyForm" method="post" class="form-horizontal"> 
    <div class="form-group"> 
     <label class="col-xs-3 control-label">Options</label> 
     <div class="col-xs-5"> 
      <input type="text" class="form-control" name="option[]" /> 
     </div> 
     <div class="col-xs-4"> 
      <button type="button" class="btn btn-default addButton"><i class="fa fa-plus"></i></button> 
     </div> 
    </div> 

    <!-- The option field template containing an option field and a Remove button --> 
    <div class="form-group hide" id="optionTemplate"> 
     <div class="col-xs-offset-3 col-xs-5"> 
      <input class="form-control" type="text" name="option[]" /> 
     </div> 
     <div class="col-xs-4"> 
      <button type="button" class="btn btn-default removeButton"><i class="fa fa-minus"></i></button> 
     </div> 
    </div> 

    <div class="form-group"> 
     <div class="col-xs-5 col-xs-offset-3"> 
      <button type="submit" class="btn btn-default">Validate</button> 
     </div> 
    </div> 
</form> 

<script> 
$(document).ready(function() { 
    // The maximum number of options 
    var MAX_OPTIONS = 5; 

    $('#surveyForm') 
     .formValidation({ 
      framework: 'bootstrap', 
      icon: { 
       valid: 'glyphicon glyphicon-ok', 
       invalid: 'glyphicon glyphicon-remove', 
       validating: 'glyphicon glyphicon-refresh' 
      }, 
      fields: { 
       question: { 
        validators: { 
         notEmpty: { 
          message: 'The question required and cannot be empty' 
         } 
        } 
       }, 
       'option[]': { 
        validators: { 
         notEmpty: { 
          message: 'The option required and cannot be empty' 
         }, 
         stringLength: { 
          max: 100, 
          message: 'The option must be less than 100 characters long' 
         } 
        } 
       } 
      } 
     }) 

     // Add button click handler 
     .on('click', '.addButton', function() { 
      var $template = $('#optionTemplate'), 
       $clone = $template 
           .clone() 
           .removeClass('hide') 
           .removeAttr('id') 
           .insertBefore($template), 
       $option = $clone.find('[name="option[]"]'); 

      // Add new field 
      $('#surveyForm').formValidation('addField', $option); 
     }) 

     // Remove button click handler 
     .on('click', '.removeButton', function() { 
      var $row = $(this).parents('.form-group'), 
       $option = $row.find('[name="option[]"]'); 

      // Remove element containing the option 
      $row.remove(); 

      // Remove field 
      $('#surveyForm').formValidation('removeField', $option); 
     }) 

     // Called after adding new field 
     .on('added.field.fv', function(e, data) { 
      // data.field --> The field name 
      // data.element --> The new field element 
      // data.options --> The new field options 

      if (data.field === 'option[]') { 
       if ($('#surveyForm').find(':visible[name="option[]"]').length >= MAX_OPTIONS) { 
        $('#surveyForm').find('.addButton').attr('disabled', 'disabled'); 
       } 
      } 
     }) 

     // Called after removing the field 
     .on('removed.field.fv', function(e, data) { 
      if (data.field === 'option[]') { 
       if ($('#surveyForm').find(':visible[name="option[]"]').length < MAX_OPTIONS) { 
        $('#surveyForm').find('.addButton').removeAttr('disabled'); 
       } 
      } 
     }); 
}); 
</script> 

我請求類是如下:

public class OptionsRequest implements Serializable { 

    private List<String> options; 

    // getters and setters 
} 

控制器類是

@Controller 
@RequestMapping("/register") 
public class RegistrationController { 
@RequestMapping(value = "/registerOptions", method = RequestMethod.POST) 
    public String registerDepartmentsPost(OptionsRequest request) { 
     return "something"; 
    } 
} 

一旦請求提交,的異常堆棧跟蹤是

java.lang.NumberFormatException: For input string: "" 
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:1.8.0_121] 
    at java.lang.Integer.parseInt(Integer.java:592) ~[na:1.8.0_121] 
    at java.lang.Integer.parseInt(Integer.java:615) ~[na:1.8.0_121] 
    at org.springframework.beans.AbstractNestablePropertyAccessor.processKeyedProperty(AbstractNestablePropertyAccessor.java:322) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:275) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:266) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:97) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:834) ~[spring-context-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.validation.DataBinder.doBind(DataBinder.java:730) ~[spring-context-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:197) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:107) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:157) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:126) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:869) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:775) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:86) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:981) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:915) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:881) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855) ~[spring-webmvc-5.0.0.RC3.jar:5.0.0.RC3] 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:105) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) ~[spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE] 
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.0.RC3.jar:5.0.0.RC3] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_121] 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_121] 
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.16.jar:8.5.16] 
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121] 

回答

1

OptionsRequest包含名爲options的列表,因此建立了命名約定。服務器預計在格式接收數據,如

options[0]=value1&options[1]=value2 

但它會獲得

option[]=value1&option[]=value2 

代替。發生這種情況的原因是每個添加的行都包含一個<input>,並且其屬性值爲。

爲了履行慣例,您應該調整您的代碼,以便每行包含索引選項(options[0]options[1],...)作爲其輸入的name屬性值。請取決於this example,而不是您發佈的那個。

+0

太好了。謝謝。我改變了我的表單,以遵循你提到的命名約定,它的工作。 – OneMoreError