Validator 분리

@Component
public class ItemValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        // Item 및 Item의 자식의 타입인지 확인한다.
        // 자식까지 확인하기 위해 isAssignableFrom()을 쓴다.
        return Item.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        // Object 타입이기 때문에 캐스팅을 해야 한다.
        Item item = (Item) target;

        if (!StringUtils.hasText(item.getItemName())) {
            // Errors의 자식이 BidingResult라서 담을 수 있다.
            errors.rejectValue("itemName", "required");
        }

        if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
            errors.rejectValue("price", "range", new Object[]{1000, 1000000}, null);
        }

        if (item.getQuantity() == null || item.getQuantity() > 10000) {
            errors.rejectValue("quantity", "max", new Object[]{9999}, null);
        }

        // 특정 필드 예외가 아닌 전체 예외
        if (item.getPrice() != null && item.getQuantity() != null) {
            int resultPrice = item.getPrice() * item.getQuantity();
            if (resultPrice < 10000) {
                errors.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);
            }
        }
    }
}

검증 로직을 분리해 컨트롤러의 코드를 깔끔하게 유지할 수 있다.

  • supports()

    • 검증기를 지원하는지 확인한다.

  • validate(Object target, Errors errors)

    • 검증 대상 객체와 BindingResult를 파라미터로 받는다.

WebDataBinder

@InitBinder가 설정된 컨트롤러의 어떤 메서드든 호출될 때마다 dataBinder가 항상 새롭게 만들어져 적용된다. validator 코드를 삭제하고 애너테이션만 달아도 검증이 작동한다.

동작 방식

  • @Validator 애너테이션이 붙으면 WebDataBinder에 등록한 검증기를 찾아 실행한다.

  • 여러 검증기를 등록한다면 supports()를 사용해 어떤 검증기가 실행될지 확인한다.

    • 앞서 정의한 supports()를 호출하면 Item 타입인지 확인한다.

    • 결과가 true이므로 ItemValidator의 validate()가 호출된다.

글로벌 설정

모든 컨트롤러에 다 적용하고 싶다면 글로벌 설정이 가능하다. 따로 정의된 게 있다면 supports()가 getValidator()보다 먼저 호출된다.

참고

  • @Validated

    • 스프링 전용 검증 애너테이션

  • @Valid

    • 자바 표준 검증 애너테이션

@Validated, @Valid 모두 검증할 때 사용 가능하다. 하지만 후자는 org.springframework.boot:spring-boot-starter-validation 의존성이 필요하다.

Last updated

Was this helpful?