스프링 핵심 기술-10.Validation 추상화
Validation 추상화
Validator
org.springframework.validation.Validator
애플리케이션에서 사용하는 객체 검증용 인터페이스.
특징
- 어떤한 계층과도 관계가 없다. => 모든 계층(웹, 서비스, 데이터)에서 사용해도 좋다.
- 구현체 중 하나로, JSR-303(Bean Validation 1.0)과 JSR-349(Bean Validation 1.1)을 지원한다. (LocalValidatorFactoryBean)
- DataBinder에 들어가 바인딩 할 때 같이 사용되기도 한다.
인터페이스
- boolean supports(Class clazz): 어떤 타입의 객체를 검증할 때 사용할 것인지 결정함
내가 검증해야 하는 인스턴스의 클래스가 이 밸리데어터가 지원하는지 확인하는 메서드(검증할 수 있는 클래스인지 확인하는 메서드)
- void validate(Object obj, Errors e): 실제 검증 로직을 이 안에서 구현
실질적으로 검증을 하는 로직. 구현할 때 ValidationUtils 사용하며 편리함.
구현 방법 (직접 구현)
Event Class
public class Event {
int id;
String title;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
EventValidator Class
import org.springframework.validation.Validator;// spring 의 Validator를 가져와야 한다. (다른게 많다)
public class EventValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Event.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
System.out.println("target : " + target.toString());
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title", "notempty", "(default)title is empty...");
// 에러, 필드, 에러코드, 디폴트 에러메세지
}
}
실행
@Override
public void run(ApplicationArguments args) throws Exception {
Event event = new Event();
EventValidator eventValidator = new EventValidator();
Errors errors = new BeanPropertyBindingResult(event, "event");
// Errors 같은 구현체의 경우 많이 사용하지만
// BeanPropertyBindingResult 같은 경우 보통 spring mvc를 사용한다면 자동으로 파라미터에 전달해주기 때문에,
// 실질적으로 사용할 일은 거의 없다. (현재는 테스트를 위해 직접 구현해봄)
eventValidator.validate(event, errors); // validate 체크 (ex. 유효성 검사)
System.out.println(errors.hasErrors()); // 에러 존재 true/false 출력
errors.getAllErrors().forEach(e->{
System.out.println("==== has error code ====");
Arrays.stream(e.getCodes()).forEach(System.out::println);
System.out.println("default error msg : " + e.getDefaultMessage());
});
}
출력결과
target : com.example.ioccontainer5.demo.Event@7cf7aee
true
==== has error code ====
notempty.event.title
notempty.title
notempty.java.lang.String
notempty
default error msg : (default)title is empty...
아까 validate를 구현할 때
ValidationUtils.rejectIfEmptyOrWhitespace(errors, “title”, “notempty”, “(default)title is empty…”);
에러코드를 notempty만 주었다.
notempty.title 이렇게 주지 않았는데 실제 출력 에러코드에 보면 notempty.title 도 포함된 것을 볼 수 있다.
notempty.event.title
notempty.title
notempty.java.lang.String
notempty
실제 비즈니스 로직 구현시에는 이 에러코드들 중에서 내가 원하는 걸 골라 쓰면 된다.
그리고 validate 구현 시 rejectIfEmptyOrWhitespace 메소드 대신 이런 방식으로도 가능하다.
@Override
public void validate(Object target, Errors errors) {
System.out.println("target : " + target.toString());
// ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title", "notempty","(default)title is empty...");
// 에러, 필드, 에러코드, 디폴트 에러메세지
// 1. rejectValue
errors.rejectValue("title", "notempty", "rejectValue default title null err msh");
// 2. reject
Event event = (Event)target; // 제네릭 미지원
if (event.getTitle() == null){
errors.reject("title", "reject default title null err msg");
}
}
==== has error code ====
notempty.event.title
notempty.title
notempty.java.lang.String
notempty
default error msg : rejectValue default title null err msh
==== has error code ====
title.event
title
default error msg : reject default title null err msg
구현 방법 (어노테이션 기반 구현 - 스프링 부트 2.0.5 이상)
public class Event {
@Min(10000)
int id;
@NotEmpty
String title;
@Email
String email;
...
}
어노테이션 기반
@Autowired
Validator validator; // validator 을 그냥 주입받는다.(직접 구현하지 않음)
// LocalValidatorFactoryBean 타입
@Override
public void run(ApplicationArguments args) throws Exception {
Event event = new Event();
event.setId(9999);
event.setEmail("jaeuk2274");
Errors errors = new BeanPropertyBindingResult(event, "event");
validator.validate(event, errors); // 스프링에서 주입받은 validator
System.out.println(errors.hasErrors()); // 에러 존재 true
errors.getAllErrors().forEach(e->{
System.out.println("==== has error code ====");
Arrays.stream(e.getCodes()).forEach(System.out::println);
System.out.println("default error msg : " + e.getDefaultMessage());
});
}
실행결과
true
==== has error code ====
Min.event.id
Min.id
Min.int
Min
default error msg : 반드시 10000보다 같거나 커야 합니다.
==== has error code ====
Email.event.email
Email.email
Email.java.lang.String
Email
default error msg : 이메일 주소가 유효하지 않습니다.
==== has error code ====
NotEmpty.event.title
NotEmpty.title
NotEmpty.java.lang.String
NotEmpty
default error msg : 반드시 값이 존재하고 길이 혹은 크기가 0보다 커야 합니다.
디폴트 메세지까지 구현되어 있는 걸 볼 수 있다.
간단한 어노테이션 기반으로 검증할 수 있는 것들은 Validator 없이도 충분히 검증이 가능하지만,
이 외에 복잡한 비즈니스 로직으로 검증을 해야하는 경우에는 직접 Validator 만들어 구현이 가능하다.
앞으로 더 자세히 정리할 에정
(Validator - 데이터 바인더, 스프링 MVC 등 계속 나오면서 정리)
추가설명 및 참고 문서
부트 기반 주입받은 Validator는 LocalValidatorFactoryBean 타입.
어노테이션 기반 구현 - JSR-380(Bean Validation 2.0.1) 구현체로 hibernate-validator 사용.
beanValidation 공식문서