본문 바로가기
DEV/Thymeleaf

[Thymeleaf] th:fragment을 사용한 레이아웃

by 무사뎀벨레 2024. 12. 3.

 

 

 

 

레이아웃 사용 이유


만약 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으로 변경하였다.

반응형

댓글