개발

[Spring] Thymeleaf(타임리프란?)

orieasy1 2024. 7. 16. 05:07

 

 

Thymeleaf(타임리프)는 템플릿 엔진이다.

템플릿 엔진이란 스프링 서버에서 데이터를 받아 우리가 보는 웹페이지, 즉 HTML 상에 그 데이터를 넣어보여주는 도구이다. 웹 애플리케이션에서 동적 HTML 콘텐츠를 생성하는 도구라고 표현할 수 도 있다.

이를 사용하기 위해서는 HTML과 함께 템플릿 엔진을 위한 문법을 살짝 섞어 사용해야한다.

 

템플린 엔진 문법 예시

<h1 text=${이름}>
<p text=${나이}>

 

h1태그와 p태그에 ${이름}과 ${나이}가 text 어트리뷰트로 할당되어 있다. 

이렇게 해두면 서버에서 이름, 나이,라는 key로 데이터를 템플릿 엔진에 넘겨주고 템플릿 엔진은 이를 받아 HTML에 값을 적용한다.

 

예를 들어 서버에서 보내준 데이터 예시가 다음과 같다면

{
	이름: "윤동희"
    	나이: 22
}

 

해당 키 자리에 즉 이름 자리에는 윤동희가, 나이 자리에는 22라는 값이 들어갈 것이다.

템플릿 엔진은 주로 서버 사이드에서 실행되며 데이터와 템플릿을 결합하여 HTML을 생성하는데 사용한다라고 생각하면 된다. 값이 달라지면 그때 그때 화면에 반영하니 동적인 웹페이지를 만들 수 있게 되는 것이다.

 

템플릿 엔진은 프로그래머가 복잡한 HTML 코드를 쉽게 관리하고, 재사용이 가능하며 유지보수가 쉬운 구조로 만들 수 있도록 도와준다. 코드 가독성이 높아지며 생산성 또한 높아지는 결과를 가져온다.

템플릿 엔진으로는 JSP, 타임리프, 프리마커 등이 있다. 템플릿 엔진마다 문법이 미묘하게 다르지만 기본적인 대부분의 구조는 비슷하다.

 

 

타임리프 표현식과 문법

여러 템플릿 엔진 중 타임리프에 대해 자세히 알아보려고 한다.

타임리프는 주로 Spring 프레임워크와 함께 사용되며 HTML 파일을 그대로 열어볼 수 있는 WYSIWYG(What You See is What You Get) 방식을 지원한다.

 

타임리프 표현식

표현식 설명
${ ... } 변수의 값 표현식
#{ ... } 속성 파일 값 표현식
@{ ... } URL 표현식
*{ ... } 선택한 변수의 표현식, th:object에서 선택한 객체에 접근

 

 

타임리프 문법

표현식 설명 예제
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 이동경로 th:href= "@{/persons(id = ${person.id})}"
th:with 변숫값으로 지정 th:with= "name = ${person.name}" 
th:object 선택한 객체로 지정 th:object= "${person}"

 

 

타임리프 사용법

타임리프를 사용하기 위해서는 다음과 같이 build.gradle 파일에 의존성을 추가해야한다.

 

 

예시)

요청을 받아 사용자에게 뷰를 보여주기 위해서는 뷰 컨트롤러가 필요하다.

API를 만들기 위해서 컨트롤러 메서드가 데이터를 직렬화한 JSON 문자열을 반환하도록 했지만 뷰 컨트롤러 메서드는 뷰의 이름을 반환하고, 모델 객체에 값을 담는다.

/thymeleaf/example GET요청이 오면 특정 데이터를 뷰(HTML)로 넘겨주는 모델 객체에 추가하는 컨트롤러 메서드 작성

package com.mysite.myblog.controller;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.time.LocalDate;
import java.util.List;

