Thymeleaf Layout 재정리

Kang.__.Mingu·2025년 1월 1일

Spring Boot

목록 보기
5/8
post-thumbnail

레이아웃을 적용하는 이유?

  1. 편안함(복붙할 이유가 없음)
  2. 유지보수(header, footer에 문제가 생기면 하나만 고치면 됨)

기본 세팅

  • Thymeleaf-Layout

  • 최신 버전 들어가서 Gradle(short) 누르고 build.gradle에 추가해주면 됨

  • application.properties에 타임리프 설정

# thymeleaf
spring.thymeleaf.enabled=true
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

spring.thymeleaf.enabled=true
thymeleaf 사용 활성화
spring.thymeleaf.cache=false
개발 환경에서는 소스코드 변경을 자주하기 때문에 캐시 저장은 꺼두고 작업하는게 좋음.
=> 배포 환경에서는 캐시 활성화 해주기
spring.thymeleaf.prefix=classpath:/templates/
thymeleaf에서 파일 경로 지정 시 자동으로 붙여쥬눈 prefix 설정.
/templates/ 경로에 파일을 생성하고 저장한다 했으니 thymeleaf 파일은 templates 폴더에 위치시키고 다음 경로 작성하며 된다.
spring.thymeleaf.suffix=.html
thymeleaf에서 파일 경로 마지막에 .html을 자동으로 붙여준다.


폴더 구조 같은 경우에는 세분화하여 작업하는 걸 중요하시하는 성격이라

templates>common>fragments,templates>common>layouts,templates>pages>main, templates>pages>user 이런식으로 나눠서 작업한다.

fragment 속성

  • fragment는 부서진 조각이라는 뜻으로 추후 layout에서 조각을 모아 붙여야한다.

  • 다른 HTML 문서에 태그를 제공하기 위한 Thymeleaf 속성

  • 속성값으로 태그를 구분하기 위한 식별자를 속성값으로 설정

config.html

templates>common>fragments>config.html
config.html에서는 공통적으로 작업하는 파일들을 추가하고 관리할 수 있다.

js, css, font 등등을 관리하기 위해 공통 작업 파일 생성

xmlns:th="http:www.thymeleaf.org
thymeleaf를 사용하기 위해 추가

<head th:fragment="ConfigFragment">
추후 head에 교체하기 위해 설정

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:fragment="ConfigFragment">
    <meta charset="UTF-8">
    <title>config</title>
    <!-- 공통적으로 사용되는 파일들을 추가하고 관리하기 위한 파일 -->
    <!-- ex) 부트스트랩 같은 css, js -->

    <!-- jQuery -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <!-- 부트스트랩 JS -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
    <!-- 부트스트랩 CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
</head>
<body>
</body>
</html>

header.html

templates>common>fragments>header.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" >
<head>
    <meta charset="UTF-8">
    <title>header</title>
</head>
<body>
<header th:fragment="HeaderFragment" class="p-3 text-bg-dark">
    <div class="container">
        <div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
            <a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none">
                <svg class="bi me-2" width="40" height="32" role="img" aria-label="부트스트랩"><use xlink:href="#bootstrap"></use></svg>
            </a>

            <ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
                <li><a href="#" class="nav-link px-2 text-secondary"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;"></font></font></a></li>
                <li><a href="#" class="nav-link px-2 text-white"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">특징</font></font></a></li>
                <li><a href="#" class="nav-link px-2 text-white"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">가격</font></font></a></li>
                <li><a href="#" class="nav-link px-2 text-white"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">자주 묻는 질문</font></font></a></li>
                <li><a href="#" class="nav-link px-2 text-white"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">에 대한</font></font></a></li>
            </ul>

            <form class="col-12 col-lg-auto mb-3 mb-lg-0 me-lg-3" role="search">
                <input type="search" class="form-control form-control-dark text-bg-dark" placeholder="찾다..." aria-label="찾다">
            </form>

            <div class="text-end">
                <button type="button" class="btn btn-outline-light me-2"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">로그인</font></font></button>
                <button type="button" class="btn btn-warning"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">가입하기</font></font></button>
            </div>
        </div>
    </div>
</header>
</body>
</html>

footer.html

templates>common>fragments>footer.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" >
<head>
    <meta charset="UTF-8">
    <title>footer</title>
</head>
<body>
<div th:fragment="FooterFragment" class="container">
    <footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
        <div class="col-md-4 d-flex align-items-center">
            <a href="/" class="mb-3 me-2 mb-md-0 text-body-secondary text-decoration-none lh-1">
                <svg class="bi" width="30" height="24"><use xlink:href="#bootstrap"></use></svg>
            </a>
            <span class="mb-3 mb-md-0 text-body-secondary">© 2024 Company, Inc</span>
        </div>

        <ul class="nav col-md-4 justify-content-end list-unstyled d-flex">
            <li class="ms-3"><a class="text-body-secondary" href="#"><svg class="bi" width="24" height="24"><use xlink:href="#twitter"></use></svg></a></li>
            <li class="ms-3"><a class="text-body-secondary" href="#"><svg class="bi" width="24" height="24"><use xlink:href="#instagram"></use></svg></a></li>
            <li class="ms-3"><a class="text-body-secondary" href="#"><svg class="bi" width="24" height="24"><use xlink:href="#facebook"></use></svg></a></li>
        </ul>
    </footer>
</div>
</body>
</html>

Layout

Layout에서는 fragment(부서진 조각)을 모아서 작품을 만드는 역할을 한다.
xmlns:th="http://www.thymeleaf.org"
thymeleaf를 사용하기 위해서 필요함

xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout을 사용하려면 xmlns에 추가해줘야됨

replace 속성

  • fragment 속성으로 설정된 태그를 제공받아 태그를 변경하는 Thymeleaf 속성

  • ~{HTML 문서 경로 :: Fragment 식별자} 형식으로 속성값을 설정해 태그를 제공받아 사용

  • insert 속성 또는 include 속성으로 fragment 속성으로 설정된 태그를 제공받아 사용 가능

defaultLayout.html

templates>common>layouts>defaultLayout.html

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head th:replace="~{common/fragments/config :: ConfigFragment}">
    <meta charset="UTF-8">
    <title>Layout</title>
</head>
<body>
<!-- header와 footer를 화면 상단과 하단에 붙여놓기 위한 설정 -->
<div class="d-flex flex-column min-vh-100">
    <header th:replace="~{common/fragments/header :: HeaderFragment}"></header>

    <th:block class="flex-grow-1" layout:fragment="content"></th:block>

    <footer th:replace="~{common/fragments/footer :: FooterFragment}"></footer>
</div>
</body>
</html>

content

decorate 속성

  • 응답 처리될 템플릿 페이지의 HTML 문서의 파일을 설정

main.html

templates>pages>main>main.html
defayltLayout.html에서 layout:fragment="content" 설정한 부분에 들어갈 내용을 작성하는것이다.
쉽게 말해 그때 그때 필요한 content 부분을 교체해준다고 생각하면 된다.

=> decorate를 설정한 페이지에서 이름이 같은 layout:fragment 부분을 교체한다

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{common/layouts/defaultLayout}"
      >
<head>
    <meta charset="UTF-8">
    <title>main</title>
</head>
<body>
    <main layout:fragment="content">
        <p class="container">메인페이지</p>
    </main>
</body>
</html>

Container

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

@Controller
@RequestMapping("/th")
public class LayoutController {
    @GetMapping("/test")
    public String fragment() {
        return "pages/main/main";
    }
}

profile
최선을 다해 꾸준히 노력하는 개발자 망고입니당 :D

0개의 댓글