안녕하세요. 오늘은 스프링 부트와 타임리프를 활용해서 다국어 메일을 보내려고 합니다.
제 코드가 더 나은 방향이 될 수 있게 댓글 남겨주시면 감사하겠습니다.
먼저 요구사항 먼저 정리하겠습니다.
[요구사항]
한 서버에 여러 개의 프로젝트가 생성되어 있습니다.
여러 개의 프로젝트가 회원에게 메일을 전송합니다. 그래서 메일을 전송하는 프로젝트를 따로 생성하여
관리하게 되었습니다.
[기존]
[변경 후]
메일 전송을 담당하는 Project D는 앞으로 메일 서버라고 하겠습니다.
메일 서버는 http 요청을 받아서 html메일을 전송합니다.
[새로운 요구사항]
국제화 기능을 추가해야합니다. 기본에는 target이 한국뿐이었기 때문에 html 파일에 static하게 한국어가 들어가
있었습니다. 이를 국제화를 해야합니다.
[고민하는 과정]
1. 스프링에서 제공하는 기능을 사용해보자.
2. 스프링과 타임리프를 사용하여 다국어 처리를 해보자. (기존에는 그냥 html)
3. 들어오는 요청마다 어떤 언어로 보낼지 확인해서 보내보자
먼저 dependency를 추가해줍니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
}
스프링부트에서는 다국어 처리를 위해 LocalResolver라는 기능을 제공합니다.
LocaleResolver는 요청에서 Locale 정보를 가져오는 역할을 합니다.
LocalResolver 종류
1. AcceptHeaderLocaleResolver : HTTP 요청 헤더인 "Accept-Language"를 사용하여 Locale 정보를 가져옵니다.
2. CookieLocaleResolver : 쿠키를 사용하여 Locale 정보를 가져옵니다.
3. SessionLocaleResolver : 세션을 사용하여 Locale 정보를 가져옵니다.
4. FixedLocaleResolver: 설정되고, 고정된 Locale 정보를 무조건 사용합니다.
기본적으로는 AcceptHeaderLocaleResolver가 사용됩니다.
저는 각각의 메일전송 요청마다 다르게 언어를 선택해야하기 때문에 AcceptHeaderLocaleResolver를 사용하기로 결정하였습니다.
ThymeleafConfig
@Configuration
public class TymeleafConfig {
@Bean
public TemplateEngine htmlTemplateEngine() {
TemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(springResourceTmeplateResolver());
return templateEngine;
}
@Bean
public SpringResourceTemplateResolver springResourceTmeplateResolver() {
SpringResourceTemplateResolver springResourceTemplateResolver = new SpringResourceTemplateResolver();
springResourceTemplateResolver.setOrder(1);
springResourceTemplateResolver.setPrefix("classpath:templates/");
springResourceTemplateResolver.setSuffix(".html");
springResourceTemplateResolver.setTemplateMode(TemplateMode.HTML);
springResourceTemplateResolver.setCharacterEncoding("UTF-8");
springResourceTemplateResolver.setCacheable(false);
return springResourceTemplateResolver;
}
}
템플릿 엔진을 설정해주는 클래스입니다.
htmlTemplateEngine() 메서드는 SpringTemplateEngine 객체를 생성하고 SpringResourveTemplateResolver를 추가하여 이를 템플릿 엔진으로 사용합니다.
SpringResourceTemplateResolver() 메서드는 SpringResourveTemplateResolver 객체를 생성하여 템플릿 파일을 읽어올 위치를 설정합니다.
prefix : "classpath:templates/" 템플릿 파일을 읽어올 경로를 설정합니다.
suffix : ".html" 파일 확장자를 설정합니다.
templateMode : TemplateMode.HTML 템플릿 모드를 HTML로 설정합니다.
characterEncoding : "UTF-8" 템플릿 파일의 인코딩을 UTF-8로 설정합니다.
cacheable(false) : 캐시를 사용하지 않도록 설정합니다.
WebMvcConfiguration
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Bean
public LocaleResolver localeResolver() {
// en-US, fr-CA, de-DE, es-ES, ko-KR, zh-CN 등이 있다.
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(Locale.KOREAN);
return localeResolver;
}
@Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:/messages/message");
messageSource.setCacheSeconds(180);
Locale.setDefault(Locale.KOREAN);
return messageSource;
}
}
localResolver() 메서드는 기본적으로 사용할 언어를 설정합니다. 저는 기본으로 한국어를 설정하였습니다.
messageSource() 메서드는 다국어 처리가 된 message.properties 파일들을 읽어오는 설정을 합니다.
제 다국어 properties 파일들의 경로입니다.
/src/main/resources/messages/message_en.properties
/src/main/resources/messages/message_ko.properties
MailController
@RequestMapping(method = RequestMethod.POST, value = "/mail/send")
public CommonResponse sendMail(@Valid @RequestBody MailInfoDto mailInfo, Locale locale) throws Exception {
mailService.sendMail(mailInfo, locale);
return responseService.getSuccessResult();
}
해당 코드는 생략된 부분이 꽤 많은걸 감안해주세요 ㅎ
여기서 중요한 부분은 컨트롤러의 파라미터로 Locale locale을 받을 수 있다는 것입니다.
http 요청 시에 헤더에 Accept-Language를 설정해주면 lcoale에는 해당 언어 정보가 담기게 됩니다.
postman Accept-Language 설정 예시
이제 해당 locale에 담긴 정보를 활용하여 properties 파일을 가져오겠습니다.
import org.thymeleaf.context.Context;
// ~ 생략
@Autowired
private TemplateEngine htmlTemplateEngine;
@Override
public CommonResponse sendMail(MailInfoDto mailInfo, Locale locale) throws Exception {
// 이전 작업 생략
String mailName = "helloMail"; // 예시 : html 파일 이름 입니다.
Map<String, Object> propMap = getProperties(locale);
Context context = getContext(propMap);
String body = htmlTemplateEngine.process(mailName, context);
// 메일 발송부분 생략
}
private Map<String, Object> getProperties(Locale locale) throws Exception{
Map<String, Object> result = new HashMap<>();
Properties properties = PropertiesLoaderUtils.loadProperties
(new EncodedResource(new ClassPathResource("messages/message_"+locale.getLanguage()+".properties"), "UTF-8"));
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
result.put((String) entry.getKey(), (String) entry.getValue());
}
return result;
}
private Context getContext(Map<String, Object> propMap) {
Context context = new Context();
context.setVariables(propMap);
return context;
}
getProperties 메서드는 해당 lcoale 에 맞는 properties의 모든 값을 Map<String, Object>로 리턴합니다. 그냥 가져오면 한글이 깨지는 문제 때문에 new EncodedResource -> "UTF-8"로 인코딩 해주었습니다.
그리고 그 map을 타임리프의 Context에 담았습니다.
htmlTemplateEngine.process 메서드에서는 mailName과 context를 인자로 html의 다국어화를 하여 String으로 return 받습니다.
html은 타임리프에서 지원하는 것처럼 th:text를 사용하여 설정해주시면 됩니다.
다국어화한 html을 메일로 전송하면 완료입니다.
메일을 전송하는 방법은 다른 참조 블로그가 많기 때문에 저는 다루지 않도록 하겠습니다.
좀 더 좋은 방법이 있을 것이라고 생각합니다. 있다면 저에게 조언해주시면 감사하겠습니다😉
'개인 지식 > Spring' 카테고리의 다른 글
[Spring boot] API 호출 시(에러) HTTP 상태 코드, 오류 메시지 전달하기 (0) | 2022.12.20 |
---|