본문 바로가기

Advance I/Spring MVC

22.08.26

3. 메세지, 국제화

메시지, 국제화 소개

메세지

기획자가 화면에 보이는 문구가 마음에 들지 않는다고, 상품명이라는 단어를 모두 상품이름으로 고쳐달라고 하면 어떻게 해야할까?

여러 화면에 보이는 상품명, 가격, 수량 등, label 에 있는 단어를 변경하려면 다음 화면들을 다 찾아가면서 모두 변경해야 한다. 왜냐하면 해당 HTML 파일에 메시지가 하드코딩 되어 있기 때문이다.

 

이런 다양한 메시지를 한 곳에서 관리하도록 하는 기능을 메시지 기능이라 한다.

 

예시)

messages.properties

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

 

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

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

국제화

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

예를 들어서 다음과 같이 2개의 파일을 만들어서 분류한다.

 

HTTP accept-language 헤더 값을 사용하거나 사용자가 직접 언어를 선택하면, 쿠키 등을 사용해서 해당하는 메세지 파일을 웹 애플리케이션에 적용시킨다.

 

메시지와 국제화 기능을 직접 구현할 수도 있겠지만, 스프링은 기본적인 메시지와 국제화 기능을 모두 제공한다.

그리고 타임리프도 스프링이 제공하는 메시지와 국제화 기능을 편리하게 통합해서 제공한다.

스프링 메시지 소스 설정

메시지 관리 기능을 사용하려면 스프링이 제공하는 MessageSource 를 스프링 빈으로 등록하면 되는데, MessageSource 는 인터페이스이다. 따라서 구현체인 ResourceBundleMessageSource 를 스프링 빈으로 등록하면 된다.

 

직접 등록

@Bean
public MessageSource messageSource() {
     ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
     messageSource.setBasenames("messages", "errors");
     messageSource.setDefaultEncoding("utf-8");
     return messageSource;
}

 

basenames : 설정 파일의 이름을 지정한다.

  • messages 로 지정하면 messages.properties 파일을 읽어서 사용한다.
  • 추가로 국제화 기능을 적용하려면 messages_en.properties , messages_ko.properties 와 같이 파일명 마지막에 언어 정보를 주면된다. 만약 찾을 수 있는 국제화 파일이 없으면 messages.properties (언어정보가 없는 파일명)를 기본으로 사용한다.
  • 파일의 위치는 /resources/messages.properties 에 두면 된다.
  • 여러 파일을 한번에 지정할 수 있다. 여기서는 messages , errors 둘을 지정했다.

defaultEncoding : 인코딩 정보를 지정한다. utf-8 을 사용하면 된다.

스프링 부트

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

 

스프링 부트 메시지 소스 설정

>application.properties

spring.messages.basename=messages,config.i18n.messages
spring.messages.basename=messages //기본 값

 

MessageSource 를 스프링 빈으로 등록하지 않고, 스프링 부트와 관련된 별도의 설정을 하지 않으면 messages 라는 이름으로 기본 등록된다. 따라서 [ messages_en.properties , messages_ko.properties , messages.properties ] 파일만 등록하면 자동으로 인식된다.

 

*그 외 옵션 : 'spring.messages' 검색

https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#appendix.application-properties

 

주의! 파일명은 massage가 아니라 messages. 마지막 s에 주의하자.

 

/resources/messages.properties

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

 

/resources/messages_en.properties

hello=hello
hello.name=hello {0}

스프링 메세지 소스 사용

스프링 빈에 등록된 메세지 소스를 가져다 사용한다.

MessageSource 인터페이스

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;
    ...

ms.getMessage("hello", null, null)

  code: hello

  args: null

  locale: null

 

코드에 대한 메시지가 없는 경우에는 NoSuchMessageException 이 발생한다.

메시지가 없어도 기본 메시지( defaultMessage )를 사용하면 기본 메시지가 반환된다.

 

Locale 정보가 없는 경우,  Locale.getDefault() 을 호출해서 시스템의 기본 로케일을 사용

예) locale = null 

