▼ Backend/└ 게시판 만들기

Spring Boot (게시판) | Header, Footer 공통영역 레이아웃 설정

Valar 2021. 11. 1. 17:00
반응형

📌 구성환경

SpringBoot, Gradle, Thymeleaf, Jpa(JPQL), Jar, MariaDB

 

Thymeleaf Layout

Header, Footer와 같이 공통적으로 사용되는 코드를 화면마다 작성하지 않고 레이아웃 처리를 통해 공통 내용은 고정적으로 설정함으로써, 본래의 콘텐츠 내용에 집중할 수 있게 도와준다.

 

build.gradle

implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'

 

 

Gradle Refresh (적용)

프로젝트 우 클릭    Gradle    Refresh Gradle Project

 

 

헤더 HTML

header.html (/src/main/resources/templates/fragments)

 

각 화면의 상단 부분에 공통적으로 들어갔던 영역을 작성한다.

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <th:block th:fragment="headerFragment">
    <head>
      <title>Board List</title>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1"/>
      <!--부트스트랩 css 추가-->
      <link rel="stylesheet" href="/css/lib/bootstrap.min.css">
      <!--jQuery 추가-->
      <script src="/js/lib/jquery.min.js"></script>
      <!--부트스트랩 script 추가-->
      <script src="/js/lib/bootstrap.min.js"></script>
    </head>
  </th:block>
</html>

 

푸터 HTML

footer.html (/src/main/resources/templates/fragments)

 

각 화면의 하단 부분에 공통적으로 들어갔던 영역을 작성한다.

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <th:block th:fragment="footerFragment">
    <div class="card mt-5">
        <div class="card-body text-center">
            <p class="card-text">
                <small class="text-muted">Copyright © Venh.log Tistory Corp. All Rights Reserved.</small>
            </p>
        </div>
    </div>
  </th:block>
</html>

 

레이아웃 HTML

default_layout.html (/src/main/resources/templates/layout)

 

각 화면의 구성에 대한 설정을 한다.

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
    <th:block th:replace="fragments/header :: headerFragment"></th:block>
        <body>
            <th:block layout:fragment="content"></th:block>
        </body>
    <th:block th:replace="fragments/footer :: footerFragment"></th:block>
</html>

 

※ 본문 (실제 각 화면에 들어가는 내용)

1. html 태그에 레이아웃 설정을 해준다.

  • xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
  • layout:decorator="layout/default_layout"

2. th:block에 layout:fragment 설정을 한다.

  • layout:fragment="content"

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout/default_layout">
	<!-- layout Content -->
	<th:block layout:fragment="content">
    	[본문 작성 영역..]
	</th:block>
</html>

 

적용된 목록 HTML

list.html (/src/main/resources/templates/board)

 

<!DOCTYPE html>
<html
    xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout/default_layout">
    <!-- layout Content -->
    <th:block layout:fragment="content">
        <div id="wrapper">
            <div class="container">
                <form action="/board/list" id="frm" method="get">
                    <div class="col-md-12 mt-4">
                        <button type="button" class="btn btn-danger" onclick="fnDelete()">Delete</button>
                        <button type="button" class="btn btn-primary" onclick="javascript:location.href='/board/write'">Register</button>
                        <table class="table table-striped table-horizontal table-bordered mt-3">
                            <thead class="thead-strong">
                                <tr>
                                    <th width="5%"><input type="checkbox" id="chkAll"></th>
                                    <th width="10%">No.</th>
                                    <th width="">Title.</th>
                                    <th width="20%">Writer.</th>
                                    <th width="10%">Views.</th>
                                    <th width="20%">Reg Time.</th>
                                </tr>
                            </thead>
                            <tbody id="tbody">
                                <tr th:each="list,index : ${resultMap.list}" th:with="paging=${resultMap.paging}">
                                    <td>
                                        <input type="checkbox" name="deleteId" th:value="${list.id}">
                                    </td>
                                    <td>
                                        <span th:text="${(resultMap.totalCnt - index.index) - (paging.pageNumber * paging.pageSize)}"></span>
                                    </td>
                                    <td>
                                        <a th:href="@{./view(id=${list.id})}">
                                            <span th:text="${list.title}"></span>
                                        </a>
                                    </td>
                                    <td>
                                        <span th:text="${list.registerId}"></span>
                                    </td>
                                    <td>
                                        <span th:text="${list.readCnt}"></span>
                                    </td>
                                    <td>
                                        <span th:text="${list.registerTime}"></span>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        <div class="row">
                            <div class="col">
                                <ul class="pagination">
                                    <li class="page-item" th:each="index : ${#numbers.sequence(1, resultMap.totalPage)}" th:with="paging=${resultMap.paging}">
                                        <a class="page-link" th:classappend="${paging.pageNumber ==  (index-1)} ? bg-primary : bg-secondary" th:href="@{./list(page=${index - 1},page=${paging.pageSize})}">
                                            <span class="text-white" th:text="${index}"></span>
                                        </a>
                                    </li>
                                </ul>
                            </div>
                        </div>
                    </div>
                </form>
            </div>
        </div>
        <script th:inline="javascript">
            // header checkbox event
            $("#chkAll").click(function () {
                if (this.checked) {
                    $("input[name='deleteId']").prop("checked", true);
                } else {
                    $("input[name='deleteId']").prop("checked", false);
                }
            });
            // body checkbox event
            $("input[name='deleteId']").click(function () {
                let delInpLen = $("input[name='deleteId']").length;
                let delInpChkLen = $("input[name='deleteId']:checked").length;
                if (delInpLen == delInpChkLen) {
                    $("#chkAll").prop("checked", true);
                } else {
                    $("#chkAll").prop("checked", false);
                }
            });
            function fnDelete() {
                let delInpChkLen = $("input[name='deleteId']:checked").length;
                if (delInpChkLen > 0) {
                    if (confirm("Do you want to delete it?")) {
                        let frm = $("#frm");
                        frm.attr("action", "/board/delete");
                        frm.attr("method", "post");
                        frm.submit();
                    }
                } else {
                    alert("Not selected.");
                }
            }
        </script>
    </th:block>
</html>

 

 

테스트

 

 

※ thymeleaf:thymeleaf-layout-dialect의 최신 버전 적용 후  Layout 설정이 적용이 안될 때

layout:decorator="layout/default_layout"
↓
layout:decorate="~{layout/default_layout}"

 

GitHub

https://github.com/conf312/board_study.git

 

프로젝트 Import

압축을 풀고, 이클립스 import    General    Existing Projects into Workspace

board.zip
0.21MB

 

반응형