YONG-MIN

간단하게 공부를 할때나 테스트를 할때면 아래처럼 간혹 소스에 메시지를 그냥 넣습니다.

HashMap<String, object> map = new HashMap<String,object>(); map.put("msg", "하드코딩식 입력!!");

하지만, 이런식으로 소스를 구현한다면 공통 메시지를 변경할때 일일히 모든 소스파일을 찾아 바꿔줘야해서 관리하기가 안좋습니다.

그렇기 때문에 Spring에서 제공하는 MesageSource를 bean으로 등록해서 사용하면 관리가 편해지고 

심지어는 웹어플리케이션의 리로딩 없이도 메시지 변경이 가능합니다.



1. Spring에서 제공하는 주요 MessageSource 구현체


1.1. org.springframework.context.support.StaticMessageSource : 

    MessageSource의 가장 간단한 구현체. 기본적인 다국어 기능을 지원하면서 테스트용도로 사용됩니다.


1.2. org.springframework.context.support.ResourceBundleMessageSource

    ResourceBundle Class, MessageFormat Class 기반으로 만들어져 Bundle에 특정 명칭으로 접근이 가능합니다.


1.3. org.springframework.context.support.ReloadableResourceBundelMessageSource

    Property  설정을 통해 Reloading 정보를 입력해 주기적인 Message Reloading을 수행합니다. 

    그렇기 때문에 Application 종료없이도 실행 도중에 변경이 가능한 장점이 있습니다.


    이번 포스팅에선 3번재에서 언급한 ReloadableResourceBundleMessageSource 구현체를 이용한 메시지 설정법을 다루겠습니다.


2. MessageSource 샘플 구조(간략)

아래 단계에 걸쳐 포스팅을 진행하겠습니다.

2.1. web.xml을 통해 message-servlet.xml을 읽도록 합니다. (context-message 등 각자 환경에 맞는 context를 이용하면 됩니다.)

2.2. 사용할 Message Property를 만듭니다. ex) labels_ko_KR.properties

2.3. message-servlet.xml에 MesageSource와 사용하기 위한 MessageSourceAccessor를 설정합니다.

2.4. MessageSourceAccessor를 사용할 수 있도록 MessageUtils.java를 생성합니다.

2.5. CommonController에서 테스트합니다.


3. Web.xml

  ...
