빙응의 공부 블로그

[Spring]스프링 MVC 2편 - 메시지, 국제화 본문

Spring/인프런_개념

[Spring]스프링 MVC 2편 - 메시지, 국제화

빙응이 2024. 1. 24. 19:33

📝메시지

만약 요구사항을 수정하는 중에 각 웹 페이지의 상품명이라는 단어를 모두 상품이름으로 고쳐야 한다면 어떻게 해야할까?

그러면 HTML 구현 기준으로 모두 고쳐야 한다. 

이것을 HTML 하드 코딩이라고 한다.

하드 코드 예)
    <div>
            <label for="itemName">상품명</label>
            <input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요">
        </div>
        <div>
            <label for="price">가격</label>
            <input type="text" id="price" th:field="*{price}" class="form-control" placeholder="가격을 입력하세요">
        </div>
        <div>
            <label for="quantity">수량</label>
            <input type="text" id="quantity" th:field="*{quantity}" class="form-control" placeholder="수량을 입력하세요">
        </div>

 

 

이것을 해결하는 방법이 메시지 일관 관리 기능이다.

 

messages.properties 라는 메시지 관리용 파일을 만들고

item=상품
item.id=상품ID
item.itemName=상품명

item.price=가격
item.quantity=수량

 

각 HTML들은 다음과 같이 해당 데이터를 key 값으로 불러서 사용할 것이다.

addForm.html
<label for="itemName" th:text="#{item.itemName}"></label>
editForm.html
<label for="itemName" th:text="#{item.itemName}"></label>

 

 

📝국제화

메시지에서 한 발 더 기능을 업그레이드해보자.

메시지에서 설명한 메시지 파일(messages.properties)을 각 나라별로 별도로 관리하면서 서비스를 국제화할 수 있다.

 

전에 포스팅에서 봤듯이 우리는 요청이 어느나라 언어로 오는지 알 수 있다.

바로 HTTP accept-language 헤더 

이것을 이용해 헤더에 따라 언어를 다르게 해주면 된다. 

messages_en.properties
item=Item
item.id=Item ID
item.itemName=Item Name
item.price=price
item.quantity=quantity

messages_ko.properties
item=상품
item.id=상품ID
item.itemName=상품명
item.price=가격
item.quantity=수량

 

참고! 스프링은 기본적인 메시지와 국제화 기능은 모두 제공한다. 그리고 타임리프도 스프링이 제공하는 메시지와 국제화 기능을 편리하게 제공한다.

 

📝스프링 메시지 소스 설정 

스프링은 기본적으로 메시지 관리 기능을 제공한다.

 

그러나 일단 직접 등록을 해보자

직접 등록
@Bean
public MessageSource messageSource() {
 ResourceBundleMessageSource messageSource = newResourceBundleMessageSource();
 messageSource.setBasenames("messages", "errors");
 messageSource.setDefaultEncoding("utf-8");
 return messageSource;
}

이렇게 빈에 넣어서 직접 등록을 할 수 있다. 

 

자동 사용

스프링 부트를 사용하면 스프링 부트가 MessageSource를 자동으로 스프링 빈에 등록한다.

 

또한 해당 스프링 부트 메시지 소스를 사용하려면 application.properties에 해당 구문을 추가해줘야 한다.

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

해당 구문은 기본 이름을 messages로 하고 여러개의 파일을 쉼표로 구분한다는 뜻이다. 

즉 messages_en.properties , messages_ko.properties , messages.properties 이런것이 포함된다.

 

 

📝메시지 소스 사용해보기

MessageSource를 사용하는 인터페이스는 다음과 같은 메소드를 가진다.

public interface MessageSource {
     String getMessage(String code, @Nullable Object[] args, @Nullable StringdefaultMessage, Locale locale);
     String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;

이 메소드들은 코드를 포함한 일부 파라미터로 메시지를 읽어오는 기능을 제공한다. 

 

실습
@SpringBootTest
public class MessagesSourceTest {

  @Autowired
  MessageSource messagesSource;

  @Test
  @DisplayName("메시지 국제화 테스트")
  void MessagesTest(){
    String result = messagesSource.getMessage("hello", null, null);
    Assertions.assertThat(result).isEqualTo("hello");
  }
  @Test
  @DisplayName("메시지 국제화 매개변수 테스트")
  void MessagesTest2() {
    String result = messagesSource.getMessage("hello.name", new Object[]{"John"}, Locale.getDefault());
    Assertions.assertThat(result).isEqualTo("안녕 John");
  }
}

해당 코드는 messages.propertiesmessages_en.properties를 이용해서 테스트를 해보았다.

첫번째 테스트는 기본이 ko이기 때문에 틀리게 나온다. result는 안녕이 나오기 때문이다.

 

 

이제 HTML에 적용하는 법을 알아보자! 

 

label.item=Item
label.item.id=Item ID
label.item.itemName=Item Name
label.item.price=price
label.item.quantity=quantity

해당 코드처럼 messages.properties에 지정했다고 해보자.

 

<th>ID</th>
<th>상품명</th>
<th>가격</th>
<th>수량</th>

이것을 바꾸면

<th th:text="#{label.item.id}">ID</th>
<th th:text="#{label.item.itemName}">상품명</th>
<th th:text="#{label.item.price}">가격</th>
<th th:text="#{label.item.quantity}">수량</th>

이렇게 된다.

 

 

 

 

잘된다!!!!!

 

📝스프링의 국제화 메시지 선택

그렇다면 스프링은 어떻게 국제화 메시지를 선택할 수 있는걸까?

 

그것은 Locale 선택 방식을 변경하는 LocaleResolver 라는 인터페이스에 있다!

 

LocaleResolver
public interface LocaleResolver {
   Locale resolveLocale(HttpServletRequest request);
   void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale);
}

만약 Locale 선택 방식을 변경하려면 LocaleResolver의 구현체를 변경해서 쿠키나 세션 기반으로 변경할 수 있다.