1. Thymeleaf의 기본 객체와 LocalDateTime

Thymeleaf에는 내부적으로 여러 종류의 기본 객체를 지원함.

1) sno를 5자리로 포맷해서 출력

1
2
3
<li th:each="dto : ${list}">
    [[${#numbers.formatInteger(dto.sno,5)}]]
</li>

image

2) LocalDateTime 포맷팅

LocalDate타입이나 LocalDateTime을 좀 더 편하게 처리하기 위해 build.gradle에 의존성 추가

1
2
3
dependencies {
	implementation 'org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE'
}
1
2
3
<li th:each="dto : ${list}">
    [[${dto.sno}]] --- [[${#temporals.format(dto.regTime, 'yyyy/MM/dd')}]]
</li>

image

2. Thymeleaf의 레이아웃

1) include 방식의 처리

특정한 부분을 다른 내용으로 변경할 수 있는 th:insert, th:replace

  • th:replace : 기존의 내용을 완전히 대체
  • th:insert : 기존 내용의 바깥쪽 태그는 그대로 유지하면서 추가되는 방식

1-1) exLayout1.html

  • exLayout1.html은 내부적으로 다른 파일(fragment1.html)에 있는 일부분을 조각처럼 가져와서 구성할 것임.
  • th:replace:: 뒤에는 fragment의 이름을 지정하거나 CSS의 #id와 같은 선택자를 사용할 수 있음.
  • ::이하를 생략하면 해당 파일의 전체 내용을 가져옴.
1
2
3
4
5
6
7
8
9
10
11
12
<body>
<h1>Fragment Test</h1>

<h1>Layout 1 - 1</h1>
<div th:replace="~{/fragments/fragment1 :: part1}"></div>

<h1>Layout 1 - 2</h1>
<div th:insert="~{/fragments/fragment1 :: part2}"></div>

<h1>Layout 1 - 3</h1>
<th:block th:replace="~{/fragments/fragment1 :: part3}"></th:block>
</body>

1-2) th:block의 쓰임새

  • th:block 미사용시
1
2
3
4
5
6
7
8
<div th:each="user : ${userList}">
  <span th:text="user.username}">username</span>
  <span th:text="user.age}">age</span>
</div>

<div th:each="user : ${userList}">
<span th:text="${user.username} + ' & ' + ${user.age}">username&age</span>
</div>
  • th:block 사용
1
2
3
4
5
6
7
8
9
<th:block th:each="user : ${userList}">
  <div>
      <span th:text="user.username}">username</span>
      <span th:text="user.age}">age</span>
  </div>
  <div>
      <span th:text="${user.username} + ' & ' + ${user.age}">username&age</span>
 </div>	
</th:block> 

1-3) fragment1.html

조각이 될 파일을 담는 fragments 폴더
image

1
2
3
4
5
6
7
8
9
10
11
12
13
<body>
  <div th:fragment="part1">
    <h2>Part 1</h2>
  </div>

  <div th:fragment="part2">
    <h2>Part 2</h2>
  </div>

  <div th:fragment="part3">
    <h2>Part 3</h2>
  </div>
</body>

실행 결과
image
th:insert를 사용한 part2 부분은 <div>태그 내에 다시 <div>태그가 생성됨.

1-4) fragment2.html (전체 가져오기)

1
2
3
4
5
6
7
<div>
    <hr/>
    <h2>Fragment2 File</h2>
    <h2>Fragment2 File</h2>
    <h2>Fragment2 File</h2>
    <hr/>
</div>

⇒ 전체 내용을 특정 부분에 갖다붙이는 것이므로 html코드(<body>등)이 필요하지 않음.

1
2
3
4
<!-- fragment2 뒤에 '::' 생략함 -->
<div style="border: 1px solid blue">
    <th:block th:replace="~{/fragments/fragment2}"></th:block>
</div>

image

2) 파라미터 방식의 처리

  • Thymeleaf를 이용하면 특정한 ‘태그’를 파라미터처럼 전달해서 다른 th:fragment에서 사용할 수 있음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <div th:fragment="target(first, second)">
    <style>
      .c1 {
        background-color : red;
      }
      .c2 {
        background-color : blue;
      }
    </style>

    <div class="c1">
      <th:block th:replace = "${first}"></th:block>
    </div>

    <div class="c2">
      <th:block th:replace = "${second}"></th:block>
    </div>
  </div>