<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
      	/WEB-INF/config/*-servlet.xml
      </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
...

web.xml에 message-servlet.xml 을 읽을 수 있도록 설정합니다.


4. Message Property 파일 작성 : {basename}_언어코드_국가코드.properties


Message Source의 Property 파일은 아래와 같은 Naming Rule을 지켜야합니다.

{basename}_언어코드_국가코드.properties

{basename}은 개발자가 사용목적에 따라 임의로 지정할 수 있습니다.

저는 src/main/resource 아래 message란 폴더를 만들고 labels란 basename을 사용하였습니다.

결과적으로 아래와 같은 Property Naming이 가능합니다.

 {basename}.properties

 Default Message로 시스템의 언어 및 지역에 맞는 Property 파일이 존재하지 않을 경우 사용

 {basename}_en.properties

 시스템 언어 코드가 영어일 때 사용

 {basename}_ko.properties

 시스템 언어 코드가 한글일 때 사용

 {basename}_en_UK.properties

 시스템 언어 코드가 영어일때 영국(국가코드)을 위한 메시지 


[labels_ko_KR.properties]

error.common=오류가 발생했습니다.
error.minlength={0}은 {1}자 이상의 문자를 입력하셔야 합니다.

{0}, {1} 은 String을 배열 파라미터로 받아서 오류메시지를 탬플릿 맞춰 출력하기 위한 것입니다.

Eclipse에서 New FIle로 만들면 첫 Encoding이 UTF-8이 아니므로, Properties에 들어가 변경해줍니다.



5. Application Context 설정: message-servlet.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- Encoding 설정 --> <property name="defaultEncoding" value="UTF-8"/> <!-- Reload Cache 설정 --> <property name="cacheSeconds" value="5"/> <!-- basenames 설정: 아래처럼 하면 WEB-INF 밑의 message 폴더 아래의 labels로 시작하는 모든 Property--> <property name="basenames"> <list> <value>/WEB-INF/message/labels</value> </list> </property> </bean> <!-- MessageSource를 사용하기 위한 Accessor 설정 --> <bean id="messageSourceAccessor" class="org.springframework.context.support.MessageSourceAccessor"> <constructor-arg ref="messageSource"/> </bean> <!-- MessageSource를 사용하기위한 MessageUtils 매핑 --> <bean id="message" class="moim.common.util.MessageUtils"> <property name="messageSourceAccessor" ref="messageSourceAccessor"/> </bean> <!-- Default Location 설정 --> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"> <property name="defaultLocale" value="ko"></property> </bean> </beans>

우선, MessageSource를 설정하기 위한 Bean의 ID를 꼭 "messageSource"로 설정하여야 합니다. (고정)

그리고 한글 출력시 문제가 없도록하기 위한 Encoding 설정과 Reload 시간에 대한 설정을 진행했습니다.

basename는 밑에 작성할 실질적인 Message가 들어있는 Property 파일과 관련되므로 정확히 적어주셔야 합니다.

<list>...</list>인 것처럼 여러 Message Property를 등록할 수 있습니다.

<value></value>에는 root(src/main/resource)로부터 경로를 적어주시면 됩니다. 

labels는 Message Property에서 {basename}으로 사용한 것입니다.

해당 {basename}으로 시작하는 모든 Property를 읽어서 사용하는 Locale에 해당하는 Property를 사용하게 됩니다.

그리고 MessageSource 를 이용하기위한 Accessor와 MessageUtils를 Bean으로 등록합니다.

이번 포스팅에선 <bean id="localResolver">에서 Default Locale을 ko로 설정하였습니다.


6. MessageUtils.java

이제 설정한 Bean으로부터 Message Property를 편하게 사용하기 위한 유틸 객체를 작성하겠습니다.

공부용 Project에 공통요소들은 Common 패키지 밑에 묶어놓았습니다.

common 패키지에 util 패키지를 만들고 그 아래에 MessageUtils.java를 만들었습니다.

import java.util.Locale;

import org.springframework.context.support.MessageSourceAccessor;
  
public class MessageUtils {
	private static MessageSourceAccessor msAcc = null;
	
	public void setMessageSourceAccessor(MessageSourceAccessor msAcc) {
		MessageUtils.msAcc = msAcc;
	}
	
	public static String getMessage(String code) {
		return msAcc.getMessage(code, Locale.getDefault());
	}
	
	public static String getMessage(String code, Object[] objs) {
		return msAcc.getMessage(code, objs, Locale.getDefault());
	}
}


MessageSourceAccessor(msAcc)는 앞서 5에서 설정한 message-servlet.xml에서 bean id="message"에서 연결됩니다.

나머지는 아주 간단해서 설명할 부분이 별로 없습니다.

파라미터로 들어오는 String code는 

4에서 만든 labels_ko_KR.properties에 작성된 error.common, error.minlength와 같은 식별자가 입력됩니다.


7. 테스트(사용법)

7.1. Java

<Code>

	@RequestMapping(value="/common/test.do")
	public ModelAndView test(HttpServletRequest request) throws Exception{
		ModelAndView mv = new ModelAndView("/common/test");
		
		log.debug("error.common: "+MessageUtils.getMessage("error.common"));
		log.debug("error.minlength: "+MessageUtils.getMessage("error.minlength", new String[] {"테스트글자", "2"}));

		return mv;
	}	

<Result(Console)>


7.2. JSP

위에서 Controller에서 /common/test.jsp로 연결되도록 ModelAndView를 return하였습니다.

<test.jsp>

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

<spring:message code="error.common"></spring:message>
<spring:message code="error.minlength" arguments="테스트글자, 1"></spring:message>

<Result(View)>