2023.12.18 - [Spring] - Spring 검증 - BindingResult (FieldError, ObjectError, rejectValue, reject)
해당 글은 위의 게시글에 이어 작성함을 참고하고 읽어주길 바람
Validator
public interface Validator {
boolean supports(Class<?> clazz);
void validate(Object target, Errors errors);
}
supports , validate 기능을 제공하는 인터페이스이다.
- supports() {} : 해당 검증기를 지원하는 여부 확인(나중에 더 자세하게 설명)
- validate(Object target, Errors errors) : 검증 대상 객체와 BindingResult(Errors 의 자식 클래스)
Validator를 상속하는 나만의 ItemValidator를 만들어보자. (컨트롤러에 있는 검증 로직을 분리하기 위함)
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);
}
}
}
}
@Component을 통해 스프링이 컴포넌트 스캔을 통해 사용할 수 있도록 설정해준다.
또한, supports를 통해 ItemValidator를 적용하는 객체가 item 객체인지 아닌지 확인한다.
( isAssignableFrom을 사용하면 자식 클래스까지 확인 가능 )
그리고, validate를 통해 검증 로직을 실행한다.
WebDataBinder
위에서 만든 ItemValidator를 컨트롤러에서 사용하려면 WebDataBinder를 사용하면 된다.
WebDataBinder 는 스프링의 파라미터 바인딩의 역할을 해주고 검증 기능도 내부에 포함한 isAssignableFrom 다.
컨트롤러에 추가해보자.
@InitBinder
public void init(WebDataBinder dataBinder) {
log.info("init binder {}", dataBinder);
dataBinder.addValidators(itemValidator);
}
이렇게 WebDataBinder에 검증기를 추가하면 해당 컨트롤러에서는 검증기를 자동으로 적용할 수 있다.
@InitBinder → 해당 컨트롤러에만 영향을 준다. 글로벌 설정은 별도로 해야한다.
이제 검증기를 사용할 부분에서 @Validated 를 통해 검증기를 적용해보자.
@PostMapping("/add")
public String addItemV6(@Validated @ModelAttribute Item item, BindingResult
bindingResult, RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
log.info("errors={}", bindingResult);
return "validation/v2/addForm";
}
//성공 로직
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/validation/v2/items/{itemId}";
}
@Validated 는 검증기를 실행하라는 에노테이션이다.
이 애노테이션이 붙으면 앞서 WebDataBinder 에 등록한 검증기를 찾아서 실행한다.
그런데 여러 검증기를 등록한다면 그 중에 어떤 검증기가 실행되어야 할지 구분이 필요하다.
이때 supports() 가 사용된다.
→ supports(Item.class) 호출되고, 결과가 true 이므로 ItemValidator 의 validate() 가 호출된다.
참고
검증시 @Validated @Valid 둘다 사용가능
@Valid 를 사용하려면 build.gradle 의존관계 추가가 필요하다.
implementation 'org.springframework.boot:spring-boot-starter-validation'
@Valid는 java 표준 검증 에노테이션이고, @Validated는 자바 스프링이 제공하는 검증 에노테이션이다.
정리
컨트롤러의 부담을 줄이고 검증 로직을 따로 Validator를 통해 분리했다.
WebDataBinder를 통해 컨트롤러에 검증기를 추가했고, @Validated 를 통해 검증기를 적용시켰다.
다음 게시글에서는 BeanValidator에 대해서 설명할 것이다.
이는 스프링이 제공하는 편리한 기능이니 기대해도 좋다.
'Spring' 카테고리의 다른 글
Spring(스프링) - 서블릿 예외 처리 및 오류 페이지(필터, 인터셉터) (1) | 2023.12.29 |
---|---|
Spring 검증 - Bean Validation (1) | 2023.12.21 |
Spring 검증 - BindingResult (FieldError, ObjectError, rejectValue, reject) (1) | 2023.12.18 |
스프링 메세지 소스 및 국제화(MessageSource, Locale) (0) | 2023.12.14 |
Spring - ArgumentResolver 활용 (0) | 2023.09.26 |