Akashic Records

타임리프(Thymeleaf) 본문

Spring for Beginners

타임리프(Thymeleaf)

Andrew's Akashic Records 2024. 12. 2. 15:03
728x90

타임리프와 스프링 부트를 활용하는 웹 개발

타임리프(Thymeleaf)는 자바 기반의 서버 사이드 템플릿 엔진으로, 주로 스프링 프레임워크(Spring Framework)와 함께 사용됩니다. HTML, XML, JavaScript, CSS 등을 자연스럽게 처리할 수 있는 기능을 제공하여, 뷰 템플릿을 손쉽게 생성하고 데이터와 결합할 수 있도록 도와줍니다.

 

타임리프는 특히 스프링 MVC와 통합이 잘 되어 있어, 서버에서 제공되는 데이터를 HTML 기반의 동적인 웹 페이지로 쉽게 표현할 수 있습니다. 기본적으로 타임리프는 HTML을 템플릿으로 사용하면서도 웹 브라우저에서 바로 볼 수 있는 형태로 디자인되어 있어, 프론트엔드 개발자와 협업이 매우 용이하다는 장점이 있습니다.

 

타임리프의 주요 특징과 기능들을 살펴보면 다음과 같습니다:

 

1. 자연 템플릿(Natural Templates)

  • 타임리프는 HTML 파일을 "그대로" 템플릿으로 사용하여, 서버 측 템플릿 엔진을 사용하기 전에도 브라우저에서 볼 수 있습니다. 즉, 타임리프 태그가 있어도 유효한 HTML 문서로 동작합니다.
  • 예를 들어, 개발 중 브라우저에서 템플릿 파일을 열어 볼 수 있고, 이 파일을 그대로 사용하여 백엔드와 통합할 수 있습니다.

2. 스프링과의 긴밀한 통합

  • 타임리프는 스프링 MVC와 밀접하게 통합되어 있으며, 모델 속성을 손쉽게 렌더링할 수 있습니다. 이를 통해 컨트롤러에서 제공하는 데이터를 템플릿에 쉽게 전달하고, 이를 표현할 수 있습니다.
  • 스프링의 기본적인 설정에 타임리프 뷰 리졸버(View Resolver)를 추가하여, JSP 대신 타임리프 템플릿을 사용할 수 있습니다.

3. 표현식 언어(Thymeleaf Expression Language)

  • 타임리프는 다양한 표현식 언어를 사용하여 HTML 템플릿 내에 서버에서 제공되는 데이터를 출력합니다.
  • 표현식 유형:
    • ${} 변수 표현식: 모델 속성에 접근합니다.
    • # Utility Object: 기본적인 유틸리티 기능 제공 (#dates, #numbers 등).
    • @{} URL 표현식: URL을 생성합니다.
    • ~{} 프래그먼트 표현식: HTML 내 특정 프래그먼트를 참조합니다.

4. 조건부 렌더링과 반복

  • 조건부 렌더링: 타임리프의 th:ifth:unless 속성을 사용하여 특정 조건에 따라 HTML 요소를 렌더링할 수 있습니다.
<div th:if="${user != null}">
    환영합니다, <span th:text="${user.name}">사용자 이름</span>!
</div>
  • 반복 처리: th:each 속성을 사용하여 컬렉션을 순회하며 반복적으로 HTML 요소를 생성할 수 있습니다.
<ul>
    <li th:each="item : ${items}" th:text="${item.name}">아이템 이름</li>
</ul>

 

5. 프래그먼트와 레이아웃

  • 타임리프는 프래그먼트(Fragments) 기능을 제공하여, 템플릿 파일의 특정 부분을 다른 템플릿에서 재사용할 수 있습니다. 이를 통해 코드의 중복을 줄이고 유지보수를 쉽게 할 수 있습니다.
<!-- header.html -->
<header th:fragment="site-header">
    <h1>사이트 헤더</h1>
</header>

