프로그래밍 노트/SPRING BOOT

Validation 알아보기_2(Spring Validation)

깡냉쓰 2021. 1. 9. 16:10
728x90
반응형

Srping Validation

Spring에서는 AOP와 같은 방식으로 더 편리하게 유효성검사를 할 수 있다.

Validated

스프링에서는 유효성검사에 진입하게되는 지점에 @Validated라는 애노테이션을 사용하는 방법을 제공한다.

필요한 클래스나 메소드에 @Validated 어노테이션을 추가해서 사용한다.

@Service
@Validated
public class UserService{
    public User add(@NotNull User user){

    }
}

만약 제약조건에 위반되면 ConstraintViolationException이 발생하게 된다.
(※ @ControllerExceptionHanlder를 사용하여 요긴하게 써먹을 수 있음. ConstrainoViolationException에서 getConstraintViolations를 사용하여 Set<ConstraintViolation<T>>를 얻을 수 있다.)

@Validate를 사용하기 위해선, MethodValidationPostProcessor를 빈으로 등록해야 한다. SpringBoot에서는 ValidationAutoConfiguration에 이미 MethodValidationPostProcessor가 정의되어 있으므로 따로 선언할 필요는 없다.

Spring MVC에서 유효성 검사

Spring 내부에서 사용하는 Validator(org.springframework.validation.Validator) 인터페이스를 살펴보자.

public interface Validator {
    // 이 검사기가 지원하는 클래스인지를 판단
    boolean supports(Class<?> clazz);
    // 유효성검사를 진행, errors 객체에 상태를 저장한다.
    void validate(@Nullable Object target, Errors errors);

}

Spring MVC에서는 데이터 바인딩 시점에 유효성 검사를 실시한다. 바인딩에 실패한 경우 MethodArgumentNotValidException이 발생하게 된다.
유효성 검사 결과를 사용하려면 BindingResult 객체를 주입받아서 사용할 수 있으며, 이 객체에는 유효성 검사를 실행한 결과 정보가 담겨져 있다.

@Slf4j
@RestController
public class UserController {

        // 바인딩 실패시 MethodArgumentNotValidException 발생
        @PostMapping("/api/user")
    public void addUser(@Valid @RequestBody User user){

    }

        // 유효성 검사 실패시, BindingResult 객체에서 결과정보 획득 가능
    @PostMapping("/api/user")
    public void addUser(@Valid @RequestBody User user, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            for(ObjectError obj : bindingResult.getAllErrors()){
                log.info("message : {}", obj.getDefaultMessage());
                log.info("code : {}", obj.getDefaultMessage());
                log.info("object name : {}", obj.getObjectName());
            }
        }
    }
}

Validator 커스터마이징

JSR-303, JSR-380 스펙으로 유효성 검사를 한 후 추가적으로 다른 유효성 검사를 하고자 할때 사용한다.

  1. Validator 인터페이스 구현

    • supports : 유효성 검사할 데이터를 가지고 있는 객체가 유효성 검사가 가능한지 확인

    • validate : 유효성을 검사하는 메서드

      public class UserValidator implements Validator {
      @Override
      public boolean supports(Class<?> aClass) {
        return User.class.isAssignableFrom(aClass);
      }
      
      @Override
      public void validate(Object o, Errors errors) {
      
      }
      }
  2. Validator를 컨트롤러에 등록
    사용할 Validator가 하나면 setValidator, 한 개 이상이면 addValidators 메서드를 사용한다.

    @InitBinder
    protected void initBinder(WebDataBinder binder){
     binder.setValidator(new UserValidator());
    }

ValidateUtils

⇒ 지정된 값에 대해 유효성 검사를 하는 메서드들이 존재함.

  • rejectIfempty(error 객체, 프로퍼티 이름, 코드이름)
  • rejectIfEmptyOrWhitespace(error 객체, 프로퍼티 이름, 코드이름)

rejectValue

⇒ 유효성 조건을 직접 만들어 검사할 때 사용

  • rejectValue(프로퍼티 이름, 코드 이름, 디폴트 메세지)

입력값에 문제가 있다면 error 객체에 오류정보를 저장한다. 사용할 오류 메시지는 "코드이름.객체이름.프로퍼티이름"으로 구성됨

public class UserValidator implements Validator {
    @Override
    public boolean supports(Class<?> aClass) {
        return User.class.isAssignableFrom(aClass);
    }

    @Override
    public void validate(Object o, Errors errors) {
        User user = (User) o;

        int age = user.getAge();
        String adminNumber = user.getAdminNumber();

        if(age<0){
            errors.rejectValue("age", "positive", "나이는 0 이상이어야 합니다.");
        }
        if(StringUtils.isEmpty(adminNumber)){
            errors.rejectValue("adminNumber", "isEmpty");
        }
    }
}

위의 메소드에서 코드 이름이란, MessageSource에 등록된 코드이름을 뜻한다.

728x90
반응형