-
[김영한 스프링] 09. 타임리프 기본 기능 - 템플릿 조각 & 템플릿 레이아웃Spring/스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 2023. 8. 12. 00:45
템플릿 조각
웹 페이지를 개발할 때는 공통 영역이 많이 있다. 예를 들어서 상단 영역이나 하단 영역, 좌측 카테고리 등등 여러 페이지에서 함께 사용하는 영역들이 있다. 이런 부분을 코드를 복사해서 사용한다면 변경 시 여러 페이지를 다 수정해야 하므로 상당히 비효율 적이다. 타임리프는 이런 문제를 해결하기 위해 템플릿 조각과 레이아웃 기능을 지원한다.
TemplateController
package hello.thymeleaf.basic; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/template") public class TemplateController { @GetMapping("/fragment") public String template() { return "template/fragment/fragmentMain"; } }
main/java/hello/thymeleaf/basic/TemplateController 생성
footer.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <body> <footer th:fragment="copy"> 푸터 자리 입니다. </footer> <footer th:fragment="copyParam (param1, param2)"> <p>파라미터 자리 입니다.</p> <p th:text="${param1}"></p> <p th:text="${param2}"></p> </footer> </body> </html>
main/resources/templates/template/fragment/footer.html 생성
th:fragment가 있는 태그는 다른곳에 포함되는 코드 조각으로 이해하면 된다.
fragmentMain.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>부분 포함</h1> <h2>부분 포함 insert</h2> <div th:insert="~{template/fragment/footer :: copy}"></div> <h2>부분 포함 replace</h2> <div th:replace="~{template/fragment/footer :: copy}"></div> <h2>부분 포함 단순 표현식</h2> <div th:replace="template/fragment/footer :: copy"></div> <h1>파라미터 사용</h1> <div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></div> </body> </html>
main/resources/templates/template/fragment/fragmentMain.html 생성
- template/fragment/footer :: copy : template/fragment/footer.html 템플릿에 있는 th:fragment="copy"라는 부분을 템플릿 조각으로 가져와서 사용한다는 의미이다.
footer.html의 copy 부분
<footer th:fragment="copy">
푸터 자리 입니다.
</footer>부분 포함 insert
<div th:insert="~{template/fragment/footer :: copy}"></div>
<h2>부분 포함 insert</h2>
<div>
<footer>
푸터 자리 입니다.
</footer>
</div>th:insert를 사용하면 현재 태그(div) 내부에 추가한다.
부분 포함 replace
<div th:replace="~{template/fragment/footer :: copy}"></div>
<h2>부분 포함 replace</h2>
<footer>
푸터 자리 입니다.
</footer>th:replace를 사용하면 현재 태그(div)를 대체한다.
부분 포함 단순 표현식
<div th:replace="template/fragment/footer :: copy"></div>
<h2>부분 포함 단순 표현식</h2>
<footer>
푸터 자리 입니다.
</footer>~{...}를 사용하는 것이 원칙이지만 템플릿 조각을 사용하는 코드가 단순하면 이 부분을 생략할 수 있다.
파라미터 사용
다음과 같이 파라미터를 전달해서 동적으로 조각을 렌더링 할 수도 있다.
<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></div>
<h1>파라미터 사용</h1>
<footer>
<p>파라미터 자리 입니다.</p>
<p>데이터1</p>
<p>데이터2</p>
</footer>footer.html의 copyParam 부분
<footer th:fragment="copyParam (param1, param2)">
<p>파라미터 자리 입니다.</p>
<p th:text="${param1}"></p>
<p th:text="${param2}"></p>
</footer>실행
템플릿 레이아웃1
예를 들어서 <head>에 공통으로 사용하는 css, javascript같은 정보들이 있는데, 이러한 공통 정보들을 한 곳에 모아두고, 공통으로 사용하지만, 각 페이지마다 필요한 정보를 더 추가해서 사용하고 싶다면 다음과 같이 사용하면 된다.
TemplateController
@GetMapping("layout") public String layout() { return "template/layout/layoutMain"; }
base.html
<html xmlns:th="http://www.thymeleaf.org"> <head th:fragment="common_header(title,links)"> <title th:replace="${title}">레이아웃 타이틀</title> <!-- 공통 --> <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}"> <link rel="shortcut icon" th:href="@{/images/favicon.ico}"> <script type="text/javascript" th:src="@{/sh/scripts/codebase.js}"></script> <!-- 추가 --> <th:block th:replace="${links}" /> </head>
main/resources/templates/template/layout/base.html 생성
layoutMain.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head th:replace="template/layout/base :: common_header(~{::title},~{::link})"> <title>메인 타이틀</title> <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"> <link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}"> </head> <body> 메인 컨텐츠 </body> </html>
main/resources/templates/template/layout/layoutMain.html 생성
- common_header(~{::title},~{::link})이 부분이 핵심이다.
- ::title은 현재 페이지의 title 태그들을 전달한다.
- ::link는 현재 페이지의 link 태그들을 전달한다.
실행
- 메인 타이틀이 전달한 부분으로 교체되었다.
- 공통 부분은 그대로 유지되고, 추가 부분에 전달한 <link>들이 포함된 것을 확인할 수 있다.
이 방식은 사실 앞서 배운 코드 조각을 조금 더 적극적으로 사용하는 방식이다. 쉽게 이야기해서 레이아웃 개념을 두고, 그 레이아웃에 필요한 코드 조각을 전달해서 완성하는 것으로 이해하면 된다.
템플릿 레이아웃2
템플릿 레이아웃 확장
앞서 이야기한 개념을 <head>정도에만 적용하는 것이 아니라 <html>전체에 적용할 수도 있다.
TemplateController
@GetMapping("/layoutExtend") public String layoutExtend() { return "template/layoutExtend/layoutExtendMain"; }
layoutFile.html
<!DOCTYPE html> <html th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org"> <head> <title th:replace="${title}">레이아웃 타이틀</title> </head> <body> <h1>레이아웃 H1</h1> <div th:replace="${content}"> <p>레이아웃 컨텐츠</p> </div> <footer> 레이아웃 푸터 </footer> </body> </html>
main/resources/templates/template/layoutExtend/layoutFile.html 생성
기본 레이아웃을 가지고 있는데, <html>에 th:fragment 속성이 정의되어 있다. 이 레이아웃 파일을 기본으로 하고 여기에 필요한 내용을 전달해서 부분부분 변경하는 것으로 이해하면 된다.
layoutExtendMain.html
<!DOCTYPE html> <html th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title},~{::section})}" xmlns:th="http://www.thymeleaf.org"> <head> <title>메인 페이지 타이틀</title> </head> <body> <section> <p>메인 페이지 컨텐츠</p> <div>메인 페이지 포함 내용</div> </section> </body> </html>
main/resources/templates/template/layoutExtend/layoutExtendMain.html 생성
현재 페이지인데, <html> 자체를 th:replace를 사용해서 변경하는 것을 확인할 수 있다. 결국 layoutFile.html에 필요한 내용을 전달하면서 <html> 자체를 layoutFile.html로 변경한다.
실행
출처 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2
'Spring > 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술' 카테고리의 다른 글
[김영한 스프링] 11. 타임리프 스프링 통합과 폼 - 입력 폼 처리 & 요구사항 추가 (0) 2023.08.21 [김영한 스프링] 10. 타임리프 스프링 통합과 폼 - 프로젝트 설정 & 타임리프 스프링 통합 (0) 2023.08.21 [김영한 스프링] 08. 타임리프 기본 기능 - 자바스크립트 인라인 (0) 2023.08.11 [김영한 스프링] 07. 타임리프 기본 기능 - 조건부 평가 & 주석 & 블록 (0) 2023.08.11 [김영한 스프링] 06. 타임리프 기본 기능 - 속성 값 설정 & 반복 (0) 2023.07.26