ํ๋ฆฌ๋ง์ปค ํ ํ๋ฆฟ
์คํ๋ง ๋ถํธ ํ๋ก์ ํธ์ ๋ํ ์์ ๋ฅผ ์ดํด๋ณด๋ฉด ๋๋ถ๋ถ ํ ํ๋ฆฟ ์์ง์ผ๋ก ํ์๋ฆฌํ๋ฅผ ์ ํํ์ฌ ์ฌ์ฉํจ์ ์ ์ ์๋ค. ๋๋ถ๋ถ ํ์๋ฆฌํ์ ๋ํด์ ์ค๋ช ํ๋ฏ๋ก ํ๋ฆฌ๋ง์ปค ํ ํ๋ฆฟ ์์ง์ ๋ํด์ ์ ๋ฆฌํ ๊ธ์ ์๊ฐ๋ณด๋ค ๋ง์ง ์๋ค. ๋๋ ํ์๋ฆฌํ๋ผ๋ ํ ํ๋ฆฟ ์์ง ๋ณด๋ค๋ ํ๋ฆฌ๋ง์ปค์ ๋ฌธ๋ฒ์ด ๋ ๊ฐ๋จํ๊ณ ๋๋ผ๊ธฐ์ ๋ ์ ํธํ๋ ํธ์ด๋ค. ์ฌ๋ฌ๊ฐ์ง ํ ํ๋ฆฟ ์์ง๊ณผ ๋น๊ตํด์๋ ์ค์ํ ๋ ๋๋ง ์ฑ๋ฅ์ ๋ณด์ฌ์ฃผ๊ณ ์๋ค.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
}
FreeMarkerAutoConfiguration
์คํ๋ง ๋ถํธ์ ์๋ ๊ตฌ์ฑ์ FreeMarkerAutoConfiguration๋ก ์์๋๋ฉฐ FreeMarkerServletWebConfiguration์์ ๋ทฐ ๋ฆฌ์กธ๋ฒ๊ฐ ๋ฑ๋ก๋๋ฉฐ FreeMarkerNonWebConfiguration์ผ๋ก FreeMarkerConfigurationFactoryBean๊ฐ ๋ฑ๋ก๋์ด ์ด๋ฉ์ผ ๋ด์ฉ ์ฒ๋ฆฌ์ ๊ฐ์ ์น ์์ฒญ๊ณผ ๊ด๋ จ๋์ง ์์ ๊ณณ์์๋ ํ ํ๋ฆฟ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋๋ก ์ง์ํ๋ค. ์คํ๋ง ํ๋ ์์ํฌ์์๋ SpringTemplateLoader๋ก ํด๋์คํจ์ค์ ์กด์ฌํ๋ ํ ํ๋ฆฟ์ ๋ถ๋ฌ์ฌ ์ ์๋๋ก ์ง์ํ๋ฉฐ ํ๋ฆฌ๋ง์ปค์์๋ StringTemplateLoader๋ฅผ ํตํด ๋ฌธ์์ด๋ก ์ ์๋ ํ ํ๋ฆฟ์ ๋ง๋ค ์ ์๊ฒ ์ ๊ณตํ๋ค.
Internationalization
์คํ๋ง ํ๋ ์์ํฌ์์๋ ํ๋ฆฌ๋ง์ปค ํ ํ๋ฆฟ์ ์ฌ์ฉํด์ ๋ค๊ตญ์ด ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ ์ ์๋๋ก spring.ftl๋ผ๋ ๋งคํฌ๋ก๊ฐ ํฌํจ๋ ํ ํ๋ฆฟ ํ์ผ์ ์ ๊ณตํ๊ณ ์์ผ๋ฉฐ ์๋์ ๊ฐ์ด ํ๋ฆฌ๋ง์ปค ํ ํ๋ฆฟ์์ ์คํ๋ง ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค. ํ๋ฆฌ๋ง์ปค ํ ํ๋ฆฟ ํ์ผ์ ์ง์ ๋ช ์ํ๊ฑฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ํ๋กํผํฐ๋ก auto_import ์ต์ ์ ์ฌ์ฉํด์ ์ถ๊ฐํ ์๋ ์๋ค.
<#import "/spring.ftl" as spring/>
<@spring.message "messageKey"/>
spring:
freemarker:
settings:
auto_import: spring.ftl as spring
๋ค๋ง, ์ spring.ftl ํ์ผ์ ์ ์๋ ๋ฉ์์ง ์ฒ๋ฆฌ๋ ์น ์์ฒญ์ ์ํ ์ค๋ ๋ ๋ด์์๋ง ์ฌ์ฉ๋ ์ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฉ์ผ ๋ด์ฉ ์ฒ๋ฆฌ์ ๊ฐ์ด ์น ์์ฒญ์ด ์๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ ์์ ์ฌ์ฉํ ์ ์๋ค.
๋ฐฑ๊ทธ๋ผ์ด๋ ์์ ์ ๋ค๊ตญ์ด ๋ฉ์์ง ์ฒ๋ฆฌ
์ฌ์ฉ์์ ์น ์์ฒญ์ ์ํ ํ ํ๋ฆฟ ์ฒ๋ฆฌ๊ฐ ์๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ ์์ ํ๋ฆฌ๋ง์ปค ํ ํ๋ฆฟ ์์ง์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ ๋ค๊ตญ์ด ๋ฉ์์ง๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด์๋ ํ๋ฆฌ๋ง์ปค ํ ํ๋ฆฟ ์์ง์์ ๋ฆฌ์์ค ๋ฒ๋ค์ ๋ชจ๋ธ๋ก ๋ฉ์์ง ๋ณด๊ฐ์ ์ฒ๋ฆฌํ ์ ์๋ ResourceBundleModel๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค. ๋ค์์ ์คํ๋ง ๋ถํธ ์๋ ๊ตฌ์ฑ์ ์ํด ๋ฑ๋ก๋๋ FreeMarkerConfigurationFactoryBean๊ณผ ResourceBundleModel์ ํตํด ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋ํ ์์์ด๋ค.
Locale locale = Locale.ROOT;
Configuration configuration = configurationFactoryBean.createConfiguration();
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
stringTemplateLoader.putTemplate("template", "${bundle(\"application.name\")}");
configuration.setTemplateLoader(stringTemplateLoader);
Template template = configuration.getTemplate("template", locale);
ResourceBundle resourceBundle = ResourceBundle.getBundle("messages", locale);
Map<String, Object> model = new HashMap<>();
model.put("bundle", new ResourceBundleModel(resourceBundle, new BeansWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).build()));
String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
ํ ํ๋ฆฟ ์ฒด์ด๋
ํ๋ฆฌ๋ง์ปค ํ ํ๋ฆฟ ์์ง์์ ์ง์ํ๋ MultiTemplateLoader๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ์์ ํ ํ๋ฆฟ ๋ก๋ฉ์ ํตํด ํ ํ๋ฆฟ ๋ก๋์ ์ํด ๋ก๋๋๋ ํ ํ๋ฆฟ์ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค. ๋ํ, MultiTemplateLoader์ ์ ๋ฌ๋๋ ํ ํ๋ฆฟ ๋ก๋์ ์์์ ๋ฐ๋ผ SpringTemplateLoader๋ก ๊ธฐ๋ณธ ํ ํ๋ฆฟ ๋ ์ด์์์ ๋ง๋ค๊ณ ์ค์ ํ ํ๋ฆฟ ๋ด์ฉ์ StringTemplateLoader๋ก ์ฌ์ ์ํ๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ค.
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
stringTemplateLoader.putTemplate("email.ftlh", "${bundle(\"application.name\")}");
stringTemplateLoader.putTemplate("template", "<#include \"email.ftlh\" >");
Configuration configuration = configurationFactoryBean.createConfiguration();
SpringTemplateLoader springTemplateLoader = new SpringTemplateLoader(resourceLoader, "classpath:/templates/");
MultiTemplateLoader multiTemplateLoader = new MultiTemplateLoader(new TemplateLoader[]{stringTemplateLoader, springTemplateLoader});
configuration.setTemplateLoader(multiTemplateLoader);
Template template = configuration.getTemplate("template", locale);
MultiTemplateLoader์ ์์ฑ์์ ์ ๋ฌ๋๋ ํ ํ๋ฆฟ ๋ก๋์ ์์๋๋ก ํ ํ๋ฆฟ์ ์ฐพ๋๋ก ์์ํ๋ค๋ ๊ฒ์ ์ฃผ์ํด์ผํ๋ค.