<!-- main.html -->
<div th:insert="fragments/header :: site-header"></div>
  • 또한, 템플릿 파일들을 결합하여 페이지의 공통 레이아웃을 구성할 수 있습니다. 레이아웃을 사용하면 페이지의 일관성을 유지하면서 반복적인 요소를 쉽게 관리할 수 있습니다. 아래 예시에서 home.html은 기본 레이아웃 default.html을 사용하여 페이지의 일관된 구조를 유지하며, 콘텐츠 부분만 정의합니다.

레이아웃 템플릿 (layouts/default.html):

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <meta charset="UTF-8">
    <title th:text="${pageTitle}">기본 페이지 제목</title>
    <link rel="stylesheet" href="/css/style.css" />
</head>
<body>
    <header layout:fragment="header">
        <nav>
            <ul>
                <li><a href="/home">Home</a></li>
                <li><a href="/about">About</a></li>
                <li><a href="/contact">Contact</a></li>
            </ul>
        </nav>
    </header>
    <main layout:fragment="content">
        <!-- 기본 콘텐츠가 여기에 들어갑니다 -->
    </main>
    <footer layout:fragment="footer">
        <p>Copyright &copy; 2024 My Website</p>
    </footer>
</body>
</html>

 

페이지별 콘텐츠 템플릿 (views/home.html):

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layouts/default}">
<head>
    <title>홈페이지</title>
</head>
<body>
    <div layout:fragment="content">
        <h2>환영합니다!</h2>
        <p>이곳은 홈페이지입니다. 최신 소식을 확인하세요.</p>
    </div>
</body>
</html>

 

6. 국제화(i18n) 지원

  • 타임리프는 국제화 메시지를 간단히 처리할 수 있습니다. 스프링의 메시지 번들 파일을 활용해 다국어 지원을 할 수 있습니다.
<p th:text="#{welcome.message}">Welcome message here</p>

 

7. HTML 속성 조작

  • 타임리프는 HTML 요소의 속성을 동적으로 설정할 수 있는 기능을 제공합니다. 예를 들어 th:href, th:src, th:class 등을 사용하여 속성 값을 동적으로 변경할 수 있습니다.
<a th:href="@{/home}" th:text="'홈으로 이동'">링크</a>

 

타임리프 사용 예시

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Thymeleaf 예제</title>
</head>
<body>
    <h1 th:text="'안녕하세요, ' + ${username} + '님!'">Hello, User!</h1>

    <ul>
        <li th:each="item : ${items}" th:text="${item}">아이템 이름</li>
    </ul>

    <form th:action="@{/submit}" method="post">
        <input type="text" name="name" th:value="${user.name}"/>
        <button type="submit">제출하기</button>
    </form>
</body>
</html>

이 예시는 타임리프의 표현식과 속성 조작을 이용하여, 서버에서 전달된 데이터를 동적으로 HTML에 바인딩하는 방법을 보여줍니다.


타임리프와 JSP의 차이점

  • HTML 친화성: 타임리프는 브라우저에서 유효한 HTML로 동작하기 때문에 디자이너와 협업하기 좋습니다. 반면, JSP는 브라우저에서 직접 열기에는 적합하지 않습니다.
  • 확장성: 타임리프는 다양한 템플릿 파일을 조합하거나 레이아웃을 구성하는 데 유리한 기능들을 제공합니다.
  • 성능: 타임리프는 템플릿 엔진으로서 성능이 우수하며, 특히 스프링 환경에서 사용될 때 더욱 최적화된 경험을 제공합니다.

타임리프 아키텍쳐

타임리프는 이렇게 스프링 MVC 애플리케이션의 뷰를 쉽고 효율적으로 개발할 수 있는 도구로서, 직관적인 문법과 강력한 기능을 통해 서버와 클라이언트 간의 데이터를 매끄럽게 연결하는 역할을 합니다.

 

