레이아웃 사용 이유
만약 100개의 페이지에 똑같은 header와 footer가 들어갈 경우 각각의 HTML마다 똑같은 header와 footer를 추가하는 것은 상당히 비효율적이고 유지보수면에서도 좋지 않다. 그래서 반복되는 화면이 있어 HTML 코드를 줄일 때 레이아웃을 적용하면 상당히 효과적이다.
템플릿 조각
템플릿 조각은 공통으로 적용할 부분을 조각조각으로 만들어 필요한 공통의 부분들에 가져다 쓰는 방식이다. <th:fragment>가 있는 태그는 다른 곳에 포함되는 코드 조각으로 코드 조각을 사용할 때는 조각 표현식 ~{...}를 사용한다.
Controller
@Controller
@RequestMapping("/template")
public class TemplateController {
@GetMapping("/fragment")
public String template() {
return "template/fragment/fragmentMain";
}
}
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>
fragmentMain.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>부분 포함</h1>
<h2>1. insert</h2>
<div th:insert="~{template/fragment/footer :: copy}"></div>
<h2>2. replace</h2>
<div th:replace="~{template/fragment/footer :: copy}"></div>
<h2>3. 부분 포함 단순 표현식</h2>
<div th:replace="template/fragment/footer :: copy"></div>
<h1>4. 파라미터 사용</h1>
<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></div>
</body>
</html>
파일 경로 :: 부분 명
위 fragmentMain.html에서 template/fragment/footer :: copy라고 표현한 부분은 template/fragment/footer.html 에 있는 <th:fragment="copy"> 라는 부분을 템플릿 조각으로 가져와서 사용한다는 의미다.
1. insert / 2. replace
th:insert="~{template/fragment/footer :: copy}"와 같이 <th:insert> 를 사용하면 현재 태그( div ) 내부에 추가되며 th:replace="~{template/fragment/footer :: copy}"와 같이 <th:replace>를 사용하면 현재 태그( div )를 대체한다.
3. 부분 포함 단순 표현식
~{...} 를 사용하는 것이 원칙이지만 템플릿 조각을 사용하는 코드가 경로나 이름 정도만 있는 단순한 경우에는 th:replace="~{template/fragment/footer :: copy}"와 같이 ~{...}부분을 생략할 수 있다.
4. 파라미터 사용
또한, fragment명(데이터)의 형식을 사용한 4. 파라미터 사용 부분의 copyParam ('데이터1', '데이터2')와 같이 파라미터를 전달해서 동적으로 조각을 렌더링 할 수도 있다.
템플릿 레이아웃
위에서 설명한 템플릿 조각을 조금 더 활용해 레이아웃으로 사용할 HTML 파일의 속성에 th:fragment 속성을 추가하여 HTML 전체에 적용할 수도 있다.
Controller
@Controller
@RequestMapping("/template")
public class 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>
layoutExtendMain.html
<!DOCTYPE html>
<html th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title},~{::content})}" xmlns:th="http://www.thymeleaf.org">
<head>
<title>메인 페이지 타이틀</title>
</head>
<body>
<content>
<p>메인 페이지 컨텐츠</p>
<div>메인 페이지 포함 내용</div>
</content>
</body>
</html>
layoutExtendMain.html의 th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title},~{::content})}"를 하나씩 살펴보자면 다음과 같다.
앞의 layout은 layoutFile 파일의 fragment 이름인 layout을 뜻하며, (~{::title},~{::content})은 이 layout의 <태그> 이름을 뜻한다.
::title는 현재 페이지(layoutExtendMain.html)의 title 태그들을 전달한다는 것이고, ::content는 는 현재 페이지(layoutExtendMain.html)의 content태그들을 전달한다는 의미이다.
layoutExtendMain.html는 현재 페이지인데, 이 페이지 자체를 th:replace를 사용해서 layoutFile으로 변경하였다.
'DEV > Thymeleaf' 카테고리의 다른 글
[Thymeleaf] 타임리프 에서 null과 빈 문자열 확인하기 (2) | 2023.01.31 |
---|---|
[Thymeleaf] 동적으로 클래스 지정, 추가하기(th:class / th:classappend) (2) | 2023.01.17 |
[Thymeleaf] 커스텀 데이터 속성(th:attr) (2) | 2023.01.05 |
[Thymeleaf] 타임리프 날짜 형식 포맷(String to Date / Date to Date) (0) | 2022.11.25 |
[Thymeleaf] 타임리프 주요 기능 유틸리티 - Utility Objects(Strings, Numbers, Objects, Arrays, Lists, Maps, Messages, Dates, Calendars) (2) | 2022.08.12 |
댓글