스프링/4. 스프링 MVC-2

28. BindingResult

sdafdq 2023. 8. 29. 22:48

BindingResult는 스프링에서 제공해주는 에러관련 기능이다. 

 

@PostMapping("/add")
public String addItemV1(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) {
    //검증 오류 보관


    //검증 로직
    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 result = item.getQuantity() * item.getPrice();
        if(result < 10000){
            bindingResult.addError(new ObjectError("item", "가격 * 수량의 합은 10,000원 이상이어야 합니다. 현재값 = \" + result"));
        }
    }

    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}";
}

순서가 중요하다. 내가 다룰 객체 바로 뒤에 넣어야 한다. 이번 같은 경우는 Item 다음에 바로 넣었다.

쉽다.

BindingResult.addError(new Error(객체명, 객체의오류를내보낼필드명, 오류메시지 ))

 

뭐 당연히 인자로 받았기 때문에 자동으로 모델에 들어가고, 거기에다 스프링에서 제공해주는 기능이라 더더욱 자동으로 모델에 들어간다.

 

FieldError가 필드에 관한에러, (나중에 템플릿에 이 필드에 관해서 묶어줌)

ObjectError는 그냥 오브젝트 전체에 관련한 에러라고 보면 된다.

 

<form action="item.html" th:action th:object="${item}" method="post">
    <div th:if="${#fields.globalErrors()}">
        <p class="field-error" th:each="err : ${#fields.globalErrors()}" th:text="${err}">전체 오류 메시지</p>
    </div>

    <div>
        <label for="itemName" th:text="#{label.item.itemName}">상품명</label>
        <input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요"
               th:errorclass="field-error">
        <div class="field-error" th:errors="*{itemName}">
            <p >상품 이름 오류</p>
        </div>
    </div>
    <div>
        <label for="price" th:text="#{label.item.price}">가격</label>
        <input type="text" id="price" th:field="*{price}" class="form-control" placeholder="가격을 입력하세요"
               th:errorclass="field-error">
        <div  class="field-error" th:errors="*{price}">
            <p>가격 오류</p>
        </div>
    </div>
    <div>
        <label for="quantity" th:text="#{label.item.quantity}">수량</label>
        <input type="text" id="quantity" th:field="*{quantity}" class="form-control" placeholder="수량을 입력하세요"
               th:errorclass="field-error">
        <div  class="field-error" th:errors="*{quantity}">
            <p>수량 오류</p>
        </div>
    </div>

    <hr class="my-4">

    <div class="row">
        <div class="col">
            <button class="w-100 btn btn-primary btn-lg" type="submit" th:text="#{button.save}">상품 등록</button>
        </div>
        <div class="col">
            <button class="w-100 btn btn-secondary btn-lg"
                    onclick="location.href='items.html'"
                    th:onclick="|location.href='@{/validation/v2/items}'|"
                    type="button" th:text="#{button.cancel}">취소</button>
        </div>
    </div>

</form>

<div th:if="${#fields.globalErrors()}">

bindingResult에 접근하려면 #fields 이걸로 접근하면 된다.

만약 bindingResult에 글로벌에러가 있다면

 

<input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요"
               th:errorclass="field-error">

errorclass는 에러 있으면 저 클래스 추가.

참고로 이거 뭐 아래 errors="*{price}" 처럼 우리가 따로 필드명 명시하지도 않았는데 되는 이유는 

저 th:field 가 에러까지 포함함. 그냥 th:errors="*{itemName}" 까지 했다고 생각하면 됨.

 

 

 

<div  class="field-error" th:errors="*{price}">

th:errors 에러가 있으면 저 태그 출력, 아니면 안함.

여기서 오브젝트접근으로 쓸 수 있는 이유는 필드명 똑같이 했고 바인딩 했기 때문. 

 

 

 

그리고 이 bindingResult,

Rest API에서도 Json으로 바꿔서 내려줄 수 있다고 함.

'스프링 > 4. 스프링 MVC-2' 카테고리의 다른 글

30. FieldError, ObjectError  (0) 2023.08.29
29. BindingResult2  (0) 2023.08.29
27. 검증 직접 구현  (0) 2023.08.28
26. 검증  (0) 2023.08.27
25. 메시지, 국제화 적용  (0) 2023.08.27