FieldError, ObjectError를 이용하면 사용자가 입력한 잘못된 데이터도 서버에 다녀왔어도 그대로 화면에서 보존해준다.
VaidationItemControllerV2 - addItemV2
@PostMapping("/add")
public String addItemV2(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) {
// 검증 로직
if(!StringUtils.hasText(item.getItemName())) {
bindingResult.addError(new FieldError("item", "itemName", item.getItemName(), false, null, null, "상품 이름은 필수입니다"));
}
if(item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
bindingResult.addError(new FieldError("item", "price", item.getPrice(), false, null, null, "가격은 1,000 ~ 1,000,000 까지 허용합니다."));
}
if(item.getQuantity() == null || item.getQuantity() > 9999) {
bindingResult.addError(new FieldError("item", "quantity", item.getQuantity(), false, null, null, "수량은 최대 9,999 까지 허용합니다."));
}
// 특정 필드가 아닌 복합 룰 검증
if(item.getPrice() != null && item.getQuantity() != null) {
int resultPrice = item.getPrice() * item.getQuantity();
if(resultPrice < 10000) {
bindingResult.addError(new ObjectError("item", null, null, "가격 * 수량의 합은 10,000원 이상어야 합니다. 현재 값 = " + resultPrice));
}
}
// 검증에 실패하면 다시 입력 폼으로
// 부정의 부정을 하면 읽기 복잡하다
if(bindingResult.hasErrors()) {
log.info("errors = {} ", bindingResult);
// bindingResult 는 model Attribute에 안담아도 자동으로 view로 넘겨준다
return "validation/v2/addForm";
}
// 성공로직
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/validation/v2/items/{itemId}";
// 여기까지 하고 한번 돌려보고 REsponse 보기
}
기존 소스에서 addItemV1()의 @PostMapping("/add")을 주석처리해야한다.
FieldError 생성자
FieldError 는 두 가지 생성자를 제공한다.
public FieldError(String objectName, String field, String defaultMessage);
public FieldError(String objectName, String field, @Nullable Object rejectedValue, boolean bindingFailure,
@Nullable String[] codes, @Nullable Object[] arguments, @Nullable String defaultMessage)
파라미터 목록
- objectName : 오류가 발생한 객체 이름
- field : 오류 필드
- rejectedValue : 사용자가 입력한 값(거절된 값)
- bindingFailure : 타입 오류 같은 바인딩 실패인지, 검증 실패인지 구분 값
- codes : 메시지 코드
- arguments : 메시지에서 사용하는 인자
- defaultMessage : 기본 오류 메시지
ObjectError도 유사하게 두 가지 생성자를 제공한다.
FieldError는 오류 발생 시 사용자 입력 값을 유지할 수 있다.
new FieldError("item", "price", item.getPrice(), false, null, null, "가격은 1,000 ~ 1,000,000 까지 허용합니다.")
사용자의 입력 데이터가 컨트롤러의 @ModelAttribute에 바인딩되는 시점에 오류가 발생하면 모델 객체에
사용자 입력 값을 유지하기 어렵다.
예를 들어서 가격에 숫자가 아닌 문자가 입력된다면 가격은 Integer 타입이므로 문자를 보관할 수 있는 방법이 없다.
그래서 오류가 발생한 경우 사용자의 입력 값을 보관하는 별도의 방법이 필요하다.
그리고 이렇게 보관한 사용자 입력 값을 검증 오류 발생 시 화면에 다시 출력하면 된다.
FieldError 는 오류 발생 시 사용자 입력 값을 저장하는 기능을 제공한다.
타임리프의 사용자 입력 값 유지
th:field="*{price}"
타임리프의 th:field는 매우 똑똑하게 동작하는데, 정상 상황에는 모델 객체의 값을 사용하지만, 오류가 발생하면 FieldErorr에서 보관한 값을 사용해서 처리한다.
스프링의 바인딩 오류 처리
타입 오류로 바인딩에 실패하면 스프링은 FieldError를 생성하면서 사용자가 입력한 값을 넣어둔다.
그리고 해당 오류를 BindingResult에 담아서 컨트롤러를 호출한다.
따라서 타입 오류같은 바인딩 실패시에도 사용자의 오류 메시지를 정상 출력할 수 있다.
'스프링 > 스프링 웹 개발 활용' 카테고리의 다른 글
[Spring] BindingResult의 rejectValue(), reject() 를 사용하여 FieldError, ObjectError를 직접 생성하지 않고 검증하기 (0) | 2023.09.27 |
---|---|
[Spring] erros.properties 를 이용한 오류 코드와 메시지 처리 (0) | 2023.09.26 |
[Spring] BindingResult를 이용한 검증처리 (1) | 2023.09.22 |
[Spring] 직접 검증처리 (0) | 2023.09.22 |
[Spring] 검증(Validation) 오류처리 및 프로젝트 생성 + 프로젝트 명칭 바꾸기 (0) | 2023.07.27 |
댓글