타임리프(Thymeleaf)는 동적인 웹 페이지를 생성하기 위해 서버 사이드 템플릿 엔진으로 동작하며, 그 내부에는 웹 애플리케이션과의 상호작용을 효율적으로 처리하기 위한 구조적 아키텍처가 포함되어 있습니다. 이 아키텍처는 뷰 렌더링을 쉽게 하고 확장 가능하도록 설계되어 있어 스프링 MVC와 같은 프레임워크에서 널리 사용됩니다. 타임리프 아키텍처의 기본 개념을 이해하면, 그 작동 원리와 사용 방법을 더 잘 활용할 수 있습니다.

 

타임리프의 아키텍처는 크게 템플릿, 템플릿 프로세서, 표현식 언어, 컨텍스트 등의 개념으로 구성됩니다. 각 구성 요소가 어떤 역할을 하고, 어떻게 서로 연동되는지 살펴보겠습니다.

1. 템플릿(Template)

  • 템플릿은 HTML, XML, JavaScript, 텍스트 파일 등과 같이, 렌더링될 기본적인 문서 구조입니다.
  • 템플릿 파일은 일반적인 HTML로 구성되며, 여기에 타임리프 전용 속성(예: th:text, th:each 등)이 추가되어 서버 측 데이터가 동적으로 주입될 수 있도록 합니다.
  • 타임리프의 주요 목표는 이러한 템플릿을 자연스럽게 사용할 수 있도록 지원하는 것으로, 프론트엔드와 백엔드 모두에서 쉽게 사용할 수 있습니다.

2. 템플릿 엔진과 템플릿 프로세서(Template Engine & Template Processor)

  • 타임리프 아키텍처의 핵심에는 템플릿 엔진이 존재합니다. 템플릿 엔진은 개발자가 작성한 템플릿 파일을 해석하고 렌더링하여 최종 HTML 문서를 생성합니다.
  • 템플릿 엔진은 여러 종류의 템플릿 프로세서와 상호작용하며, 이 프로세서들은 각각의 특정 목적을 가진 플러그인 역할을 합니다. 예를 들어 HTML 프로세서, 텍스트 프로세서 등이 있습니다.
  • 템플릿 프로세서는 문서의 각 요소를 처리하며, 예를 들어 HTML 프로세서는 HTML 태그 내의 타임리프 속성(th:*)을 해석하고 이를 데이터와 결합해 최종 결과를 만들어냅니다.

3. 컨텍스트(Context)

  • 컨텍스트는 템플릿이 렌더링될 때 필요한 데이터가 저장되는 공간입니다. 쉽게 말해 템플릿을 렌더링할 때 사용하는 데이터 모델입니다.
  • 이 컨텍스트 객체는 주로 서버의 컨트롤러에서 생성되며, 템플릿 엔진에 전달됩니다.
  • 예를 들어, 스프링 MVC 컨트롤러에서 모델 데이터를 Model이나 ModelMap에 저장하면 타임리프는 이를 템플릿의 컨텍스트로 활용하여 데이터에 접근할 수 있습니다.위의 코드에서 model.addAttribute("name", "John")은 템플릿에서 ${name}으로 접근 가능한 데이터를 제공합니다.
@Controller
public class MyController {
    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("name", "John");
        return "hello";
    }
}

4. 표현식 언어(Expression Language)

  • 타임리프 표현식 언어(Thymeleaf Expression Language)는 컨텍스트에 포함된 데이터에 접근하고 이를 변형하거나 출력을 결정하는 데 사용됩니다. 아래에서 자세히 설명

5. 템플릿 리졸버(Template Resolver)

  • 템플릿 리졸버는 템플릿 파일의 위치를 지정하고 해당 파일을 찾는 역할을 합니다.
  • 타임리프는 템플릿 리졸버를 통해 지정된 경로에서 템플릿 파일을 찾고, 이를 템플릿 엔진이 렌더링할 수 있도록 전달합니다.
  • 스프링 부트와 통합 시, 기본적으로 resources/templates/ 디렉터리에서 템플릿 파일을 찾도록 설정되어 있습니다.

