BindingResult
- 스프링이 제공하는 검증 오류를 보관하는 객체
- BindingResult가 있으면 @ModelAttribute에 데이터 바인딩 시 오류가 발생해도 컨트롤러가 호출됨
- 검증할 대상 바로 다음에 와야함 ex) @ModelAttribute Item item , BindingResult bindingResult
FieldError
가격에 숫자가 아닌 문자가 입력될 때 문자를 보관할 방법이 없음 → FieldError가 오류 발생시 사용자 입력 값 저장
- objectName : 오류가 발생한 객체 이름
- field : 오류 필드
- rejectedValue : 사용자가 입력한 값(거절된 값) - 오류 발생시 사용자 입력 값을 저장하는 필드
- bindingFailure : 타입 오류 같은 바인딩 실패인지 여부( 바인딩 실패, 검증 실패 구분 값)
- codes : 메시지 코드
- arguments : 메시지에서 사용하는 인자
- defaultMessage : 기본 오류 메시지
타임리프 스프링 검증 오류 통합 기능
- #fields : #fields로 BindingResult가 제공하는 검증 오류에 접근
- th:errors : 해당 필드에 오류가 있는 경우에 태그를 출력한다. th:if의 편의 버전
- th:errorclass="field-error" : th:field에서 지정한 필드에 오류가 있으면 class 정보 추가
글로벌 오류 처리
<div th:if="${#fields.hasGlobalErrors()}">
<p class="field-error" th:each="err : ${#fields.globalErrors()}" th:text="${err}">글로벌 오류 메시지</p>
</div>
필드 오류 처리
<input type="text" id="itemName" th:field="*{itemName}"
th:errorclass="field-error" class="form-control" placeholder="이름을 입력하세요">
<div class="field-error" th:errors="*{itemName}">
상품명 오류
</div>
Bean Validation
- 애노테이션을 통한 검증 로직 적용
- 바인딩에 성공한 필드만 Bean Validation 적용
검증 애노테이션 모음
Hibernate Validator 6.2.5.Final - Jakarta Bean Validation Reference Implementation: Reference Guide
Validating data is a common task that occurs throughout all application layers, from the presentation to the persistence layer. Often the same validation logic is implemented in each layer which is time consuming and error-prone. To avoid duplication of th
docs.jboss.org
검증 애노테이션
- @NotBlank : 빈값 + 공백만 있는 경우를 허용하지 않음
- @NotNull : null 을 허용하지 않음
- @Range(min = 1000, max = 1000000) : 범위 안의 값이어야 함
- @Max(9999) : 최대 9999까지만 허용
검증 순서
- @ModelAttribute 각각의 필드에 타입 변환 시도
- 성공하면 다음으로
- 실패하면 typeMismatch로 FieldError 추가
- Validator 적용
Bean Validation 에러 코드
- 오류 코드가 애노테이션 이름으로 등록됨
- 오류 코드를 기반으로 MessageCodesResolver 를 통해 다양한 메시지 코드가 순서대로 생성됨
// @NotBlank
NotBlank.item.itemName
NotBlank.itemName
NotBlank.java.lang.String
NotBlank
errors.properties
#Bean Validation 추가
NotBlank={0} 공백X
BeanValidation 메시지 찾는 순서
- 생성된 메시지 코드 순서대로 messageSource에서 메시지 찾기
- 애노테이션의 message 속성 사용 → @NotBlank(message = "공백! {0}")
- 라이브러리가 제공하는 기본 값 사용 → 공백일 수 없습니다.
Form 전송 객체 분리
폼 데이터 전달을 위한 별도의 객체 사용
- HTML Form → ItemSaveForm → Controller → Item 생성 → Repository
- 등록 → ItemSaveForm
- 수정 → ItemUpdateForm
ValidationItemController - @ModelAttribute (POST Form, URL 쿼리 스트링)
@PostMapping("/add")
public String addItem(@Validated @ModelAttribute("item") ItemSaveForm form, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
// 특정 필드가 아닌 복합 룰 검증
if (form.getPrice() != null && form.getQuantity() != null) {
int resultPrice = form.getPrice() * form.getQuantity();
if (resultPrice < 10000) {
bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);
}
}
// 검증에 실패하면 다시 입력 폼으로
if (bindingResult.hasErrors()) {
log.info("errors = {}", bindingResult);
return "validation/v4/addForm";
}
// 성공 로직
Item item = new Item();
item.setItemName(form.getItemName());
item.setPrice(form.getPrice());
item.setQuantity(form.getQuantity());
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/validation/v4/items/{itemId}";
}
ValidationItemController - @RequestBody (HTTP Body의 데이터 객체로 변환)
@PostMapping("/add")
public Object addItem(@RequestBody @Validated ItemSaveForm form, BindingResult bindingResult) {
log.info("API 컨트롤러 호출");
if (bindingResult.hasErrors()) {
log.info("검증 오류 발생 errors={}", bindingResult);
return bindingResult.getAllErrors();
}
log.info("성공 로직 실행");
return form;
}
}
API의 3가지 경우
- 성공 요청: 성공
- 실패 요청: JSON을 객체로 생성하는 것 자체가 실패함 (컨트롤러 자체가 호출되지 않음)
- 검증 오류 요청: JSON을 객체로 생성하는 것은 성공했고, 검증에서 실패함
@ModelAttribute vs @RequestBody
@ModelAttribute
- 필드 단위로 정교하게 바인딩이 적용
- 특정 필드가 바인딩 되지 않아도 나머지 필드는 정상 바인딩 되고, Validator를 사용한 검증도 적용 가능
@RequestBody
- HttpMessageConverter 단계에서 JSON 데이터를 객체로 변경하지 못하면 이후 단계가 진행되지 않고 예외 발생
- 컨트롤러도 호출되지 않고, Validator도 적용할 수 없음
참고 강의:
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의
웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있
www.inflearn.com
'Spring Boot' 카테고리의 다른 글
서블릿 필터, 스프링 인터셉터 (0) | 2023.07.10 |
---|---|
쿠키, 세션 - 스프링 적용 (0) | 2023.07.10 |
Thymeleaf - 스프링 통합과 폼 (0) | 2023.07.04 |
Thymeleaf 기본 기능 (0) | 2023.07.02 |
Thymeleaf (0) | 2023.06.30 |