[SpringBoot] Thymeleaf의 레이아웃 기능

aseol·2023년 10월 11일
0

Thymeleaf의 레이아웃 기능

: ragments 를 이용해서 레이아웃을 분리하고 조립하는 방식의 페이지 처리 가능

프로세스

https://mvnrepository.com/

Thymeleaf Layout Dialect 검색하여 3.3.0 버전 클릭

Maven 선택하여 해당 코드 복사 

pom.xml 파일을 열어 </dependencies> 전에 붙여 넣기


css 파일 복사하여 static 폴더 하위에 붙여 넣기

main.html

fragment로 구성요소 정의하기

⭐ (계속 재사용할 부분을 제외한) 고정되는 부분을 조각으로 빼기 🔽
프로젝트 내 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>

0개의 댓글

관련 채용 정보