본문 바로가기
Spring

[Thymeleaf] Thymeleaf 기초

by sgyeong 2025. 8. 29.

Thymeleaf

 

HTML 파일을 템플릿으로 사용하여 동적인 웹 페이지를 생성할 수 있게 해주는 템플릿 엔진

서버에서 데이터를 동적으로 삽입해 브라우저에 렌더링 되는 HTML을 만든다.

 

 

특징

  • 자연스러운 템플릿 : HTML로 열어봐도 깨지지 않으며, 브라우저에서 정적 HTML처럼 볼 수 있음
  • 표현 언어 : ${user.name} 같은 표현으로 서버 데이터를 표현
  • 서버 사이드 렌더링 (SSR) : 서버에서 HTML을 완성해서 클라이언트에 전송
  • Spring과 강력한 통합 : Spring MVC의 모델 데이터를 쉽게 출력 가능
  • 확장성 : 커스텀 태그와 확장 기능 제공

 

Thymeleaf 구조

 

1. 템플릿 엔진 (Thymeleaf Engine) : HTML을 분석하고 필요한 데이터로 치환해 렌더링

2. 표현 언어 (OGNL) : 객체 그래프 내의 값에 접근하기 위해 사용

3. 템플릿 리졸버 (Template Resolver) : HTML 파일이 어디 있는지 탐색

4. View Resolver (Spring MVC) : 컨트롤러에서 어떤 뷰를 반환할지 결정

 

 

 

장점

 

1. HTML을 그대로 브라우저에서 열어볼 수 있다.

2. Spring과 강력한 통합

3. 쉬운 문법과 높은 생산성

 

단점

 

1. 자바스크립트 SPA 프레임워크에 비해 제한적이다.

2. 복잡한 프론트엔드 로직에선 비효율적이다.

3. 초기 학습이 어렵다.

 

 

 

Spring Boot 설정

 

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
}

 

 

 

 

기본 문법 및 사용법

 

Thymeleaf 선언

HTML <html> 태그에 xmlns:th 속성을 선언하여 사용한다.

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

 

 

변수 출력 

<p th:text="${name}">이름</p>

 

${name} : 모델(Model)에 있는 변수 출력

이름 : 값이 없을 경우 표시될 기본 값

 

 

조건문

<div th:if="${user.isAdmin}">관리자</div>
<div th:unless="${user.isAdmin}">일반 사용자</div>

 

 

반복문 (for-each)

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

 

 

링크 처리

<a th:href="@{/user/{id}(id=${user.id})}">프로필 보기</a>

 

 

폼 처리

<form th:action="@{/submit}" th:object="${user}" method="post">
  <input type="text" th:field="*{name}" />
  <input type="submit" value="저장" />
</form>

 

th:object : 폼 객체 지정

th:field : 객체의 필드 바인딩

 

 

비교 연산자

연산자 의미
== 또는 eq 같음
!= 또는 ne 다름
> 또는 gt 크다
< 또는 lt 작다
>= 또는 ge 크거나 같다
<= 또는 le  작거나 같다

 

예시)

<p th:if="${user.age >= 18}">성인입니다.</p>
<p th:if="${user.name eq '홍길동'}">홍길동님 환영합니다.</p>

 

 

null 확인

<p th:if="${user != null}">정보 있음</p>
<p th:if="${user == null}">정보 없음</p>

 

 

필드가 null인지 확인

<p th:if="${user.name != null}">이름: <span th:text="${user.name}"></span></p>

 

 

삼항 연산자

<p th:text="${user.age >= 18 ? '성인' : '미성년자'}"></p>

 

 

논리 연산자

연산자 의미
and 논리 AND
or 논리 OR
! 또는 not 논리 NOT

 

<p th:if="${user.age > 18 and user.isMember}">성인 회원</p>
<p th:if="${not user.active}">비활성 사용자입니다.</p>

 

 

조건문 안에서의 변수 설정

th:with를 사용해 변수를 중간에 정의할 수 있다. 복잡한 조건이나 계산식이 필요한 경우 유리하다.

<div th:with="isAdult=${user.age >= 18}">
  <p th:if="${isAdult}">성인입니다</p>
</div>

 

 

 

반복문 + 조건문

<ul>
  <li th:each="item : ${items}" th:if="${item.available}">
    <span th:text="${item.name}"></span> - 판매중
  </li>
</ul>

 

 

th:switch / th:case

<div th:switch="${user.role}">
  <p th:case="'ADMIN'">관리자</p>
  <p th:case="'USER'">일반 사용자</p>
  <p th:case="*">알 수 없는 사용자</p>
</div>

 

th:case="*"는 반드시 마지막에 위치해야 한다. 그렇지 않으면 이후 case는 무시된다.

 

 

복수 조건 처리 (OR 조건)

<div th:switch="${user.role}">
  <p th:case="'ADMIN','MANAGER'">관리자 또는 매니저</p>
  <p th:case="'USER'">일반 사용자</p>
  <p th:case="*">기타</p>
</div>

 

th:case="*"는 반드시 마지막에 위치해야 한다. 그렇지 않으면 이후 case는 무시된다.

 

 

 

블록 태그를 활용한 다중 렌더링

<div>, <section> 같은 컨테이너 요소 안에서 여러 태그를 그룹으로 처리할 수 있다.

<div th:switch="${status}">
  <section th:case="'APPROVED'">
    <h2>승인됨</h2>
    <p>요청이 처리되었습니다.</p>
  </section>

  <section th:case="'REJECTED'">
    <h2>거절됨</h2>
    <p>사유를 확인해 주세요.</p>
  </section>

  <section th:case="*">
    <h2>대기 중</h2>
    <p>검토 중입니다.</p>
  </section>
</div>

 

 

 

th:switch 중첩 사용

다단계 조건 처리가 필요한 경우 th:switch를 중첩하여 사용할 수 있다.

<div th:switch="${user.role}">
  <div th:case="'ADMIN'">
    <p>관리자</p>

    <div th:switch="${user.department}">
      <p th:case="'HR'">인사팀 관리자</p>
      <p th:case="'IT'">IT 관리자</p>
      <p th:case="*">기타 부서 관리자</p>
    </div>
  </div>

  <p th:case="'USER'">사용자</p>
</div>

 

th:case="*"는 반드시 마지막에 위치해야 한다. 그렇지 않으면 이후 case는 무시된다.

 

 

 

EL 변수 활용 (복잡한 비교값 추출)

<div th:with="userType=${user.role}" th:switch="${userType}">
  <p th:case="'GUEST'">비회원</p>
  <p th:case="'MEMBER'">회원</p>
  <p th:case="'VIP'">VIP 회원</p>
</div>