Thymeleaf
κΈ°λ³Έ κΈ°λ₯
μ¬μ© μ μΈ
Copy <html xmlns:th="http://www.thymeleaf.org"></html>
μμ± λ³κ²½
Copy th:href="@{/css/bootstrap.min.css}"
URL λ§ν¬ ννμ
Copy th:href="@{/css/bootstrap.min.css}"
<!-- -->
th:href="@{/basic/items/{itemId}(itemId=${item.id})}"
th:href="@{/basic/items/{itemId}(itemId=${item.id}, query='test')}"
th:href="@{|/basic/items/${item.id}|}"
μμ± λ³κ²½
Copy th:onclick="|location.href='@{/basic/items/add}'|"
λ°λ³΅ μΆλ ₯
Copy <tr th:each="item : ${items}"></tr>
λ³μ ννμ
Copy <td th:text="${item.price}">10000</td>
μμ± λ³κ²½
Copy <input
type="text"
id="price"
name="price"
value="10000"
th:value="${item.price}"
/>
κΈ°λ³Έ ννμ
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#standard-expression-syntax
Copy γ
κ°λ¨ν νν
- λ³μ ννμ: ${...}
- μ ν λ³μ ννμ: \*{...}
- λ©μμ§ ννμ: #{...}
- λ§ν¬ URL ννμ: @{...}
- μ‘°κ° ννμ: ~{...}
γ
리ν°λ΄
- ν
μ€νΈ: 'one text', 'Another one!',β¦
- μ«μ: 0, 34, 3.0, 12.3,β¦
- λΆλ¦°: true, false
- λ: null
- 리ν°λ΄ ν ν°: one, sometext, main,β¦
γ
λ¬Έμ μ°μ°
- λ¬Έμ ν©μΉκΈ°: +
- 리ν°λ΄ λ체: |The name is ${name}|
γ
μ°μ μ°μ°
- Binary operators: +, -, \*, /, %
- Minus sign (unary operator): -
γ
λΆλ¦° μ°μ°
- Binary operators: and, or
- Boolean negation (unary operator): !, not
γ
λΉκ΅μ λλ±
- λΉκ΅: >, <, >=, <= (gt, lt, ge, le)
- λλ± μ°μ°: ==, != (eq, ne)
γ
쑰건 μ°μ°
- If-then: (if) ? (then)
- If-then-else: (if) ? (then) : (else)
- Default: (value) ?: (defaultvalue)
γ
νΉλ³ν ν ν°
- No-Operation: \_
ν
μ€νΈ
ν
μ€νΈ μΆλ ₯
κΈ°λ³Έμ μΌλ‘ escape λ₯Ό μ 곡
escape : HTML μμ μ¬μ©νλ νΉμ λ¬Έμλ₯Ό HTML μν°ν°λ‘ λ³κ²½νλ κ²
HTML μν°ν° : <
λ¬Έμλ₯Ό νκ·Έμ μμμ΄ μλ λ¬Έμλ‘ νννλ λ°©λ²
Copy <ul>
<li>th:text μ¬μ© = <span th:text="${data}"></span></li>
<li>컨ν
μΈ μμμ μ§μ μΆλ ₯νκΈ° = [[${data}]]</li>
</ul>
Unescape
Copy <ul>
<li>th:utext = <span th:utext="${data}"></span></li>
<li><span th:inline="none">[(...)] = </span>[(${data})]</li>
</ul>
SpringEL ννμ
Object
${user['username']}
= userA
${user.getUsername()}
= userA
List
${users[0].username}
= userA
${users[0]['username']}
= userA
${users[0].getUsername()}
= userA
Map
${userMap['userA'].username}
= userA
${userMap['userA']['username']}
= userA
${userMap['userA'].getUsername()}
= userA
Safe Navigation Operator
Copy <div th:if="${errors?.containsKey('globalError')}"></div>
errors?.
μ errors κ° null μΌλ NullPointerException λμ , null μ λ°ννλ λ¬Έλ² μ°Έκ³
μ§μλ³μ
Copy <div th:with="first=${users[0]}">
<p>first member name : <span th:text="${first.username}"></span></p>
</div>
κΈ°λ³Έ κ°μ²΄
Thymeleaf κΈ°λ³Έ κ°μ²΄
νΈμ κ°μ²΄
HTTP μμ² νλΌλ―Έν° μ κ·Ό: ${param.paramData}
HTTP μΈμ
μ κ·Ό: ${session.sessionData}
μ€νλ§ λΉ μ κ·Ό: ${@helloBean.hello('Spring!')}
μ νΈλ¦¬ν° κ°μ²΄μ λ μ§
#message : λ©μμ§, κ΅μ ν μ²λ¦¬
#uris : URI μ΄μ€μΌμ΄ν μ§μ
#dates : java.util.Date μμ μ§μ
#calendars : java.util.Calendar μμ μ§μ
#temporals : μλ°8 λ μ§ μμ μ§μ
#numbers : μ«μ μμ μ§μ
#strings : λ¬Έμ κ΄λ ¨ νΈμ κΈ°λ₯
#objects : κ°μ²΄ κ΄λ ¨ κΈ°λ₯ μ 곡
#bools : boolean κ΄λ ¨ κΈ°λ₯ μ 곡
#arrays : λ°°μ΄ κ΄λ ¨ κΈ°λ₯ μ 곡
#lists , #sets , #maps : 컬λ μ
κ΄λ ¨ κΈ°λ₯ μ 곡
#ids : μμ΄λ μ²λ¦¬ κ΄λ ¨ κΈ°λ₯ μ 곡, λ€μμ μ€λͺ
Reference
νμ리ν μ νΈλ¦¬ν° κ°μ²΄
μ νΈλ¦¬ν° κ°μ²΄ μμ
URL λ§ν¬
λ¨μ URL
/hello
Copy <a th:href="@{/hello}"></a>
query parameter
/hello?param1=data1¶m2=data2
Copy <a th:href="@{/hello(param1=${param1}, param2=${param2})}"></a>
path variable
/hello/data1/data2
Copy <a
th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}"
></a>
query parameter + path variable
/hello/data1?param2=data2
Copy <a th:href="@{/hello/{param1}(param1=${param1}, param2=${param2})}"></a>
Reference
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#link-urls
리ν°λ΄
λ¬Έμ: 'hello' (λ¬Έμ 리ν°λ΄μ νμ μμλ°μ΄νλ‘ κ°μΈμΌ ν¨)
Copy <span th:text="'hello'"></span>
μ°μ°
μ°μ μ°μ°
Copy 10 + 2 = <span th:text="10 + 2"></span>
λΉκ΅ μ°μ°
Copy <!--
> (gt)
< (lt)
>= (ge)
<= (le)
! (not)
== (eq)
!= (neq, ne)`
-->
1 >= 10 = <span th:text="1 >= 10"></span>
쑰건μ
Copy (10 % 2 == 0) ? = <span th:text="(10 % 2 == 0)?'μ§μ':'νμ'"></span>
Elvis μ°μ°μ
Copy <!-- λ°μ΄ν°κ° μμ κ²½μ° μ€μ λ¬Έμμ΄ μΆλ ₯ -->
${data} = <span th:text="${data}?: 'λ°μ΄ν°κ° μμ΅λλ€.'"></span>
No-Operation
Copy <!-- λ°μ΄ν°κ° μμ κ²½μ° tag λ°μ΄ν° κ·Έλλ‘ μΆλ ₯ (Thymeleaf κ° μ€νλμ§ μλ κ² μ²λΌ λμ) -->
${data} = <span th:text="${data}?: _">λ°μ΄ν°κ° μμ΅λλ€.</span>
μμ± κ° μ€μ
μμ± μ€μ
Copy <input type="text" name="mock" th:name="userA" />
μμ± μΆκ°
Copy <input type="text" class="text" th:classappend="large" /><br />
checked μ²λ¦¬
Copy <input type="checkbox" name="active" th:checked="true" /><br />
<input type="checkbox" name="active" th:checked="false" /><br />
<input type="checkbox" name="active" th:checked="${isChecked}" /><br />
λ°λ³΅
λ°λ³΅
Copy <tr th:each="user : ${users}">
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
</tr>
μν μ μ§
Copy <!-- μλ΅ μ userStat λ‘ μ¬μ© -->
<tr th:each="user, state : ${users}"></tr>
even , odd : ν/μ§μ μ¬λΆ
first , last :μ²μ/λ§μ§λ§ μ¬λΆ
μ‘°κ±΄λΆ νκ°
if, unless
Copy <span th:text="'μ΄λ₯Έ'" th:if="${user.age gt 20}"></span>
<span th:text="'μ΄λ₯Έ'" th:unless="${user.age le 20}"></span>
switch
Copy <td th:switch="${user.age}">
<span th:case="10">10μ΄</span>
<span th:case="20">20μ΄</span>
<span th:case="*">κΈ°ν</span>
</td>
μ£Όμ
νμ€ HTML μ£Όμ
νμ리νκ° λ λλ§νμ§ μκ³ μ μ§
Copy <!-- <span th:text="${data}"></span> -->
νμ리ν νμ μ£Όμ
λ λλ§μμ μ£Όμ λΆλΆμ μ κ±° (νμ리ν μ£Όμ)
Copy <!--/* [[${data}]] */-->
<!--/*-->
<span th:text="${data}">html data</span>
<!--*/-->
νμ리ν νλ‘ν νμ
μ£Όμ
νμ리ν λ λλ§μ κ±°μ³μΌλ§ μ΄ λΆλΆμ΄ μ μ λ λλ§ (HTML μμλ§ μ£Όμ μ²λ¦¬)
Copy <!--/*/
<span th:text="${data}">html data</span>
/*/-->
λΈλ‘
th:each λ‘ ν΄κ²°μ΄ μ΄λ €μΈ λ μ¬μ©
Copy <th:block th:each="user : ${users}">
<div>
name: <span th:text="${user.username}"></span> age:
<span th:text="${user.age}"></span>
</div>
<div>μμ½ <span th:text="${user.username} + ' / ' + ${user.age}"></span></div>
</th:block>
JavaScript Inline
javascript inline
Copy <script th:inline="javascript">
var username = [[${user.username}]];
var age = [[${user.age}]];
//μλ°μ€ν¬λ¦½νΈ λ΄μΆλ΄ ν
νλ¦Ώ
var username2 = /*[[${user.username}]]*/ "test username";
//κ°μ²΄
var user = [[${user}]];
</script>
<!--
var username = "userA";
var age = 10;
var username2 = "userA";
var user = {"username":"userA","age":10};
-->
each
Copy <script th:inline="javascript">
[# th:each="user, stat : ${users}"]
var user[[${stat.count}]] = [[${user}]];
[/]
</script>
<!--
var user1 = {"username":"userA","age":10};
var user2 = {"username":"userB","age":20};
var user3 = {"username":"userC","age":30};
-->
ν
νλ¦Ώ μ‘°κ°
/resources/templates/template/fragment/footer.html
Copy <!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>
/resources/templates/template/fragment/fragmentMain.html
Copy <!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<h1>λΆλΆ ν¬ν¨</h1>
<h2>λΆλΆ ν¬ν¨ insert (div tag μμ μ½μ
)</h2>
<div th:insert="~{template/fragment/footer :: copy}"></div>
<h2>λΆλΆ ν¬ν¨ replace (div tag λ체)</h2>
<div th:replace="~{template/fragment/footer :: copy}"></div>
<h1>νλΌλ―Έν° μ¬μ©</h1>
<div
th:replace="~{template/fragment/footer :: copyParam ('λ°μ΄ν°1', 'λ°μ΄ν°2')}"
></div>
</body>
</html>
ν
νλ¦Ώ λ μ΄μμ
λμ μΈ λ μ΄μμ
/resources/templates/template/layout/base.html
λ μ΄μμμ΄λΌλ ν° ν
Copy <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>
</html>
/resources/templates/template/layout/layoutMain.html
ν μμ νμν μ½λ μ‘°κ°λ€μ μ λ¬
::title μ νμ¬ νμ΄μ§μ title tag λ€μ μ λ¬
::link μ νμ¬ νμ΄μ§μ link tag λ€μ μ λ¬
Copy <!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>
λ©μΈ λ μ΄μμ
/resources/templates/template/layoutExtend/layoutFile.html
κΈ°λ³Έ λ μ΄μμ(header, footer) νμ μ μ§νκ³ title, content λ§ λ³κ²½
Copy <!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>
/resources/templates/template/layoutExtend/layoutExtendMain.html
κΈ°λ³Έ λ μ΄μμ νλ‘ κ΅μ²΄νλλ° νλλ° title, content λ μ λ¬
Copy <!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>
Form
μ
λ ₯ νΌ μ²λ¦¬
Copy <form action="item.html" th:action th:object="${item}" method="post">
<div>
<label for="itemName">μνλͺ
</label>
<input
type="text"
id="itemName"
th:field="*{itemName}"
class="formcontrol"
placeholder="μ΄λ¦μ μ
λ ₯νμΈμ"
/>
</div>
</form>
th:object
: 컀맨λ κ°μ²΄λ₯Ό μ§μ
\*{...}
: μ ν λ³μ μ (th:object μμ μ νν κ°μ²΄μ μ κ·Ό)
th:field
: HTML νκ·Έμ id , name , value μμ±μ μλμΌλ‘ μμ±
λ λλ§ μ /ν
Copy <input type="text" th:field="*{itemName}" />
Copy <input type="text" id="itemName" name="itemName" th:value="*{itemName}" />
μ²΄ν¬ λ°μ€
λ¨μΌ
Register
Copy <div>
<div class="form-check">
<input
type="checkbox"
id="open"
th:field="*{open}"
class="form-checkinput"
/>
<label for="open" class="form-check-label">ν맀 μ€ν</label>
</div>
</div>
νμ리νκ° μλμΌλ‘ <input type="hidden" name="_open" value="on"/>
μμ±
μ²΄ν¬ λ°μ€λ₯Ό 체ν¬ν κ²½μ° on μ μ λ¬νμ§λ§, 체ν¬νμ§ μμ κ²½μ° κ° μ체λ₯Ό μ λ¬νμ§ μμ -> μ΄ κ²½μ° hidden type μ _name input νκ·Έλ₯Ό μ¬μ©νκ² λλ©΄, false λ‘ κ°μ μ λ¬ (_open=on)
View
Copy <div>
<div class="form-check">
<input
type="checkbox"
id="open"
th:field="${item.open}"
class="form-check-input"
disabled
/>
<label for="open" class="form-check-label">ν맀 μ€ν</label>
</div>
</div>
λ©ν°
(μ°Έκ³ ) @ModelAttribute λ₯Ό μ¬μ©νλ©΄ ν΄λΉ Controller νΈμΆ μ regions() μμ λ°νν κ°μ΄ μλμΌλ‘ Modelμ νμ λ΄κΈ°κ² λ¨
Copy @ModelAttribute("regions")
public Map<String, String> regions() {
Map<String, String> regions = new LinkedHashMap<>();
regions.put("SEOUL", "μμΈ");
regions.put("BUSAN", "λΆμ°");
regions.put("JEJU", "μ μ£Ό");
return regions;
}
Register
Copy <div th:each="region : ${regions}" class="form-check form-check-inline">
<input
type="checkbox"
th:field="*{regions}"
th:value="${region.key}"
class="form-check-input"
/>
<label
th:for="${#ids.prev('regions')}"
th:text="${region.value}"
class="form-check-label"
>μμΈ</label
>
</div>
νμ리νλ eachλ‘ μ²΄ν¬λ°μ€ μμ± μ λμ μΌλ‘ idμ μλ²μ 맀겨μ€λ€. #ids
λ λμ μΌλ‘ μμ±λ idλ₯Ό μΈμ
result
Copy <input
type="checkbox"
value="SEOUL"
class="form-check-input"
id="regions1"
name="regions"
/>
<input
type="checkbox"
value="BUSAN"
class="form-check-input"
id="regions2"
name="regions"
/>
<input
type="checkbox"
value="JEJU"
class="form-check-input"
id="regions3"
name="regions"
/>
View
Copy <div th:each="region : ${regions}" class="form-check form-check-inline">
<input
type="checkbox"
th:field="${item.regions}"
th:value="${region.key}"
class="form-check-input"
disabled
/>
<label
th:for="${#ids.prev('regions')}"
th:text="${region.value}"
class="form-check-label"
>μμΈ</label
>
</div>
νμ리νλ th:field
μ μ§μ ν κ°κ³Ό th:value
μ κ°μ λΉκ΅ν΄μ 체ν¬λ₯Ό μλμΌλ‘ μ²λ¦¬
λΌλμ€ λ²νΌ
Copy public enum ItemType {
BOOK("λμ"), FOOD("μν"), ETC("κΈ°ν"); // NAME(description)
private final String description;
ItemType(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
Copy <div th:each="type : ${itemTypes}" class="form-check form-check-inline">
<input
type="radio"
th:field="*{itemType}"
th:value="${type.name()}"
class="form-check-input"
/>
<label
th:for="${#ids.prev('itemType')}"
th:text="${type.description}"
class="form-check-label"
>
BOOK
</label>
</div>
λΌλμ€ λ²νΌμ νμ νλμ κ°μ΄ μ νλμ΄μΌ νλ―λ‘ νλ λ²νΌμ λ°λ‘ μμ±νμ§ μμ.
μ
λ νΈ λ°μ€
Register
Copy <select th:field="*{deliveryCode}" class="form-select">
<option value="">==λ°°μ‘ λ°©μ μ ν==</option>
<option
th:each="deliveryCode : ${deliveryCodes}"
th:value="${deliveryCode.code}"
th:text="${deliveryCode.displayName}"
>
FAST
</option>
</select>
Reference
곡μ μ¬μ΄νΈ
곡μ λ©λ΄μΌ - κΈ°λ³Έ κΈ°λ₯
곡μ λ©λ΄μΌ - μ€νλ§ ν΅ν©