</body>
</html>


  • 선언된 target부분에 firstsecond라는 파라미터를 받을 수 있도록 구성.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<th:block th:replace="~{/fragments/fragment3:: target(~{this:: #ulFirst}, ~{this:: #ulSecond})}">
    <ul id="ulFirst">
        <li>AAA</li>
        <li>BBB</li>
        <li>CCC</li>
    </ul>

    <ul id="ulSecond">
        <li>111</li>
        <li>222</li>
        <li>333</li>
    </ul>
</th:block>


image

  • exLayout2.html에서 id선택자로 #ulFirst#ulSecond태그를 fragment3.html로 전송하고, fragment3.html에서 해당 태그를 각각 firstsecond로 받음.
  • fragment3.html<div>태그 내부에 exLayout2.html에서 받아온 태그들(first와 second로 받은)을 출력함.
  • 최종적으로 exLayout2.html에서 th:replace가 전부 감싸고 있으므로 fragment3.html의 코드에 exLayout2.html에서 받아온 태그들이 포함되서 출력됨.

3. 레이아웃 템플릿 만들기

  • 앞에서 파라미터로 필요한 영역을 전달해서 처리할 수 있다면 레이아웃 전체를 하나의 페이지로 구성하고, 필요한 부분을 파라미터로 전달하는 방식으로 공통의 레이아웃을 사용할 수 있다는 의미가 됨.

1) layout1.html

image

↓ 전체적인 레이아웃(=템플릿)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<!-- content라는 파라미터를 받을 수 있게 설정-->
<th:block th:fragment="setContent(content)">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .header {
      width: 100vw;
      height: 20vh;
      background-color: aqua;
    }
    .content {
      width: 100vw;
      height: 70vh;
      background-color: lightgray;
    }
    .footer {
      width: 100vw;
      height: 10vh;
      background-color: green;
    }
  </style>

  <div class="header">
    <h1>HEADER</h1>
  </div>
  <!-- CONTENT 영역을 변경 가능하도록 수정 -->
  <div class="content">
    <!-- <h1>CONTENT</h1> -->
    <!-- 파라미터로 전달되는 content를 출력 -->
    <th:block th:replace = "${content}"></th:block>
  </div>
  <div class="footer">
    <h1>FOOTER</h1>
  </div>

</body>
</th:block>
</html>

2) layout1.html을 사용하기 위한 exTemplate.html 생성

  • 전체 내용은 layout1.html로 처리하고, 파라미터로 현재 파일의 content 부분만을 전달.
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<th:block th:replace="~{/layout/layout1 :: setContent(~{this::content})}">

  <th:block th:fragment="content">
    <h1>exTemplate Page</h1>
  </th:block>

</th:block>

image

4. 부트스트랩 템플릿 적용

🔗 부트스트랩 템플릿

1. 다운받은 파일을 resources의 static폴더 내로 복사.
2. layout 폴더에 basic.html 파일을 추가하고 위에서 복사한 index.html의 내용을 그대로 복붙.
3. basic.html 파일 수정
  • Thymeleaf와 관련된 설정 추가 + content 파라미터 전달받을 수 있는 구조로 설정

    1
    2
    3
    4
    5
    
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    
    <th:block th:fragment="setContent(content)">
    <head>
    


  • 링크를 Thymeleaf의 링크로 처리

    1
    2
    3
    4
    5
    6
    7
    8
    
    <!-- Favicon-->
    <link rel="icon" type="image/x-icon" th:href="@{/assets/favicon.ico}" />
    <!-- Core theme CSS (includes Bootstrap)-->
    <link th:href="@{/css/styles.css}" rel="stylesheet" />
    <!-- Bootstrap core JS-->
    <script th:href="@{https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js}"></script>
    <!-- Core theme JS-->
    <script th:href="@{/js/scripts.js}"></script>    
    


  • container-fluid 부분에 파라미터로 전송되는 content를 출력하도록 수정

    1
    2
    3
    4
    
    <!-- Page content-->
    <div class="container-fluid">
        <th:block th:replace = "${content}"></th:block>
    </div>
    


4. exSidebar.html 추가
  • basic.html에 전달하는 파라미터(=content)로 th:fragment="content"를 전송.

    1
    2
    3
    4
    5
    6
    7
    8
    
      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
    
      <th:block th:replace="~{/layout/basic :: setContent(~{this::content})}">
      <th:block th:fragment="content">
          <h1>exSidebar Page</h1>
      </th:block>
      </th:block>
    


5. 적용 결과

image