๐Ÿ“š Study/Spring

Thymeleaf Fragment (Fragment ๋‚˜๋ˆ„๊ธฐ)

kkh1902 2022. 9. 6. 04:05
728x90
๋ฐ˜์‘ํ˜•

Fragment๋กœ ๋ ˆ์ด์•„์›ƒ์„ ๋‚˜๋ˆ„๊ณ  ๊ฐ ํŽ˜์ด์ง€์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” Fragment๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋„˜๊ธธ์ˆ˜๋„ ์žˆ๋‹ค.

 

Thymeleaf Fragment - 1 : Fragment๋ฅผ ๋‚˜๋ˆ„๊ธฐ
Thymeleaf Fragment - 2 : ํŒŒ๋ผ๋ฏธํ„ฐ ์ „๋‹ฌ, ์‚ฌ์šฉํ•˜๊ธฐ

 

 

 

Thymeleaf Fragment ๋‚˜๋ˆ„๊ธฐ

๊ฐœ๋ฐœํ™˜๊ฒฝ์€ Springboot + Thymeleaf๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์—ˆ๊ณ 

ํ”„๋กœ์ ํŠธ์—์„œ Thymeleaf๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์œ„ํ•ด Thymeleaf ์˜์กด์„ฑ ์ฃผ์ž…,

Web์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Spring-boot-starter-web ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์•˜๋‹ค.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

 

 

Fragment ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜๋ˆ„์–ด ์ƒ์„ฑํ•˜์˜€๋‹ค.

  • header (html ํ—ค๋” ์˜์—ญ)
  • nav (์ƒ๋‹จ์˜ ๋ฉ”๋‰ด ์˜์—ญ)
  • footer (ํ•˜๋‹จ์˜ footer ์˜์—ญ)

๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

 

๊ฐ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ํŽ˜์ด์ง€๋Š” fragments ๋””๋ ‰ํ† ๋ฆฌ์— ์ƒ์„ฑํ•˜๊ณ 

๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ ํ•ด๋‹น fragment(๊ณตํ†ต๋ถ€๋ถ„)๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ• ๊ฒƒ์ด๋‹ค.

 

 

๋จผ์ € header.html์—์„œ๋Š” ํŽ˜์ด์ง€์˜ head ๋ถ€๋ถ„์—์„œ ํ•ด๋‹นํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Thymeleaf๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์„ ์–ธ์œผ๋กœ html ํƒœ๊ทธ์— xmlns:th="http://www.thymeleaf.org"๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

    <head th:fragment="fragment-header">
        <title>Thymeleaf Fragment</title>

        <!-- Bootstrap -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
        <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

    </head>

</html>

 

head ๋ถ€๋ถ„์„ fragment๋กœ ์„ ์–ธํ•˜๋ ค๋ฉด headํƒœ๊ทธ์— th:fragment="fragment๋ช…"์„ ์ž‘์„ฑํ•ด์ค€๋‹ค.

์„ ์–ธํ•œ fragment๋ช…์œผ๋กœ ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ ํ•ด๋‹น fragment๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

th:fragment๋Š” ํ•ด๋‹น ๋ถ€๋ถ„์„ fragment๋กœ ์„ ์–ธํ•œ๋‹ค๋Š” ์˜๋ฏธ

 

๋‹ค๋ฅธ ํŽ˜์ด์ง€ ํ™”๋ฉด์—์„œ๋Š” ์ด ์„ ์–ธํ•œ fragment๋ฅผ ๊ฐ€์ ธ์™€๋ณด์ž.

 

 

index.html ์—์„œ fragment-header๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด th:replace๋กœ fragment๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <div th:replace="/fragments/header.html :: fragment-header"></div>
</head>
<body>

    Index Page
    
</body>
</html>

 

Index ํŽ˜์ด์ง€์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด  fragment๋กœ ์„ ์–ธํ•ด๋†“์€ fragment-header๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด

head ๋ถ€๋ถ„์— th:replace="fragment ์œ„์น˜ :: fragment๋ช…" ์„ ํ˜ธ์ถœํ•˜์—ฌ fragment๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ์ˆ˜ ์žˆ๋‹ค.

th:replace๋Š” ํ•ด๋‹น ํƒœ๊ทธ์— fragment๋กœ ์„ ์–ธํ•œ ์ฝ”๋“œ๋กœ ๋ฐ”๊พผ๋‹ค๋Š” ์˜๋ฏธ

 

 

