Spring boot - 메시지 국제화 MessageSource

목차

참고

메시지 관리를 위한 MessageSource

어플리케이션 개발을 진행하다가 보면 메시지를 보낼때 하드 코딩으로 넣다 보면 같은 맥략으로 쓰인 메시지들이 서로 상이하게 관리되는 것을 느낄 수 있었고 무엇보다 가장 큰 문제는 메시지를 변경하게 될 경우 해당 메시지가 사용된 소스를 전부 찾아 변경해 줘야 하는 문제점이 있다. 이런 메시지 파편화를 막고 한 곳에서 모든 메시지를 관리할 수 있도록 Spring 에서는 MessageSource 를 제공한다.

  • MessageSource
    • 메시지를 한 파일 message.properties 에서 관리할 수 있다.
      • 경로 : main/resource/message.properties
    • 메시지에 대한 다국어 처리 를 지원한다.
      • 사용법 : message_[언어코드].properties
      • 영어 : message_en.properties
      • 한국어 : message_ko.properties

메시지 등록

경로 : main/resource/message.properties

  • Key, Value 형식으로 메시지를 등록해 사용할 수 있다.
  • 값을 동적으로 받아 Message 를 띄우고 싶을 경우 {0}, {1} 형식으로 argument 를 받을 수 있다.
created.message=Successfully {0} is created

MessageSource 인터페이스

MessageSource 객체를 사용해 message.properties 에 저장된 Message 를 읽어올 수 있다.

public interface MessageSource {

@Nullable
String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}

MessageSource Bean 생성

ResourceBundleMessageSource 를 이용해 Resource 에 저장된 message.properties 파일을 읽어온 후 MessageSource Bean 을 만들어준다.

@Bean
public MessageSource messageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages"); // 메시지 리소스 번들 지정
messageSource.setDefaultEncoding("UTF-8"); // 문자 Encoding 설정

return messageSource;
}

application.properties 를 이용한 등록

Java Code 를 이용해 MessageSource Bean 을 등록할 수 있지만 Spring Boot 의 경우 MessageSource 빈을 자동으로 등록해준다.(default name = messages) 또한, Application.properties 를 이용해 추가적인 설정을 해줄 수 있다.

spring.messages.basename=messages,config.i18n.messages

MessageSource 를 이용해 메시지 사용하기

  • MessageSource 객체내 getMessage 메소드를 이용해 등록된 메시지를 사용할 수 있다.
  • getMessage 첫번째 값은 등록된 key 값, 두번째 값은 전달하고자 하는 argument 값, 세번째 값은 다국어 처리를 위한 Locale 정보다.
@RequestMapping("/api/auth")
@RestController
@RequiredArgsConstructor
public class AuthController {

private final UserInfoService userInfoService;

private final MessageSource messageSource;

@PostMapping("/signup")
public ResponseEntity registerUser(@RequestBody RequestRegisterUser registerUser) {
registerUser.setPassword(registerUser.getPassword());
UserInfo userinfo = userInfoService.saveUser(registerUser);

return new ResponseEntity(messageSource.getMessage("created.message", new String[]{"User Account"}, null), HttpStatus.OK);
}

@GetMapping("/logout")
public void logout() {
}
}

MessageSource Error

MessageSource 에 등록되지 않은 메시지를 조회하게 될 경우 NoSuchMessageException 예외가 발생한다.

@Test
public void MessageFailTest(){
assertThatThrownBy(() -> {
messageSource.getMessage("code", null, null);
}).isInstanceOf(NoSuchMessageException.class);
}

LocaleResolver 인터페이스

Spring 은 Locale 정보를 읽어올 수 있게 LocalResolver 라는 인터페이스를 제공한다.

LocalResolver 객체를 이용해 Locale 객체가 만들어 지면 해당 객체를 이용해 LocaleContext 객체가 만들어지고 LocaleContextHolder 라는 저장소에 저장된다. LocaleContextHolder 은 LocaleContext 를 ThreadLocal 을 이용해 관리하기 때문에 Thread Safe 하게 Locale 정보를 저장할 수 있다.

public interface LocaleResolver {
Locale resolveLocale(HttpServletRequest request);

void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale);
}

AcceptHeaderLocaleResolver

Accept Header 기반으로 Locale 정보를 읽어오는 Resolver

LocaleResolver 의 대표적인 구현체는 Request Header 로부터 Locale 정보를 읽어오는 AcceptHeaderLocaleResolver 가 있다. AcceptHeaderLocaleResolver 객체는 LocaleContextHolder 에 Locale 정보를 저장하지 않는다.

@Override
public Locale resolveLocale(HttpServletRequest request) {
Locale defaultLocale = getDefaultLocale();
if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
return defaultLocale;
}
Locale requestLocale = request.getLocale();
List<Locale> supportedLocales = getSupportedLocales();
if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) {
return requestLocale;
}
Locale supportedLocale = findSupportedLocale(request, supportedLocales);
if (supportedLocale != null) {
return supportedLocale;
}
return (defaultLocale != null ? defaultLocale : requestLocale);
}
Share