[스프링부트] 타임리프 (Thymeleaf)의 모든것

업데이트:



🟢 타임리프(Thymeleaf)란?

타임리프(Thymeleaf)는 스프링(Spring) 기반의 서버사이드 템플릿 엔진으로, HTML, XML, JavaScript, CSS 등의 정적 파일을 동적으로 변환하여 렌더링할 수 있는 뷰 템플릿 엔진이다.

📌 템플릿 엔진 (Template Engine):
지정된 템플릿 양식에 데이터 모델을 전달하여 동적 컨텐츠를 생성하는 소프트웨어


타임리프는 서버(WAS)에서 동작하는 서버사이드 템플릿 엔진으로, 최종 HTML을 생성한 후 브라우저에 반환하는 방식으로 동작한다. JSP처럼 서블릿 컨테이너에서 실행되는 것이 아니라, HTML 문서를 변환하여 반환하는 방식이다.



🔹 Spring Boot에서 사용 가능한 템플릿 엔진







✅ 타임리프를 사용하는 이유

1️⃣ HTML 친화적 (Natural Templates)

  • 순수 HTML 코드로도 브라우저에서 정상적으로 렌더링 가능
  • JSP와 다르게 HTML 문서를 직접 열어서도 확인 가능

2️⃣ 서버사이드 렌더링 (SSR, Server-Side Rendering)

  • 서버에서 데이터 처리 후, 최종 HTML 생성 → 클라이언트 전달
  • 보안성 우수 (브라우저에서 직접 데이터 바인딩하지 않음)

3️⃣ Spring MVC와 통합 용이

  • Spring MVC 패턴과 궁합이 잘 맞음
  • 컨트롤러(Model 객체)와 쉽게 연동 가능

4️⃣ 높은 확장성

  • XML, JSON, JavaScript, CSS 등 다양한 영역에서 사용 가능
  • 프론트엔드 & 백엔드 분리하여 협업하기 용이







✅ JSP vs 타임리프 비교

1️⃣ Spring Boot에서는 JSP 기본 지원 X

Spring Boot는 기본적으로 JSP 사용을 권장하지 않으며, JAR 배포를 기본으로 하기 때문에 JSP 실행이 어렵다. (내장 톰캣이 JSP를 직접 컴파일할 수 없음)


2️⃣ 스프링 부트는 JAR 방식 배포가 기본

구분 JAR 배포 (Spring Boot 기본) WAR 배포 (전통적인 Spring)
톰캣 내장 톰캣 포함 (spring-boot-starter-web) 외부 톰캣(WebLogic 등) 필요
실행 방식 java -jar myapp.jar WAS에 WAR 파일 배포 필요
View 위치 src/main/resources/templates/ src/main/webapp/WEB-INF/views/
JSP 지원 지원 안됨 ✅ 사용 가능
배포 방식 ✅ 단일 JAR 패키지로 배포 ❌ WAS 서버 설정 필요

스프링 부트는 JAR방식으로 배포를 하는것이 기본이다. 그러나 JSP는 서블릿으로 변환후 실행되는 구조이다.

즉, JSP 파일이 실행되려면 톰캣 같은 서블릿 컨테이너가 JSP파일을 컴파일하고 서블릿 클래스로 변환하는 과정이 필요하다.



💡 JSP 실행 과정

  1. JSP 파일을 서블릿(Java 코드)으로 변환 (Jasper Compiler가 수행)

  2. 서블릿을 .class 파일로 컴파일

  3. 서블릿 컨테이너(Tomcat 등)에서 실행

이 과정에서 JSP 파일은 반드시 톰캣의 webapps/ 디렉토리에 존재해야 하고, WEB-INF/views/ 등의 물리적인 경로가 필요하다. 그러나 JAR로 배포 시에 모든 리소스에 JAR 내부의 BOOT-INF/classes/에 포함되므로 톰캣이 JSP 파일을 인식할 수 없다. 한마디로 JAR 내부에서 JSP를 직접 컴파일하고 실행하는 환경이 제공되지 않는다.

WAR 배포 방식에서는 JSP 파일이 WEB-INF/views/에 위치하며, 톰캣이 이를 인식하고 컴파일하는 구조를 가진다.

myapp.war
└──  WEB-INF
├──  views
│  ├──  home.jsp
│  ├──  login.jsp
├──  web.xml

그러나 JAR배포 방식에서는 JSP 파일을 BOOT-INF/classes/templates/ 같은 경로에 넣어야 하는데, 톰캣이 이를 인식하지 못한다.

