[Spring] 스프링 Validation 추상화, Validator( Spring Validation Abstraction, Validator )
| 스프링 Validation 추상화
스프링에서는 Validator 인터페이스를 지원하여 어플리케이션에서 사용하는 객체를 검증할 수 있는 기능을 제공한다. 이 Validator 인터페이스는 어떤 특정 계층에 사용하는 기능이 아닌 모든 계층에서 사용할 수 있다.
Validator는 Java EE Spec인 Bean Validation의 어노테이션을 이용하여 객체가 제대로 요구사항에 맞추어 생성 됬는지 검증할 수 있다.
| Validator 인터페이스
Validator 인터페이스를 상속한 클래스는 두 메서드를 구현해야 한다.
boolean supports(Class clazz) : 어떤 타입의 객체를 검증할 때 이 객체의 클래스가 이 Validator가 검증할 수 있는 클래스인 지를 판단하는 매서드
void validate(Object target, Errors error) : 실제 검증 로직이 이루어지는 메서드, 구현할 때 ValidationUtils를 사용하여 편리하게 작성 가능
public class Event {
Integer id;
String title;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
public class EventValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Event.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title", "notempty", "Empty title is now allowed.");
}
}
위의 코드는 Validator 인터페이스를 구현한 클래스다.
- supports 메서드에서는 인자로 넘어온 객체의 클래스가 Event인지를 검사하는 로직이 들어가있다.
- validate 메서드에서는 ValidationUtils의 rejectIfEmptyOrWhitespace 메서드를 사용하여 객체의 title 필드가 비어있거나 공백일 경우에는 errors에 에러 정보를 담는 로직을 구현하였다. "notempty"는 에러코드이며 "Empty title is now allowed."는 디폴트 메세지다.
위에서 작성한 클래스와 함께 아래의 스프링부트의 ApplicationRunner를 구현한 AppRunner 클래스를 동작할 경우 검증 로직이 동작한다는 것을 알 수 있다. 참고로 BeanPropertyBindingResult는 객체에 대한 에러 정보를 담는 객체이며 Errors의 구현체다. event 객체에 에러가 있을 경우 이 객체에 정보가 담기게 되며 errors를 통해 에러 정보를 구할 수 있다.
BeanPropertyBindingResult는 Spring MVC에서 Error 인터페이스의 디폴트 구현체로 사용되며, 자동적으로 주입되기 때문에 실제 개발하는 동안에는 쓸 일이 거의 없다. 하지만 아래 코드에서는 테스트 용도이기 때문에 임시적으로 사용했다.
@Component
public class AppRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
Event event = new Event();
EventValidator eventValidator = new EventValidator();
Errors errors = new BeanPropertyBindingResult(event, "event");
eventValidator.validate(event, errors);
System.out.println(errors.hasErrors());
errors.getAllErrors().forEach(e->{
System.out.println("==== error code ====");
Arrays.stream(e.getCodes()).forEach(System.out::println);
System.out.println(e.getDefaultMessage());
});
}
}
true
==== error code ====
notempty.event.title
notempty.title
notempty.java.lang.String
notempty
Empty title is now allowed.
위 출력결과를 보면은 validate 메서드에서는 에러코드는 notempty라고 명시했지만 Validator가 알아서 에러 코드를 여러 개 자동적으로 생성한 것을 볼 수 있다.
| Bean Validation을 이용한 검증 로직 구현
스프링 부트2.05 이상 버전을 이용할 시에는 따로 Validator 구현체를 작성하지 않고도 Validator 타입의 필드 변수에 @Autowired 같은 의존성 주입 어노테이션을 붙일 경우 LocalValidatorFactoryBean을 빈이 자동으로 등록된다. 이 LocalValidatorFactoryBean는 @NotEmpty, @Email 와 같은 Bean Validation을 체크하여 검증한다.
public class Event {
Integer id;
@NotEmpty
String title;
@Min(0)
Integer limit;
@Email
String email;
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
Validator validator;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(validator.getClass());
Event event = new Event();
event.setLimit(-1);
event.setEmail("aaa2");
Errors errors = new BeanPropertyBindingResult(event, "event");
validator.validate(event, errors);
System.out.println(errors.hasErrors());
errors.getAllErrors().forEach(e->{
System.out.println("==== error code ====");
Arrays.stream(e.getCodes()).forEach(System.out::println);
System.out.println(e.getDefaultMessage());
});
}
}
class org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
true
==== error code ====
Min.event.limit
Min.limit
Min.java.lang.Integer
Min
반드시 0보다 같거나 커야 합니다.
==== error code ====
NotEmpty.event.title
NotEmpty.title
NotEmpty.java.lang.String
NotEmpty
반드시 값이 존재하고 길이 혹은 크기가 0보다 커야 합니다.
==== error code ====
Email.event.email
Email.email
Email.java.lang.String
Email
이메일 주소가 유효하지 않습니다.
참고자료 : https://www.inflearn.com/course/spring-framework_core/