@Valid 注解不验证子对象列表

Posted

技术标签:

【中文标题】@Valid 注解不验证子对象列表【英文标题】:@Valid annotation is not validating the list of child objects 【发布时间】: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

【问题讨论】:

【参考方案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 可以用来指定验证顺序。 我的详细问题***.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>

【讨论】:

以上是关于@Valid 注解不验证子对象列表的主要内容,如果未能解决你的问题,请参考以下文章

@Valid注解 简化参数验证

validator 手动验证 表单字段 不基于注解@Valid

Kotlin Spring Boot Webflux 使用 @Valid 注解验证 @RequestBody

@Validated注解和@Valid注解区别

authority_not_in_valid_list:“权限”不在有效地址列表中

Spring框架 之@Valid注解的使用(嵌套类型的效验)