복붙노트

[SPRING] Controller 메소드의 Collection에 바인딩 된 RequestBody 매개 변수에 대한 Spring 유효성 검사

SPRING

Controller 메소드의 Collection에 바인딩 된 RequestBody 매개 변수에 대한 Spring 유효성 검사

나는 가지고있다

엔티티 :

package org.ibp.soq;

public class MyEntity {

    private String field1;
    private String field2;

    //..getters and setters

}

엔티티에 대한 검사기 :

package org.ibp.soq;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

@Component
public class MyEntityValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return MyEntity.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        MyEntity myEntity = (MyEntity) target;
        // Logic to validate my entity
        System.out.print(myEntity);
    }

}

대량 PUT 방법을 사용하는 REST 컨트롤러 :

package org.ibp.soq;

import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/myEntity")
public class MyEntityRestResource {

    @Autowired
    private MyEntityValidator myEntityValidator;

    @InitBinder
    protected void initBinder(final WebDataBinder binder) {
        binder.addValidators(this.myEntityValidator);
    }

    @RequestMapping(method = RequestMethod.PUT)
    public void bulkCreate(@RequestBody @Valid List<MyEntity> myEntities) {
        // Logic to bulk create entities here.
        System.out.print(myEntities);
    }
}

다음 요청 본문으로이 자원에 PUT 요청을 할 때 :

[
  {
    "field1": "AA",
    "field2": "11"
  },

  {
    "field1": "BB",
    "field2": "22"
  }
]

내가 얻는 오류는 다음과 같습니다.

"Invalid target for Validator [org.ibp.soq.MyEntityValidator@4eab617e]: [org.ibp.soq.MyEntity@21cebf1c, org.ibp.soq.MyEntity@c64d89b]"

이것이 MyEntityValidator가 MyEntity 유효성 검사를 "지원"하고 ArrayList 유효성 검사가 아니기 때문에 가능하다는 것을 알 수 있습니다.

요청 본문에 단일 MyEntity 객체가 있고 @RequestBody @Valid MyEntity myEntity 매개 변수가있는 해당 컨트롤러 메소드가 있으면 MyEntityValidator가 완벽하게 작동합니다.

MyEntity의 콜렉션 유효성 검증을 지원하기 위해 유효성 검사기 설정을 어떻게 확장 할 수 있습니까?

해결법

  1. ==============================

    1.해결책은 Collection에 대한 사용자 정의 검사기를 작성하고 WebDataBinders에 해당 Validator를 등록하는 @ControllerAdvice를 작성하는 것입니다.

    해결책은 Collection에 대한 사용자 정의 검사기를 작성하고 WebDataBinders에 해당 Validator를 등록하는 @ControllerAdvice를 작성하는 것입니다.

    검사기 :

    import java.util.Collection;
    
    import org.springframework.validation.Errors;
    import org.springframework.validation.ValidationUtils;
    import org.springframework.validation.Validator;
    import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
    
    /**
     * Spring {@link Validator} that iterates over the elements of a 
     * {@link Collection} and run the validation process for each of them
     * individually.
     *   
     * @author DISID CORPORATION S.L. (www.disid.com)
     */
    public class CollectionValidator implements Validator {
    
      private final Validator validator;
    
      public CollectionValidator(LocalValidatorFactoryBean validatorFactory) {
        this.validator = validatorFactory;
      }
    
      @Override
      public boolean supports(Class<?> clazz) {
        return Collection.class.isAssignableFrom(clazz);
      }
    
      /**
       * Validate each element inside the supplied {@link Collection}.
       * 
       * The supplied errors instance is used to report the validation errors.
       * 
       * @param target the collection that is to be validated
       * @param errors contextual state about the validation process
       */
      @Override
      @SuppressWarnings("rawtypes")
      public void validate(Object target, Errors errors) {
        Collection collection = (Collection) target;
        for (Object object : collection) {
          ValidationUtils.invokeValidator(validator, object, errors);
        }
      }
    }
    

    ControllerAdvice :

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
    import org.springframework.web.bind.WebDataBinder;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.InitBinder;
    
    /**
     * Controller advice that adds the {@link CollectionValidator} to the 
     * {@link WebDataBinder}.
     * 
     * @author DISID CORPORATION S.L. (www.disid.com)
     */
    @ControllerAdvice
    public class ValidatorAdvice {
    
      @Autowired
      protected LocalValidatorFactoryBean validator;
    
    
      /**
       * Adds the {@link CollectionValidator} to the supplied 
       * {@link WebDataBinder}
       * 
       * @param binder web data binder.
       */
      @InitBinder
      public void initBinder(WebDataBinder binder) {
        binder.addValidators(new CollectionValidator(validator));
      }
    }
    
  2. ==============================

    2.짐작할 수 있듯이 스프링 밸리데이션을 사용하여이를 달성 할 수는 없습니다. Spring 유효성 검사는 객체 유효성 검사와 달리 Bean 유효성 검사 (JSR 303/349)를 구현합니다. 불행히도 컬렉션은 Java Bean이 아닙니다. 두 가지 옵션이 있습니다.

    짐작할 수 있듯이 스프링 밸리데이션을 사용하여이를 달성 할 수는 없습니다. Spring 유효성 검사는 객체 유효성 검사와 달리 Bean 유효성 검사 (JSR 303/349)를 구현합니다. 불행히도 컬렉션은 Java Bean이 아닙니다. 두 가지 옵션이 있습니다.

  3. ==============================

    3.실제로 이것은 Spring Validation과 JSR303을 사용하여 얻을 수 있습니다.

    실제로 이것은 Spring Validation과 JSR303을 사용하여 얻을 수 있습니다.

  4. from https://stackoverflow.com/questions/34011892/spring-validation-for-requestbody-parameters-bound-to-collections-in-controller by cc-by-sa and MIT license