[Spring] @Valid 기본 메세지 바꾸기

klmin·2024년 10월 13일
0

버전 : 3.3.4
jdk : 21

스프링 컨트롤러에서 @Valid로 유효성 검사를 할때 클라이언트에 값이 잘못되었을경우 Request객체에 @NotNull, @NotBlank등을 사용하여 유효성 검사를 하고 메세지를 전달하는 방법을 사용할때 기본 메세지를 바꾸는 방법을 알아보자.

기본 컨트롤러와 Request 객체를 만들고 @NotNull, @NotBlank, @Size
를 선언했다. 컨트롤러에서 따로 BindingResult는 선언하지 않았으며 @Valid만 선언하여 ExceptionHandler로 위임했다.

  • controller

  • request

  • exception response 객체

  • exceptionhandler

  • MethodArgumentNotValidException
    @ModelAttribute 선언되있는 객체에 모든 유효성을 통과하지 못했을경우 발생
    선언되있는 필드와 msg를 추출해 클라이언트에 응답하도록 해놨다.
    유효성을 모두 만족하지 못해 exceptionhandler에서 만들어준 형태로 응답이 전송된다.

  • HttpMessageNotReadableException
    @RequestBody 선언되있는 객체에 유효성으로 검사하는 변수의 key가 하나도 없을경우 발생
    요청객체를 찾기가 힘들어 고정 메세지로 선언했다.

  • MethodArgumentNotValidException
    @RequestBody 선언되있는 객체에 key는 존재하지만 모든 유효성을 통과하지 못했을경우 발생.
    선언되있는 필드와 msg를 추출해 클라이언트에 응답하도록 해놨다.

  • @NotBlank
  • @NotNull

어노테이션마다 locale에 따른 파일을 찾고 그 파일에 default 메세지가 선언되어있다.
hibernate-validator.jar에
ValidationMessags.properties에서 확인할 수 있다.

만약 이렇게 어노테이션마다의 message를 입력해주면 해당하는 변수는 작성한 message로 응답이 전송돤다.

프로젝트에서
/resources에 ValidationMessages_ko.properties,
ValidationMessages_en.properties 등으로 기존에 hibernate-validator에 있는 파일과 동일한 이름으로 생성 한 후에
메세지를 작성한다면 각 locale에 맞는 default 메세지가 오버라이딩 된다.

# ValidationMessages_ko.properties

jakarta.validation.constraints.NotBlank.message=필수 입력값 입니다.
jakarta.validation.constraints.NotNull.message=필수 입력값 입니다.
jakarta.validation.constraints.Size.message={min} - {max}사이로 입력해주세요.
# ValidationMessages_en.properties

jakarta.validation.constraints.NotBlank.message=This is a required input value.
jakarta.validation.constraints.NotNull.message=This is a required input value.
jakarta.validation.constraints.Size.message=Please enter between {min} and {max}.


하드코딩되어 message와 name의 msg가 한글로 나온다.

만약 locale에 맞는 메세지를 전달하려면
ValidationMessages에 key를 추가하고
어노테이션 message에 "{추가한key}" 형태로 입력해야 한다.

또한 MessageSource를 추가해 ExceptionHandler에 하드코딩 되어있는 message도 바꿔줘야 한다.

# ValidationMessages_ko.properties

jakarta.validation.constraints.NotBlank.message=필수 입력값 입니다.
jakarta.validation.constraints.NotNull.message=필수 입력값 입니다.
jakarta.validation.constraints.Size.message={min} - {max}사이로 입력해주세요.
user.name.notblank=이름을 입력해주세요. -- 추가
# ValidationMessages_en.properties

jakarta.validation.constraints.NotBlank.message=This is a required input value.
jakarta.validation.constraints.NotNull.message=This is a required input value.
jakarta.validation.constraints.Size.message=Please enter between {min} and {max}.
user.name.notblank=Please enter your name. -- 추가
@NotBlank(message="{user.name.notblank}")

  • 테스트코드 사용시 locale
    localeResolver를 등록해주지 않으면 테스트코드에서 기본 locale이 US로 잡힌다. 그래서 항시 MockMvc에 .locale(Locale.KOREAN) 선언해줘야한다. Locale.getDefault() - os locale로 선언해줬다.
@Configuration
public class LocaleConfig {

    @Bean
    public LocaleResolver localeResolver() {
        AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
        localeResolver.setDefaultLocale(Locale.getDefault())
        return localeResolver;
    }
}
  • MessageSource - 메세지소스를 사용해 프로퍼티에 정의한 key에 대해 value를 locale별로 설정할 수 있다.
    MessageSource bean 등록 해야함.
    ResourceBundleMessageSource - 최초 실행시 파일을 읽어와서 메모리에 적재. 수정하려면 서버 재실행
    ReloadableResourceBundleMessageSource - 최초 실행시 파일을 읽어오고 cachesecond마다 refresh. 서버 재실행 없이 파일 수정 가능.
    baseName - properties 경로(해당 경로에 맞게 파일 생성)
@Configuration
public class MessageSourceConfig {


    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:messages/messages");
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.setCacheSeconds(3600);
        messageSource.setFallbackToSystemLocale(false);
        return messageSource;
    }

}

LocaleContextHolder.getLocale() - thread locale 따라감.

@Component
@RequiredArgsConstructor
public class MessageSourceService {

    private final MessageSource messageSource;

    public String getMessage(String key){
        return messageSource.getMessage(key, null, LocaleContextHolder.getLocale());
    }

    public String getMessage(String key, Object[] args, Locale locale) {
        return messageSource.getMessage(key, args, locale);
    }
}

resources/경로 - messages.properties 추가(locale - ko, en등)

# messages_ko.properties

MISSING_REQUIRED_VALUE=필수값이 누락되었습니다.
# messages_en.properties

MISSING_REQUIRED_VALUE=A required value is missing.

  • locale : ENGLISH시 값
  • locale : default시 값
profile
웹 개발자

0개의 댓글