1 분 소요


BindingResult1

Controller

@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() > 1000000) {
        bindingResult.addError(new FieldError("item", "price", "가격은 1,000 ~ 1,000,000 까지 허용합니다."));
    }

    // 수량 생략..

    //특정 필드 예외가 아닌 전체 예외
    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);
        return "validation/v2/addForm";
    }
}

BindingResult bindingResult 파라미터의 위치는 @ModelAttribute Item item 다음에 와야 한다.

FieldError

public FieldError(String objectName, String field, String defaultMessage) {}

필드에 오류가 있으면 FieldError 객체를 생성해서 bindingResult에 담아두면 된다.

  • objectName: @ModelAttribute 이름
  • field: 오류가 발생한 필드 이름
  • defaultMessage: 오류 기본 메시지

ObjectError

public ObjectError(String objectName, String defaultMessage) {}

특정 필드를 넘어 오류가 있으면 ObjectError객체를 생성해서 bindingResult에 담아두면 된다.

  • objectName: @ModelAttribute의 이름
  • defaultMessage: 오류 기본 메시지

addForm.html

<!-- 글로벌 오류 -->
<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="이름을 입력하세요">
    <div class="field-error" th:errors="*{itemName}">
    상품명 오류
    </div>
</div>

<!-- 이하 생략.. -->

타임리프 스프링 검증 오류 통합 기능

  • #fields: #fieldsBindingResult가 제공하는 검증 오류에 접근할 수 있다.
  • th:errors: 해당 필드에 오류가 있는 경우에 태그를 출력한다. th:if의 편의 버전.
  • th:errorclass: th:field에서 지정한 필드에 오류가 있으면 class 정보를 추가한다.


BindingResult2

  • 스프링이 제공하는 검증 오류를 보관하는 객체.
  • BindingResult가 있으면 @ModelAttribute에 데이터 바인딩 시 오류가 발생해도 컨트롤러가 호출된다.


Ex) @ModelAttribute에 바인딩 시 타입 오류가 발생

  • BindingResult(X) -> 400오류가 발생하면서 컨트롤러 호출X
  • BindingResult(O) -> 오류 정보(FieldError)를 BindingResult에 담아서 컨트롤러 정상 호출

BindingResult에 검증 오류를 적용하는 방법

  • @ModelAttribute의 객체에 타입 오류 등으로 바인딩이 실패하는 경우 스프링이 FieldError 생성해서 BindingResult에 넣어준다.
    • bindingResult.addError(new FieldError("item", "price", "qqq", ...))이런 식으로 스프링이 알아서 생성해서 넣어준 뒤 컨트롤러를 호출해준다.
  • 개발자가 직접 넣어준다.
  • Validator 사용

[주의]

  • BindingResult는 검증 대상 바로 다음에 와야 한다.
    Ex) @ModelAttribute Item item 바로 다음에 BindingResult
  • BindingResult는 Model에 자동으로 포함된다.

BindingResult와 Errors

  • org.springframework.validation.Errors
  • org.springframework.validation.BindingResult

인터페이스 BindingResultErrors인터페이스를 상속받고 있다.
Errors는 단순한 오류 저장과 조회 기능을 제공하고, BindingResult는 여기에 추가적인 기능들(addError())을 제공하므로 BindingResult를 사용하면 된다.


<출처 : 인프런 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술(김영한)>

댓글남기기