지금까지 구현한 V2 의 method 는
비지니스 로직보다 검증로직의 길이가 더 길어 유지보수성이 매우 떨어진다.
@Component
로 Spring Bean 으로 등록Validator
를 상속받아 상황에 맞게 검증 로직을 완성시켜줄 수 있다.supports
validate
method 가 객체를 검증할 수 있는지 판단하는 로직validate
BindingResult
을 변수로 받는다.BindingResult
는 error
를 상속받았기 때문에 별도 케스팅 없이 형변환이 가능하다.package hello.itemservice.web.validation;
import hello.itemservice.domain.item.Item;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
/**
* 검증 로직을 담당하는 객체
*/
@Component
public class ItemValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
// 매개변수 Class 가 Item 과 같은 타입인지 확인하는 로직
// isAssignableFrom 은 자식 Class 까지도 true 를 반환한다.
return Item.class.isAssignableFrom(clazz);
}
//-- 실질적인 검증 로직이 작동되는 method --//
@Override
public void validate(Object target, Errors errors) {
// 매개변수를 Item 으로 케스팅
Item item = (Item) target;
//-- 실질적 검증로직 --//
// Errors 는 BindingResult 의 부모 클레스 이므로
// BindingResult 도 매개변수로 받을 수 있다.
if (!StringUtils.hasText(item.getItemName()))
errors.rejectValue("itemName", "required");
if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 100000)
errors.rejectValue("price", "range",
new Object[]{1000,1000000}, null);
if (item.getQuantity() == null || item.getQuantity() >= 9999)
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);
}
}
}
ItemValidator
을 DI 한다.@Slf4j
@Controller
@RequestMapping("/validation/v2/items")
@RequiredArgsConstructor
public class ValidationItemControllerV2 {
private final ItemRepository itemRepository;
private final ItemValidator itemValidator;
validate
을 호출한다.validate
method 내부에서 검증에 실패할경우 RedirectAttributes
에 오류코드를 저장해준다.//-- validation 분리 --//
@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";
}
// 검증 성공 로직
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/validation/v2/items/{itemId}";
}