: ragments
를 이용해서 레이아웃을 분리하고 조립하는 방식의 페이지 처리 가능
Thymeleaf Layout Dialect 검색하여 3.3.0 버전 클릭
Maven 선택하여 해당 코드 복사
pom.xml 파일을 열어 </dependencies>
전에 붙여 넣기
⬇
css 파일 복사하여 static 폴더 하위에 붙여 넣기
main.html
⭐ (계속 재사용할 부분을 제외한) 고정되는 부분을 조각으로 빼기 🔽
프로젝트 내 fragments 폴더 만들고 header, aside, footer 영역 html 파일 생성하여 main.html을 뜯어서 각 부분에 붙여 주기
th:fragment="조각이름" 추가
프로젝트 내 layout 폴더 만들고 dufault.html 파일 생성
thymeleaf > Ecosystem > thymeleaf-layout-dialect > 깃허브 코드 복사
붙여 넣기
main.html 의 head, body 영역 모두 지우고 layout:decorate
속성 작성
// MainController.java
@Controller
public class MainController {
@GetMapping("/")
public String mainPage(Model model) {
model.addAttribute("title","메인화면");
model.addAttribute("content", "Spring Boot thymeleaf layout");
model.addAttribute("content2", "동적인 영역");
return "main";
}
}
main.html 화면 🔽
admin과 user의 컨트롤러 이름을 동일하게 설정하여 에러 발생
수정 예시 🔽
localhost
admin에서도 GET [/] 사용하고 user에서도 GET [/]를 사용하여 나는 에러
admin("/") httpmethod get
user("/") httpmethod get
수정 예시 🔽
admin("/admin") httpmethod get
user("/user") httpmethod get
or
admin("/") httpmethod get
user("/") httpmethod post
httpmethod 방식이 다름
페이지 depth 예시 🔽
첫 번째 방법이 두 번째 방법보다 관리하기 수월하다
static > admin > css 파일 폴더 복사하기
> user > css 파일 폴더 복사하기
templates > admin > fragments > aside.html
> footer.html
> header.html
> layout > default.html
> user > fragments > aside.html
> footer.html
> header.html
> layout > default.html
<!-- default.html 생성-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
</body>
</html>
추가 🔽
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
</html>
❗ gentelella-1.4.0/production/tables_dynamic.html 페이지 사용
부트스트랩 파일에서 head 부분 복사해서 가져오기 (Datatables 제외) + title 수정
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- Meta, title, CSS, favicons, etc. -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
✔ <title th:text="${title}"></title>
<!-- Bootstrap -->
<link href="../vendors/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="../vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<!-- NProgress -->
<link href="../vendors/nprogress/nprogress.css" rel="stylesheet">
<!-- iCheck -->
<link href="../vendors/iCheck/skins/flat/green.css" rel="stylesheet">
<!-- Custom Theme Style -->
<link href="../build/css/custom.min.css" rel="stylesheet">
</head>
</html>
경로를 올바르게 수정 🔽
href=""
➡th:href="@{}
<title th:text="${title}"></title>
<!-- Bootstrap -->
<link th:href="@{/admin/vendors/bootstrap/dist/css/bootstrap.min.css}" rel="stylesheet">
<!-- Font Awesome -->
<link th:href="@{/admin/vendors/font-awesome/css/font-awesome.min.css}" rel="stylesheet">
<!-- NProgress -->
<link th:href="@{/admin/vendors/nprogress/nprogress.css}" rel="stylesheet">
<!-- iCheck -->
<link th:href="@{/admin/vendors/iCheck/skins/flat/green.css}" rel="stylesheet">
<!-- Custom Theme Style -->
<link th:href="@{/admin/build/css/custom.min.css}" rel="stylesheet">
부트스트랩 파일에서 body 부분 복사해서 가져오기 🔽
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
...
</head>
<body class="nav-md">
<div class="container body">
<div class="main_container">
<!-- aside 메뉴 시작 -->
<div class="col-md-3 left_col">
...
</div>
<!-- aside 메뉴 끝 -->
...
</body>
</html>
aside 영역에 해당하는 코드를 복사하여 aside.html에 붙여 넣고 th:fragment=""
추가한 뒤, default.html의 해당 코드는 모두 지우고 th:replace
속성 추가🔽
th:fragment
➡ 현재 템플릿에서 이름을 가진 템플릿 조각을 정의한다.
정의한 조각(프래그먼트)을 다른 곳에서 th:replace 또는 th:insert 등의 속성을 사용하여 호출하거나 재사용할 수 있다.
th:replace
➡ 다른 템플릿에서 프래그먼트를 사용할 수 있게 해 준다
<!-- aside.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="col-md-3 left_col" th:fragment="asideFragment">
...
</html>
<!-- default.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
...
</head>
<body class="nav-md">
<div class="container body">
<div class="main_container">
<!-- aside 메뉴 시작 -->
<div th:replace="~{admin/fragments/aside :: asideFragment}"></div>
<!-- aside 메뉴 끝 -->
...
</body>
</html>
위 과정을 header와 footer에도 마찬가지로 적용해 준다
right 컬럼 부분 (동적 페이지 부분)
<!-- default.html -->
<div class="row">
<!-- 사용자정의 contents start -->
<th:block layout:fragment="customContents"></th:block>
<!-- 사용자정의 contents end -->
</div>
templates 하위의 main.html에
<!--main.html-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{admin/layout/default}">
<!-- 사용자별 css file 추가 부분 -->
<head>
</head>
<!-- 사용자 페이지별 javascript file 추가-->
<th:block layout:fragment="customJsFile">
</th:block>
<!-- 사용자별 스크립트 작성 -->
<th:block layout:fragment="customJsCode">
</th:block>
<!--/* layout:decorate 이부분의 파일에서 사용자 정의로 선언한 조각에 작성한 html코드를 삽입 */-->
<th:block layout:fragment="customContents">
</th:block>
</html>
💡 Thymeleaf 템플릿 엔진에서 레이아웃 관리를 위해 사용되는 속성
layout:decorate
➡ 주로 기본 레이아웃 템플릿을 정의하고, 이 템플릿에 내용을 포함시킬 때 사용
layout:fragment
➡ layout:decorate 속성으로 레이아웃 템플릿에 전체 페이지 레이아웃을 설정한 이후 템플릿 내에서 layout:fragment 속성을 사용하여 구성 요소를 정의한다.
(layout:fragment를 작성해 줄 경우 기본 레이아웃을 덮어 쓴다)
사용자별 코드 추가한 예시 🔽
<!--memberList.html-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{admin/layout/default}">
<!-- 사용자별 css file 추가 부분 -->
<head>
<!-- Datatables -->
<link th:href="@{/admin/vendors/datatables.net-bs/css/dataTables.bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/admin/vendors/datatables.net-buttons-bs/css/buttons.bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/admin/vendors/datatables.net-fixedheader-bs/css/fixedHeader.bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/admin/vendors/datatables.net-responsive-bs/css/responsive.bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/admin/vendors/datatables.net-scroller-bs/css/scroller.bootstrap.min.css}" rel="stylesheet">
</head>
<!-- 사용자 페이지별 javascript file 추가-->
<th:block layout:fragment="customJsFile">
<!-- Datatables -->
<script th:src="@{/admin/vendors/datatables.net/js/jquery.dataTables.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-bs/js/dataTables.bootstrap.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-buttons/js/dataTables.buttons.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-buttons-bs/js/buttons.bootstrap.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-buttons/js/buttons.flash.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-buttons/js/buttons.html5.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-buttons/js/buttons.print.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-fixedheader/js/dataTables.fixedHeader.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-keytable/js/dataTables.keyTable.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-responsive/js/dataTables.responsive.min.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-responsive-bs/js/responsive.bootstrap.js}"></script>
<script th:src="@{/admin/vendors/datatables.net-scroller/js/dataTables.scroller.min.js}"></script>
<script th:src="@{/admin/vendors/jszip/dist/jszip.min.js}"></script>
<script th:src="@{/admin/vendors/pdfmake/build/pdfmake.min.js}"></script>
<script th:src="@{/admin/vendors/pdfmake/build/vfs_fonts.js}"></script>
</th:block>
<!-- 사용자별 스크립트 작성 -->
<th:block layout:fragment="customJsCode">
<script>
$(function(){
alert('회원목록');
})
</script>
</th:block>
<!--/* layout:decorate 이부분의 파일에서 사용자 정의로 선언한 조각에 작성한 html코드를 삽입 */-->
<th:block layout:fragment="customContents">
<div class="col-md-12 col-sm-12
col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Responsive example<small>Users</small></h2>
<ul class="nav navbar-right panel_toolbox">
<li><a class="collapse-link"><i class="fa fa-chevron-up"></i></a>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-wrench"></i></a>
<ul class="dropdown-menu" role="menu">
<li><a
="#">Settings 1</a>
</li>
<li><a href="#">Settings 2</a>
</li>
</ul>
</li>
<li><a class="close-link"><i class="fa fa-close"></i></a>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<p class="text-muted font-13 m-b-30">
Responsive is an extension for DataTables that resolves that problem by optimising the table's layout for different screen sizes through the dynamic insertion and removal of columns from the table.
</p>
<table id="datatable-responsive" class="table table-striped table-bordered dt-responsive nowrap" cellspacing="0" width="100%">
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
<th>Extn.</th>
<th>E-mail</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger</td>
<td>Nixon</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011/04/25</td>
<td>$320,800</td>
<td>5421</td>
<td>t.nixon@datatables.net</td>
</tr>
<tr>
<td>Garrett</td>
<td>Winters</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011/07/25</td>
<td>$170,750</td>
<td>8422</td>
<td>g.winters@datatables.net</td>
</tr>
<tr>
<td>Ashton</td>
<td>Cox</td>
<td>Junior Technical Author</td>
<td>San Francisco</td>
<td>66</td>
<td>2009/01/12</td>
<td>$86,000</td>
<td>1562</td>
<td>a.cox@datatables.net</td>
</tr>
<tr>
<td>Cedric</td>
<td>Kelly</td>
<td>Senior Javascript Developer</td>
<td>Edinburgh</td>
<td>22</td>
<td>2012/03/29</td>
<td>$433,060</td>
<td>6224</td>
<td>c.kelly@datatables.net</td>
</tr>
<tr>
<td>Donna</td>
<td>Snider</td>
<td>Customer Support</td>
<td>New York</td>
<td>27</td>
<td>2011/01/25</td>
<td>$112,000</td>
<td>4226</td>
<td>d.snider@datatables.net</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</th:block>
</html>