안녕하세요. 빈코입니다! 오늘은 Java에서 자주 사용하는 spring:message에 대해 자세히 포스팅하려 합니다. message 적용을 위해서는 web.xml, applicationContext.xml에 대해 알아야 하기 때문에 각각의 역할이 무엇인지 알아본 후 message 적용하는 방법에 대해 포스팅하겠습니다😁
Spring:message란?📗
개발을 하다보면 국제화가 필요할 때가 있습니다. Spring에서는 메시지 처리의 다국어 지원 및 국제화를 위한 기능을 spring:message로 지원합니다. 이를 위해 Spring은 'MessageSources' 인터페이스를 제공하고 주로 'ReloadableResourcesBundleMessageSource' 클래스를 사용합니다.
Spring message는 국제화뿐만 아니라, 작성한 key-value 형태의 값들을 한 번에 수정할 때도 유용하게 사용됩니다. 만약 여러 곳에서 쓰이는 '성공' 이라는 글자를 '성공하였습니다'로 바꿔야 하는 상황이 왔을 때, 수기로 모든 페이지에 작성했다면, 모든 페이지를 찾아 바꿔줘야 하는 번거로움이 있습니다.
하지만, Spring message를 사용하면
// message.properties
common.success=성공하였습니다
'common.success'라는 값만 '성공'에서 '성공하였습니다'로 수정해 주면 끝이 납니다. jsp, js, controller, service에서 'common.success'라는 key를 사용하는 모든 곳이 한 번에 수정되겠죠?(application.yml과 비슷합니다)
적용하기 위해서는 Spring의 일부분인 web.xml, application.xml에 대해서 먼저 알아야 합니다. 하단에서 설명할게요 :)
Web.xml이란?📙
web.xml은 서블릿(Servlet), 필터(Filter), 리스너, Error 페이지 정의 등 여러 웹 컴포넌트 및 설정에 대한 정보를 제공하고, 서버에게 웹 애플리케이션을 구동하는 방법을 알려주는 역할을 합니다. 'web.xml' 파일은 WEB-INF 디렉터리 하위에 위치하며, 해당 파일은 웹 애플리케이션 디렉터리마다 딱 하나만 존재할 수 있습니다. 저희는 spring:message를 사용하기 위해 서블릿을 등록해야 하는 상황입니다.
서블릿을 등록하는 방법은 위에 언급된 applicationContext.xml과 servlet_context.xml에 Bean을 등록하면 되는데, applicationContext.xml에는 특정 Servlet 설정과 관계 없는 설정은 하지 않고 서로 다른 여러 Servlet에서 공통적으로 공유해서 사용할 수 있는 Bean을 선언합니다(메세지는 여러 군대에서 사용하니깐 이곳에 등록하면 되겠죠?)
반대로, servlet_context.xml에는 특정 URL설정이 있는 Bean들을 생성합니다(@Controller)
Spring에서는 Bean을 찾는 순서가 Servelt Context를 먼저 찾은 후에, 찾지 못할 경우 Application Context에 정의된 Bean을 찾게 됩니다. 즉, 개별적인 것(servlet_context)들을 먼저 찾은 후에 없다면 공통적인 것(applicationContext.xml)을 찾는다는 것이죠!
쉽게 정리하면, 저희는 공통적으로 사용하는 spring:message를 applicationContext.xml에 정의하고, 이 정의한 내용을 서버에게 알려주기 위해 applicationContext.xml을 web.xml에 정의해야 한다는 이야기입니다😃
ApplicationContext.xml📘
등록 코드 먼저 살펴볼까요?
<!-- 다국어 지원 properties -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages/messages</value>
</list>
</property>
<property name="cacheSeconds" value="100000" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="messageSourceAccessor" class="org.springframework.context.support.MessageSourceAccessor">
<constructor-arg ref="messageSource"/>
</bean>
<bean id="messageUtil" class="com.test.util.MessageUtil">
<property name="messageSourceAccessor" ref="messageSourceAccessor"/>
</bean>
첫번째로 'messageSource'는 리로드가 가능한 ResourcesBundle을 사용하여 메시지를 로드하는 'ReloadableResourceBundleMessageSource' 클래스의 인스턴스를 생성합니다. 이 클래스의 'basenames' 프로퍼티는 메시지 번들 파일의 경로를 지정하는데 여기서 'classpath:messages/messages'로 설정된 부분은 'messages' 폴더의 'messages'라는 기본 파일명을 가진 리소스 번들을 사용하겠다는 의미입니다. 아래 사진처럼요!
💡 classpath는 Java Build Path를 의미합니다. 'TestProject/src/main/resources'와 같은 경로를 뜻하는데, classpath는 설정에서 Java Build Path를 찾아 설정해 주시면 됩니다 :)
이어서 설명하면 'cacheSeconds'는 메시지 번들 캐시를 갱신하는 주기를 초 단위로 지정합니다. 위 코드는 100,000초로 설정되어 있어서 매우 긴 시간 동안 캐시를 사용하겠다는 의미입니다. 'defaultEncoding'은 메시지 번들의 기본 인코딩을 설정하는 부분입니다.
이렇게 해서 저희는 'messageSource'라는 빈을 생성했습니다. 그러면 이 메시지 소스에 쉽게 액세스하기 위한 유틸리티 클래스가 필요합니다. 바로 하단에 있는 'messageSourcesAccessor'이죠!
<constructor-arg ref="messageSource"/>
위에서 만든 'messageSource' 빈을 인자로 사용하고 있습니다. 그러면 마지막으로 Util 클래스의 인스턴스를 생성해야 합니다. 마지막 코드인 'messageUtil'을 뜻합니다. 'messageUtil'을 통해 추후에 Controller 단이나, Service 단에서 다국어 메시지에 접근을 하게 됩니다. 사용법은 하단에서 보여드릴게요🙇♂️
MessageUtil.java📒
바로 위에서 만든 'MessageUtil' 클래스를 살펴볼게요.
public class MessageUtil {
private MessageSourceAccessor msAcc = null;
public void setMessageSourceAccessor(MessageSourceAccessor msAcc) {
this.msAcc = msAcc;
}
public String getMessage(String key) {
Locale locale = Locale.getDefault();
try{
HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
locale = httpRequest.getLocale();
}catch(Exception e) {
if(ConfigUtil.getDefaultLocale().equals("ko")){
locale = new Locale("ko", "KR");
}else if(ConfigUtil.getDefaultLocale().equals("en")){
locale = new Locale("en", "US");
}
}
return msAcc.getMessage(key, locale);
}
}
해당 클래스는 다국어 지원을 사용하기 위해 필요합니다. 프로젝트마다 필요한 언어가 다를텐데, 저는 가장 흔한 예시인 한국어와 영어로 예시를 들었습니다. 아까 등록한 'MessageSourcesAccessor'을 이용하게 되고, getMessage(String key) 함수는 java 단(controller, service)에서 사용하게 됩니다.
코드 먼저 살펴보자면, Spring 프레임워크에서 현재 요청의 'HttpServletRequest' 객체를 사용하여 사용자의 locale(지역)을 가져온 후 Controller,Service에서 넘겨받은 key값과 함께 getMessage를 호출합니다.(여기서 key 값은 추후 작성할 message.properties의 key값을 이야기합니다 - 아래 예시로 보면 key 값은 login.id or login.password)
💡catch 부분에서는 만약 사용자의 위치를 찾는 httpRequest.getLocale()에서 오류가 난다면 config.xml에 등록되어 있는 'default.locale'을 사용하겠다는 의미입니다. 이건 각 프로젝트마다 기본 지역이 다르고 추가사항이기 때문에 catch 코드 부분은 생략하셔도 됩니다.
그러면 마지막에 return 하는 msAcc.getMessage(key, locale); 에는 사용자가 작성한 message.properties의 key값과 방금 설정한 지역 locale 값이 들어갑니다. 이후에는 spring에서 bean 생성 시 만들어지는 MessageSourceAccessor.class의 내부 동작으로 우리가 원하는 message 파일에서 사용자가 입력한 key 값을 찾아 value 값을 return 해줍니다.
정리📒
마지막으로 정리해볼까요?
첫 번째로, Spring에서 사용하는 다국어 지원 properties인 message를 공통으로 사용하는 Bean들을 정의하는 applicationContext.xml에 정의합니다.
두 번째로, 서버에게 웹 애플리케이션을 구동하는 방법을 알려주는 web.xml에 applicationContext.xml을 등록합니다.
세 번째로, applicationContext.xml에 등록한 메시지 관련 코드 중 Java 단(Controller, Service)에서 접근하기 위한 클래스 MessageUtil을 정의해줍니다.
네 번째로, messages.properties를 작성합니다(포스팅 내용 X, 각자 프로젝트에 맞게 Key-Value 형식으로 작성)
마치며
오늘은 Spring Message를 프로젝트에 적용했습니다. 그럼 이제 Front 단(jsp, thymeleaf), js(javascript), Java 단(Controller, Service)에서 각각 어떻게 사용하는지 다음 포스팅에서 설명할게요😊
👨👩👦👦 오픈채팅방 운영
취업을 준비하는 예비 개발자분들을 위한 질문&답변할 수 있는 공간을 만들었습니다. 취업과 이직을 하기 위해서 어떤 걸 중점적으로 준비해야 하는지부터 포트폴리오&이력서 작성법 등 다양한 질문들을 받고 답변을 드립니다. 참여하셔서 다양한 정보 얻고 가시면 좋을 것 같네요😁
참여코드 : 456456
https://open.kakao.com/o/gVHZP8dg
👨💻 전자책 출간
아울러 제가 🌟비전공자에서 2년만에 보안 전문 중견기업으로 이직 한 방법들을 정리한 전자책을 출간 하게 되었습니다. 어떤 걸 공부해야 하는지, 이직을 위해서 무엇을 준비해야 하는지, 제가 받았던 기술 면접 리스트 등 다양한 목차로 구성되어 있습니다. 또한, 구매 시 1:1 채팅을 이용하여 포트폴리오 첨삭을 도와드리고 있습니다. 🐕전자책으로 얻은 모든 수익은 유기견 센터 '팅*벨 입양센터'에 후원될 예정입니다. 관심 있으신 분들은 아래 링크를 참고해주세요😁
'TIL' 카테고리의 다른 글
Java Spring Message 사용하는 방법 완벽정리 (1) | 2024.01.10 |
---|---|
jstree 핸들링 방법(이전 선택 값 남아있는 오류) (1) | 2024.01.09 |
JavaScript 다중 검색 기능 만들기 (0) | 2023.09.26 |
[Java] csv 파일 프로그램 여러가지 Tip (0) | 2023.09.14 |
Java String, StringBuilder, StringBuffer 차이와 장단점 (2) | 2023.08.21 |