[Thymeleaf] 템플릿 레이아웃

2025. 9. 16. 20:35·타임리프

웹 화면을 개발할 때, 여러 페이지에 공통으로 들어가는 부분이 많다. 예를 들어, 모든 페이지의 <head> 안에는 공통 CSS, 자바스크립트, 파비콘 같은 것들이 들어간다. 또 <header> 메뉴, <footer> 저작권 표시처럼 사이트 전반에 반복적으로 쓰이는 영역도 있다.

 

이런 코드를 매번 복사해 넣는다면 유지보수가 매우 힘들어진다. 한 부분을 수정할 때 모든 페이지를 고쳐야 하기 때문이다.

타임리프는 이런 문제를 해결하기 위해 템플릿 조각(fragment) 과 레이아웃(layout) 기능을 제공한다. 이번 글에서는 레이아웃을 적용해서 공통 구조를 만들고, 각 페이지에서 필요한 정보만 교체하는 방법을 알아본다.

 

1. <head> 부분에 레이아웃 적용하기

먼저 공통 CSS/JS가 들어 있는 <head>를 만들어 두고, 페이지마다 필요한 제목과 추가 CSS만 전달하는 방식이다.

레이아웃 베이스 (base.html)

<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="common_header(title, links)">
    <title th:replace="${title}">레이아웃 타이틀</title>

    <!-- 공통 -->
    <link rel="stylesheet" th:href="@{/css/awesomeapp.css}">
    <link rel="shortcut icon" th:href="@{/images/favicon.ico}">
    <script th:src="@{/sh/scripts/codebase.js}"></script>

    <!-- 추가 -->
    <th:block th:replace="${links}" />
</head>
</html>

여기서 th:fragment="common_header(title, links)"는 "title과 links를 받아서 렌더링할 수 있는 조각(fragment)"이라는 뜻이다.

 

실제 페이지 (layoutMain.html)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="template/layout/base :: common_header(~{::title}, ~{::link})">
    <title>메인 타이틀</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
    <link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">
</head>
<body>
    메인 컨텐츠
</body>
</html>

여기서 ~{::title} 은 현재 페이지의 <title> 태그를, ~{::link} 는 현재 페이지의 <link> 태그들을 그대로 전달한다.

 

렌더링 결과

<head>
<title>메인 타이틀</title>
<!-- 공통 -->
<link rel="stylesheet" href="/css/awesomeapp.css">
<link rel="shortcut icon" href="/images/favicon.ico">
<script src="/sh/scripts/codebase.js"></script>
<!-- 추가 -->
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/themes/smoothness/jquery-ui.css">
</head>

공통 <head> 리소스는 유지되면서, 각 페이지에서 지정한 <title>과 <link>가 추가된 것을 확인할 수 있다.

 

2. <html> 전체를 레이아웃으로 확장하기

이번에는 <html> 전체 구조를 공통 레이아웃으로 두고, 각 페이지에서 제목과 본문만 교체하는 방식이다.

 

레이아웃 파일 (layoutFile.html)

<!DOCTYPE html>
<html th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org">
<head>
    <title th:replace="${title}">레이아웃 타이틀</title>
</head>
<body>
    <h1>레이아웃 H1</h1>
    <div th:replace="${content}">
        <p>레이아웃 컨텐츠</p>
    </div>
    <footer>레이아웃 푸터</footer>
</body>
</html>

여기서 layout (title, content)는 두 개의 영역을 받는다: 제목(title)과 본문(content).

 

실제 페이지 (layoutExtendMain.html)

<!DOCTYPE html>
<html th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title}, ~{::section})}"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <title>메인 페이지 타이틀</title>
</head>
<body>
    <section>
        <p>메인 페이지 컨텐츠</p>
        <div>메인 페이지 포함 내용</div>
    </section>
</body>
</html>

여기서 ::title은 <title> 태그, ::section은 <section> 태그를 전달한다.

 

렌더링 결과

<!DOCTYPE html>
<html>
<head>
    <title>메인 페이지 타이틀</title>
</head>
<body>
    <h1>레이아웃 H1</h1>
    <section>
        <p>메인 페이지 컨텐츠</p>
        <div>메인 페이지 포함 내용</div>
    </section>
    <footer>레이아웃 푸터</footer>
</body>
</html>

즉, 기본 뼈대(레이아웃)는 유지하면서, 각 페이지에서 작성한 <title>과 <section>만 교체된 결과를 얻는다.

 

마무리하며

타임리프의 레이아웃 기능은 공통 부분과 개별 부분을 분리해서 관리할 수 있게 도와준다.

 

덕분에 프로젝트 전체의 일관성을 유지할 수 있고, 공통 코드의 수정도 한 곳에서만 하면 되기 때문에 유지보수가 훨씬 수월하다. 또한 페이지마다 필요한 리소스를 쉽게 추가할 수 있어 개발 생산성도 올라간다.

 

정리하면, 템플릿 조각이 “작은 단위의 재사용”이라면, 레이아웃은 “전체 페이지 구조의 재사용”이라고 이해하면 쉽다.

 

 

감사합니다.

'타임리프' 카테고리의 다른 글

[타임리프] 체크박스  (0) 2025.09.17
[Thymeleaf] 템플릿 조각  (0) 2025.09.16
[Thymeleaf] 자바스크립트 인라인  (0) 2025.09.16
[Thymeleaf] 블록  (0) 2025.09.16
[Thymeleaf] 주석  (0) 2025.09.16
'타임리프' 카테고리의 다른 글
  • [타임리프] 체크박스
  • [Thymeleaf] 템플릿 조각
  • [Thymeleaf] 자바스크립트 인라인
  • [Thymeleaf] 블록
0kingki_
0kingki_
자바 + 스프링 웹 개발
  • 0kingki_
    0kingki_
    0kingki_
  • 전체
    오늘
    어제
    • 분류 전체보기 (134)
      • 코딩 테스트 (54)
      • 자바 (21)
      • 스프링 (27)
      • 타임리프 (16)
      • 스프링 데이터 JPA (8)
      • 최적화 (2)
      • QueryDSL (4)
      • AWS (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백준
    코딩테스트
    dfs
    타임리프
    JPA
    불변객체
    BFS
    스프링
    코딩 테스트
    예외 처리
    mvc
    thymeleaf
    QueryDSL
    객체지향
    다형성
    LocalDateTime
    컬렉션
    재귀
    최적화
    Java
    쿼리
    SpringDataJpa
    쿼리dsl
    예외처리
    자바
    스프링 컨테이너
    fetch join
    SOLID
    spring
    스프링 데이터 JPA
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
0kingki_
[Thymeleaf] 템플릿 레이아웃
상단으로

티스토리툴바