본문 바로가기
카테고리 없음

[Freemarker] 프리마커 - 자바 템플릿 엔진(Java Template Engine)

by 꼬마낙타 2019. 7. 25.
반응형

업무에 사용하기 위해서 오픈소스 자바 템플릿엔진(Java Template Engine)을 조사하다가 Freemarker(프리마커)라는 템플릿 엔진을 알게 되었다.

템플릿 엔진(Template Engine)이란?

아파치 프리마커(Apache Freemarker)는 텍스트 형태로 데이터를 출력해주는 자바 템플릿 엔진(Java Template Engine) 라이브러리다. (링크 : https://freemarker.apache.org)

 

 

템플릿 엔진(Template Engine)이란 템플릿 양식과 데이터 모델에 입력되어 있는 데이터를 합성하여 문서를 만들어주는 소프트웨어를 말한다. 사용자는 템플릿을 작성하여 템플릿 엔진에 입력한 다음, 데이터 모델을 차례로 템플릿 엔진에 입력하면 데이터 모델에 대응되는 결과 문서를 차례로 얻을 수 있다.

 

템플릿 엔진이 사용되는 대표적인 예로 웹 템플릿 엔진(Web template engine)을 들수 있다. 웹 페이지의 전체적인 모습(View)을 템플릿으로 만들어 놓고, 웹 페이지에 들어가는 웹 컨텐츠 정보를 이용해서 HTML 문서를 결과로 만들어주는 템플릿 엔진이다.

 

웹 템플릿 엔진을 이용하면 데이터의 표현을 담당하는 View 코드와 데이터를 다루는 로직 코드를 분리해낼 수 있다는 장점이 있다. View 코드를 담당하는 개발자는 데이터베이스의 연결이나 비즈니스 로직에 관계없이 템플릿을 이용한 데이터의 표현에 집중할 수 있고 데이터 로직을 담당하는 개발자는 데이터의 표현 방식에서부터 자유로워 질 수 있다.

프리마커(Freemarker)

프리마커(Freemarker)는 현재 자바 진영에서 가장 많이 사용되는 템플릿 엔진(Template Engine) 중 하나다.

2015년 9월 2일부터 아파치 프로젝트로 관리가 되고 있으며, 아파치 라이센스 2.0이 적용되는 Free Software다. (Freemarker 라이센스) 아파치 소프트웨어 재단(Apache Software Foundation)의 관리를 받고 있기 때문에 유지보수가 끊길 염려가 적은 오픈소스이며, 다년간 많은 사용자들에 의해 사용되었기 때문에 탄탄한 유저 커뮤니티와 웹 문서들의 백업을 받을 수 있다.

 

Freemarker의 템플릿은 FTL(Freemarker Template Language)이라는 언어로 작성하게 된다. FTL은 간단한 데이터 추출에서부터 조건문, 반복문과 매크로, 메소드 등 범용 프로그래밍언어에서 지원하고 있는 다양한 기능들을 지원한다. 간단하게 템플릿 기능을 사용하려는 사용자에서부터 복잡하지만 효율적으로 사용하려는 고급 사용자들까지도 만족하면서 쓸 수 있는 기능들을 제공한다. 더 자세한 기능들은 FTL의 사용자 매뉴얼을 참고하기 바란다.

 

Freemarker는 데이터 모델을 만드는 데이터 로직 개발자와 템플릿을 작성하는 템플릿 작성자 사이의 독립성을 최대한 보장해준다. 이를 통해서 데이터 로직 개발자는 데이터가 어떻게 보여질지 최소한으로 고민할 수 있고, 반대로 템플릿 개발자들도 데이터가 어떻게 가져와지는지에 대해서 최소한으로 연관될 수 있다.

프리마커(Freemarker) 템플릿(Template)과 데이터 모델(Data Model)

간단한 예제를 통해서 Freemarker 템플릿과 데이터 모델에 대해서 알아보자.

 

우선 다음과 같은 웹 페이지를 생각해보자. 로그인한 사용자의 정보에 따라서 다음과 같은 웹 페이지가 출력된다고 하자.

<html>
    <head>
        <title>Welcome!</title>
    </head>
    <body>
        <h1>Welcome Dave!</h1>
        <p> welcome to our home page Dave. </p>
    </body>
</html>

로그인한 사용자의 이름이 'Dave'인 경우 위와 같은 HTML 문서가 사용된다. 만약 'Tom'이라는 사용자가 로그인 했으면, 'Dave'라는 글자가 위치한 곳에 'Tom'이라는 글자가 출력될 것이다. 로그인한 사용자의 데이터에 따라서 변하는 부분을 프리마커에서는'${...}'라는 문법을 사용해서 가져오게 되는데 이 문법을 'interpolation'이라고 한다. interpolation이라는 단어는 "써넣음"이라는 뜻을 가지고 있다.

 

위 HTML 페이지에서 로그인한 사용자의 이름에 따라 바뀌는 부분을 interpolation을 통해 끄집어내면 다음과 같이 작성할 수 있다.

<html>
    <head>
        <title>Welcome!</title>
    </head>
    <body>
        <h1>Welcome ${name}!</h1>
        <p> welcome to our home page ${name}. </p>
    </body>
</html>

"${name}"이라는 부분이 공란으로 남겨져있고, 나머지 부분은 로그인 한 사용자에 상관없이 동일하게 결과 문서로 복사된다. 로그인한 사용자에 따라서 "${name}" 부분만 바뀌게 된다. 나머지 부분은 데이터 모델에 들어 있는 데이터가 어떤 것이냐에 따라서 달라진다.

 

프리마커의 데이터 모델은 트리 형태의 구조를 가지고 있다. (데이터를 제공하는 프로그래머는 프리마커 엔진이 데이터 모델을 트리 구조를 따라가는 것처럼 해석할 수 있게 모델링 해줘야 한다.) Interpolation의 중괄호({, }) 안쪽에 쓰여 있는 표현식(expression)을 이용해서 트리 구조의 데이터 모델에서 값을 찾게 된다.

 

 

예를 들어 위와 같은 데이터 모델이 있을 때, ${name}는 트리의 루트 중, 'name'이라는 이름의 자식 노드가 가지고 있는 값을 가지고 와서 템플릿을 완성해준다. "dept.dept_name" 혹은 "dept.dept_id" 같은 표현식(expression)이 Interpolation에 있다면, Dot('.') 문자를 이용해서 여러 항목으로 우선 나눈다. "dept.dept_name"이라는 표현식은 "dept"와 "dept_name"이라는 항목으로 나뉘게 된다. 이는 루트의 자식중 "dept"라는 자식을 찾아서, 그 노드의 자식 중 "dept_name"이라는 자식을 찾고, 그 노드가 가지고 있는 값을 가져다 사용하겠다는 의미로 해석된다.

 

 

프리마커(Freemarker) 사용해보기

프리마커 엔진을 이용한 간단한 자바 애플리케이션을 작성해보자.

프리마커(Freemarker) 다운로드

Freemarker를 사용하기 위해서 Freemarker의 다운로드 페이지에 들어가서 필요한 라이브러리 파일을 다운로드한다.

 

메이븐을 사용하고 있는 경우 다음과 같은 dependency를 사용하면 된다.

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.28</version>
</dependency>

데이터 모델(Data model) 만들어주기

Freemarker Engine은 트리 형태로 구성된 데이터 모델을 사용한다. 즉, 템플릿으로 출력한 데이터 모델을 트리 형태로 구성해야 한다. 다행히 프리마커 엔진이 HashMap을 통한 데이터 모델은 해석할 수 있으므로 HashMap을 이용해서 데이터 모델을 만들어 보겠다.

 

다음 코드를 참고해보자.

import java.io.File;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;

public class TestFreemarker {

    public static void main(String []args) throws Exception {

        // Data Model 만들기
        Map<String, Object> root = new HashMap<>();
        root.put("key1", "value1");
        Map<String, Object> key2 = new HashMap<>();
        key2.put("key3", "value3");
        key2.put("key4", "value4");
        root.put("key2", key2);

        // Template Loader 
        Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        FileTemplateLoader loader = new FileTemplateLoader(new File("/tmp"));
        cfg.setTemplateLoader(loader);

        StringWriter writer = new StringWriter();

        // /tmp 디렉토리에 있는 "template2.ftl" 파일을 로드
        Template template = cfg.getTemplate("template2.ftl");

        // Map 객체를 이용해서 템플릿 처리
        template.process(root, writer);

        System.out.println(writer);
    }
}

다행히 Map 컬렉션을 Freemarker가 지원해서 Map 컬렉션을 이용해 트리 형태의 모델을 만들어 봤다. 두 개의 HashMap으로 만든 트리 형태의 데이터 모델을 그림으로 표현하면 다음과 같다.

 

 

Freemarker에서는 파일에 정의되어 있는 템플릿을 로드할 수 있는 FileTemplateLoader 클래스를 지원한다. FileTemplateLoader 클래스는 템플릿 파일이 위치한 디렉토리 경로를 인자로 받아 생성된다. 이렇게 생성된 로더 객체는 해당 디렉토리에 있는 템플릿 파일을 불러들일 수 있다. "cfg.getTemplate()" 메소드에서 입력한 템플릿 파일을 FileTemplateLoader가 생성할 때 입력했던 디렉토리에서 찾게 된다. (Freemarker는 여러 템플릿을 동시에 번갈아가면서 쓸 수 있는 기능을 제공한다)

 

cfg.getTemplate("template.ftl") 코드에서 "template.ftl" 파일에 있는 템플릿을 로드하고, Template 객체로 돌려준다. Template 클래스의 process() 메소드를 이용하면 Writer 클래스에 완성된 텍스트를 써주게 된다.

템플릿 작성하기

템플릿을 완성하는 로직은 구현했으니 이제 템플릿 파일을 작성하면 된다.

 

다음과 같은 템플릿 파일을 "/tmp/template.ftl" 파일로 만들어 보자.

key1 : ${key1}
key3 : ${key2.key3}
key4 : ${key2.key4}

템플릿 문법에 대한 자세한 내용은 Freemarker의 매뉴얼을 참조하면 된다.

 

간략하게 설명하자면 일반 문자열은 그대로 결과 텍스트에 출력된다. '${key1}' 이라는 부분은 Freemarker에서 interpolation이라고 부르는 문법으로 데이터 모델에서 중괄호 안쪽에 있는 경로에 대응되는 값을 가져와 치환하겠다는 의미다. '${key1}'은 데이터 모델의 루트에서 'key1'에 해당하는 노드의 값을 꺼내오라는 의미다. 비슷하게 '${key2.key3}'는 루트에서 'key2'에 대응되는 노드를 찾고, 그 자식 중에서 'key3'에 대응되는 노드를 찾아서 치환하라는 의미다.

결과 확인

위 템플릿을 지정된 경로에 저장을 하고 자바 프로그램을 수행시키면 다음과 같은 출력결과를 얻을 수 있다.

 

key1 : value1
key3 : value3
key4 : value4

 

만약 존재하지 않는 경로를 입력했을 경우에는 freemarker.core.InvalidReferenceException 을 만나게 된다. (Freemarker에서 기본값을 명시할 수 있는 문법을 제공하고 있다. ${key5!"default"} 라고 적어 넣으면 key5 가 존재하지 않을 경우 "default"라는 문자열을 대신 적어주게 된다. 관련 내용은 위에서 링크해 놓은 Freemarker 매뉴얼에서 찾아 볼 수 있다.)

 

 

 

코딩없이 템플릿 만들어보기

템플릿 작성자의 경우 불필요하게 코딩하기 싫은 경우가 있다. 프리마커(Freemarker)에서는 "온라인 프리마커 템플릿 테스터(Online Freemarker Template Tester)" 페이지를 제공하고 있다. 자바 코딩 없이 템플릿과 데이터 모델을 입력해서 테스트해볼 수 있다.

 

- Online FreeMarker Template Tester

 

Data model 부분에 데이터 모델에 대한 정보를 넣고, Template 부분에 출력하고 싶은 템플릿을 입력한다음 [Evaluate] 버튼을 눌러서 템플릿을 실행시키면 결과를 얻을 수 있다.

 

기본적인 개념은 이 포스트에서 다룬 내용과 같다. 하지만 프리마커는 블로그 포스트 하나로 다룰 수 없을 정도로 다양한 기능을 제공하고 있다. 더 많은 내용은 프리마커 매뉴얼을 참고하기 바란다.

Reference

반응형

댓글