์œ„ 2๊ฐ€์ง€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ ํ›„ ์‹คํ–‰ํ•œ๋’ค ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋ฅผ ์—ด์–ด์„œ ํ™•์ธํ•ด๋ณด๋ฉด head๋ถ€๋ถ„์— fragment-header์—์„œ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ  ๊ฐ€์ ธ์˜จ๊ฑธ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

head์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ footer์™€ nav๋„ ์ž‘์„ฑํ•ด๋ณด์ž.

 

footer.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <footer th:fragment="fragment-footer" class="footer">
        <div class="row justify-content-center">
            <img class="mb-2" alt="" width="20" src="data:image/png;base64,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">
            <small class="d-block mb-3 ml-3 text-muted">&copy;GHSONG 2020</small>
        </div>
    </footer>
</html>

 

nav.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <div th:fragment="fragment-nav">
        <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
            <a class="navbar-brand" href="#">์ƒ๋‹จ๋ฉ”๋‰ด</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav mr-auto">
                    <li class="nav-item active">
                        <a class="nav-link" href="#" th:href="@{/index}">๋ฉ”์ธ <span class="sr-only">(current)</span></a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" th:href="@{/index2}">์„ค์ •</a>
                    </li>
                </ul>
                <form class="form-inline my-2 my-lg-0">
                    <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
                    <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
                </form>
            </div>
        </nav>
    </div>
</html>

 

๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋  fragment๋ฅผ ์„ ์–ธ ํ›„ ํŽ˜์ด์ง€์—์„œ fragmet๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

 

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <div th:replace="/fragments/header.html :: fragment-header"></div>
</head>
<body>

    <div th:replace="/fragments/nav.html :: fragment-nav"></div>

    <!-- ํŽ˜์ด์ง€ ์†Œ์Šค -->
    <div class="jumbotron jumbotron-fluid">
        <div class="container">
            <h1 class="display-4">Index</h1>
            <p class="lead">ghsong tistory</p>
        </div>
    </div>
    <!-- ํŽ˜์ด์ง€ ์†Œ์Šค -->

    <footer th:replace="/fragments/footer.html :: fragment-footer"></footer>

</body>
</html>

 

fragment๋กœ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๊ณ  ๊ฐ ํŽ˜์ด์ง€์˜ ์†Œ์Šค๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋ ˆ์ด์•„์›ƒ์„ ๋‚˜๋ˆŒ์ˆ˜ ์žˆ๋‹ค.

 

 

๋‹ค๋ฅธ ํŽ˜์ด์ง€๋„ ์ž‘์„ฑํ•˜์—ฌ ๋น„๊ตํ•ด๋ณด์ž.

 

index2.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <div th:replace="/fragments/header.html :: fragment-header"></div>
    <style>
        .jumbotron {background-color: aqua !important;}
    </style>
</head>
<body>

    <div th:replace="/fragments/nav.html :: fragment-nav"></div>

    <div class="jumbotron jumbotron-fluid">
        <div class="container">
            <h1 class="display-4">Index2</h1>
            <p class="lead">ghsong tistory</p>
        </div>
    </div>

    <div th:replace="/fragments/footer.html :: fragment-footer"></div>

</body>
</html>

 

index2 ํŽ˜์ด์ง€์—์„œ๋Š” ๊ณตํ†ต head ๋ถ€๋ถ„ ๋ง๊ณ ๋„ ์ด ํŽ˜์ด์ง€์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ฝ”๋“œ๋ฅผ ๋„ฃ์—ˆ๋Š”๋ฐ

head ๋ถ€๋ถ„์— fragment ์„ ์–ธ๋ถ€๋ถ„ ์•„๋ž˜์— <style> ํƒœ๊ทธ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ํ•ด๋‹น ํŽ˜์ด์ง€์—์„œ๋งŒ ์‚ฌ์šฉํ•  style์„ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด style ํƒœ๊ทธ๋Š” index ํŽ˜์ด์ง€์—์„œ๋Š” ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.

 

index.html ํ™”๋ฉด

 

index2.html ํ™”๋ฉด

 

 

์ด์ฒ˜๋Ÿผ Thymeleaf๋ฅผ ์‚ฌ์šฉํ• ๋•Œ fragment๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ th:fragmet๋กœ ์„ ์–ธ, th:replace๋กœ ํ˜ธ์ถœํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ์„

๋ณด๋‹ค ์‰ฝ๊ฒŒ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.

 

git source : https://github.com/sgoho01/Thymeleaf-Fragments/tree/fragment

728x90
๋ฐ˜์‘ํ˜•