@Valid 注释未验证子对象列表

发布于 2024-10-19 16:50:25 字数 6151 浏览 2 评论 0原文

主要模型类如下:

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不验证ListUserAddressesForm 类中是否存在地址

Main model classes are as follows :

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
}

An endpoint in one of my controllers :

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

 // logic here 

}

A .jsp page :

<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>

Why @Valid is not validating the List<AddressForm> addresses present in UserAddressesForm class ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

凑诗 2024-10-26 16:50:25

您需要使用 @Valid 注解来装饰 UserAddressesFormaddresses 成员。请参阅 JSR 303:Bean 验证 的第 3.1.3 和 3.5.1 节。正如我在回答问题是否有一种标准方法可以使用带注释的方法启用 JSR 303 Bean 验证,这是根据 JSR 303 的 @Valid 注释的真正用途。

编辑< /强>
示例代码: Hibernate 验证器-对象图表。 (车内乘客列表)

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

在 6 之前的版本中,Hibernate Validator 支持对容器元素子集的级联验证,并且它是在容器级别实现的(例如,您可以使用 @Valid private List 来启用级联验证)验证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 中的新增功能。

You need to decorate addresses member of UserAddressesForm with @Valid annotation. See section 3.1.3 and 3.5.1 of JSR 303: Bean Validation. As I explained in my answer to the question Is there a standard way to enable JSR 303 Bean Validation using annotated method, this is the real use of @Valid annotation as per JSR 303.

Edit
Example code: Hibernate Validator- Object Graph. (The list of passengers in Car)

Edit From Hibernate Validator 6 Reference doc:

In versions prior to 6, Hibernate Validator supported cascaded validation for a subset of container elements and it was implemented at the container level (e.g. you would use @Valid private List<Person> to enable cascaded validation for Person).

This is still supported but is not recommended. Please use container
element level @Valid annotations instead as it is more expressive.

Example:

public class Car {

        private List<@NotNull @Valid Person> passengers = new ArrayList<Person>();

        private Map<@Valid Part, List<@Valid Manufacturer>> partManufacturers = new HashMap<>();

       //...
   }

Also see what's new in Bean Validation 2.0/Jakarta Bean Validation.

耀眼的星火 2024-10-26 16:50:25

添加到@Ritesh答案,@Valid约束将指示Bean验证器深入研究其应用属性的类型并验证在那里找到的所有约束。用代码回答您的问题,验证器在看到 addresses 属性上的 @Valid 约束时,将探索 AddressForm 类并验证所有< code>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

Adding to @Ritesh answer, @Valid constraint will instruct the Bean Validator to delve to the type of its applied property and validate all constraints found there. Answer with code to your question, the validator, when seeing a @Valid constraint on addresses property, will explore the AddressForm class and validate all JSR 303 constraints found inside, as follows:

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
鲸落 2024-10-26 16:50:25

在 UserAddressesForm 类中添加以下行

@Valid
private List<AddressForm> addresses;

In the class UserAddressesForm add the following lines

@Valid
private List<AddressForm> addresses;
空城仅有旧梦在 2024-10-26 16:50:25

工作解决方案。

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

Working solution.

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
花开半夏魅人心 2024-10-26 16:50:25

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

幸运的是,现在已经解决了,问题是由于依赖性造成的。
作为解决方案,我使用下面的依赖项

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

而不是

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

I implemented all the suggestions and annotated child field in the parent class with with @Valid but still the child entities were not getting validated.

Luckily it is resolved now and the issue was because of the dependency.
As a solution I used below dependency

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

instead of

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
</dependency>
嘿嘿嘿 2024-10-26 16:50:25

对我来说,它是子级中的 @NotNull,而不是 @NotEmpty 注释。我必须在 @Valid 注释之前放置一个 @NotNull 才能使其工作。

像这样:

private List<@NotNull @Valid YourObject> yourObjects;

For me, it was @NotNull, in the child, and not a @NotEmpty annotation. I had to put a @NotNull before the @Valid annontation to make it work.

like this:

private List<@NotNull @Valid YourObject> yourObjects;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文