【问题标题】:@Valid annotation is not validating the list of child objects@Valid 注解不验证子对象列表
【发布时间】:2011-07-05 18:02:19
【问题描述】:

主要模型类如下:

public class UserAddressesForm {

    @NotEmpty
    private String firstName;

    @NotEmpty
    private String lastName;

    private List<AddressForm> addresses;

    // setters and getters 

}

public class AddressForm {
    
    @NotEmpty
    private String customName;
    @NotEmpty
    private String city;
    @NotEmpty
    private String streetAn;
    @NotEmpty
    private String streetHn;
    @NotEmpty
    private String addressCountry;
    @NotEmpty
    private String postCode;
    
    // setters and getters
}

我的一个控制器中的一个端点:

@RequestMapping(value = "/up", method = RequestMethod.POST)
public String completeForm(@Valid @ModelAttribute("userAddressesForm") UserAddressesForm userAddressesForm,  
            BindingResult result, HttpServletRequest req) {

 // logic here 

}

.jsp 页面:

<form:form commandName="userAddressesForm" action="registered">
    <table>

        <tr>
            <td class="formLabels"><form:label path="firstName">
                <spring:message code="label.name" />
            </form:label></td>
            <td><form:input path="firstName" /></td>
            <td><form:errors path="firstName" cssClass="error" /></td>
        </tr>
        <tr>
            <td class="formLabels"><form:label path="lastName">
                <spring:message code="label.surname" />
            </form:label></td>
            <td><form:input path="lastName" /></td>
            <td><form:errors path="lastName" cssClass="error" /></td>
        </tr>
    </table>
    
    <c:forEach items="${userAddressesForm.addresses}" varStatus="gridRow">  
        <div id="main_address" class="address_data_form">
            <fieldset>
                <legend><spring:message code="label.stepThreeMainAddressInfo" /></legend>
                <a href="#" class="deleteItem"></a>
                <table>
                    <tr>            
                        <td class="formLabels">
                            <spring:message code="label.address.custom.name" />
                        </td>
                        <td>
                            <spring:bind path="addresses[${gridRow.index}].customName">
                                <input type="input" name="<c:out value="${status.expression}"/>"
                                    id="<c:out value="${status.expression}"/>"
                                    value="<c:out value="${status.value}"/>" />
                                    <form:errors path="${status.expression}"/>
                            </spring:bind>
                        </td>   
                    </tr>               
                    <tr>            
                        <td class="formLabels">
                            <spring:message code="label.streetAnStreetHn" />
                        </td>
                        <td>
                            <spring:bind path="addresses[${gridRow.index}].streetAn">
                                <input type="input" name="<c:out value="${status.expression}"/>"
                                    id="<c:out value="${status.expression}"/>"
                                    value="<c:out value="${status.value}"/>" />
                            </spring:bind>
                            <spring:bind path="addresses[${gridRow.index}].streetHn">
                            <input type="input" name="<c:out value="${status.expression}"/>"
                                id="<c:out value="${status.expression}"/>"
                                value="<c:out value="${status.value}"/>" >
                            <form:errors path="addresses[${gridRow.index}].streetHn"/>
                            </spring:bind>
                            
                        </td>
                    </tr>
                    <tr>                        
                        <td class="formLabels">
                            <spring:message code="label.postCode" />
                        </td>
                        <td>
                            <spring:bind path="addresses[${gridRow.index}].postCode">
                                <input type="input" name="<c:out value="${status.expression}"/>"
                                    id="<c:out value="${status.expression}"/>"
                                    value="<c:out value="${status.value}"/>" />
                            </spring:bind>
                        </td>                   
                    </tr>
                    <tr>                
                        <td class="formLabels">
                            <spring:message code="label.city" />
                        </td>
                        <td>
                            <spring:bind path="addresses[${gridRow.index}].city">
                                <input type="input" name="<c:out value="${status.expression}"/>"
                                    id="<c:out value="${status.expression}"/>"
                                    value="<c:out value="${status.value}"/>" />
                                <form:errors path="addresses[${gridRow.index}].city" cssClass="error" />
                            </spring:bind>
                        </td>
                    </tr>       
                </table>    
            </fieldset>
        </div>
    </c:forEach>

