Back-End/Spring

[Spring MVC2][검증2(Validation)] - Bean Validation

얄루몬 2022. 5. 3. 14:02

💻본 포스팅은 '스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 김영한'님의 강의를 듣고 작성되었습니다.

https://inf.run/vQHp

 

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의

웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있

www.inflearn.com


1. Bean Validation이란?
2. Bean Validation 시작
   - 검증 애노테이션
   - 검증기 생성
   - 검증기 실행
3. Bean Validation - 스프링 적용
    - 검증 순서
4. Bean Validation - 에러코드
    - FieldError 메시지 코드 우선순위
    - BeanValidation 메시지 찾는 순서
5. Bean Validation - 오브젝트 오류
    - ObjectError 메시지 코드 우선순위
6. Bean Validation의 한계

[Bean validation이란?]

  • 검증 로직을 모든 프로젝트에 적용할 수 있게 공통화하고, 표준화한 것이 Bean Validation이라고 한다.
  • Bean Validation은 특정 구현체가 아닌 인터페이스와 애노테이션의 모음인 셈이다.
    • JPA를 표준 기술로 그 기술을 구현하는 구현체에 하이버네이트가 있는 것과 같다.
    • Bean Validation을 구현하는 구현체로는(일반적으로 사용하는 구현체) 하이버네이트 Validaitor이고 이름이 하이버네이트가 붙었을 뿐 ORM과는 관계가 없다.
    • 구현체를 바꿔낄 수 있다.(오픈 소스에서 구현하거나 상용에서 구현할 수 있다.)

 

[Bean Validation 시작]

implementation 'org.springframework.boot:spring-boot-starter-validation'
  • 의존관계를 주입시켜 주어야 사용할 수 있다.
  • 자동으로 라이브러리를 spring이 추가해준다.
    • javax validation(인터페이스)을 추가해준다.
    • 하이버네이트 validator(구현체)도 추가해준다.(대다수의 기업이 하이버네이트 validator을 사용한다.)
package hello.itemservice.domain.item;

import lombok.Data;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
public class Item {

    private Long id;

    @NotBlank(message = "공백 X")
    private String itemName;

    @NotNull
    @Range(min = 1000, max = 1000000)
    private Integer price;

    @NotNull
    @Max(9999)
    private Integer quantity;

    public Item() {
    }

    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    }
}

 

[검증 애노테이션]

  • @NotBlank : 빈값 + 공백만 있는 경우를 허용하지 않는다.
  • @NotNull : null 을 허용하지 않는다.
  • @Range(min = 1000, max = 1000000) : 범위 안의 값이어야 한다.
    • 하이버네이트 validator 구현체 사용에만 사용할 수 있다.
  • @Max(9999) : 최대 9999까지만 허용한다.

[검증기 생성]

  • 스프링과 통합하면 우리가 직접 검증기 생성 코드를 작성하지 않음

[검증기 실행]

  • 검증 대상을 직접 검증기에 넣고 그 결과를 받는다.
  • Set에는 ConstraintViolation이라는 검증 오류가 담긴다.
  • 따라서 결과가 비어있으면 검증 오류가 없는 것이다.
Set<ConstraintViolation<Item>> violations = validator.validate(item);

 

[Bean Validation - 스프링 적용]

  • 우리가 직접 만든 검증 class를 뺏을 때도 Bean Validation 애노테이션 검증이 제대로 작동하는 이유?
    • 스프링부트에 라이브러리를 추가해주어서 스프링부트가 자동으로 Bean Validator를 작동시켜준다.
    • 스프링부트는 global validator로 적용해서 NotNull과 같은 경우를 다 찾아서 검증해준다.

[검증 순서]

  • @ModelAttribute 바인딩
    • 성공하면 다음으로
    • 실패하면 typeMismath로 FieldError 추가
  • Bean Validator 적용
    • 타입 변환에 성공한 경우만 적용 된다.

 

[Bean Validation - 에러코드]

NotBlank라는 오류 코드를 기반으로 MessageCodesResolver를 통해 다양한 메시지 코드가 순서대로 생성된다.

 

[Error 메시지 코드 우선순위]

@NotBlank

  1. NotBlank.item.itemName
  2. NotBlank.itemName
  3. NotBlank.java.lang.String
  4. NotBlank

 

@Range

  1. Range.item.price
  2. Range.price
  3. Range.java.lang.Integer
  4. Range

[BeanValidation 메시지 찾는 순서]

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

 

[Bean Validation - 오브젝트 오류]

  • FieldError가 아닌 ObjectError는 어떻게 처리를 할까?
    • @ScriptAssert( )를 사용하면 된다.
@ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >= 10000")

 

[메시지 코드 우선순위]

  1. ScriptAssert.item
  2. ScriptAssert
강사님 주관적인 의견으로 필드 관련 에러는 Bean Validation 사용하고 Object 관련 에러는 자바 코드로 작성하는 것을 권장한다고 한다. 

 

[Bean Validation의 한계]

  • 요구 사항 변경이 요청될 경우 상충하는 요구 사항이 충돌할 수 있어서 이를 계속 검증해야 한다.
  • 즉 동일 모델 객체를 등록할 때와 수정할 때 각각 다르게 검증하는 방법을 알아보아야 한다.
    • (다음 포스팅에서 계속...)