6. 다이얼렉트(Dialect)

  • 다이얼렉트는 타임리프에 다양한 템플릿 처리 기능을 추가하는 확장 모듈입니다. 기본적으로 타임리프는 표준 다이얼렉트(Standard Dialect)를 제공하며, 이는 HTML 템플릿에서 사용하는 대부분의 기능(th:text, th:if, th:each 등)을 포함하고 있습니다.
  • 개발자는 필요에 따라 커스텀 다이얼렉트(Custom Dialect)를 정의하여, 추가적인 기능을 타임리프에 통합할 수 있습니다. 이를 통해 복잡한 비즈니스 로직을 손쉽게 처리할 수 있습니다.

8. 렌더링 흐름(Rendering Flow)

  • 타임리프 아키텍처의 주요 흐름은 다음과 같습니다:
    1. 컨트롤러가 요청을 처리하고, 데이터와 함께 특정 템플릿 파일을 반환합니다.
    2. 템플릿 리졸버가 지정된 위치에서 해당 템플릿 파일을 찾습니다.
    3. 템플릿 엔진컨텍스트템플릿을 받아 최종적인 HTML을 생성합니다.
    4. 최종적으로 생성된 HTML은 서버에서 클라이언트(브라우저)로 반환됩니다.

728x90

타임리프 문법

타임리프(Thymeleaf)는 HTML 기반 템플릿을 서버 측 데이터와 결합하기 위해 다양한 표현식과 문법을 제공합니다. 이러한 표현식은 동적으로 HTML 문서 내의 데이터를 삽입하거나, 조건부 로직을 적용하거나, 반복문을 사용하여 데이터를 표현하는 데 사용됩니다. 아래에서는 타임리프에서 자주 사용하는 표현식과 문법을 자세히 살펴보겠습니다.

1. 변수 표현식 (Variable Expressions) - ${}

변수 표현식은 모델에 포함된 데이터에 접근하는 데 사용됩니다. 스프링 컨트롤러에서 전달된 모델 데이터는 ${} 구문을 통해 템플릿에서 접근할 수 있습니다.

<p th:text="${user.name}">사용자 이름</p>
  • 위의 예시에서 ${user.name}은 모델 속성 username 필드를 참조하여 출력합니다.

2. 선택 변수 표현식 (Selection Variable Expressions) - *{}

선택 변수 표현식은 특정 객체를 기준으로 데이터를 접근할 때 사용됩니다. 주로 th:object와 함께 사용되며, 폼에서 데이터를 다룰 때 유용합니다.

<form th:object="${user}">
    <input type="text" th:field="*{name}" />
</form>
  • 여기서 *{name}user 객체의 name 필드를 참조합니다. th:object로 지정된 객체가 기준이 되기 때문에 더 간단하게 사용 가능합니다.

3. 메시지 표현식 (Message Expressions) - #{}

메시지 표현식은 국제화(i18n) 메시지를 처리하는 데 사용됩니다. 스프링의 메시지 번들에서 정의된 값을 가져옵니다.

<p th:text="#{welcome.message}">Welcome message here</p>
  • 여기서 #{welcome.message}는 메시지 번들 파일에 정의된 welcome.message 키의 값을 출력합니다. 다국어 지원을 위해 매우 유용합니다.

4. 링크 URL 표현식 (Link URL Expressions) - @{}

URL 표현식은 동적인 URL을 생성할 때 사용됩니다. 컨텍스트 경로를 자동으로 포함하거나 경로 변수 및 쿼리 파라미터를 처리할 수 있습니다.

<a th:href="@{/home}">홈으로 이동</a>
<a th:href="@{/user/profile(id=${user.id})}">프로필 보기</a>
  • @{/user/profile(id=${user.id})}user.id 값을 경로 변수로 포함하여 URL을 생성합니다.

5. 프래그먼트 표현식 (Fragment Expressions) - ~{}

