본문 바로가기
Spring Boot

[Spring Boot] 타임리프(Thymeleaf) 엔진

by byeongoo 2020. 3. 4.

오늘은 Spring Boot에서 자주 사용하는 타임리프 템플릿 엔진에 대해서 알아보겠습니다. 템플릿 엔진이 무엇인지 알고 싶으시다면 여기를 클릭해주세요. 

1. Spring MVC 템플릿 엔진 VS Spring Boot 템플릿 엔진

Java Object에서 데이터를 생성하여 Template에 넣어주면 템플릿 엔진에서 Template에 맞게 변환하여 html을 생성하고 클라이언트에게 제공합니다.

 

  Spring Template Engine Spring Boot Template
종류 JSP, Thymeleaf, Groovy, Freemarker, Jade4j, JMustache, Pebble, Handlebars, Velocity Mustache, Thymeleaf, Groovy, Freemarker
추천 Thymeleaf Handlebars, Mustache
비추천 Velocity는 Spring 버전 4.3부터 사용 중단 Freemarker, JSP

자주사용되는 jsp의 경우 임베디드 서블릿 컨테이너를 사용하는 Spring Boot에서는 제한 사항이 있습니다. 공식문서를 참고해주세요.

2. 타임리프(Thymeleaf)란?

이제 제가 자주 사용하는 타임리프 템플릿엔진에 대해서 알아보겠습니다. 타임리프는 HTML, XML, JavaScript, CSS, text를 생성하기 위한 자바 템플릿 엔진입니다. 이 라이브러리는 확장성이 매우 높으며 기본 템플릿기능만으로 백엔드 없이 템플릿을 프로토타입화 할 수 있습니다. 스프링에서 타임리프를 사용하기 위해서는 Maven POM.XML에 다음 의존성을 추가해야합니다.

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>2.1.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring4</artifactId>
    <version>2.1.4.RELEASE</version>
</dependency>

Spring 3 에서는 thymeleaf-spring4 대신 thymeleaf-spring3 라이브러리를 사용해야합니다. 

 

Spring Template Engine은 환경설정의 모든 단계를 수행합니다. 여러분의 자바 환경설정 파일에 하나의 빈으로서 이 클래스를 다음과 같이 구현할 수 있습니다.

@Bean
@Description("Thymeleaf Template Resolver")
public ServletContextTemplateResolver templateResolver() {
    ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
    templateResolver.setPrefix("/WEB-INF/views/");
    templateResolver.setSuffix(".html");
    templateResolver.setTemplateMode("HTML5");
 
    return templateResolver;
}
 
@Bean
@Description("Thymeleaf Template Engine")
public SpringTemplateEngine templateEngine() {
    SpringTemplateEngine templateEngine = new SpringTemplateEngine();
    templateEngine.setTemplateResolver(templateResolver());
    templateEngine.setTemplateEngineMessageSource(messageSource());
    return templateEngine;
}

templateResolver 의 속성 중  prefix 는 webapp  디렉토리 내의 뷰페이지 위치를 가리키며 suffix 는 뷰페이지들에 포함되는 파일들의 확장자를 의미합니다. 

Spring MVC 의 ViewResolver 인터페이스는 컨트롤러가 반환하는 뷰 이름들과 실제 뷰 객체들을 매핑합니다. ThymeleafViewResolver 는 ViewResolver 인터페이스를 구현하며 주어진 뷰 이름을 렌더링 하기 위해 어느 Thymeleaf 뷰들을 사용할지를 결정하는데 사용됩니다. 

마지막 통합 단계은 ThymeleafViewResolver 를 빈으로 추가하는 것입니다.

@Bean
@Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver() {
    ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
    viewResolver.setTemplateEngine(templateEngine());
    viewResolver.setOrder(1);
    return viewResolver;
}

3. 자주 사용하는 문법 및 표현식

TitleDescription

th:text

텍스트 내용 

<span th:text="${user.name}"></span>

th:utext

html 내용
<div th:utext="${content}"></div>
th:value

element value값, checkbox, input 등 

<input type="text" th:value="${title}" />

th:with

변수값 지정 

<p th:with="authType = ${user.authType}+' Type'" th:text="${authType}"></p>

th:switch
th:case

switch-case문

<div th:switch="${user.role}">

   <p th:case="'admin'">User is an administrator

   <p th:case="#{roles.manager}">User is a manager</div>
th:if 조건문 
<p th:if="${user.authType}=='web'" th:text="${user.authType}"></p>

th:unless

else 표현
<p th:unless="${user.authType}=='facebook'" th:text="'not '+ ${user.authType}"></p>
 th:each 반복문
<p th:each="user : ${users}" th:text="${user.name}"></p> 

* 참고 * 

There are quite a lot of attributes like these, each of them targeting a specific HTML5 attribute:

