[Spring] Validator 분리, 검증 분리

썸머·2022년 11월 14일
0

컨트롤러에서 검증 로직이 차지하는 부분은 매우 크다. 이런 경우 별도의 클래스로 역할을 분리하는 것이 좋다. 그리고 이렇게 분리한 검증 로직을 재사용 할 수도 있다.

Validator1

스프링은 검증을 체계적으로 제공하기 위해 다음 인터페이스를 제공한다.
검증기를 직접 불러서 사용한다.

public interface Validator {
boolean supports(Class<?> clazz);
void validate(Object target, Errors errors);
}
  • supports(){}: 해당 검증기를 지원하는 여부 확인
  • validate(Object target, Errors errors): 검증 대상 객체와 BindingResult

예시

  • Validator를 상속받은 ItemValidator
@Component
public class ItemValidator implements Validator {
 @Override
 public boolean supports(Class<?> clazz) {
 return Item.class.isAssignableFrom(clazz);
 }
 @Override
 public void validate(Object target, Errors errors) {
 Item item = (Item) target;
 ValidationUtils.rejectIfEmptyOrWhitespace(errors, "itemName",
"required");
 if (item.getPrice() == null || item.getPrice() < 1000 ||
item.getPrice() > 1000000) {
 errors.rejectValue("price", "range", new Object[]{1000, 1000000},
null);
 }
 if (item.getQuantity() == null || item.getQuantity() > 10000) {
 errors.rejectValue("quantity", "max", new Object[]{9999}, null);
 }
 //특정 필드 예외가 아닌 전체 예외
 if (item.getPrice() != null && item.getQuantity() != null) {
 int resultPrice = item.getPrice() * item.getQuantity();
 if (resultPrice < 10000) {
 errors.reject("totalPriceMin", new Object[]{10000,
resultPrice}, null);
 }
 }
 }
}
  • 검증을 사용하는 controller
private final ItemValidator itemValidator;
@PostMapping("/add")
public String addItemV5(@ModelAttribute Item item, BindingResult bindingResult,
RedirectAttributes redirectAttributes) {
 itemValidator.validate(item, bindingResult);
 
 if (bindingResult.hasErrors()) {
 log.info("errors={}", bindingResult);
 return "validation/v2/addForm";
 } 
 ...}

Validator2

WebDataBinder를 통해서 사용한다. WebDataBinder는 스프링의 파라미터 바인딩의 역할을 해주고 검증 기능도 내부에 포함한다.

예시

  • controller에 추가
@InitBinder // 1
public void init(WebDataBinder dataBinder) {
 log.info("init binder {}", dataBinder);
 dataBinder.addValidators(itemValidator);
}
  1. 해당 컨트롤러에만 영향을 준다. 글로벌 설정은 별도로 해야한다.
  • @Validated 적용
@PostMapping("/add")
public String addItemV6(@Validated //1
@ModelAttribute Item item, BindingResult 
bindingResult, RedirectAttributes redirectAttributes) {
  1. validator를 직접 호출하는 부분이 사라지고, 대신에 검증 대상 앞에 @Validated 가 붙었다

동작방식

  1. @Validated는 검증기를 실행하라는 애노테이션이다.
  2. 이 애노테이션이 붙으면 앞서 WebDataBinder에 등록한 검증기를 찾아서 실행한다.
  3. 그런데 여러 검증기를 등록한다면 그 중에 어떤 검증기가 실행되어야 할지 구분이 필요하다. 이때 supports()가 사용된다.

참고

@Validated, @Valide 둘 다 사용 가능

profile
썸머의 개발블로그

0개의 댓글