FieldError에는 2가지 생성자가 존재한다.
public FieldError(String objectName,String field, String defaultMessage);
public FieldError(String objectName,String field, @Nullable Object rejectValue, boolean bindingFailure,@Nullable String[] codes,@Nullable Object[] arguments, @Nullable String defaultMessage)
spring:
messages:
basename: messages, errors
Error.properties
required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0} ~ {1} 까지 허용합니다.
max.item.quantity=수량은 최대 {0} 까지 허용합니다.
totalPriceMin=가격 * 수량의 합은 {0}원 이상이어야 합니다. 현재 값 = {1}
메시지 코드는 위의 properties를 사용해서 지정이 가능하고, 하나가 아니라 배열로 여러 값을 전달 할 수도 있다.
arguments : new Object[]{1000,1000000} 를 사용해서 코드의 {0} ,{1} 로 치환 할 값을 전달
변경한 코드 : addItemV3
@PostMapping("/add")
public String addItemV3(@ModelAttribute("item") Item item, BindingResult bindingResult,
RedirectAttributes redirectAttributes) {
if (!StringUtils.hasText(item.getItemName())) {
bindingResult.addError(new FieldError("item", "itemName",
item.getItemName(), false, new String[]{"required.item.itemName"}, null, null));
}
if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() >
1000000) {
bindingResult.addError(new FieldError("item", "price", item.getPrice(),
false, new String[]{"range.item.price"}, new Object[]{1000,1000000}, null));
}
if (item.getQuantity() == null || item.getQuantity() >= 10000) {
bindingResult.addError(new FieldError("item", "quantity",
item.getQuantity(), false, new String[]{"max.item.quantity"}, new Object[]{9999}, null));
}
//특정 필드 예외가 아닌 전체 예외
if (item.getPrice() != null && item.getQuantity() != null) {
int resultPrice = item.getPrice() * item.getQuantity();
if (resultPrice < 10000) {
bindingResult.addError(new ObjectError("item", new String[]{"totalPriceMin"}, new Object[]{10000,item.getQuantity()*item.getPrice()}, null));
}
}
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}";
}
로그를 찍어보니 확실하게 본인이 어떤걸 target으로 하고있는지 아는걸 확인할 수있다.
어떤 걸 target으로 하는지 알고있기 때문에 bindingResult 가 제공하는 rejectValue() 와 reject()를 사용하면 FieldError와 ObjectError를 직접 생성하지 않고 검증 오류를 다룰수 있게 된다.
void rejectValue(@Nullable String field, String errorCode,@Nuallable Object[] errorArgs,
@Nullable String defaultMessage);
field : 오류 필드명
errorCode : 오류 코드(메시지에 등록된 코드가 아님.)
errorArgs : 오류메시지에서{0}을 치환하기 위한 값
defaultMessage: 오류 메시지를 찾을 수 없을 때 사용하는 기본 메시지
bindingResult.rejectValue("price", "range", new Object[]{1000, 1000000}, null)