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 |