김영한 스프링 mvc2편의 Validation을 보며, 순차적으로 Validation을 적용해보았다. Validator부터, restApi에 Validator 적용, BeanValidation을 동시에 적용해서 Validator에 복잡도를 줄이는 방식까지 최종적으로 적용했다
주요 개선 이슈
- ModelAttribute가 자동으로 model에 다시 attribute를 추가하지 못하는 문제
- Service 계층과 Validator 분리
- 한 컨트롤러에서 여러 개의 Validator 추가하기
- RestApi에서 Validator 사용하기 (RestApi에서 에러 메시지 소스 사용)
- @ModelAttribute에 BeanValidation 적용
- RestApi에 BeanValidation 적용하기
정리
결과적으로, 검증 로직이 기존에는 Service, 또는 Domaim Model에 직접 작성되어 있었다. Validation을 적용하니 검증 로직은 따로 작성 또는 annotation으로 간단하게 처리할 수 있고, 서비스와 모델에는 단순히 성공 로직만 작성해도 되어서 매우 간단해졌다.
기존 User 모델
public class User {
private final Long id;
private final String username;
private final String password;
private int remainingRents = 3; // 남은 대출 가능 권수
/**
* 책 대출 메서드, 남은 권수가 0권 이상이면, book.rent 메서드 호출해서 결과 리턴
*
* @param book : 빌릴 책
* @return 성공 여부
*/
public boolean rent(Book book) {
if (remainingRents > 0) {
remainingRents--;
return book.rent(this);
}
return false;
}
/**
* 책 반납 메서드, book.unRent 메서드 호출해서 성공하면, 대출 가능 권수 늘리고 성공 리턴
*
* @param book : 반납할 책
* @return : 성공 여부
*/
public boolean unRent(Book book) {
if (book.unRent(this)) {
remainingRents++;
return true;
}
return false;
}
}
Validation 적용 이후 User 모델
public class User {
private final Long id;
private final String username;
private final String password;
private int remainingRents = 3; // 남은 대출 가능 권수
/**
* 책 대출 메서드
* 책을 대출, 대출 권수 차감
*
* @param book : 빌릴 책
*/
public void rent(Book book) {
book.rent(this);
remainingRents--;
}
/**
* 책 반납 메서드
* 책을 반납, 대출 권수를 복구한다.
*
* @param book : 반납할 책
*/
public void unRent(Book book) {
book.unRent(this);
remainingRents++;
}
@Override
public boolean equals(Object object) {
if (object == null || getClass() != object.getClass()) return false;
User user = (User) object;
return Objects.equals(getId(), user.getId());
}
@Override
public int hashCode() {
return Objects.hashCode(getId());
}
}