Spring/Spring

[Spring][Validation] 1. Validator Interface

noahkim_ 2025. 4. 6. 21:33

1. Spring의 Validator 인터페이스를 이용한 검증

Validator 인터페이스

public interface Validator {
    boolean supports(Class<?> clazz);
    void validate(Object target, Errors errors);
}
메서드명 설명
supports(Class<?> clazz) 검증 대상 타입 확인
(이 Validator가 특정 클래스 타입을 검증할 수 있는지 여부를 반환)
validate(Object target, Errors errors) 실제 검증 로직 수행
- Errors 객체 제공: 검증 중 발생한 오류를 수집함

 

 

예제) 객체

더보기
더보기
public class PersonValidator implements Validator {
    public boolean supports(Class clazz) {
        return Person.class.equals(clazz); // Person 타입만 검증
    }

    public void validate(Object obj, Errors e) {
        ValidationUtils.rejectIfEmpty(e, "name", "name.empty"); // name 필드 비었는지 확인
        Person p = (Person) obj;
        if (p.getAge() < 0) {
            e.rejectValue("age", "negativevalue");
        } else if (p.getAge() > 110) {
            e.rejectValue("age", "too.darn.old");
        }
    }
}
ValidationUtils 메서드 설명
rejectIfEmpty()
특정 필드가 null 또는 "" (빈 문자열)이면 에러로 등록
rejectIfEmptyOrWhitespace()
특정 필드가 null, "", 또는 공백 문자만 있으면 에러로 등록
invokeValidator()
다른 Validator를 호출해서 하위 객체를 검증 (중첩 검증 시 사용)

 

예제) 복합 객체

더보기
더보기
public class CustomerValidator implements Validator {

    private final Validator addressValidator;

    public CustomerValidator(Validator addressValidator) {
        if (addressValidator == null || !addressValidator.supports(Address.class)) {
            throw new IllegalArgumentException("Validator가 Address 검증을 지원해야 합니다.");
        }
        this.addressValidator = addressValidator;
    }

    public boolean supports(Class clazz) {
        return Customer.class.isAssignableFrom(clazz); // Customer 혹은 그 하위 클래스
    }

    public void validate(Object target, Errors errors) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");

        Customer customer = (Customer) target;

        try {
            errors.pushNestedPath("address");
            ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
        } finally {
            errors.popNestedPath();
        }
    }
}
ValidationUtils 메서드 설명
rejectIfEmpty()
특정 필드가 null 또는 "" (빈 문자열)이면 에러로 등록
rejectIfEmptyOrWhitespace()
특정 필드가 null, "", 또는 공백 문자만 있으면 에러로 등록
invokeValidator()
다른 Validator를 호출해서 하위 객체를 검증 (중첩 검증 시 사용)

 

2. 관련 클래스들

항목 Errors 인터페이스 ValidationUtils 클래스
주요 역할 검증 과정에서 발생한 오류 정보를 관리하는 클래스 Errors 객체를 쉽게 다루기 위해 제공되는 헬퍼 클래스
- 공통적인 검증 로직을 간단하게 사용할 수 있도록 도와줌
사용 위치 Validator의 validate 메서드 내에서 오류 저장용으로 사용
Validator 내에서 필수 값 검증 시 자주 사용됨
기능 요약 필드별/글로벌 오류 등록
에러 메시지 코드 저장
빈값/공백 검증
다른 Validator 호출 등 반복 로직 추상화
특징 Spring MVC와 통합
- <form:errors>, <spring:bind> 등에서 사용 가능
별도 인스턴스 생성 없이 바로 정적 메서드 호출 가능

 

예제) Errors - 에러 코드를 메시지로 변환하기

더보기
더보기

1. rejectValue()로 유효성 검증 실패 처리

errors.rejectValue("age", "too.darn.old");
  • 에러 코드는 "too.darn.old"

 

2.Spring은 이 에러 코드를 바탕으로 여러 메시지 코드 등록함

등록되는 메시지 코드들 설명
too.darn.old 기본 코드
too.darn.old.age 필드명(age)이 포함된 코드
too.darn.old.age.int 필드 타입(int)까지 포함된 코드
  • MessageSource에서 메시지를 유연하게 매칭할 수 있도록 하기 위함

 

3. 메시지 매핑 우선순위

too.darn.old.age.int=나이가 너무 많습니다! (int)
too.darn.old.age=나이가 너무 많습니다!
too.darn.old=나이 제한 오류입니다.
  • Spring은 위 코드 목록 순서대로 메시지를 찾다가, 가장 먼저 매칭되는 메시지를 반환
  • too.darn.old.age.int가 가장 우선해서 매칭

 

4.  처리 과정을 담당하는 컴포넌트

  • MessageCodesResolver: 에러 코드를 어떻게 변환할지 결정함
  • DefaultMessageCodesResolver: 스프링에서 기본 사용되는 구현체

 

예제) ValidationUtils

더보기
더보기
public void validate(Object obj, Errors errors) {
    ValidationUtils.rejectIfEmpty(errors, "name", "name.empty");
}
if (target.getName() == null || target.getName().isEmpty()) {
    errors.rejectValue("name", "name.empty");
}
  • 위 코드와 같은 패턴을 래핑해서 더 간결하게 쓸 수 있도록 도와줌

 

3. DataBinder와 Validator 수동 사용

Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());

binder.bind(propertyValues);
binder.validate();

BindingResult results = binder.getBindingResult();
  • DataBinder를 통해 수동으로 바인딩 + 유효성 검증
  • 여러 Validator를 조합할 수도 있음 (addValidators, replaceValidators)

 


출처

'Spring > Spring' 카테고리의 다른 글

[Spring][AOP] 1. Advice API  (0) 2025.04.09
[Spring][Validation] 2. Java Bean Validation  (0) 2025.04.06
[Spring][Object] 1. Data Binding  (0) 2025.04.06
[Spring][Field] 2. Formatting  (0) 2025.04.06
[Spring][Field] 1. Type Conversion  (0) 2025.04.06