코드 그라데이션

BindingResult 첫 번째 본문

Spring/Validation

BindingResult 첫 번째

완벽한 장면 2024. 2. 22. 00:58

BindingResult 첫 번째

지금부터 스프링이 제공하는 검증 오류 처리 방법을 알아본다. 여기서 핵심은 BindingResult이다.

 

BindingResult가 errors의 역할을 해 줄 것이다.

addItem 변경

// 메서드명 변경
@PostMapping("/add")
public String addItemV1(@ModelAttribute Item item,
                      BindingResult bindingResult,
                      RedirectAttributes redirectAttributes) {

    // 검증 로직
    if (!StringUtils.hasText(item.getItemName())) {
        bindingResult.addError(new FieldError("item", "itemName", "상품 이름은 필수입니다."));
    }
    if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 100000) {
        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", "[가격 X 수량]의 합은 10,000원 이상이어야 합니다. 현재 값 = " + resultPrice));
        }
    }

    // 에러 남기고 리다이렉트
    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}";
}

주의

 

BindingResult bindingResult 파라미터의 위치는 @ModelAttribute Item item 다음에 와야 한다.
-> 아이템 객체의 결과를 담고 있기 때문에

 

아 참고로

둘은 상속관계이다.

 

 

# 필드 오류

 

# FieldError 생성자

 

# 글로벌 오류 - ObjectError

 

# ObjectError 생성자

 


addFrom.html 수정

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link th:href="@{/css/bootstrap.min.css}"
          href="../css/bootstrap.min.css" rel="stylesheet">
    <style>
        .container {
            max-width: 560px;
        }
        .field-error {
            border-color: red;
            color: red;
        }
    </style>
</head>
<body>

<div class="container">

    <div class="py-5 text-center">
        <h2 th:text="#{page.addItem}">상품 등록</h2>
    </div>

    <form action="item.html" th:action th:object="${item}" method="post">

        <div th:if="${#fields.hasGlobalErrors()}"> <!--여기-->
            <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}"
                   th:errorclass="field-error" 
                   class="form-control" placeholder="이름을 입력하세요"> <!--여기-->

            <!-- 에러 메시지 출력 수정 --> <!-- th:errors // s 붙는 것 유의--> 
            <div class="field-error" th:errors="*{itemName}"> <!--여기-->
                상품명 오류
            </div>
        </div>
        
        <div>
            <label for="price" th:text="#{label.item.price}">가격</label>
            <!-- 에러 검증 로직 수정 -->
            <input type="text" id="price" th:field="*{price}"
                   th:errorclass="field-error" class="form-control" placeholder="가격을 입력하세요"> <!--여기-->

            <!-- 에러 메시지 출력 수정 -->
            <div class="field-error" th:errors="*{price}"> <!--여기-->
                가격 오류
            </div>
        </div>

        <div>
            <label for="quantity" th:text="#{label.item.quantity}">수량</label>
            <!-- 에러 검증 로직 수정 -->
            <input type="text" id="quantity" th:field="*{quantity}"
                   th:errorclass="field-error" class="form-control" placeholder="수량을 입력하세요"> <!--여기-->

            <!-- 에러 메시지 출력 수정 -->
            <div class="field-error" th:errors="*{quantity}"> <!--여기-->
                수량 오류
            </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> <!-- /container -->
</body>
</html>

• 검증과 오류 메시지 공식 메뉴얼
 https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#validation-and-error-messages

 

Tutorial: Thymeleaf + Spring

Preface This tutorial explains how Thymeleaf can be integrated with the Spring Framework, especially (but not only) Spring MVC. Note that Thymeleaf has integrations for both versions 3.x and 4.x of the Spring Framework, provided by two separate libraries c

www.thymeleaf.org

 

 

# 글로벌 오류 처리

 

# 필드 오류 처리

 

728x90

'Spring > Validation' 카테고리의 다른 글

FieldError와 ObjectError  (0) 2024.02.23
BindingResult 두 번째  (0) 2024.02.22
프로젝트 준비 V2  (0) 2024.02.21
검증 직접 처리  (0) 2024.02.20
초창기 샘플코드  (0) 2024.02.20
Comments