[Thymeleaf] 05.레이아웃 재사용
이번 포스트에서는 Thymeleaf에서 페이지의 레이아웃을 재사용하기 위한 thymeleaf-layout-dialect에 대해 살펴보자.
레이아웃 재사용
웹 페이지 레이아웃의 특징
Thymeleaf에서는 th:fragment, th:insert, th:replace를 이용해서 페이지마다 반복되는 뷰 부분(fragment)을 모듈화 하고 재사용할 수 있었다. 웹 페이지를 작성하다 보면 이런 fragment 만 복되드는 것이 아니라 레이아웃도 반복되는 것을 쉽게 알 수 있다.
위 그림을 보면 regist.html과 modify.html은 header+footer fragment에 각각의 content가 들어간 것을 알 수 있다. detail.html과 manage.html은 base-layout에 추가로 control을 위한 fragment가 추가된 레이아웃이다.
이런 layout을 재사용하기 위해서는 thymeleaf-layout-dialect라는 라이브러리를 사용할 수 있다.
설치
thymeleaf-dialect-layout(https://ultraq.github.io/thymeleaf-layout-dialect/)은 maven 등을 이용해서 간단히 설치할 수 있다.
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
페이지 구성
기본 절차
thymeleaf-dialect-layout을 사용할 때는 다음의 과정을 거친다.
- fragment를 작성한다.
- fragment를 이용해서 layout을 작성한다.
- layout에 content를 추가해서 페이지를 구성한다.
header와 footer, config fragment 작성
재사용되는 fragment의 작성방법은 기존과 동일하다. 하지만 여기서는 이런 fragment가 커질 것을 대비해서 fragment별로 html을 만들어보자.
<!--/fragments/header.html-->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div th:fragment="header(mainTitle)">
<h1 th:text="${mainTitle}">Welcome To Board App</h1>
<hr>
</div>
</html>
<!--/fragments/footer.html-->
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div th:fragment="footer">
<hr>
<p>since 2024</p>
</div>
</html>
<!--/fragments/config.html-->
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<th:block th:fragment="config">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet">
</th:block>
</html>
layout 작성
페이지의 틀 역할을 하는 layout에서는 fragment들을 사용하고 content가 들어올 자리를 표시해주면 된다.
이를 위해 먼저 xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" 를 추가해야 한다. fragment를 사용하기 위한 th:replace, th:insert의 사용은 동일하다. 마지막으로 페이지 마다 달라지는 content를 받아들이기 위해서 layout:fragment 를 사용하면 된다. header fragment에 전달될 값인 mainTitle은 이 layout이 사용될 때 전달될 내용이므로 변수로 처리해 주자.
<!doctype html>
<!-- th와 layout namespace 추가-->
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8" />
<th:block th:replace="~{fragments/config::config}"></th:block>
<title th:text="${headTitle}"></title>
</head>
<body>
<div th:replace="~{fragments/header :: header(${mainTitle})}"></div>
<!-- 각 페이지별로 달라지는 content가 표시될 영역-->
<div layout:fragment="content"></div>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
content 작성
마지막으로 layout을 사용해보자. html 태그에서 layout:decorate를 통해 사용할 layout을 지정하고 필요한 파라미터를 전달한다.
그리고 layout에서 선언한 layout:fragment="content"를 채울 내용만 공급해주면 된다. 이 파일은 단순히 content를 공급하는 역할이므로 이외의 내용은 화면에 표시되지 않는다.
<!--index.html-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layouts/layout-basic(mainTitle='Board App에 오신것을 환경합니다.',
headTitle='board app')}">
<body>
<h1>어차피 content만 공급하는 용도니 이런건 안나오겠죠?</h1>
<!-- layout에서 선언한 layout:fragment='content'를 채울 내용 작성-->
<div layout:fragment="content" class="container">
<h1>layout: 고유의 내용</h1>
</div>
</body>
</html>
위 페이지의 실행 결과는 아래와 같다.