티스토리 뷰

1. Overview

Thymeleaf에 관련한 소개와 자세한 내용은 링크로 대체하겠습니다. 스프링과 통합이 비교적 쉽고 개발자가 사용하기 무난한 편입니다. 런닝커브가 크지 않아서 기존에 freemarker나 velocity 등을 써봤다면 1,2시간 내용을 보고 적용할 수 있는 수준입니다. 저는 화면 레이아웃을 별도 프레임워크를 사용하지 않아도 된다는 것과 스프링 프레임워크와 쉬운 통합, 잘 만들어진 문서 때문에 사용하게 되었습니다. 


Thymeleaf 홈페이지 

https://www.thymeleaf.org/index.html

Thymeleaf + Spring

 - https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html

Introduction to Using Thymeleaf in Spring

https://www.baeldung.com/thymeleaf-in-spring-mvc


Thymeleaf 만의 특징은 다른 템플릿 엔진과 다르게 Html Tag를 그대로 사용한다는 것입니다. 

예를 들면 다른 템플릿 언어는 <if>..</if>, {{if(조건)}} .. {{/if}} 뭐 이런 식의 문법이 별로도 코딩이 되는데 Thymeleaf는 html tag 안에 포함이 됩니다. 

Freemarker

<#list user as users>

  ${user.name}

</#list>


Velocity

#foreach($user in $users)

  ${user.name}

#end


Thymeleaf

<p th:each="user : ${users}" th:text="${user.name}"></p>

이렇게 코딩이 된 것을 서버가 아닌 브라우저에 그냥 열어도 화면을 확인이 됩니다. th라는 엘리먼트 자체를 무시해 버리기 때문에 브라우저에 보는데 아무런 문제가 없습니다. 그런데 이것은 장점이기도 하지만 또 커다란 단점이기도 합니다. html element에 id가 중복이 되거나 태그를 제대로 닫지 않는 경우 에러가 발생할 수 있습니다. 


스프링부트에서 Thymeleaf 설정은 간단합니다. 프로젝트 생성시 설정에서 Thymeleaf를 선택하는 것만으로도 자동으로 환경 구성을 해줍니다. application.properties 추가해주고 테스트하기 위해 Controller, VO, html 만들기 까지 20분 정도면 충분합니다.  

2. 기본 설정 

Spring Starter Project 생성시 아래처럼 Template Engines에서 Thymeleaf를 선택하세요. 
기본적으로 생성되는 dependency와 프로젝트 구조를 확인하면 됩니다.  
 

Maven Dependencies

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-thymeleaf</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>


<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-tomcat</artifactId>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

</dependencies>

Gradle Dependencies

dependencies {

implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

implementation 'org.springframework.boot:spring-boot-starter-web'

providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'

testImplementation 'org.springframework.boot:spring-boot-starter-test'

}

프로젝트 구조 

Thymeleaf 파일 위치 : /src/main/resources/templates

application.properties 설정 

spring.thymeleaf.prefix=classpath:templates/

spring.thymeleaf.check-template-location=true

spring.thymeleaf.suffix=.html

spring.thymeleaf.mode=HTML5

spring.thymeleaf.cache=false

spring.thymeleaf.order=0


설정없이도 기본적인 작동은 합니다. 개발모드로 수정하면서 내용 확인하고 싶다면 'spring.thymeleaf.cache'를 false로 선언하시면 되고 운영 모드에서는 true로 해야 합니다.


application.properties 설정 없이 Java Configuration 설정 예제입니다. 
java Configuration 설정 예제는 참고만 하세요. 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@Configuration
public class ThymeleafViewResolverConfig { 
    
    @Value("${thymeleaf.cache}")
    private boolean isCache;
    
    @Bean
    public SpringResourceTemplateResolver templateResolver() {
        SpringResourceTemplateResolver  templateResolver = new SpringResourceTemplateResolver ();
        templateResolver.setPrefix("classpath:templates/");
        templateResolver.setCharacterEncoding("UTF-8");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode("LEGACYHTML5");
        templateResolver.setCacheable(isCache);
        return templateResolver;
    }
    
