2023.11.09 - [공부해야할 것/java] - [SpringBoot] 웹 프로젝트 만들기(4) - 템플릿 적용
여기서 이어진다
그 이전에 template 받은 파일좀 많이 열어봤는가 파일을 열어보면 각 페이지 별로 공통된 섹션이 있는걸 확인 할 수 있을것이다.
그저 의미 없이 나열해보인것처럼 보이겠지만 얼추 공통된 부분들이 보일것이다.
모든페이지에서 저 빨간부분이 반복됨을 확인할수 있을것이다.
저거 다 html인데 매페이지마다 똑같은거 복붙할것인가 귀찮지 아니한가 그래서 타임리프를 이용하여 그 모든페이지에서 한페이지의 소스만 긁어다가 템플릿을 하도록 만들것이다.
우선 ide를 키고 project를 열면 build.gradle이란 파일이 보일것이다.
거기에 뭐 블라블라 뭔가 이상한게 있을텐데 자세히 보면 우리가 spring initializer 했을 당시에 넣었던 dependencies와 연관된 자바패키지리스트가 들어있음을 알수 있다.
해당 부분에 implemntation이 모여있는 부분에 implementation을 하나 더 추가해준다
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.3.0'
해당부분을 추가한 뒤에 gradle 탭에서 reload all gradle project를 하자. 해당 라이브러리가 다운받아질 것이다.
이제 프로젝트 내에 src/main/resources/templates 경로 내에 fragment 폴더와 layout 폴더를 만들자
fragment는 우리가 아까 빨갛게 표시한 부분을 분리한 html파일을 넣을 부분이고
layout은 우리가 분리한 fragment들을 어떻게 배치할지 정하는 레이아웃 html파일을 넣을 예정이다.
fragment 내에 파일 4개를 만들어주자
- config.html
- css,javascript불러오는 html구문을 모아놓을 짬처리 부분이다.
- footer.html
- 말그대로 밑하단 관련된 html을 정의할 부분
- header.html
- 이것도 그 윗부분 검색하는 부분을 분리시켜 놓을 부분이다.
- sidebar.html
- 사이드바 부분을 분리시켜 놓을 부분이다
일단 빈 html부분중에 config.html을 연다
그냥 html 처음 만들면 다음과 같이 뜰텐데
이걸 지우고 다음과 같이 써준다
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org"
th:fragment="ConfigFragment">
</html>
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#fragment-specification-syntax
여기를 참조하면
In order to do this, Thymeleaf needs us to define these parts, “fragments”, for inclusion, which can be done using the
th:fragment attribute.
무튼 이렇게 조각조각 난거를 정의할때 th:fragment를 사용한다고 한다 그래서 나는 이 config.html의 fragment 부분을 ConfigFragment로 정의하였다.
이제 여기에 이전 템플릿에서 불러오는 모든 css파일,js파일 로드하는 소스 코드 부분을 붙여넣자. 나는 이전시간에 수정했던 index.html부분을 이용했다.
그냥 <link 로 시작하거나 <script로 시작하는 모든 부분을 긁어오자. 나는 지난시간 템플릿 파일들중 index.html파일을 참조 하여 만들었다.
긁어와서 만든 파일은 다음과 같다.
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org"
th:fragment="ConfigFragment">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/assets/img/favicon/favicon.ico" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
<!-- Icons. Uncomment required icon fonts -->
<link rel="stylesheet" href="/assets/vendor/fonts/boxicons.css" />
<!-- Core CSS -->
<link rel="stylesheet" href="/assets/vendor/css/core.css" class="template-customizer-core-css" />
<link rel="stylesheet" href="/assets/vendor/css/theme-default.css" class="template-customizer-theme-css" />
<link rel="stylesheet" href="/assets/css/demo.css" />
<!-- Vendors CSS -->
<link rel="stylesheet" href="/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />
<link rel="stylesheet" href="/assets/vendor/libs/apex-charts/apex-charts.css" />
<!-- Page CSS -->
<!-- Helpers -->
<script src="/assets/vendor/js/helpers.js"></script>
<!--! Template customizer & Theme config files MUST be included after core stylesheets and helpers.js in the <head> section -->
<!--? Config: Mandatory theme config file contain global vars & default theme options, Set your preferred theme option in this file. -->
<script src="/assets/js/config.js"></script>
<!-- build:js assets/vendor/js/core.js -->
<script src="/assets/vendor/libs/jquery/jquery.js"></script>
<script src="/assets/vendor/libs/popper/popper.js"></script>
<script src="/assets/vendor/js/bootstrap.js"></script>
<script src="/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.js"></script>
<script src="/assets/vendor/js/menu.js"></script>
<!-- endbuild -->
<!-- Vendors JS -->
<script src="/assets/vendor/libs/apex-charts/apexcharts.js"></script>
<!-- Main JS -->
<script src="/assets/js/main.js"></script>
<!-- Page JS -->
<script src="/assets/js/dashboards-analytics.js"></script>
<!-- Place this tag in your head or just before your close body tag. -->
<script async defer src="https://buttons.github.io/buttons.js"></script>
</head>
</html>
이제 sidebar.html부분으로 넘어가자. sidebar부분도 config.html부분처럼 th:fragment로 선언해준다.
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org"
th:fragment="SidebarFragment">
</html>
요즘 개발자들은 참해서 주석을 참 잘남겨둔다. 내가 받은 인덱스 파일들을 확인해보니 메뉴부분의 시작과 끝지점을 친절하게 표시해놓았다.
이부분을 고대로 복사해서 sidebar.html로 넣어주자.
다붙이면 너무길어서 대략 html내에 붙인 부분을 보여주었다.
이제 header.html부분도 똑같이 해주자
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org"
th:fragment="HeaderFragment">
</html>
선언해주고
index.html에 있는 부분중 <!-- Navbar -->로 감싸져있는 부분을 복붙해서 넣자
이제 마지막으로 footer도 동일한 작업을 진행한다.
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org" th:fragment="FooterFragment">
</html>
이번에 index html에서 <footer> 태그로 감싸져 있는 부분을 복붙해서 넣는다
다음은 이 만든 fragment 들을 어떻게 배치할지 지정하는 layout.html을 만들것이다.
layout 폴더에 layout.html을 만들자
layout.html을 다음과 같이 입력하자
<html lang="ko" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
</html>
저 xmlns:layout에 적힌 url은 위에서 다운받은 java 라이브러리 nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect에 대한 페이지다 해당 페이지를 가면 github와 설명이 써져있다
https://github.com/ultraq/thymeleaf-layout-dialect
대충 이거의 역할은 그 타임리프 레이아웃을 만들때 좀더 편한하게 만들어주는 기능이 들어 있는 라이브러리라 생각하면 된다. 얼추 느낌을 얘기하면 인텔리제이에서 sout치면 System.out.println()나오는 편의 기능같은 느낌이다.
layout.html을 다음과 같이 작성한다.
<html lang="ko" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head th:replace="~{fragment/config :: ConfigFragment}"><title></title></head>
<body>
<main class="main" id="top">
<div class="layout-wrapper layout-content-navbar"><!-- index.html 부분에서 해당 부분을 감싸는 div class 참조 -->
<div class="layout-container"><!-- index.html 부분에서 해당 부분을 감싸는 div class 참조 -->
<div th:replace="~{fragment/sidebar :: SidebarFragment}"></div>
<div class="layout-page"><!-- index.html 부분에서 해당 부분을 감싸는 div class 참조 -->
<nav th:replace="~{fragment/header :: HeaderFragment}"></nav>
<div class="content-wrapper"><!-- index.html 부분에서 해당 부분을 감싸는 div class 참조 -->
<div class="container-xxl flex-grow-1 container-p-y"><!-- index.html 부분에서 해당 부분을 감싸는 div class 참조 -->
<div th:block layout:fragment="content"></div>
</div>
<footer th:replace="~{fragment/footer :: FooterFragment}"></footer>
</div>
</div>
</div>
</div>
</main>
</body>
</html>
여기서 th:replace 해당 html을 요소를 다음과 같은 요소로 바꾸겟다는 얘기다
<head th:replace="~{fragment/config :: ConfigFragment}"><title></title></head>
이면 head 태그 내부를 fragment폴더내의 config.html 폴더에 있는 ConfigFragment 로 정의되 있는 부분으로 바꾸겠다는 것이다.
그럼 이제 헷깔리는 부분이 있을텐데
<div th:block layout:fragment="content"></div>
이것은 무엇인가 이부분은 content란 fragment가 들어갈 레이아웃 부분임을 명시해주는 구문이다.이제 각 페이지 별로 content라 정의된 fragment가 다 저 부분으로 들어갈 것이다.
이렇게 레이아웃이 완성됬다 그러면 이제 레이아웃을 적용을 해보자
main폴더에 test.html이라는 파일을 만들어보자 해당 파일을 만들고 다음과 같이 넣어주자
<html
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}">
<div layout:fragment="content">
넌 내게 모욕감을 줬어
</div>
</html>
https://ultraq.github.io/thymeleaf-layout-dialect/
해당 페이지 가보면
layout:decorate가 뭔지 설명이 잘나와있다.
layout:decorate="~{layout/layout}">는 layout폴더에 있는 layout.html을 이 페이지의 템플릿 양식으로 사용하겠다는 뜻이다
아까 layout.html에서 선언한
package com.kkkkim.forStudy.main.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MainController {
@RequestMapping("/")
public String main(Model modele) {
return "main/test";
}
}
이제 재가동을 하고 메인페이지로 가보자
맨처음에 탬플릿 봤던것과 똑같이 적용되있고 그리고 content내용이 제대로 들어가있음을 볼수 있을것이다.
하지만 진짜 제대로 적용됬는지 아리까리 할수 도 있기때문에 실제 여러페이지에서도 같은 템플릿이 되는지 적용해보자.
아까랑 똑같은 main폴더에 test2.html 을 만들어보자. 이 파일안에 아무요소나 넣어보자 나는 index.html에 있던 콘텐츠중에 아무거나 골라넣었다.
이제 mainController 파일로가서 test2라는 함수를 만들어 주고 재기동하자 test2는 test2.html로 이동하는 함수이다.
package com.kkkkim.forStudy.main.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MainController {
@RequestMapping("/")
public String main(Model modele) {
return "main/test";
}
@RequestMapping("test2")
public String test2(Model modele) {
return "main/test2";
}
}
이제 스프링 부트를 재가동 해보자 그리고 test2로 이동해보자(http://localhost:8080/test2)
복붙한 리소스가 잘 보임을 알수있고 템플릿도 잘 적용됨을 알수 있다.
'공부해야할 것 > java' 카테고리의 다른 글
[SpringBoot] 웹 개발(7) - 로그인 기능 만들기(2)(회원 가입) (1) | 2023.11.11 |
---|---|
[SpringBoot] 웹개발(6) - 로그인 기능 만들기(1) (0) | 2023.11.11 |
[SpringBoot] 웹개발(4) - 다운받은 템플릿 적용 (0) | 2023.11.09 |
[springBoot] 웹개발(3) - bootstrap적용 (0) | 2023.11.04 |
[springBoot] 웹개발(2) - DB연결 설정 (0) | 2023.11.04 |