최근에 Thymeleaf를 프로젝트에서 사용해 봤다. Thymeleaf에 대해서 들어본 지 한 1,2년 정도 된 것같은데 실제로 써본 것은 이번이 처음이다. 아주 다양한 케이스에 하드하게 사용해 본건 아니다.(사용한 버전은 2.0.x이다.)
Thymeleaf
Thymeleaf는 Tiles, FreeMarker, SiteMesh처럼 자바에서 사용할 수 있는 뷰 템플릿 엔진이다. 스프링소스에서 만든건지는 모르겠지만 스프링소스에서 열심히 밀고 있기는 하고 Spring MVC와 통합이 잘 되어 있다.
Thymeleaf의 가장 큰 특징이라면 네츄럴 템플릿 기능을 들 수 있는데 쉽게 말하면 템플릿 코드자체가 그냥 HTML이기 때문에 뷰 파일을 WAS없이도 브라우저에서 직접 띄워볼 수 있다는 점이다. 이는 Thymeleaf가 다른 템플릿 엔진처럼 전용 문법(브라우저가 해석하지 못하는)을 사용하지 않고 HTML 엘리먼트에 속성으로 적어줌으로써 동작하기 때문에 Thymeleaf는 이를 해석해서 뷰 파일을 만들어주고 브라우저는 모르는 속성은 그냥 무시하므로 브라우저에서도 동작을 하게 된다.
<td th:text="${name}">Oranges</td>
위와 같이 작성하는데 th는 thymeleaf에 대한 속성이다. 브라우저에서 이 코드를 보았을 때는 <td>Oranges</td>
와 다름 없으므로 그냥 그대로 보이고 Thymeleaf는 name이라는 변수 값으로 <td>
안의 값을 대체해버린다. 그래서 Thymeleaf에서 작성할 때는 예시용 코드를 위처럼 같이 넣어주는 것이 일반적이다.
뷰 파일을 작업할 때 그러니까 JavaScript나 CSS 작업등을 할 때 WAS를 띄워야 하는 불편함을 둘째치더라도 변경한 정적 파일이 서버에 적용되는데 까지의 지연 시간(JRebel을 쓰면 훨 낫다.)은 무척 괴로운 일이기 때문에 이 기능은 무척 장점으로 보였고 처음 이 컨셉으로 Thymeleaf를 보았을 때 다음에 꼭 써봐야지 하면서 맘에 들었다. 솔직히 그때는 "이게 바로 내가 기다리던 템플릿 엔진이야"라는 정도의 반응이었다.
단점
결론부터 얘기하면 써보니 별로라서 다음에 선택권이 있다면 쓰지 않을것 같다. 물론 아주 하드하게 오랫동안 써본건 아니라서 여기에 쓰는 단점들에 대한 대안들이나 해결책들이 존재할 것으로 생각하지만(이런 것들을 알려주시면 감사~) 그 해결책들이 아주 깔끔하고 근본적으로 해결되는게 아니라면 내 생각이 크게 달라지진 않을것 같다.
- 네츄럴 템플릿을 이용해서 WAS없이 뷰페이지를 작업할 수 있는게 가장 큰 장점인데 실제로는 이렇게 작업할 수 없다. 불가능한 것은 아니지만 별 의미가 없어서 그냥 WAS를 켜놓고 작업하는게 낫다.(느린게 짜증나면 JRebel로...) Thymeleaf는 자체 파싱엔진을 가지고 있기 때문에 HTML코드가 완전한 XML이어야 하고 이는 설정에서 HTML5 모드로 하더라도 마찬가지다. 즉, 태그의 속성으로 템플릿문법을 사용하므로 범위를 명확히 하기 위해서 XML을 사용하고 있는 듯 하다. HTML도 XML기반이기는 하지만 훨씬 관대하기 때문에 XHTML strict 모드가 유행하던 몇년전 외에는 그렇게 사용하지 않는다. 그래서 평소 습관처럼 브라우저에 HTML작업을 하고 WAS에서 띄우면 거의 100% 컴파일 오류를 볼 것이다. 실수로 닫는태그를 안써준 것은 당연하고
<img>
태그나<input>
태그등의 단독 태그를 모두 찾아서 닫아주어야 컴파일 오류를 피할 수 있다. 별거 아닌 작업이라고 말할 수도 있지만 HTML에서 닫는태그빠지거 찾는건 나에겐 무척 고통스럽고 경험상 컴파일 오류메시지가 그렇게 정확히 찝어주진 않는다. 일반적인 경우처럼 HTML 작업해주는 사람이 따로 있다면 이는 오로지 서버사이드에서 닫는 태그를 붙혀주어야 할 일이고 UI를 변경할 때마다 해야할 것이다.(HTML작업하는 사람한테 가서 태그는 꼭 닫아달라고 하던지...) (참고로 이 엄격한 XML 파싱을 끌 수도 있다고 들었는데 Thymeleaf가 구문을 정확히 파악해서 처리하는 지를 확실히 보장하기 어려운 듯 하다.) - 템플릿을 사용한다는 것은 서버의 변수를 넣어서 동적으로 만들기 위함도 있지만 페이지의 공통부분은 헤더, 푸터등을 별도의 템플릿으로 뽑아서 재사용하는 것도 포함된다. Thymeleaf에서는 이를
include
로 불러오게 되는데 당연히 HTML에는 그러한 기능이 없으므로 인쿨루드는 동작하지 않는다.include
를 쓰지 않으면서 템플릿 엔진을 쓴다는 건 당연히 말도 안되고 이 문제를 해결하기 위한 Thymol 자바스크립트 라이브러리가 있어서 이 라이브러리를 쓰면 일단 인클루드문제는 해결할 수 있어보인다.(써보진 않았다.) 하지만 긴급한 상황에서 대안은 될 수 있지만 계속되는 작업에서 Thymol을 HTML에 넣었다가 실제 Thymeleaf를 사용할 때는 빼는 작업을(당연히 실제로는 필요없는 것이므로) 반복해야 하는 것은 별로 좋은 해결책으로 보이지 않는다.1 - 템플릿을 쓰면 많이 쓰는 것 중 하나가 컬렉션의 데이터를 반복해서 뿌려주는 반복구문이다. Thymeleaf를 처음부터 WAS에서만 쓰고 HTML파일만 따로 브라우저에서 해본적은 없지만 구조상 반복구문을 사용한 경우 HTML을 단독으로 열면 1번 반복한 것처럼 나올 것이다. 뷰 페이지를 작업하면 처음에는 1개로 작업하지만 5개일때 10개일때의 스타일을 잡아줘야 하는데 HTML입장에서는 반복구문이 전혀 아니므로 이런 건 볼 수 없고 그냥 각 부분은 10번이고 20번이고 복사해서 테스트한 뒤에 지워야 한다.(서버에 연결되어 있다면 Mock객체에 데이터만 추가하면 되겠지.) 사실 이건 앞에 얘기한 거에 비하면 아주 큰 문제까진 아니긴 하다.2
- 숙달이 되면 나아질 지 모르겠지만 태그에 속성으로 템플릿구문을 넣는 구조에서 오는 제약이 상당히 있어서 작성하다보면 원하는 HTML 구조를 어떻게 만들어야 하는지 고민이 상당히 될때가 있다. 고민만 되면 다행이겠지만 마땅한 해결책도 없다.
<div class="row">
<div class="span3">Something</div>
<div class="span3">Something</div>
<div class="span3">Something</div>
<div class="span3">Something</div>
</div>
<div class="row">
<div class="span3">Something</div>
<div class="span3">Something</div>
<div class="span3">Something</div>
<div class="span3">Something</div>
</div>
예를 들어 위와 같은 HTML 구조를 만든다고 해보자. 리스트에 있는 데이터를 4개씩 Row를 구분해서 출력해 주고 싶다고 할 때 일반적인 템플릿엔진에서는 다음과 같이 작성할 것이다.
{{#each list}}
{{#if @index % 4 == 0}}
<div class="row">
{{/if}}
<div class="span3">{{this.name}}</div>
{{#if @index % 4 == 0}}
</div>
{{/if}}
{{/each}}
이는 전용 템플릿구문이 있고 HTML의 여는 태그와 닫는 태그를 그냥 문자열처럼 다루기 때문에 아주 유연하게 원하는 구조를 만들어 낼 수 있다. 하지만 Thymeleaf에서는 HTML 태그의 속성으로 템플릿구문을 작성하므로 Thymeleaf를 여는태그와 닫는태그를 한꺼번에 다루기 때문에 한참을 고민해도 이 문제를 해결할 수가 없었다.
<div class="row" th:each="item: ${list}">
<div class="span3" th:text="${name}">Something</div>
</div>
Thymeleaf에서는 위처럼 작성해야 하는데 list
와 <div>
태그가 연결되어 있기 때문에 중간에 div태그를 새로 만든다거나 하기가 좀처럼 쉽지 않다. 이 문제를 Stackoverflow에 질문해서 가능한 해결책을 찾기는 했지만 Thymeleaf에 대한 인상이 좋아질 정도의 해결책은 아니고 앞으로도 이와 비슷한 문제는 많이 만날 것이라고 생각한다. (추가로 Angular.js도 Thymeleaf처럼 태그에 속성으로 작성을 하고 있지만 Thymeleaf같은 뷰템플릿의 기능은 아니고 JavaScript와 연동되기 때문에 이러한 답답함은 많이 안느껴지는듯 하다.)
- 좀 사용해 본 결과 사용자가 그리 많지 않은 느낌이다. 대부분의 문제는 유저커뮤니티만 활성화 되어 있으면 해결가능하다고 보기 때문에 이 문제가 가장 큰 문제로 다가온다. 검색을 해보면 튜토리얼이라던지 소개라던지 하는 자료들이 대부분이고 다양한 활용사례나 문제해결들에 대한 글은 많지 않다. 앞에서 스택오버플로우에 질문을 올렸을 때도 2일 지났을때 읽은 사람이 5명밖에 없었다. 문제가 생겼을때 유저 커뮤니티(꼭 그룹스나 IRC만을 얘기하는 건 아니다)에 도움을 받지 못하는 것 상당히 문제다. 결국은 Thymeleaf 사이트가서 가이드 문서를 찾아가면서 직접 연구해 보는것 외에는 아직 큰 답이 없어 보인다.
장점
가장 큰 장점이라고 생각했던(다른 템플릿 엔진에서도 그리 불편하진 않았기 때문에) 네츄럴 템플릿이 기대 이하였기 때문에 딱히 Thymeleaf만의 장점이라고 하면 잘 생각나진 않지만 그래도 가장 큰 장점은 Spring MVC와 통합이 잘 되다는 장점이 있고 스프링소스에서 꽤 밀고 있는 부분에 기대를 걸어볼 수 있지만 스프링소스가 밀었지만 잘 통하지 않았던 것들도 꽤 있으므로 이는 시간을 두고 볼 일이다.
결론
특별한 장점을 느끼지 못한 이상 기존해 사용하던 템플릿 엔진을 대안으로 쓸 것 같다. 이 글은 Thymeleaf에 대한 초기 인상을 기록하기 위한 것이므로 아직 대안을 테스트해보거나 심도있게 고민해 보진 않았다. 장점을 안적다시피해서 너무 안좋게 얘기한것같기는 하지만 뭐 인상이 그런것이고 다른 템플릿엔진에서도 되는 것은 딱히 장점이라고 생각하지 않기 때문이다. 어쨌든 언어를 떠나서 가장 괜찮은 템플릿 엔진은 (HTML 작업에 대한 협업이 큰 고려사항이 아니라면) Jade인듯.. ㅎㅎㅎ
저도 잠시 Thymeleaf를 써볼까 하고 페이지를 만들어보다가...
JSP에서 사용하던 TagLib 를 사용할수가 없다는 것을 확인하는 순간...!!
바로 드러내고, sitemesh로 변경을 했습니다. ㅡ_-)>
학습용으로 간단하게 만들고 있는 페이지들인데, JSP에 익숙한 제가 사용하기에는...
제공되는 것들이 많이 낯설고 학습하면서 살펴볼 시간도 부족하고 해서 바로 통과.
처음 뭔가 배우면 익숙하지 않음에 대한 불편함이 있기는 하지만 이 불편함을 넘어섰을때 이득이 있을까 라는 고민에서 부정적이 되어버렸네요...
처음 자바 웹개발을 하시는 분들께 오해의 소지가 있어 보여서 하나 말씀드립니다.
Tiles,Sitemesh 는 "레이아웃 템플릿 엔진"입니다.
Freemarker, JSP, thymeleaf는 "텍스트 템플릿 엔진"입니다.
둘은 역할이 다르며 섞어서 사용하는 것이지 서로 배타적인 것이 아닙니다.
thymeleaf/freemarker/jsp는 sitemesh/tiles와 "함께" 사용할 수 있는 것입니다.
Tiles 홈페이지를 보면 자신을 "a templating framework "이라고 부르는데, 사실 여기서 템플릿은 레이아웃 템플릿을 가리키는 말입니다.
그리고 저도 Thymeleaf를 보기만 했는데, outsider님과 비슷한 이유(HTML을 직접 보는 것은 이론적으로는 그럴듯 하지만 실전에서는 거의 쓸모없다는 점)로 Jade가 더 땡기네요.
Spring Jade4j가 좀 더 완결되면 Jade로 확가버리고 싶습니다..
좋은 지적 감사합니다. Tiles는 안써봐서 개념을 제대로 못잡고 뭉뚱구려서 적어버렸네요. 오해를 불러일으킬뻔 했네요.. ㅎㅎㅎ
저도 컨셉자체는 정말 Jade가 젤 좋은데 그동안 Jade 좋아해주는 사람이 없어서 혼자 쓸쓸했었는데 권남님이 Jade를 맘에 들어하셔서 참 반가웠습니다. ㅎㅎ 요즘은 Jade를 지원하는 Scalate쪽으로 관심이 좀 갔는데 Spring Jade4j 프로젝트도 있었군요.
지나가다가
스프링진영에서의 기본 템블릿 엔진이었던건 나름 장점이 많아서 였습니다.
tagLib 보다는 아래를 이용하면 더 파워풀하게 공통화 할수 있습니다.
1. 아규먼트를 이용한 인클루드
<div th:include="::frag (${value1},${value2})">...</div>
<div th:include="::frag (onevar=${value1},twovar=${value2})">...</div>
2. 태그및 속성 추가 및 재정의
<newTag th:newAttr />
3. 일반 유틸성 java 파일을 등록하면 아래처럼도 사용
<div th:text="#cDate.formatYMD( ${result.inputDate} )" />
위 예제에서
꼭 8개라는 제한이 없다면 타임리프 소스가 더 간단하고 나중에 수정이 쉬움.
<div class="row" th:each="item : ${list}" th:if="${itemStat.index} % 4 == 0">
<div class="span3"
th:each="item2 : ${list}"
th:if="${item2Stat.index} >= ${itemStat.index} and ${item2Stat.index} < ${itemStat.index + 4} "
>Something</div>
</div>
3년전 글이라서 지금은 어떤 상황인지 잘 모르지만 사실 Java에서는 괜찮은 템플릿 엔진이 없어서 Thymeleaf가 그나마 괜찮은 선택이기도 합니다. 조만간 3.0이 나올 예정이라고는 하더군요. 좋은 내용 감사합니다.
현재에 와서는 많이 낡고 고개를 갸우뚱하게 하는 글입니다만,
thymeleaf가 3.0버전 들어서는 꽤나 물건이 되어가고 있다고 생각합니다.
익숙해지고 잘 다루게 되니 기존 템플릿엔진보다 훨씬 강력하다고 느껴집니다.
저도 안쓴지 오래되어서 정확한 판단은 안되지면 요즘은 Thymeleaf를 대부분 쓰는것 같긴 하더라고요.
어쩔 수 없이 사용 중이지만 xml기반이라는 것 자체가 굉장한 마이너스 요소이며
작업자가 원하는대로 html이 생성되지 않습니다.
xml 형태로 쓰지 않으면 쓸만한데 아니라면 비추입니다.
단순 작업시엔 나쁘지 않습니다만 깊이 있게 화면을 나누고 알 수 없는 객체들이 정의되는 순간 프로젝트는 작업자에 의존적으로 되며 그 구조를 만들 사람이 아니라면 분석 조차 할 수 없는 지경이 이르게 되는 템플릿.
운영적인 요소에선 굉장한 마이너스