이전 포스팅( Bean Validation )에서 Bean Validation에 대해서 정리를 했었다.
근데... ModelAndView 방식의 Controller와 아니라 API Controller인 경우 Bean Validation 동작후 에러 메시지를 제대로 가져오지 않아 조금 삽질을 했다..
이번 포스팅에서는 API서버에서 Bean Validation을 적용하고 에러 메시지를 커스텀하여 적용하는 방법을 정리하려고 한다.
우선 전지전능의 chatgpt에게 물어보았다.
질문)
@ModelAttribute는 errors.properties에서 알아서 가져오는데 @Requestbody는 코딩을 해줘야해?
답변)
@ModelAttribute는 스프링이 폼 데이터를 처리하고 에러 메시지를 errors.properties에서 가져오는 데에 자동으로 도움을 줍니다. 반면에 @RequestBody를 사용할 때에는 수동으로 에러 처리를 해주어야 하며, 에러 메시지를 명시적으로 관리해야 합니다.
김영한님의 Spring-MVC2 강의를 다시 들어보니.. 거기에서도 마찬가지로 말씀하셨다.
즉, @ModelAttribute는 자동으로 errors.properties에서 가져와서 사용하지만, @RequestBody는 내가 직접 메시지를 가져와서 사용해야한다.
좀더 정확히 표현하자면.. thymeleaf의 th:error와 같은 기능들이 알아서 해결해주는것이다. ModelAttribute가 해결해주는건 아니다!!
이제 어떻게 가져올 수 있을까?
메시지를 가져오기 위해서는 아래의 포스팅에서 정리한 내용을 이해하고 있어야한다.
스프링은 기본적인 메시지 관리 기능을 제공합니다.
메시지 관리 기능을 사용하려면 스프링이 제공하는 MessageSource
를 스프링빈으로 등록하면 되는데, MessageSource
는 인터페이스이며 이 구현체인 ResourceBundleMessageSource
를 스프링빈으로 등록하면 됩니다.
하지만, 스프링 부트를 사용하면 MessageSource
가 자동으로 스프링빈으로 등록되기 때문에 application.properties
에 아래와 같이 설정 값만 넣어주면 됩니다.
spring.messages.basename=messages,config.i18n.messages
물론 기본값도 존재합니다.
spring.messages.basename=message
BindingResult에 존재하는 FieldError와 rejectValue는 내부에서 MessageCodeResolver를 사용해서 오류 코드를 구성합니다.
MessageCodeResolver
아래와 같은 기능을 수행합니다.
MessageCodeResolver
인터페이스와 기본 구현체인 DefaultMessageCodeResolver
가 존재합니다.rejectValue()
와 reject()
는 내부에서 MessageCodeResolver
를 통해서 생성된 순서대로 오류 코드를 보관합니다.따라서 MessageCodeResolver를 기반으로 생성된 오류코드를 순서대로 MessageSource에서 찾아서 사용합니다.
스프링 부트는 spring-boot-starter-validation
라이브러리를 넣으면 자동으로 Bean Validator를 인지하고 스프링에 통합합니다.
스프링 부트는 자동으로 글로벌 Validator로 등록합니다.
LocalValidatorFactoryBean
을 글로벌 Validator로 등록합니다. 이 Validator는 @NotNull
같은 애노테이션을 보고 검증을 수행합니다. 이렇게 글로벌 Validator가 적용되어 있기 때문에 @Valid
, @Validated
만 적용하면 됩니다.
검증 오류가 발생하면 FieldError
, ObjectError
를 생성해서 BindingResult
에 담아줍니다.
기본적으로 Bean Validation은 아래와 같은 순서로 메시지를 찾습니다.
messageSource
에서 메시지 찾기message
속성 사용 참고
RequestBody의 Validation추가하기
김영한님의 SpringMVC2
해당 포스팅은 아래의 강의를 공부하여 정리한 내용입니다.
김영한님의 스프링 핵심 원리 고급