- Spring mvc2 타임리프 기본기능
- Spring mvc2 타임리프 스프링 통합과 폼
- Spring mvc2(2) 메세지, 국제화
- Spring mvc2(3) 검증1 validation
- Spring mvc2 검증2 1 bean validation
- Spring mvc2 검증2 2 로그인 처리1 쿠키, 세션
- Spring mvc2 검증2 3 로그인 처리2 필터, 인터셉터
- Spring mvc2 검증2 4 예외 처리와 오류 페이지
- Spring mvc2(1) api 예외처리
- Spring mvc2(2) 스프링 타입 컨버터
- Spring mvc2(3) 파일 업로드
Spring mvc2(2) 메세지, 국제화
0. 메시지, 국제화
- MVC 2 타임리프에서 마지막에 만들었던 상품관리 페이지 사용
- 소스파일 message-start 사용
- 타임리프에서 체크 박스, 라디오 버튼, 셀렉트 박스는 뺐다.
메시지
-
하드 코딩된 html 내 ‘상품명’이라는 단어를 모두 ‘상품이름’으로 고치려면 일일히 다 변경해야 한다.
-
이런 다양한 메시지를 한 곳에서 관리하도록 하는 기능을 메시지 기능이라 한다.
-
예를 들어서 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 )을 각 나라별로 별도로 관리하면 서비스를 국제화 할 수 있다.
-
예를 들어 다음과 같이 2개 파일을 만들어서 분류하면,
-
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=수량
-
-
-
영어를 사용하는 사람이면 messages_en.properties 를 사용하고, 한국어를 사용하는 사람이면 messages_ko.properties 를 사용하게 개발하면 된다.\
-
한국에서 접근한 것인지 영어에서 접근한 것인지는 인식하는 방법은 HTTP accept-language 해더 값을 사용하거나 사용자가 직접 언어를 선택하도록 하고, 쿠키 등을 사용해서 처리하면 된다.
스프링과 메시지, 국제화
- 메시지와 국제화 기능을 직접 구현할 수도 있겠지만, 스프링은 기본적인 메시지와 국제화 기능을 모두 제공한다.
- 그리고 타임리프도 스프링이 제공하는 메시지와 국제화 기능을 편리하게 통합해서 제공한다.
1. 스프링 메시지 소스 설정
- 스프링에서
@Bean public MessageSource messageSource()
으로 직접 등록해도 되지만 스프링 부트에서 MessageSource 를 자동으로 스프링 빈으로 등록한다.
스프링 부트 메시지 소스 기본 값
- properties :
spring.messages.basename=messages
- MessageSource 를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 하지 않으면 messages 라는 이름으로 기본 등록된다.
- 따라서 messages_en.properties , messages_ko.properties , messages.properties 파일만 등록하면 자동으로 인식된다.
메시지 파일 만들기
messages.properties :기본 값으로 사용(한글)
-
/resources/messages.properties
-
hello=안녕 hello.name=안녕 {0}
messages_en.properties : 영어 국제화 사용
-
/resources/messages_en.properties
-
hello=hello hello.name=hello {0}
2. 스프링 메시지 소스 사용
스프링 메시지 소스 사용
-
public interface MessageSource { String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale); String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
- MessageSource 인터페이스를 보면 코드를 포함한 일부 파라미터로 메시지를 읽어오는 기능을 제공한다.
테스트 코드
-
내부 주석 참조
-
package hello.itemservice.message; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.MessageSource; import org.springframework.context.NoSuchMessageException; import java.util.Locale; import static org.assertj.core.api.Assertions.*; @SpringBootTest public class MessageSourceTest { //springbean 으로 필드 주입 @Autowired MessageSource ms; @Test //getMessage()로 "hello" 의 value 값 = "안녕" void helloMessage(){ String result = ms.getMessage("hello", null, null); assertThat(result).isEqualTo("안녕"); } @Test //메세지가 없는 경우에는 NoSuchMessageException 을 터트린다. void notFoundMessageCode(){ assertThatThrownBy(() -> ms.getMessage("no_code", null, null)) .isInstanceOf(NoSuchMessageException.class); } @Test //defaultMessage 를 생성하면 그 메세지가 나온다. void notFoundMessageCodeDefaultMessage(){ String result = ms.getMessage("no_code", null, "기본 메시지", null); assertThat(result).isEqualTo("기본 메시지"); } @Test //properties 에서 "hello.name=안녕 {0}" 이다. 여기서 new Object[]{"Spring"} 으로 리스트로 매개변수 전달이 가능하다. 그러면 {0} 에 "Spring" 이 들어간다.==> "안녕 Spring" void argumentMessage(){ String message = ms.getMessage("hello.name", new Object[]{"Spring"}, null); assertThat(message).isEqualTo("안녕 Spring"); } @Test //기본값이 Locale.KOREA 이므로 당연한 결과 void defaultLang(){ assertThat(ms.getMessage("hello", null, null)).isEqualTo("안녕"); assertThat(ms.getMessage("hello", null, Locale.KOREA)).isEqualTo("안녕"); } @Test //locale 정보가 Locale.ENGLISH 이므로 messages_en 을 찾아서 사용 void enLang(){ assertThat(ms.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello"); } }
로케일을 찾는 순서
- Locale 정보가 없는 경우
Locale.getDefault()
을 호출해서 시스템의 기본 로케일을 사용한다.- 예) locale = null 인 경우 시스템 기본 locale 이 ko_KR 이므로 messages_ko.properties 조회 시도
- 조회 실패 시 messages.properties 조회
3. 웹 어플리케이션에 메시지 적용하기
messages.properties 에 메시지 등록
-
label.item=상품 label.item.id=상품 ID label.item.itemName=상품명 label.item.price=가격 label.item.quantity=수량 page.items=상품 목록 page.item=상품 상세 page.addItem=상품 등록 page.updateItem=상품 수정 button.save=저장 button.cancel=취소
타임리프에 메시지 적용
- 타임리프의 메시지 표현식 #{…} 를 사용하면 스프링의 메시지를 편리하게 조회할 수 있다.
예시 (addForm)
-
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <link th:href="@{/css/bootstrap.min.css}" href="../css/bootstrap.min.css" rel="stylesheet"> <style> .container { max-width: 560px; } </style> </head> <body> <div class="container"> <div class="py-5 text-center"> <h2 th:text="#{page.addItem}">상품 등록 폼</h2> </div> <form action="item.html" th:action th:object="${item}" method="post"> <div> <label for="itemName" th:text="#{label.item.itemName}">상품명</label> <input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요"> </div> <div> <label for="price" th:text="#{label.item.price}">가격</label> <input type="text" id="price" th:field="*{price}" class="form-control" placeholder="가격을 입력하세요"> </div> <div> <label for="quantity" th:text="#{label.item.quantity}">수량</label> <input type="text" id="quantity" th:field="*{quantity}" class="form-control" placeholder="수량을 입력하세요"> </div> <hr class="my-4"> <div class="row"> <div class="col"> <button class="w-100 btn btn-primary btn-lg" type="submit" th:text="#{button.save}">상품 등록</button> </div> <div class="col"> <button class="w-100 btn btn-secondary btn-lg" onclick="location.href='items.html'" th:onclick="|location.href='@{/message/items}'|" type="button" th:text="#{button.cancel}">취소</button> </div> </div> </form> </div> <!-- /container --> </body> </html>
<h2 th:text="#{page.addItem}">상품 등록 폼</h2>
처럼 properties 에 있는page.addItem =상품 등록
으로 치환되어 렌더링 된다.- 나머지도 다 똑같다..
4. 웹 애플리케이션에 국제화 적용하기
영어 메시지를 추가
-
messages_en.properties
-
label.item=Item label.item.id=Item ID label.item.itemName=Item Name label.item.price=price label.item.quantity=quantity page.items=Item List page.item=Item Detail page.addItem=Item Add page.updateItem=Item Update button.save=Save button.cancel=Cancel
-
앞에서 템플릿 파일에는 모두 #{…} 를 통해서 메시지를 사용하도록 적용해두었기 때문에 작업이 끝났다.
-
웹 브라우저의 언어 설정 값을 변경하면 설정값으로 나온다.
-
웹 브라우저의 언어 설정 값을 변경하면 요청시 Accept-Language 의 값이 변경된다.
- 스프링은 언어 선택시 기본으로 AcceptLanguage 헤더의 값을 사용한다.
LocaleResolver
- 스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver 라는 인터페이스를 제공하는데, 스프링 부트는 기본으로 Accept-Language 를 활용하는 AcceptHeaderLocaleResolver 를 사용한다.
LocaleResolver 변경
- 만약 Locale 선택 방식을 변경하려면 LocaleResolver 의 구현체를 변경해서 쿠키나 세션 기반의 Locale 선택 기능을 사용할 수 있다.
- 예를 들어서 고객이 직접 Locale 을 선택하도록 하는 것이다.
- 관련해서 LocaleResolver 를 검색하면 수 많은 예제가 나온다.
댓글남기기