개발천재

[Spring Boot] Thymeleaf 개념 이해하기, 사용방법 본문

개발 준비/Spring Boot

[Spring Boot] Thymeleaf 개념 이해하기, 사용방법

세리블리 2025. 2. 11. 23:51
반응형
Thymeleaf는 웹사이트의 HTML 페이지를 Java 코드에서 바꿔주는 도구

 

 

Thymeleaf 개념 이해

Thymeleaf(타임리프)는 HTML 파일에서 동적으로 데이터를 넣어주는 템플릿 엔진이다. 쉽게 말해, HTML과 Java를 연결해주는 역할을 한다.

Thymeleaf는 Java 기반 템플릿 엔진이기 때문에 주로 Java(Spring Boot)에서 사용된다. 하지만 Java에서만 쓸 수 있는 것은 아니고, HTML 템플릿 엔진으로서 독립적으로도 사용 가능하긴 하다.

하지만 Thymeleaf는 기본적으로 Java와 가장 잘 맞도록 설계된 템플릿 엔진이기 때문에, Python, Node.js 같은 다른 언어에서는 거의 사용되지 않고, 그 언어에 맞는 템플릿 엔진(예: Python은 Jinja2, Node.js는 EJS/Pug)을 더 많이 사용한다.

 

 

Thymeleaf 사용방법

Thymeleaf를 사용하기 위해서는 html을 선언하는 부분에 xmlns:th="http://www.thymeleaf.org"을 명시해야한다. 

 

그러나 Thymeleaf 3.0 이상에서는 xmlns:th="http://www.thymeleaf.org"을 명시하지 않아도 기본적으로 Thymeleaf 문법이 정상적으로 동작한다. Thymeleaf 2.x 이하에서는 반드시 xmlns:th="http://www.thymeleaf.org"을 명시해야 한다.

하지만 IDE 지원과 가독성을 위해 xmlns:th를 추가하는 것이 권장한다. 또한 th:text, th:if 같은 속성을 사용할 때 자동 완성 기능이 활성화되고, 실수로 잘못된 속성을 입력했을 때, IDE에서 오류를 감지해 줄 수 있다.

<!-- index.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Hello Thymeleaf</title>
</head>
<body>
	<h1>안녕하세요, <span th:text="${name}">사용자</span>님!</h1>
</body>
</html>
// Controller

package com.my.testApp.myController;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {
    @GetMapping("login")
    public String login(Model model) {
        model.addAttribute("name", "sehee");
        return "user/login";
    }

    @GetMapping("logout")
    public String logout(Model model) {
        model.addAttribute("name", "sehee");
        return "user/logout";
    }
}

 

 

 

타임리프(Thymeleaf) 기본 표현식

변수표현식

컨트롤러에서 전달한 모델(Model) 속성 값을 참조할 때 사용

${...}   ${student.id}  ${student.name}

 

 

선택자 표현식

현재 객체의 속성을 간단하게 접근할 때 사용 (주로 th:object가 설정된 경우)

*{...}   *{id}
*{id} → th:object="${student}"가 설정된 상태라면 student.id를 의미

 

 

메시지 표현식

messages.properties 같은 메시지 파일에서 값을 가져올 때 사용

#{...}   #{id}
#{id} → messages.properties 파일에 id=학생 ID가 정의되어 있으면 학생 ID로 출력

 

 

링크URL 표현식

URL을 동적으로 생성할 때 사용