为什么@Valid 没有验证UserAddressesForm 类中的List&lt;AddressForm&gt; addresses

【问题讨论】:

    标签: java spring spring-mvc jsr


    【解决方案1】:

    你需要用@Valid注解来装饰UserAddressesFormaddresses成员。请参阅JSR 303: Bean Validation 的第 3.1.3 和 3.5.1 节。正如我在对问题 Is there a standard way to enable JSR 303 Bean Validation using annotated method 的回答中所解释的那样,这是根据 JSR 303 对 @Valid 注释的真正用途。

    编辑 示例代码:Hibernate Validator- Object Graph。 (车内乘客名单)

    编辑来自Hibernate Validator 6参考文档:

    在 6 之前的版本中,Hibernate Validator 支持对容器元素的子集进行级联验证,并且它是在容器级别实现的(例如,您可以使用 @Valid private List&lt;Person&gt;Person 启用级联验证)。

    这仍然受支持,但不推荐。请使用容器 元素级别 @Valid 注释,因为它更具表现力。

    例子:

    public class Car {
    
            private List<@NotNull @Valid Person> passengers = new ArrayList<Person>();
    
            private Map<@Valid Part, List<@Valid Manufacturer>> partManufacturers = new HashMap<>();
    
           //...
       }
    

    还可以查看 Bean Validation 2.0/Jakarta Bean Validation 的新增功能。

    【讨论】:

    • 分组呢?我希望仅在验证 A 组时验证地址。 @Valid 忽略该组。
    • @Akshay @Valid 注释在较低级别工作。我认为@GroupSequence 可以用来指定验证顺序。
    • 我的详细问题stackoverflow.com/q/41457404/1534925。不要认为顺序对我有用。
    【解决方案2】:

    添加到@Ritesh 答案,@Valid 约束将指示 Bean 验证器深入研究其应用属性的类型并验证在那里找到的所有约束。用代码回答您的问题,验证器在看到addresses 属性上的@Valid 约束时,将探索AddressForm 类并验证内部找到的所有JSR 303 约束,如下所示:

    public class UserAddressesForm {
    
        @NotEmpty
        private String firstName;
    
        @NotEmpty
        private String lastName;
    
        @Valid
        private List<AddressForm> addresses;
    
    ...
    setters and getters 
    
    public class AddressForm {
    
        @NotEmpty
        private String customName;
        @NotEmpty
        private String city;
        @NotEmpty
        private String streetAn;
        @NotEmpty
        private String streetHn;
        @NotEmpty
        private String addressCountry;
        @NotEmpty
        private String postCode;
    ...
    setters and getters
    

    【讨论】:

    • 分组呢?我希望仅在验证 A 组时验证地址。 @Valid 忽略组
    • 我什至没有阅读您的答案,但只是看着setters and getters 解决了我的问题。
    【解决方案3】:

    在 UserAddressesForm 类中添加以下行

    @Valid
    private List<AddressForm> addresses;
    

    【讨论】:

      【解决方案4】:

      工作解决方案。

      public class UserAddressesForm {
      
          @NotEmpty(message="firstName is required")
          private String firstName;
      
          @NotEmpty(message="lastNameis required")
          private String lastName;
      
          @NotNull(message="addresses attributes are required")
          @Valid
          private List<AddressForm> addresses;
      
      ...
      setters and getters 
      
      public class AddressForm {
      
          @NotEmpty(message="customNameis required")
          private String customName;
          @NotEmpty
          private String city;
          @NotEmpty
          private String streetAn;
          @NotEmpty
          private String streetHn;
          @NotEmpty
          private String addressCountry;
          @NotEmpty
          private String postCode;
      ...
      setters and getters
      

      【讨论】:

        【解决方案5】:

        我使用@Valid 实现了父类中的所有建议和注释子字段,但子实体仍未得到验证。

        幸运的是它现在已解决,问题是由于依赖关系。 作为我在依赖项下使用的解决方案

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        

        而不是

        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
        </dependency>
        

        【讨论】:

          猜你喜欢
          • 2021-06-23
          • 2021-12-29
          • 1970-01-01
          • 2018-07-14
          • 2015-01-04
          • 2015-10-02
          • 2012-12-31
          • 2022-01-01
          相关资源
          最近更新 更多