SpringMVC - 14. BindingResult
BindingResult
-
Spring이 제공하는 검증 오류 처리 기능
-
방법
- @ModelAttribute의 객체 타입 오류 등으로 바인딩 실패 시, Spring이 FieldError 자동 생성 후 BindingResult에 넣어줌
- 개발자가 직접 넣음
- Validator 사용
-
주의 사항
-
BIndingResult는 검증 대상 바로 다음에 작성해야함
-
public String addItemV1(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model)
- 위의 코드에서 보면 Item 객체가 검증 대상이므로 그 다음에 바로 BindingResult 작성
-
-
addError 메소드를 이용하여 FieldError와 ObjectError를 추가할 수 있음
FieldError
- 두가지 생성자 제공
-
public FieldError(String objectName, String field, String defaultMessage) { this(objectName, field, null, false, null, null, defaultMessage); } public FieldError(String objectName, String field, @Nullable Object rejectedValue, boolean bindingFailure, @Nullable String[] codes, @Nullable Object[] arguments, @Nullable String defaultMessage) { super(objectName, codes, arguments, defaultMessage); Assert.notNull(field, "Field must not be null"); this.field = field; this.rejectedValue = rejectedValue; this.bindingFailure = bindingFailure; }
-
파라미터 목록
- objectName : 오류가 발생한 객체 이름 (@ModelAttribute에 담기는 이름)
- field : 오류 필드 (필드명)
- rejectedValue : 사용자가 입력한 값 (거절된 값) => 사용 시 에러 발생해도 필드값 유지
- bindingFailure : 타입 오류 같은 바인딩 실패인지, 검증 실패인지 구분
- codes : 메세지 코드
- arguments : 메세지에서 사용하는 인자
- defaultMessage : 기본 오류 메세지
ObjectError
- 데이터가 넘어와서 처리되는 에러가 아니므로 기존 데이터를 보관할 필요가 없음
- 즉, 바인딩을 실패할 일이 없음 (벌써 넘어온 필드 데이터를 조합하는 것)
- 따라서 파라미터 목록에 rejectedValue, bindingFailure가 없음
codes, arguments 파라미터를 활용하여 error 관리
-
IDE의 기본 Encoding값이 UTF-8인지 확인 필수
-
errors.properties로 error 포괄적인 관리 가능
-
/resources/apllication.properties에 아래 코드추가
- spring.messages.basename=messages,errors (메세지, 에러 둘 다 사용)
- 생략 시 default로 messages.properties 읽어들임
- errors를 추가하여 errors.properties 읽어들임
- [에러 메세지 생성 규칙]
codes 파라미터
- String[] 으로 값을 받음
- 하나의 에러 코드가 아닌 여러 에러 코드를 검토할 수 있음
- errors.properties에 지정해준 error code Name으로 지정
arguments 파라미터
- Object[] 으로 값을 받음
- 여러 파라미터를 전달할 수 있음
- errors.properties에서 파라미터 값을 전달할 때, 그 순서에 맞게 입력
예시
# errors.properties
# ErrorCode명.Object명.Field명
range.item.price=가격은 {0} ~ {1} 까지 허용합니다.
# 에러 처리 부분
bindingResult.addError(new FieldError("item", "price", item.getPrice(), true, new String[]{"range.item.price"}, new Object[]{1000, 1000000}, null));
- codes : new String[]{“range.item.price”}
- arguments : new Object[]{1000, 1000000} => {0}, {1}에 각각 대입
reject(), rejectValue()를 활용하여 간소화
- BindingResult는 검증 대상 객체(여기선 Item)을 이미 알고 있음
- reject() - ObjectError
- rejectValue() - FieldError
- 위 두가지로 더 간소화할 수 있음
- 기존 코드 예시
# FieldError
bindingResult.addError(new FieldError("item", "price", item.getPrice(), true, new String[]{"range.item.price"}, new Object[]{1000, 1000000}, null));
# Object Error
bindingResult.addError(new ObjectError("item", new String[]{"totalPriceMin"}, new Object[]{10000, resultPrice}, null));
- reject(), rejectValue() 사용
# FieldError => rejectValue()
bindingResult.rejectValue("price", "range", new Object[]{1000, 1000000}, null);
#Object Error => reject()
bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);
- 변경 사항
- 검증 대상을 미리 알고 있으므로 objectName(“item”) 사용 X
- rejectedValue 파라미터 필요 X
- 기존 codes => errorCode 변경 (MessageCodeResolver 참고)
MessageCodesResolver
- 검증 오류 코드로 메세지 코드들을 생성
- 주로 DefaultMessageCodesResolver 구현체 사용
- 기본 메세지 생성 규칙 (구체적 -> 범용적)
- 객체 오류
- code + “.” + object name
- code
- 필드 오류
- code + “.” + object name + “.” + field
- code + “.” + field
- code + “.” + field type
- code
- 객체 오류
- FieldError, ObjectError의 생성자에서, 오류 코드는 String 배열로 여러가지를 가질 수 있었음
- MessageCodesResolver가 위의 생성 규칙의 순서에 맞게 오류 코드들을 보관함
- 구체적 -> 범용적으로 내려가면서 일치하는 오류 메세지에 맞게 오류를 최종적으로 출력해줌
Spring이 직접 처리하는 에러 메세지 수정
-
데이터의 타입이 불일치하는 것과 같은 에러들은 Spring이 알아서 에러를 처리해줌
-
이 때, Spring이 뿌리는 default message는 사용자가 보아서 좋을 것이 없음
-
이런 경우의 에러들 또한 errors.properties에서 개발자가 직접 정의해줄 수 있음
-
# typeMismatch 에러 발생 (숫자에 문자를 입력함) Field error in object 'item' on field 'price': rejected value [A]; codes [typeMismatch.item.price,typeMismatch.price,typeMismatch.java.lang.Integer,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [item.price,price]; arguments []; default message [price]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.lang.Integer' for property 'price'; nested exception is java.lang.NumberFormatException: For input string: "A"]
-
# errors.properties에 추가 typeMismatch.java.lang.Integer=숫자를 입력해주세요. typeMismatch=타입 오류입니다.
댓글남기기