myapp.jar
└──  BOOT-INF
├──  classes
│  ├──  templates
│  │  ├──  home.jsp  ❌  JSP  인식  안됨
│  │  ├──  login.jsp  ❌  JSP  인식  안됨


또한 스프링 부트의 내장 톰캣에는 JSP 컴파일러(Jasper)가 기본적으로 포함되지 않는다. 때문에 스프링부트의 JAR기반 배포 하에서는 org.apache.tomcat.embed:tomcat-embed-jasper 라이브러리를 추가해줘야만 한다. 그러나 이를 단순히 추가해준다고해서 또 배포가 완벽하게 되는 것은 아니다. 추가적인 우회설정이 많이 필요하다..



💡 JAR 배포에서 JSP를 사용하려면?

Ⅰ.tomcat-embed-jasperjstl 라이브러리 추가

<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>


Ⅱ. application.properties 설정 추가

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp


Ⅲ. pom.xml에서 WAR 배포 방식으로 변경

<packaging>war</packaging>


Ⅳ. SpringBootServletInitializer를 상속하여 서블릿 컨테이너에서 실행하도록 설정

@SpringBootApplication
public  class  MyApplication  extends  SpringBootServletInitializer {

}

사실 이렇게 단순하게 코드를 적용한다고 JAR 배포환경에서 JSP를 뚝딱 사용할 수 있는건 아니다. 경우에 따라 위 코드정도만 적용해줘도 JSP를 사용할 수 있을 수 있지만 본인의 경우에는 이밖에 무수히 많은 설정과 시행착오를 겪었다. 되도록이면 스프링 부트 환경에서는 타임리프나 다른 템플릿 엔진을 사용하도록 하고 JSP는 최대한 지양하자.. 정말정말 어쩔수 없는 상황에서 JSP를 사용해야만 한다면 JSP Precompiler 게시글을 참고해서 적용해보면 도움이 될 것 같다.


3️⃣ JSP보다 타임리프가 성능이 뛰어남

JSP는 실행 전에 서블릿(Servlet) 코드로 변환 후 컴파일하는 과정이 필요하지만 타임리프는 서블릿 변환 과정이 없어서 속도가 훨씬 빠르다.

  • JSP: JSP → 서블릿 변환 → 컴파일 → 실행 (속도가 느림)
  • 타임리프: HTML 템플릿 엔진으로 바로 실행 (속도가 빠름)


4️⃣ 타임리프는 오류발생시에도 화면 유지

JSP에서는 오류가 발생하면 전체 페이지가 깨져버리지만 타임리프는 오류가 발생해도 이를 제외한 나머지 HTML 부분은 정상적으로 출력된다. 예를들어 JSP에 어떤 데이터를 매핑해서 사용하는 경우 해당 데이터가 존재하지 않거나 태그에 오타가 있으면 500 Internal Server Error가 출력되지만, 타임리프는 해당 데이터만 안나올 뿐 기본적인 HTML 구조는 유지된다.


5️⃣ 스프링 부트와 호환성이 좋다

Spring Boot는 타임리프를 기본적으로 지원하기 때문에 설정이 간편하다. JSP를 사용하려면 복잡한 설정이 필요하지만, 타임리프는 별다른 설정 없이 spring-boot-starter-thymeleaf만 추가하면 된다. 스프링 부트 스타터를 사용하는 경우에는 타임리프 기능을 추가해서 프로젝트를 만들기만 하면 된다.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>








타임리프 기본 문법

1️⃣ 텍스트 출력 (th:text)

<p  th:text="${message}">기본 텍스트</p>

위 코드에서 message 변수의 값이 Hello, Thymeleaf!라면, 브라우저에서는 다음과 같이 출력된다.

<p>Hello, Thymeleaf!</p>


2️⃣ 변수 값 설정(th:value)

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


3️⃣ 조건문 (th:if, th:unless)

<p  th:if="${isAdmin}">관리자입니다.</p>
<p  th:unless="${isAdmin}">일반 사용자입니다.</p>


4️⃣ 반복문 (th:each)

<ul>
	<li  th:each="user : ${userList}"  th:text="${user.name}"></li>
</ul>


5️⃣ 링크 연결 (th:href)

<a  th:href="@{/home}">홈으로 이동</a>


6️⃣ 날짜 포맷팅 (#dates.format)

<p  th:text="${#dates.format(today, 'yyyy-MM-dd')}"></p>







댓글남기기