@Controller
public class ExampleController {
    @GetMapping("/thymeleaf/example")
    public String thymeleafExample(Model model) {   //뷰로 데이터를 넘겨주는 모델 객체
        List<Player> players = List.of(
                new Player("1번 타자", 0, "황성빈", 26, List.of("중견수", "우투좌타")),
                new Player("2번 타자", 91, "윤동희", 20, List.of("우익수", "우투우타")),
                new Player("3번 타자", 8, "전준우", 38, List.of("지명타자", "우투우타")),
                new Player("4번 타자", 29, "빅터 레이예스", 29, List.of("좌익수", "우투양타")),
                new Player("5번 타자", 65, "고승민", 23, List.of("2루수", "우투좌타")),
                new Player("6번 타자", 51, "나승엽", 22, List.of("1루수", "우투좌타")),
                new Player("7번 타자", 9, "정훈", 36, List.of("3루수", "우투우타")),
                new Player("8번 타자", 00, "손성빈", 22, List.of("포수", "우투우타")),
                new Player("9번 타자", 53, "박승욱", 31, List.of("유격수", "우투좌타")),
                new Player("선발 투수", 28, "찰리 반즈", 28, List.of("선발투수", "좌투좌타"))
        );

        model.addAttribute("players", players); //players 저장
        model.addAttribute("today", LocalDate.now());

        return "example";   //example.html라는 뷰 조회
    }

    @Getter
    @Setter
    @AllArgsConstructor
    static class Player {
        private String id;
        private int uniformNum;
        private String name;
        private int age;
        private List<String> position;
    }
}

 

코드를 보면 Model이 있는데 모델 객체는 뷰(HTML)쪽으로 값을 넘겨주는 객체이다. 모델을 통해 데이터를 설정하고, 모델은 뷰로 이 데이터를 전달해 키에 맞는 데이터를 뷰에서 조회할 수 있도록 한다. (컨트롤러와 뷰의 중간 다리 역할)

모델 객체는 따로 생성할 필요없이 코드처럼 인자로 선언하기만 하면 스프링이 만들어준다.

addAttribute()라는 메서드로 모델에 값을 저장한다. (필자가 요즘 야구에 미쳐있으므로) List를 만들어서 7/10일자 선발 라인업의 세부정보들을 저장하고 addAttribute() 메서드를 사용하여 players키에 해당 정보를 저장한다. today라는 키에는 날짜정보를 저장해준다.

 

thymeleafExample() 메서드가 반환하는 값은 "example"인데 이 값은 뷰의 이름이다.

@Controller 애너테이션은 Spring MVC에서 컨트롤러 클래스를 정의하는 데 사용된다. 컨트롤러는 클라이언트의 요청을 처리하고, 비즈니스 로직을 호출하며, 결과를 뷰(View)에 전달하여 최종 응답을 생성합니다.

즉 스프링부트는 @Controller 애너테이션을 보고 반환하는 값의 이름을 가진 뷰의 파일을 찾아 웹 브라우저에서 해당 파일을 보여준다. 여기에서는 example.html을 찾아 그 파일을 보여주는 것이다.

 

 

내가 짠 example.html 파일은 다음과 같다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>투혼투지</title>
</head>
<body>
<h1>롯데 자이언츠 승리 기원</h1>
<h3>오늘은 제발 좀 이기자...</h3>

<!-- LocalDate를 yyyy-MM-dd 포맷으로 번경 -->
<p th:text="${#temporals.format(today, 'yyyy-MM-dd')}"></p>

<div th:each="player : ${players}">
    <h4 th:text="${player.id}"></h4>
    <p th:text="|등번호 : ${player.uniformNum}|"></p>
    <p th:text="|이름 : ${player.name}|"></p>
    <p th:text="|나이 : ${player.age}|"></p>
    <p>포지션</p>
    <ul th:each="position : ${player.position}">
        <li th:text="${position}"></li>
    </ul>

    <!-- 해당 등번호 블로그 글을 보러 이동하는 코드를 추가하고 싶다면..?
    <a th:href="@{/api/articles/{id}(id=${player.uniformNum})}">글보기</a>
    -->
    <br>
</div>
</body>
</html>

 

 

스프링 부트 서버를 실행한 후 웹 브라우저에서 http://localhost:8080/thymeleaf/example에 접속하면 다음과 같은 화면을 볼 수 있다.

(더 있지만 생략...)