시스템 기본 locale 이 ko_KR 이므로 messages_ko.properties 조회 시도 -> 조회 실패 messages.properties 조회

웹 애플리케이션에 메시지 적용하기

타임리프 메시지 적용

타임리프의 메시지 표현식 #{code} 를 사용하면 스프링의 메시지를 편리하게 조회할 수 있다. 

 

파라미터 사용

#{code(parameter,...)}

 

예) hello.name=안녕 {0}

th:text="#{hello.name(${item.itemName})}"

웹 애플리케이션에 국제화 적용하기

HTTP Accept-Language 에 따라 메세지 설정 파일이 다르게 적용된다. 

 

웹으로 확인하기

웹 브라우저의 언어 설정 값을 변경하면 요청시 Accept-Language 의 값이 변경된다.

Accept-Language: 클라이언트가 서버에 기대하는 언어 정보를 담아서 요청하는 HTTP 요청 헤더

 

Accept-Language: en,ko;q=0.9

=> 우선순위: en=1, ko=0.9

 

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

MessageSource 의 메시지 기능은 Locale 정보를 알아야 언어를 선택할 수 있다.

스프링도 locale 정보를 알아야 언어를 선택할 수 있는데, 스프링은 언어 선택시 기본으로 Accept-Language 헤더의 값을 사용한다. 이 방식은 사용자가 임의로 언어 설정을 바꾸기 불편하다.

 

=> 웹 애플리케이션 자체적으로 사용자 선택을 받아 쿠키나 세션에서 설정을 기억하고 적용시키는 방법 

 

LocaleResolver

스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver 라는 인터페이스를 제공한다.

=> 구현체를 변경하여 스프링 빈으로 등록

스프링 부트는 기본으로 Accept-Language 를 활용하는 AcceptHeaderLocaleResolver 를 사용한다.

 

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

4. 검증1 - Validation

검증 요구사항

상품 관리 시스템에 새로운 요구사항이 추가되었다.

요구사항: 검증 로직 추가

타입 검증

가격, 수량에 문자가 들어가면 검증 오류

 

처리 필드 검증

상품명: 필수, 공백X

가격: 1000원 이상, 1백만원 이하

수량: 최대 9999

 

특정 필드의 범위를 넘어서는 검증

가격 * 수량의 합은 10,000원 이상

 

웹 서비스는 폼 입력시 오류가 발생하면, 고객이 입력한 데이터를 유지한 상태로 어떤 오류가 발생했는지 친절하게 알려주어야 한다.

 

컨트롤러의 중요한 역할중 하나는 HTTP 요청이 정상인지 검증하는 것이다.

 

참고: 클라이언트 검증, 서버 검증

  • 클라이언트 검증은 조작할 수 있으므로 보안에 취약하다. (ex. javascript)
  • 서버만으로 검증하면, 즉각적인 고객 사용성이 부족해진다.
  • 둘을 적절히 섞어서 사용하되, 최종적으로 서버 검증은 필수
  • API 방식을 사용하면 API 스펙을 잘 정의해서 검증 오류를 API 응답 결과에 잘 남겨주어야 함

검증 직접 처리 - 소개

상품 저장 성공

사용자가 상품 등록 폼에서 정상 범위의 데이터를 입력하면, 서버에서는 검증 로직이 통과하고, 상품을 저장하고, 상품 상세 화면으로 redirect한다.

 

상품 저장 검증 실패

고객이 상품 등록 폼에서 상품명을 입력하지 않거나, 가격, 수량 등이 너무 작거나 커서 검증 범위를 넘어서면, 서버 검증 로직이 실패해야 한다.

 

이렇게 검증에 실패한 경우

1. 고객에게 다시 상품 등록 폼을 보여주고, (기존 데이터 그대로)

2. 어떤 값을 잘못 입력했는지 친절하게 알려주어야 한다.

'Advance I > Spring MVC' 카테고리의 다른 글

22.08.31  (0) 2022.08.31
22.08.30  (0) 2022.08.30
22.08.25  (0) 2022.08.25
22.08.24  (0) 2022.08.24
22.08.22  (0) 2022.08.22