프래그먼트 표현식은 타임리프 템플릿 내의 특정 부분을 참조할 때 사용됩니다. 이를 통해 공통 컴포넌트를 쉽게 재사용할 수 있습니다.

<div th:insert="~{fragments/header :: site-header}"></div>
  • ~{fragments/header :: site-header}fragments/header.html 파일에서 site-header라는 프래그먼트를 삽입합니다.

6. 조건부 표현식 - th:if, th:unless

조건부 표현식을 사용하여 특정 HTML 요소의 렌더링 여부를 결정할 수 있습니다.

<p th:if="${user != null}">환영합니다, <span th:text="${user.name}">사용자 이름</span>님!</p>
<p th:unless="${user != null}">로그인 해주세요.</p>
  • th:if는 주어진 조건이 참일 때만 해당 요소를 렌더링하며, th:unless는 조건이 거짓일 때 렌더링합니다.

7. 반복 표현식 - th:each

컬렉션을 순회하며 HTML 요소를 반복해서 렌더링할 때 사용합니다.

<ul>
    <li th:each="item : ${items}" th:text="${item.name}">아이템 이름</li>
</ul>
  • th:each="item : ${items}"items 컬렉션을 순회하며, 각 아이템에 대해 <li> 요소를 생성합니다.

8. 텍스트 및 속성 변경 표현식

타임리프는 텍스트나 속성을 동적으로 설정하는 속성을 제공하여 HTML 태그 내부에 데이터를 바인딩할 수 있습니다.

  • 텍스트 설정 (th:text): 태그의 텍스트 내용을 동적으로 설정합니다.
    • ${user.name}의 값을 스팬 태그 내부에 출력합니다.
<span th:text="${user.name}">기본 텍스트</span>
  • 속성 설정 (th:href, th:src, th:class 등): HTML 속성에 동적 값을 설정합니다.
<a th:href="@{/home}" th:text="'홈으로 이동'">링크</a>
<img th:src="@{/images/logo.png}" alt="로고 이미지">

9. 기타 표현식

타임리프에는 여러 가지 표현식을 통해 다양한 동적 처리를 할 수 있습니다.

  • 기본 객체 접근 (#): 타임리프는 여러 기본 객체에 대한 접근을 제공합니다. 예를 들어, 날짜 및 숫자 처리에 유용한 객체들이 있습니다.
    • #dates는 날짜 관련 유틸리티 객체입니다.
      <p th:text="${#dates.format(user.birthDate, 'yyyy-MM-dd')}">생일</p>
  • 배열과 리스트 표현:
    • 인덱스를 사용할 수 있습니다. 예: itemStat.index 또는 itemStat.count
      <li th:each="item, itemStat : ${items}">
        <span th:text="${item.name}">아이템 이름</span>
        <span th:text="${itemStat.index}">인덱스</span>
      </li>

10. 기본 연산자와 조건부 논리

타임리프 표현식은 다양한 연산자를 지원하여 논리적 처리를 할 수 있습니다.

  • 산술 연산자: +, -, *, /, %를 사용할 수 있습니다.
    <span th:text="${user.age + 1}">나이</span>
  • 비교 연산자: >, <, >=, <=, ==, !=
    <p th:if="${user.age > 18}">성인입니다.</p>
  • 논리 연산자: and, or, !
    <p th:if="${user.age > 18 and user.gender == 'M'}">성인 남성입니다.</p>
  • 조건부 연산자 (삼항 연산자): condition ? ifTrue : ifFalse
    <p th:text="${user.age > 18 ? '성인' : '미성년자'}"></p>
728x90

'Spring for Beginners' 카테고리의 다른 글

Spring Security 는 처음이에요.  (1) 2024.02.27
Spring Rest API는 처음인데요.  (0) 2024.02.22
Spring JPA는 처음인데요.  (0) 2024.02.19
@SpringBootApplication  (1) 2024.02.13
Spring Boot 첫 번째 예제  (0) 2024.02.13
Comments