    @Bean
    public SpringTemplateEngine templateEngine(MessageSource messageSource) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setTemplateEngineMessageSource(messageSource);
        templateEngine.addDialect(layoutDialect());
        
        return templateEngine;
    }
    
    @Bean
    public LayoutDialect layoutDialect() {
        return new LayoutDialect();
    }
 
    @Bean
    @Autowired
    public ViewResolver viewResolver(MessageSource messageSource) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine(messageSource));
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setOrder(0);
        return viewResolver;
    }
}
cs
profile에 따라 캐시 설정을 할 수 있게금 되어 있는 구조입니다. 


3. 테스트 

User 생성 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class User {
 
    private String userId;
    private String userPwd;
    private String name;
    private String authType;
    
    public User(String userId, String name, String authType) {
        super();
        this.userId = userId;
        this.name = name;
        this.authType = authType;
    }
    
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public String getUserPwd() {
        return userPwd;
    }
    public void setUserPwd(String userPwd) {
        this.userPwd = userPwd;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthType() {
        return authType;
    }
    public void setAuthType(String authType) {
        this.authType = authType;
    }
    
    @Override
    public String toString() {
        return "User [userId=" + userId + ", userPwd=" + userPwd + ", name=" + name + ", authType=" + authType + "]";
    }
}
cs


컨트롤러 생성 

1
2
3
4
5
6
7
8
9
10
@Controller
public class UserTestController {
 
    @GetMapping("/test")
    public String getUser(Model model) {
        User user = new User("kkaok""테스트""web") ;
        model.addAttribute("user", user);
        return "test";
    }
}
cs


test.html 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Thymeleaf 예제</title>
</head>
<body>
<h1>Thymeleaf 예제</h1>
<span th:text="${user.userId}"></span><br/>
<span th:text="${user.name}"></span><br/>
<span th:text="${user.authType}"></span><br/>
</body>
</html>
cs


결과


Github 링크

https://github.com/kkaok/examples

댓글
  • 프로필사진 안녕하세요! 안녕하세요. 블로그 주인님!
    제가 타임리프(+개발) 왕왕 초보라서 작성해주신 글 보고 많은 도움을 얻었습니다.
    그럼에도 더 궁금한게있는데요.
    혹시, th:unless="${#lists.isEmpty(prod.comments)}">view</a>
    " ${#lists " 중괄호 안쪽의 #은 무엇을 의미하는지 알 수 있을 런지요....
    2019.10.25 19:43
  • 프로필사진 사용자 까오기 Variable Expressions: ${...}
    Selection Variable Expressions: *{...}
    Message Expressions: #{...}
    Link URL Expressions: @{...}
    Fragment Expressions: ~{...}

    기본적인 표현은 위와 같습니다.
    그외 자체 유틸리티를 제공해주는데 날짜, 숫자, 문자 등등 이런 유틸리티를 사용할 때 앞에 #을 붙입니다.
    https://eblo.tistory.com/55?category=737346
    하단을 참고 하세요. ^^
    2019.10.31 18:21 신고
  • 프로필사진 안녕하세요! 감사 인사가 늦었네요 !!! 감사합니다!!!^^ 2019.12.13 16:12
  • 프로필사진 개발자 베니 위에 코딩해주신대로 제가 했을 때는
    thymeleaf namespace 'th' is not bound 에러가 발생하여

    html 태그를
    <html xmlns:th="http://www.thymeleaf.org">

    위와 같이 수정하였습니다~

    출처 - https://stackoverflow.com/questions/32384158/intellij-thymeleaf-namespace-th-is-not-bound
    2019.12.04 11:46 신고
  • 프로필사진 사용자 까오기 좋은 정보 감사합니다. 2019.12.11 12:02 신고
댓글쓰기 폼