Chú thích JSR-303 @Valid không hoạt động cho danh sách các đối tượng con


95

Các lớp học chính của tôi là

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

Bộ điều khiển

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

Một trang 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>

Tại sao các trường đối tượng không được xác thực AddressForm?

Xin vui lòng giúp đỡ.

Câu trả lời:


164

Bạn cần trang trí addressesthành viên của UserAddressesFormbằng @Validchú thích. Xem phần 3.1.3 và 3.5.1 của JSR 303: Xác thực Bean . Như tôi đã giải thích trong câu trả lời của mình cho câu hỏi Có cách tiêu chuẩn nào để kích hoạt tính năng Xác thực Bean JSR 303 bằng phương pháp chú thích không , đây là cách sử dụng thực sự của@Valid chú thích theo JSR 303.

Chỉnh sửa Mã ví dụ: Hibernate Validator- Object Graph . (Danh sách hành khách trên xe)

Chỉnh sửa từ Hibernate Validator 6 Tài liệu tham khảo:

Trong các phiên bản trước 6, Hibernate Validator đã hỗ trợ xác thực theo tầng cho một tập hợp con các phần tử vùng chứa và nó được triển khai ở cấp vùng chứa (ví dụ: bạn sẽ sử dụng @Valid private List<Person>để kích hoạt xác thực theo tầng cho Person).

Điều này vẫn được hỗ trợ nhưng không được khuyến khích. Vui lòng sử dụng @Validchú thích cấp phần tử vùng chứa thay vì nó biểu cảm hơn.

Thí dụ:

public class Car {

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

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

       //...
   }

Đồng thời xem có gì mới trong Bean Validation 2.0 / Jakarta Bean Validation .


Còn phân nhóm thì sao? Tôi muốn địa chỉ chỉ được xác thực khi nhóm A được xác thực. @Validbỏ qua nhóm.
Akshay

1
@ValidChú thích @Akshay hoạt động ở cấp độ thấp hơn. Tôi nghĩ rằng @GroupSequence có thể được sử dụng để chỉ định thứ tự xác thực.
Ritesh

Câu hỏi chi tiết của tôi stackoverflow.com/q/41457404/1534925 . Đừng nghĩ rằng trình tự sẽ hoạt động trong trường hợp của tôi.
Akshay

27

Thêm vào câu trả lời @Ritesh, @Validràng buộc sẽ hướng dẫn Trình xác thực Bean đi sâu vào loại thuộc tính được áp dụng của nó và xác thực tất cả các ràng buộc được tìm thấy ở đó. Trả lời bằng mã cho câu hỏi của bạn, trình xác thực, khi thấy@Valid ràng buộc về thuộc addressestính, sẽ khám phá AddressFormlớp và xác thực tất cả các JSR 303ràng buộc được tìm thấy bên trong, như sau:

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

1
Còn phân nhóm thì sao? Tôi muốn địa chỉ chỉ được xác thực khi nhóm A được xác thực. @Valid bỏ qua nhóm
Akshay

Tôi thậm chí còn không đọc câu trả lời của bạn mà chỉ xem xét setters and gettersgiải quyết vấn đề của tôi.
Shubham Khandare

7

Trong lớp UserAddressesForm thêm các dòng sau

@Valid
private List<AddressForm> addresses;

4

Giải pháp làm việc.

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.