Thymeleaf (타임리프)
HTML, XML, JavaScript, CSS, 일반 텍스트 등을 처리할 수 있는 Java 기반 템플릿 엔진으로, 서블릿 기반 웹 환경과 비웹 환경 모두에서 사용 가능하다. 컨트롤러가 전달하는 데이터를 통해 동적으로 화면을 만들어준다.
* 템플린 엔진? 지정된 템플릿 양식에 데이터 모델을 전달하여 동적 컨텐츠를 만들어주는 소프트웨어를 말한다.
1. 타임리프 특징
1) 서버 사이드 HTML 렌더링 (SSR)
백엔드 서버에서 HTML을 동적으로 렌더링한다.
2) 네추럴 템플릿
Thymeleaf로 작성된 HTML 템플릿은 일반 HTML과 거의 동일한 형태로 유지되며 정상적으로 동작한다.
따라서 애플리케이션 실행 시에도 실제 템플릿을 디자인 요소로 활용할 수 있다.
즉, 순수 HTML을 최대한 유지하는 것이 특징이다.
<table>
<thead>
<tr>
<th th:text="#{msgs.headers.name}">Name</th>
<th th:text="#{msgs.headers.price}">Price</th>
</tr>
</thead>
<tbody>
<tr th:each="prod: ${allProducts}">
<td th:text="${prod.name}">Oranges</td>
<td th:text="${#numbers.formatDecimal(prod.price, 1, 2)}">0.99</td>
</tr>
</tbody>
</table>
//https://www.thymeleaf.org/
3) 스프링 통합 지원
스프링의 다양한 기능들을 편리하게 사용할 수 있도록 지원해준다.
2. JSP와 Thymeleaf의 차이점
1) 렌더링 방식
JSP : 서버에서 실행되어 HTML을 생성한 후 클라이언트에 전달된다. JSP 파일은 서블릿으로 변환되어 실행되며, 이 과정에서 Java 코드가 HTML에 포함될 수 있다
Thymeleaf : 서버에서 동적인 HTML을 생성하는 동시에, 브라우저에서는 정적 HTML처럼 동작하도록 설계된 템플릿 엔진이다.
HTML 친화적인 문법을 사용하여 일반 HTML과 유사하게 보이며, 별도의 서버 실행 없이도 브라우저에서 직접 확인할 수 있어 디버깅에 용이하다.
2) 문법 및 사용 방식
JSP : <%= ... %>, <% ... %> 등의 태그를 사용해 Java 코드를 직접 포함할 수 있으며, JSTL을 통해 반복문이나 조건문과 같은 템플릿 로직을 작성한다.
Thymeleaf : ${} 표현식을 사용해 변수를 참조하고, th:attr 등의 속성을 통해 HTML 속성에 값을 바인딩한다.
또한 <th:block>, th:if, th:each 등과 같이 HTML 속성을 확장하는 방식으로 템플릿 로직을 구현한다.
3) 개발 경험
JSP : Java 코드가 포함된 JSP 파일은 디버깅이 복잡하고, 코드와 마크업이 혼합되어 유지보수가 어려울 수 있다.
오랜 기간 동안 Java EE 표준으로 사용되어 왔기 떄문에 널리 알려져 있고 레거시 시스템에서 사용된다.
Thymeleaf : HTML과 Java 코드를 명확히 분리하여 코드가 더 깔끔하고 유지보수하기 쉽다. 또한 브라우저에서 바로 템플릿을 확인할 수 있어 디버깅이 용이하다.
4) 통합 및 확장성
JSP : Spring MVC와 쉽게 통합되며, 많은 레거시 애플리케이션에서 사용되고 있다.
또한 서블릿과 긴밀하게 통합되어 있어 서블릿 API를 사용하는 애플리케이션에서 유용하다.
Thymeleaf : Spring Boot와 자연스럽게 통합되며, Spring의 다양한 기능을 손쉽게 활용할 수 있다.
플러그인을 통해 기능 확장이 가능하고, HTML, XML, 텍스트 등 다양한 템플릿 모드를 지원한다.
3. 타임리프 사용
자동 설정 내용:
- 템플릿 위치: src/main/resources/templates/
- 파일 확장자: .html
- 캐시: DevTools 사용 시 자동으로 false
build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
}
html 파일에 아래와 같이 코드를 작성해준다.
<html xmlns:th="http://www.thymeleaf.org">
application.properties
# Thymeleaf
spring.thymeleaf.enabled=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.mode=HTML
spring.thymeleaf.check-template=true
spring.thymeleaf.check-template-location=true
# 이 위까지 기본값
# 기본값(true) > 개발 중일때만 (false)
spring.thymeleaf.cache=false
출처 : https://pigsnowworld.tistory.com/50
//템플릿 파일의 위치 지정. 뒤에 공백 있으면 안된다.
spring.thymeleaf.prefix=classpath:/templates/
//템플릿 확장자 지정
spring.thymeleaf.suffix=.html
스프링부트가 자동 설정해줘서 application properties 안 써도 된다고 한다.
이미 템플릿 위치, 확장자, 인코딩, 뷰리졸버, 캐시를 기본값으로 처리해주기 때문.
그럼 언제 설정할까?
캐시 때문에 화면이 안 바뀔 때(개발 중)
spring.thymeleaf.cache=false
HTML 수정했는데 새로고침을 해도 안 바뀔 때만 사용
spring.thymeleaf.cache=false 설정의 기본값은 'true' 이나, 개발 중일때는 'false'로 사용한다.
Why? 캐시는 한번 만들어낸 데이터를 보관하는 장소이다. 캐시가 켜져있으면 페이지를 한 장 만들어서 내용을 수정함에도 불구하고 캐시의 내용을 반영하기 때문에 수정된 내용의 반영이 매우 느리다. 따라서 개발중에는 'false' 설정을 적용 후 사용한다.
❓ 그렇다면 계속 'false'설정을 해두면 되지 않는가?
❗ 개발 중에는 불편하지만, 운영 중에는 캐시 사용을 통해 수정된 내용에 오류가 있더라도 이를 방지할 수 있기 때문에 'true'설정을 해둠이 더 낫다.
4. 타임리프 표현식과 문법
타임리프는 다양한 기본 표현식을 제공한다. 아래 링크 참조.
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#standard-expression-syntax
✔️ 표현식
1) 변수 표현식 ${ ... }
변수를 사용할 때 이 표현식을 사용한다. 컨트롤러에서 Model 객체에 담아준 데이터를 뷰에서 사용하고 싶을 때, 이 표현식으로 해당 객체에 접근할 수 있다.
예)
@Controller
public class MemberController {
@GetMapping(value = "/member")
public String member(Model model){
Long memberId = 1;
String memberName = "memberA";
Member member = new Member(memberId, memberName);
model.addAttribute("member", member);
return "/member";
}
}
출처: https://bnzn2426.tistory.com/140 [보통의 개발자:티스토리]
Model 객체에 "member" 라는 이름으로 member 객체를 속성 값으로 추가. 이를 타임리프 템필릿에서 그대로 사용할 수 있다.
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<p th:text="${member.id}"></p>
<p th:text="${member.name}"></p>
</body>
</html>
출처: https://bnzn2426.tistory.com/140 [보통의 개발자:티스토리]
2) 메세지 표현식 #{ ... }
메세지 변수를 참조할 때 사용
3) 링크 표현식@{ ... }
링크 처리를 할 때 사용되며, 특히 URL에 쿼리 파라미터를 전달해야 하는 상황에서 조금 더 가독성 좋은 코드를 만들 수 있다. 주로 th:href 태그 속성과 함께 사용한다.
✓ 단순 URL
<a th:href="@{/hello}"></a>
렌더링 시, /hello 경로로 이동
✓ 쿼리 파라미터
<a th:href="@{/hello(param1=${param1}, param2=${param2})}"></a>
렌더링 시, /hello?param1=data1¶m2=data2 경로로 이동
✓ 경로 변수
<a th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}"></a>
렌더링 시, /hello.data1/data2 경로로 이동.
경로에 변수가 있으면, 소괄호 안의 부분을 경로 변수로 처리한다.
✓ 쿼리 파라미터 + 경로 변수
<a th:href="@{/hello/param1(param1=${param1}, param2=${param2})}"></a>
렌더링 시, /hello/data1?param2=data2 경로로 이동
4) 선택 변수 표현식 *{ ... }
선택한 변수의 표현식
${}와 거의 동일하다고 보면 되는데, 사용하기 위해서는 한 가지 전제 조건이 붙는다. Model 객체에 속성 값으로 다양한 객체가 담겨 있을 때, 하나의 객체를 먼저 지정하면 지정된 객체의 속성 이름만으로 접근할 수 있다.
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:object="${member}">
<p th:text="*{id}"></p>
<p th:text="*{name}"></p>
</div>
</body>
</html>
출처: https://bnzn2426.tistory.com/140 [보통의 개발자:티스토리]
th:object="${member}"로 먼저 어떤 속성 값을 사용할 지 미리 지정했다.
즉, member 컨텍스트 변수를 “선택”했다는 의미로, member.id로 접근하는 것이 아닌 객체 이름을 생략한 id로만 접근할 수 있다.
5) 프래그먼트 표현식 ~{ ... }
fragment라는 HTML 조각 파일들을 가져올 수 있는 표현식이다.
th:insert나 th:replace와 함께 사용한다.
예제)
<div th:insert="~{/common/nav :: nav}">
common/nav 파일에서 nav라는 fragment를 가져오겠다는 의미
✔️ 문법
| 표현식 | 설명 | 예제 |
| th:text | 텍스트를 표현할 때 사용 | th:text= ${person.name} |
| th:each | 컬렉션을 반복할 때 사용 | th:each= "person:${persons}" |
| th:if | 조건이 true인 때만 표시 | th:if= "${person.age} >= 20" |
| th:unless | 조건이 faslse인 때만 표시 | th:unless= "${person.age} >= 20" |
| th:href | url 태그를 동적으로 변경하고 싶을 때 | th:href= "@{/persons(id = ${person.id})}" |
| th:with | 지역 변수를 선언해서 선언한 태그 내에서만 사용. | th:with= "name = ${person.name}" |
| th:object | 선택한 객체로 지정 | th:object= "${person}" |
th:each
반복문. java의 for each문을 생각하면 된다.
<th:each= "person:${persons}>"
=> ${persons}의 값을 하나씩 꺼내 왼쪽 로컬변수 person에 담아 태그를 반복 실행한다.
th:each는 List, 배열, Iterable, Enumeration을 구현한 모든 객체를 사용 가능하다.
- index : 0부터 시작하는 인덱스
- count : 1부터 시작하는 인덱스
- size : 전체 크기
- even : 짝수 번째 반복 여부(boolean)
- odd : 홀수 번째 반복 여부(boolean)
- first : 첫 번째 반복 여부(boolean)
- last : 마지막 반복 여부(boolean)
- current : 현재 객체
📍 출처
https://en.wikipedia.org/wiki/Thymeleaf
https://easy1nhard2.tistory.com/13
https://blog.naver.com/acornedu/223486969510
https://imgzon.tistory.com/143
https://bnzn2426.tistory.com/140
'공부 > Spring' 카테고리의 다른 글
| [SpringBoot] 외부 API 연동하기 (RestTemplate, RestClient, WebClient, OpenFeign) (0) | 2026.01.28 |
|---|---|
| [스프링 부트 핵심 가이드] 유효성 검사와 예외 처리_예외 처리 (0) | 2025.12.01 |
| [스프링 부트 핵심 가이드] 유효성 검사와 예외 처리_유효성 검사 (0) | 2025.11.29 |
| [스프링 부트 핵심 가이드] Spring Data JPA 활용 (0) | 2025.11.20 |
| [스프링 부트 핵심 가이드] 테스트 코드 작성 (0) | 2025.11.18 |