-
상품 등록 범위 검증 - V2 (BindingResult)스프링/스프링 MVC 패턴 2023. 2. 23. 13:18
이전 게시글보다 효율적인 방법이 있다. 코드를 간결하고 명확하게 줄여주는 방법이다.
스프링에서 제공하는 BindingResult를 사용하면 된다.
@PostMapping("/add") public String addItem(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) { // BindingResult는 무조건 @ModelAttribute 다음에 넣어야함
메서드의 파라미터에서 @ModelAttribute 다음에 BindingResult를 넣어준다.
bindingResult.addError(new FieldError("item", "itemName", "상품 이름은 필수입니다."));
bindingResult는 스프링에서 제공하는 기능인데 error를 따로 만들지않아도 objectName, field, defualtMessage 순으로 입력하면 에러처리를 할 수 있는 기능이다.
@PostMapping("/add") public String addItem(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) { // BindingResult는 무조건 @ModelAttribute 다음에 넣어야함 // 검증 로직 if (!StringUtils.hasText(item.getItemName())) { bindingResult.addError(new FieldError("item", "itemName", "상품 이름은 필수입니다.")); } if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) { bindingResult.addError(new FieldError("item", "price", "가격은 1,000 ~ 1,000,000 까지 허용합니다.")); } if (item.getQuantity() == null || item.getQuantity() >= 9999) { bindingResult.addError(new FieldError("item", "quantity", "수량은 최대 9,999까지 허용합니다.")); } // 특정 필드가 아닌 복합 룰 검증 if (item.getPrice() != null && item.getQuantity() != null ) { int resultPrice = item.getPrice() * item.getQuantity(); if (resultPrice < 10000) { bindingResult.addError(new ObjectError("item", "가격 * 수량의 합은 10,000원 이상이어야 합니다. 현재 값 = " + resultPrice)); } } // 검증에 실패하면 다시 입력 폼으로 이동하는 로직 if (bindingResult.hasErrors()) { log.info("errors = {}", bindingResult); // model.addAttribute("errors", 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}"; }
bindingResult를 이용한 코드이다. 저번 게시글에서 error를 만들고 필드마다 각각 넣어서 에러처리를 했는데 그 방식보다 훨씬 간결하고 이해하기 쉬워진 것을 확인할 수 있다.
html도 bindingResult 방식으로 바꿔야 한다.
<div th:if="${#fields.hasGlobalErrors()}"> <p class="field-error" th:each="err : ${#fields.globalErrors()}" th:text="${err}">글로벌 오류 메시지</p> </div>
우선 글로벌 오류 메시지를 출력하는 코드이다. 이것도 전에 했던 코드보다 간결해졌으며 한 줄만으로 글로벌 오류 메시지를 출력할 수 있다.
<label for="itemName" th:text="#{label.item.itemName}">상품명</label> <input type="text" id="itemName" th:field="*{itemName}" th:errorclass="field-error" class="form-control" placeholder="이름을 입력하세요"> <div class="field-error" th:errors="*{itemName}"> 상품명 오류
필드별로 오류를 따로 설정해야하는데 상품명 오류같은 경우이다.
4번째 줄이 에러가 났을 때 에러를 출력하는 코드인데, th:errors="*{itemName}"으로 itemName이라는 에러가 발생했을 때 상품명 오류를 출력하고, 에러가 발생하지 않았을 때에는 "상품명 오류"라는 말이 아예 출력되지 않는다.
가격 오류와 수량 오류 필드도 위와 동일한 방식으로 설계된다.
또한 BindingResult는 객체 타입 오류 등으로 바인딩이 실패하는 경우에도 스프링이 자동으로 FieldError를 생성해서 BindingResult에 넣어준다.
이전에는 다른 타입을 넣어주면 400 에러페이지로 이동했는데 BindingResult를 사용하면 특정 FieldError가 자동으로 호출되어서 에러 메시지가 출력된다.
'스프링 > 스프링 MVC 패턴' 카테고리의 다른 글
Validation 분리 (0) 2023.02.23 오류 코드와 메시지 처리 (0) 2023.02.23 상품 등록 범위 검증 - V1 (0) 2023.02.22 셀렉트 박스 (배송 방식 : 빠른 배송, 일반 배송, 느린 배송) (0) 2023.02.19 라디오 버튼 (상품 종류 : 도서, 식품, 기타) (0) 2023.02.19