@{...}   @{https://www.naver.com}
@{https://www.naver.com} → 네이버 링크로 이동)
@{/students/list} → /students/list로 변환됨

 


부분적 표현식

프래그먼트(fragment) 템플릿을 포함할 때 사용

~{...}
~{fragments/header} → fragments/header.html을 포함

 

 

조건 연산자 

논리 연산자 : and, or, not, !

${student.age} > 20 and ${student.age} < 10  각각 분리하여서 사용하거나
${student.age > 20 or student.age < 10}  한 번에 묶어서 사용하는 것도 가능

 

 

문자열 결합

텍스트 단순 결합
${student.id}+${student.name}

문장 결합(파이프 기호 | 사용)
|학생 아이디 : ${student.id}, 학생 이름 : ${student.name} |

 


조건부 표현식

if-then (단순 조건)
<p th:text="${student.age < 20} ? '청소년'"></p>

if-then-else (삼항 연산자처럼 사용)
<p th:text="${student.age < 20} ? '청소년' : '성인'"></p>

default 값 설정 (null 체크)
student.name이 null이면 "이름 없음"을 출력
<p th:text="${student.name} ?: '이름 없음'"></p>

 

 

 

Thymeleaf의 장점

  • HTML 문법을 그대로 유지 → 웹 디자이너와 협업 가능
  • Spring Boot와 완벽한 호환 → JSP보다 간편함
  • 서버에서 동적으로 데이터 삽입 가능
  • 템플릿 기능 제공 (반복문, 조건문 등 사용 가능)

 

Thymeleaf를 사용하면 HTML을 유지하면서 동적으로 변경할 부분만 Java 코드로 채울 수 있기 때문에 유지보수가 쉽고 가독성을 높여준다.

 

 


 

 

Thymeleaf 다양한 활용 예시

반복문 사용 예시

users 리스트를 순회하여 <li> 태그에 값 출력

<!-- users.html -->
<ul>
    <li th:each="user : ${users}" th:text="${user}"></li>
</ul>
@Controller
public class UserController {
    @GetMapping("/users")
    public String getUsers(Model model) {
        List<String> users = List.of("Alice", "Bob", "Charlie");
        model.addAttribute("users", users);
        return "users";
    }
}

 

 

조건문 사용 예시

th:href를 사용하여 동적으로 URL 생성

<!-- user-status.html -->
<p th:if="${user.isAdmin}" style="color: red;">관리자 계정입니다.</p>
<p th:unless="${user.isAdmin}">일반 사용자 계정입니다.</p>
@Controller
public class UserStatusController {
    @GetMapping("/user-status")
    public String userStatus(Model model) {
        User user = new User("Alice", true);  // 관리자 계정
        model.addAttribute("user", user);
        return "user-status";
    }
}

class User {
    public String name;
    public boolean isAdmin;
    
    public User(String name, boolean isAdmin) {
        this.name = name;
        this.isAdmin = isAdmin;
    }
}

 

 

URL 링크 처리 (th:href) 예시

th:href를 사용하여 동적으로 URL 생성

<!-- links.html -->
<a th:href="@{/home}">홈으로 이동</a>
<a th:href="@{/profile(id=${userId})}">프로필 보기</a>
@Controller
public class LinkController {
    @GetMapping("/links")
    public String links(Model model) {
        model.addAttribute("userId", 123);
        return "links";
    }
}

 

 

폼 데이터 바인딩 (th:field) 예시

 th:field를 이용하여 객체의 필드와 HTML 입력 요소를 연결

<!-- form.html -->
<form th:action="@{/submit}" th:object="${formData}" method="post">
    <input type="text" th:field="*{name}" placeholder="이름 입력">
    <input type="email" th:field="*{email}" placeholder="이메일 입력">
    <button type="submit">제출</button>
</form>
@Controller
public class FormController {
    @GetMapping("/form")
    public String form(Model model) {
        model.addAttribute("formData", new FormData());
        return "form";
    }

    @PostMapping("/submit")
    public String submit(@ModelAttribute FormData formData) {
        System.out.println("이름: " + formData.getName() + ", 이메일: " + formData.getEmail());
        return "result";
    }
}

class FormData {
    private String name;
    private String email;

    // Getters & Setters
}

 

 

Fragment(공통 레이아웃) 예시
공통 헤더 파일

th:fragment를 사용해 공통 부분을 분리하고, th:replace로 불러오기

<!-- fragments/header.html -->
<div th:fragment="header">
    <h1>공통 헤더</h1>
</div>


<!-- 템플릿에서 포함 -->
<!-- home.html -->
<html>
<body>
    <div th:replace="fragments/header :: header"></div>
    <p>홈 페이지입니다.</p>
</body>
</html>



반응형