th:abbr th:accept th:accept-charset
th:accesskey th:action th:align
th:alt th:archive th:audio
th:autocomplete th:axis th:background
th:bgcolor th:border th:cellpadding
th:cellspacing th:challenge th:charset
th:cite th:class th:classid
th:codebase th:codetype th:cols
th:colspan th:compact th:content
th:contenteditable th:contextmenu th:data
th:datetime th:dir th:draggable
th:dropzone th:enctype th:for
th:form th:formaction th:formenctype
th:formmethod th:formtarget th:fragment
th:frame th:frameborder th:headers
th:height th:high th:href
th:hreflang th:hspace th:http-equiv
th:icon th:id th:inline
th:keytype th:kind th:label
th:lang th:list th:longdesc
th:low th:manifest th:marginheight
th:marginwidth th:max th:maxlength
th:media th:method th:min
th:name th:onabort th:onafterprint
th:onbeforeprint th:onbeforeunload th:onblur
th:oncanplay th:oncanplaythrough th:onchange
th:onclick th:oncontextmenu th:ondblclick
th:ondrag th:ondragend th:ondragenter
th:ondragleave th:ondragover th:ondragstart
th:ondrop th:ondurationchange th:onemptied
th:onended th:onerror th:onfocus
th:onformchange th:onforminput th:onhashchange
th:oninput th:oninvalid th:onkeydown
th:onkeypress th:onkeyup th:onload
th:onloadeddata th:onloadedmetadata th:onloadstart
th:onmessage th:onmousedown th:onmousemove
th:onmouseout th:onmouseover th:onmouseup
th:onmousewheel th:onoffline th:ononline
th:onpause th:onplay th:onplaying
th:onpopstate th:onprogress th:onratechange
th:onreadystatechange th:onredo th:onreset
th:onresize th:onscroll th:onseeked
th:onseeking th:onselect th:onshow
th:onstalled th:onstorage th:onsubmit
th:onsuspend th:ontimeupdate th:onundo
th:onunload th:onvolumechange th:onwaiting
th:optimum th:pattern th:placeholder
th:poster th:preload th:radiogroup
th:rel th:rev th:rows
th:rowspan th:rules th:sandbox
th:scheme th:scope th:scrolling
th:size th:sizes th:span
th:spellcheck th:src th:srclang
th:standby th:start th:step
th:style th:summary th:tabindex
th:target th:title th:type
th:usemap th:value th:valuetype
th:vspace th:width th:wrap
th:xmlbase th:xmllang th:xmlspace

4. 사용 예제

[Controller 소스]

@Controller
public class UserTestController {
    @GetMapping("/users")
    public String getUserList(Model model) {
        List<User> users = new ArrayList<>();
        for(int i=0;i<3;i++) {
            users.add(new User("kkaok"+i, "테스트"+i, "web") );
        }
        User user = new User("테스트ID", "테스터", "web") ;
        model.addAttribute("user", user);
        model.addAttribute("users", users);
        model.addAttribute("today", new Date());
        model.addAttribute("content", "<div><span style='font-size:20px'>Hello World</span></div>");
        return "users";
    }
}

[HTML 소스]

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Thymeleaf 예제</title>
    <!-- Link 예제 -->
    <script th:src="@{/assets/vendor/jquery/jquery.js}"></script>
</head>
<body>
<h1>Collection 객체 each 예제</h1>
<p th:each="user : ${users}" th:text="${user.name}"></p>
 
<h1>Utility Objects 예제</h1>
<p>#calendars <br>Today is: <span th:text="${#calendars.format(today,'yyyy-MM-dd')}">2019-02-15</span></p>
<p>#arrays <br>user count is <span th:text="${#arrays.length(users)}"></span>.</p>
 
<h1>객체 예제</h1>
<p th:text="${user.name}">default</p>
<p>[[${user.name}]]</p>
 
<h1>th:text 예제</h1>
<p th:text="${content}">default value</p>
 
<h1>th:utext(Html) 예제</h1>
<p th:utext="${content}">default value</p>
 
<h1>th:with 예제 : 변수 선언</h1>
<p th:with="authType = ${user.authType}+' Type'" th:text="${authType}"></p>
 
<h1>th:if 예제</h1>
<p th:if="${user.authType}=='web'" th:text="${user.authType}"></p>
 
<h1>th:unless 예제</h1>
<p th:unless="${user.authType}=='facebook'" th:text="'not '+ ${user.authType}"></p>
 
<h1>script 예제</h1>
<p><span id="scriptTest"></span></p> 
<script>
// script에서 값을 받을 때
var userId = '[[${user.userId}]]';
console.log(userId);
$("#scriptTest").html(userId);
</script>
</body>
</html>

REFERENCE

https://eblo.tistory.com/55

https://m.blog.naver.com/PostView.nhn?blogId=sthwin&logNo=221307479664&proxyReferer=https%3A%2F%2Fwww.google.com%2F