2

考虑以下场景:

  1. 我的表单模型

    public class PersonForm {
        @NotNull
        private String name;
    
        /*usual getters and setters*/
    }
    
  2. 我的控制器:

    @Controller
    @SessionAttribute(types={ PersonForm.class })
    public class MyController {
    
        @RequestAttribute(...)
        public String render(final ModelMap map) {
            /* get list of info and for each info 
             * create a PersonForm and put it in the modelmap
             * under key p0, p1, p2, ..., pn
             */
        }
    
        public String submit(final ModelMap map,
                             @Valid final PersonForm form,
                             final BindingResult result) {
    
            if (result.hasErrors()) {
                // return to page
            } else {
                // do necessary logic and proceed to next page
            }
        }
    }
    
  3. 最后是我的 JSP 视图

    ...
    <c:forEach ...>
        <form:form commandName="p${counter}">
            ... other form:elements and submit button goes here
        </form:form>
    </c:forEach>
    ...
    

如您所见,我正在尝试处理同一类类型的多种形式。提交工作——它让我很好地使用了 submit(...) 方法,验证也是如此。但是重新渲染页面并没有向我显示预期的错误消息!

更糟糕的是——我检查了提交标头中传递的内容,没有任何迹象表明提交了哪个表单,因此无法区分一个表单和另一个表单。这让我相信同一类类型的多种形式是不可能的......

有没有其他方法可以做到这一点(除了 Ajax)?

非常感谢。

4

2 回答 2

2

I managed to get this 'hack' to work. It is as what jelies has recommended so the credit goes all to him.

In simple terms, the concept is to pre-fill your view using the traditional <c:forEach> construct. The tricky part is whenever the 'Submit' button of that respective row is pressed, all of the information must be injected into a hidden form and force-submitted to the Controller. If the screen is rendered again with some errors, the script must be responsible of injecting the values back to the respective rows including the errors.


1) My model

    public class PersonForm {

        private String id;

        @NotNull
        private String name;

        /*usual getters and setters*/
    }

2) My controller

    @Controller
    @SessionAttribute(/* the hidden form name, the person list */)
    public class MyController {

        @RequestAttribute(...)
        public String render(final ModelMap map) {
            /* get list of info and for each info 
             * create a PersonForm and put it in the modelmap
             * under key p0, p1, p2, ..., pn
             */
        }

        public String submit(final ModelMap map,
                             @Valid final PersonForm form,
                             final BindingResult result) {

            if (result.hasErrors()) {
                // return to page
            } else {
                // do necessary logic and proceed to next page
            }
        }
    }

3) My view

    ...

    <form:form commandName="personForm" cssStyle="display: none;">
        <form:hidden path="id"/>
        <form:hidden path="name" />
        <form:errors path="name" cssStyle="display: none;" />
    </form:form>

    ...

    <c:forEach var="p" items="${pList}">
        <input type="text" id="${ p.id }Name" value="${ p.name }" />
        <!-- to be filled in IF the hidden form returns an error for 'name' -->
        <span id="${ p.id }nameErrorSpan"></span>
        <button type="button" value="Submit" onclick="injectValuesAndForceSubmit('${ p.id }');" />
    </c:forEach>

    ...

    <script type="text/javascript">

    injectValuesAndForceSubmit = function(id) {

        $('#id').val( id ); // fill in the hidden form's id
        $('#name').val( $('#'+id+'name').val() ); //fill in the hidden form's name

        $('#personForm').submit(); //submit!
    }



    $(document).ready(function() {

        var id = $('#id').val();    
        if (id.trim().length == 0) {
            //Empty. Nothing to do here as this is a simple render.
        } else {

            //The page seems to be returning from some sort of error ... pre-fill the respective row!
            $('#'+id+'name').val($('#name').val());
            var hiddenNameErrorSpan = $('#name.errors');
            if (hiddenNameErrorSpan) {
                $('#'+id+'nameErrorSpan').text(hiddenNameErrorSpan.html());
            }
        } //else
    }
    </script>

As you can see the view has the hairiest parts -- hopefully it will still proves to be useful for anyone who (unfortunately) comes across the same situation as mine. Cheers!

于 2012-08-14T08:31:17.237 回答
1

IMHO having multiple forms makes things overcomplicated (or at least with spring). Also, you are using multiple forms but only one is going to be submitted.

So, I suggest that the easiest way to manage this is using a unique hidden external form with person properties. When one of the buttons is pressed, fill accordingly the person properties of form and submit it. With this you are achieving the tipical spring form submit/validation.

Maybe this solution requires a bit work with JavaScript, but I don't know how to handle spring-mvc with multiple forms, I always tried to avoid it, due to previous unsuccessful attemps.

于 2012-08-08T10:24:50.273 回答