메시지

- 화면에서 사용되는 단어들을 각 화면마다 하드코딩으로 작성했다면, 수정이 필요한 경우 수정할 단어가 포함된 모든 화면을 찾아서 하나하나 수정을 해야 함

- 화면의 개수가 적으면 괜찮지만, 화면이 많으면 유지보수에 어려움이 있음

=> 메시지 : 화면에서 사용되는 다양한 단어(메시지)를 한 곳에서 관리할 수 있도록 기능

 

MessageSource

- 메시지 관리를 위해서 스프링에서  MessageSource를 스프링 빈으로 등록함

- MessageSource은 인터페이스고, 구현체인 ResourceBundleMessageSource를 스프링으로 등록해서 사용하면 됨

=> 스프링 부트는 자동으로 MessageSource를 스프링 빈으로 등록함

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 설정

application.properties

spring.messages.basename=messages

=> 기본값

=> /resources/아래에 messages_en.properties, messages_ko.properties, messages.properties라는 파일을 만들어두면 자동으로 인식하여 메시지 기능에 사용함

=> messages.properties을 기본 값으로 사용

 

messages.properties

hello=안녕
hello.name=안녕 {0}

messages_en.properties

hello=hello
hello.name=hello {0}

=> {0} 은 파라미터임

 

MessageSourceTest

@SpringBootTest
public class MessageSourceTest {

    @Autowired
    MessageSource ms;

    @Test
    void helloMsg() {
        String resultMsg = ms.getMessage("hello", null, Locale.KOREA);
        // String resultMsg = ms.getMessage("hello", null, null);        
        assertThat(resultMsg).isEqualTo("안녕");
    }

    // msg 찾지 못하면 NoSuchMessageException
    @Test
    void notFoundMsgCode() {
        assertThatThrownBy(() -> ms.getMessage("no_code", null, null))
                .isInstanceOf(NoSuchMessageException.class);
    }

// 메시지가 없는 경우 기본 메시지 (기본MSG)
    @Test
    void notFoundMsgCodeDefaultMsg() {
        String resultMsg = ms.getMessage("no_code", null, "기본MSG", null);
        assertThat(resultMsg).isEqualTo("기본MSG");
    }

// 파라미터 사용
    @Test
    void argMsg() {
        String resultMsg = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
        assertThat(resultMsg).isEqualTo("안녕 Spring");
    }

// Locale별로 메시지 가져오기
    @Test
    void defaultMsg() {
        assertThat(ms.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello");
        assertThat(ms.getMessage("hello", null, Locale.KOREA)).isEqualTo("안녕");
    }

}

=> getMessage() 메서드를 활용하여 messages.properties, messages_en.properties에서 알맞은 메시지를 불러옴

 

메시지 적용해보기

messages.properties

label.item=상품
label.item.id=상품 ID
label.item.itemName=상품명
label.item.price=가격
label.item.quantity=수량
label.item.open=판매여부
label.item.regions=판매지역
label.item.itemType=상품종류
label.item.deliveryCode=배송방식

page.items=상품 목록
page.item=상품 상세
page.addItem=상품 등록
page.updateItem=상품 수정
button.save=저장
button.cancel=취소

 

Thymeleaf로 메시지 불러오기 ( #{...} )

- 메시지 표현식인 #{...}을 사용하면 메시지를 불러올 수 있음

ex)

<h2 th:text="#{page.addItem}">상품 등록</h2>

 

국제화

messages_en.properties

label.item=Item
label.item.id=Item ID
label.item.itemName=Item Name
label.item.price=price
label.item.quantity=quantity
label.item.open=open
label.item.regions=region
label.item.itemType=itemType
label.item.deliveryCode=delivery

page.items=Item List
page.item=Item Detail
page.addItem=Item Add
page.updateItem=Item Update
button.save=Save
button.cancel=Cancel

=> 국제화 적용은 그냥 message_en.properties만 만들어두면 끝난 것임

 

Spring의 국제화 메시지 선택 방법

- Locale정보를 알아야 messages.properties을 적용할지 messages_en.properties을 적용할지 선택 가능

- Spring은 기본적으로는 LocaleResolver인터페이스의 구현체인 AcceptHeaderLocaleResolver를 활용하며, HTTP Reqeust Header의 Accept-Language보고 국제화 메시지를 선택함

  • 한국어 : Accept-Language: ko,en;q=0.9,en-US;q=0.8     => messages.properties 사용
  • 영어 : Accept-Language: en,ko;q=0.9,en-US;q=0.8       => messages_en.properties 사용

 

LocaleResolver

- Spring은 Locale선택 방식을 변경할 수 있는 인터페이스 LocaleResolver를 활용하며, 기본적으로는 Accept-Language를 활용하는 구현체 AcceptHeaderLocaleResolver를 사용함

- LocaleResolver를 구현체를 따로 만들어서 Accept-Language대신 사용자가 직접 언어를 선택하게 하고 쿠기나 세션기반(SessionLocaleResolver)으로 국제화 메시지를 선택하게 할 수도 있음

=> 인터페이스화 되어있는 스프링 장점

 

SessionLocaleResolver

@Bean
public SessionLocaleResolver localeResolver() {
	SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
	sessionLocaleResolver.setDefaultLocale(new Locale("ko"));
	return sessionLocaleResolver;
}

사용자가 언어 선택하면 해당 사용자의 session에 설정

@RequestMapping(value = "/localeChg")
public void changeLocale(String language, HttpSession session) {
	session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, new Locale(language));
}