스프링 MVC 2편 - 검증2 Bean Validation

서은경·2023년 1월 10일
0

Spring

목록 보기
40/43

Bean Validation

특정 구현체가 아닌 Bean Validation 이라는 기술 표준이다. 검증 어노테이션과 여러 인터페이스의 모음이다.(=JPA가 기술, 하이버네이트가 구현체인 것과 같음)

Bean Validation을 구현한 기술 중에 일반적으로 사용하는 구현체는 하이버네이트 Validator이다.(ORM과는 무관)

javax.validation으로 시작하면 특정 구현에 관계없이 제공되는 표준 인터페이스, org.hibernate.validator로 시작하면 하이버네이트 validator 구현체를 사용할 때만 제공되는 검증 기능

동작

스프링 부트가 spring-boot-starter-validation 라이브러리를 넣으면 자동으로 Bean Validator를 인지하고 스프링에 통합한다.

스프링 부트가 뜰 때 LocalValidatorFactoryBean(빈 검증기)을 글로벌 Validator로 등록한다.
@NotNull과 같은 어노테이션을 보고 검증을 수행한다.
이렇게 글로벌 Validator가 적용되어 있기 때문에 @Valid, @Validated만 적용하면 된다.
검증오류가 발생하면 FieldError, ObjectError를 생성해서 BindingResult에 담아준다.

검증 순서

  1. @ModelAttribute 각각의 필드에 타입 변환 시도
    • 성공하면 다음
    • 실패하면 typeMisMatch로 FieldError 추가
  2. Validator 적용

바인딩에 성공한 필드만 Bean Validation 적용‼️
itemName에 A 입력 -> 타입 변환 성공 -> Bean Validation 적용
price에 A 입력 -> A를 숫자 타입 변환 시도 실패 -> typeMismatch FieldError 추가 -> price 필드는 Bean Validation 적용 실패

Bean Validation - 에러코드

  • 메시지 찾는 순서
    1. 생성된 메시지 코드 순서대로 messageSource에서 메시지 찾기
    2. 어노테이션의 message 속성 사용 -> @NotBlank(message = "공백! {0}")
    3. 라이브러리가 제공하는 기본 값 사용 -> 공백일 수 없습니다

Bean Validation - 오브젝트 오류

@ScriptAssert 사용

@ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >= 10000", message = "총합이 10000원 넘게 입력해주세요")

❌ 근데 실제 사용해보면 제약이 많고 복잡하다. 실무에서는 검증 기능이 해당 객체의 범위를 넘어서는 경우들도 종종 등장하는데 그런 경우 대응이 어렵다!

오브젝트 오류의 경우 관련부분만 직접 자바 코드로 작성하는 것을 권장함

Bean Validation - 한계

등록시 검증 조건과 수정시 검증조건이 다를 수 있다!(ex. 등록할 땐 id가 필수가 아니지만 수정할 땐 id가 필수이다)

해결법은 ?

Bean Validation - groups

동일한 모델 객체를 상황에 따라 다르게 검증하는 방법
1. BeanValidation의 groups 기능을 사용
2. Item을 직접 사용하지 않고 ItemSaveForm, ItemEditForm을 각각 생성 -> 실무에서 주로 사용

Bean Validation - Http 메시지 컨버터

API 의 경우
1. 성공
2. 실패 - 타입 에러 시 HTTP 메시지 컨버터가 JSON을 객체로 생성할 수 없기 때문에 컨트롤러도 호출하지 않음
3. 객체 만들기는 성공했으나 검증 오류

@ModelAttribute는 vs @RequestBody

HTTP 요청 파라미터를 처리하는 @ModelAttribute는 각각의 필드 단위로 세밀하게 적용된다. 그래서 특정 필드에 타입이 맞지 않는 오류가 발생해도 나머지 필드는 정상 처리할 수 있다.

HttpMessageConverter는 @ModelAttribute와 다르게 전체 객체 단위로 적용된다. 따라서 컨버터의 작동이 성공해서 객체를 만들어야 @Valid, @Validated가 적용된다.

  • @ModelAttribute
    • 필드 단위로 정교하게 바인딩 적용. 특정 필드가 바인딩 되지 않아도 나머지 필드는 정상 바인딩 되고 Validator를 사용한 검증도 적용 가능
  • @RequestBody
    • HttpMessageConverter 단계에서 JSON 데이터를 객체로 변경하지 못하면 이후 단계 자체가 진행되지 않고 예외 발생. 컨트롤러도 호출되지 않고 Validator도 적용 불가

0개의 댓글