DevLog ๐Ÿ˜ถ

[Spring] Thymeleaf ๊ธฐ๋ณธ ๋ฌธ๋ฒ• ์ •๋ฆฌ ๋ณธ๋ฌธ

Back-end/Spring

[Spring] Thymeleaf ๊ธฐ๋ณธ ๋ฌธ๋ฒ• ์ •๋ฆฌ

dolmeng2 2022. 8. 18. 21:28

 ๊น€์˜ํ•œ ๋‹˜์˜ '์Šคํ”„๋ง MVC 2ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ™œ์šฉ ๊ธฐ์ˆ '์„ ๋ณด๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค ๐Ÿ˜Š

 

์Šคํ”„๋ง MVC 2ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ™œ์šฉ ๊ธฐ์ˆ  - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋ชจ๋“  ์›น ๊ธฐ์ˆ ์„ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์ดํ•ดํ•˜๊ณ , ์™„์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. MVC 2ํŽธ์—์„œ๋Š” MVC 1ํŽธ์˜ ํ•ต์‹ฌ ์›๋ฆฌ์™€ ๊ตฌ์กฐ ์œ„์— ์‹ค๋ฌด ์›น ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋ชจ๋“  ํ™œ์šฉ ๊ธฐ์ˆ ๋“ค์„ ํ•™์Šตํ•  ์ˆ˜ ์žˆ

www.inflearn.com


| ํƒ€์ž„๋ฆฌํ”„ ๋ฌธ๋ฒ• ์•Œ์•„๋ณด๊ธฐ

- SSR์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํƒ€์ž„๋ฆฌํ”„์˜ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

- ํ”„๋กœ์ ํŠธ dependency์—๋Š” ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋‹ค. 

: Spring Web, Lombok, Thymeleaf 

 

- ํƒ€์ž„๋ฆฌํ”„์˜ ๊ฒฝ์šฐ '๋„ค์ธ„๋Ÿด ํ…œํ”Œ๋ฆฟ'์ด๋ผ๋Š” ํŠน์ง•์ด ์žˆ๋‹ค.

: HTML์„ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ํŒŒ์ผ์„ ์—ด์–ด๋„ ๋‚ด์šฉ ํ™•์ธ์ด ๋˜๋ฉฐ, ๋ทฐ ํ…œํ”Œ๋ฆฟ์„ ๊ฑฐ์น˜๋ฉด ๋™์ ์œผ๋กœ ๊ฒฐ๊ณผ๊ฐ€ ๋ณ€ํ™˜๋œ๋‹ค.

: ์ˆœ์ˆ˜ํ•œ HTML์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋ทฐ ํ…œํ”Œ๋ฆฟ๊นŒ์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ํฐ ์žฅ์ !

 

โœ” ๊ธฐ๋ณธ ์„ ์–ธ

<html xmlns:th="http://www.thymeleaf.org">

 

โœ” ํ…์ŠคํŠธ ์ถœ๋ ฅ - text, utext

<a th:text="${data}">

: HTML content์— ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ์‹œ ์‚ฌ์šฉ, ํƒœ๊ทธ ์†์„ฑ์— ๊ธฐ๋Šฅ ์ •์˜.

 

[[${data}]]

: HTML ์ฝ˜ํ…์ธ  ์˜์—ญ ์•ˆ์—์„œ ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ

 

[ThymeleafController.java]

@Controller
@RequestMapping("/thymeleaf")
public class ThymeleafController {
    @GetMapping("/text-basic")
    public String textBasic(Model model) {
        model.addAttribute("data", "hello!");
        return "thymeleaf/text-basic";
    }
}

[text-basic.html]  - resources/templates/thymeleaf ๋ฐ‘์— ๋‘์—ˆ๋‹ค.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<h1>Data in Content</h1>
<ul>
  <li>th:text ์‚ฌ์šฉํ•˜๊ธฐ <span th:text="${data}"></span></li>
  <li>์ปจํ…์ธ  ์•ˆ์—์„œ ์ง์ ‘ ์ถœ๋ ฅํ•˜๊ธฐ = [[${data}]]</li>
</ul>
</body>
</html>

- ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ ์ž˜ ๋‚˜์˜จ๋‹ค.

- ์‹ค์šฉ์„ฑ์œผ๋กœ ๋ดค์„ ๋•Œ๋Š” [[]]์„ ๋” ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š์„๊นŒ ์‹ถ์€๋ฐ... ์ด๊ฑฐ๋Š” ์ทจํ–ฅ ์ฐจ์ด์ผ ๊ฒƒ ๊ฐ™๋‹ค.

 

 

โœ” Escape ์ฒ˜๋ฆฌํ•˜๊ธฐ

- html์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํƒœ๊ทธ์—์„œ <>์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, < ์ž์ฒด๋ฅผ ๋ฌธ์ž๋กœ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ํŠน์ˆ˜ํ•œ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•˜๋‹ค.

- < ์ด๋Ÿฌํ•œ ํŠน์ˆ˜๋ฌธ์ž๋ฅผ html ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ escape๋ผ๊ณ  ํ•˜๋ฉฐ, th:text, [[...]]์€ ๊ธฐ๋ณธ์ ์œผ๋กœ escape๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

< : &lt
> : &gt
& : &amp
" : &quot
' : &apos

 

๐Ÿšฉ HTML ์—”ํ‹ฐํ‹ฐ๋ž€?

- HTML์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์•ฝ๋œ ๋ฌธ์ž๋Š” 'HTML ์˜ˆ์•ฝ์–ด'๋ผ๊ณ  ํ•˜๋ฉฐ, ์ด๋ฅผ HTML ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์›น ๋ธŒ๋ผ์šฐ์ €๋Š” ๋‹ค๋ฅธ ์˜๋ฏธ๋กœ ํ•ด์„ํ•œ๋‹ค.

- HTML ์˜ˆ์•ฝ์–ด๋ฅผ ๊ธฐ์กด์— ์‚ฌ์šฉํ•˜๋˜ ์˜๋ฏธ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด, ๋ณ„๋„๋กœ ๋งŒ๋“  ๋ฌธ์ž์…‹์„ ์—”ํ‹ฐํ‹ฐ๋ผ๊ณ  ํ•œ๋‹ค.

- ๋ณดํ†ต ์—”ํ‹ฐํ‹ฐ๋Š” &entity_name, &#entity_number ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚ธ๋‹ค.

- ์—”ํ‹ฐํ‹ฐ์˜ ์ด๋ฆ„์€ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•œ๋‹ค.

 

- ์ด์Šค์ผ€์ดํ”„ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด th:utext, [(...)]์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

@GetMapping("/text-unescaped")
public String textUnescaped(Model model) {
    model.addAttribute("data", "<b>hello!</b>");
    return "thymeleaf/text-unescaped";
}

[text-unescaped.html]

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<h1>text vs utext</h1>
<ul>
  <li>th:text = <span th:text="${data}"></span></li>
  <li>th:utext = <span th:utext="${data}"></span></li>
</ul>

<h1><span th:inline="none">[[...]] vs [(...)]</span></h1>
<ul>
  <li><span th:inline="none">[[...]] = </span>[[${data}]]</li>
  <li><span th:inline="none">[(...)] =</span>[(${data})]</li>
</ul>
</body>
</html>

- th:inline ์˜ต์…˜์„ ์ฃผ์–ด์„œ [[...]]์ด๋‚˜ [(...)]์„ ํ•ด์„ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•˜์˜€๋‹ค.

- ๋‹ค์Œ์ฒ˜๋Ÿผ ์ด์Šค์ผ€์ดํ”„ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

 

โœ” ๋ณ€์ˆ˜ ํ‘œํ˜„์‹ - ${...}

@GetMapping("/variable")
public String variable(Model model) {
    User user1 = new User("hi", 22);
    User user2 = new User("hihi", 23);

    List<User> users = new ArrayList<>();
    users.add(user1);
    users.add(user2);

    Map<String, User> map = new HashMap<>();
    map.put("user1", user1);
    map.put("user2", user2);

    model.addAttribute("user", user1);
    model.addAttribute("userList", users);
    model.addAttribute("userMap", map);
    return "thymeleaf/variable";
}

@Getter
static class User {
    private String username;
    private int age;

    public User(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

[variable.html]

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<h1>Spring EL ํ‘œํ˜„์‹</h1>
<ul> Object
  <li>${user.username} = <span th:text="${user.username}"></span></li>
  <li>${user['username']} = <span th:text="${user['username']}"></span></li>
  <li>${user.getUsername()} = <span th:text="${user.getUsername()}"></span></li>
</ul>

<ul> List
  <li>${userList[0].username} = <span th:text="${userList[0].username}"></span></li>
  <li>${userList[0]['username']} = <span th:text="${userList[0]['username']}"></span></li>
  <li>${userList[0].getUsername()} = <span th:text="${userList[0].getUsername()}"></span></li>
</ul>

<ul>Map
  <li>${userMap['userA'].username} = <span th:text="${userMap['user1'].username}"></span></li>
  <li>${userMap['userA']['username']} = <span th:text="${userMap['user1']['username']}"></span></li>
  <li>${userMap['userA'].getUsername()} = <span th:text="${userMap['user1'].getUsername()}"></span></li>
</ul>
</body>
</html>

- ๊ฐ์ฒด ์ ‘๊ทผ

user.username
user['username']
user.getUsername()

 

- List ์ ‘๊ทผ

userList[0].username
userList[0]['username']
userList[0].getUsername()

 

- Map ์ ‘๊ทผ

userMap['user1'].username
userMap['user1]['username']
userMap['user1'].getUsername()

 

- ์ ‘๊ทผํ•˜๋ ค๋ฉด getter๊ฐ€ ํ•„์ˆ˜์ ์œผ๋กœ ์—ด๋ ค์žˆ์–ด์•ผ ํ•œ๋‹ค.

 

 

โœ” ์ง€์—ญ ๋ณ€์ˆ˜ ์„ ์–ธ - th:with

<h1>์ง€์—ญ ๋ณ€์ˆ˜ - (th:with)</h1>
<div th:with="first=${userList[0]}">
    <p>์ฒ˜์Œ ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์€ <span th:text="${first.username}"></span></p>
</div>

- th:with๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. (์กฐ๊ธˆ ๋” ๊น”๋”ํ•˜๊ฒŒ ์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ)

 

 

โœ” ๊ธฐ๋ณธ ๊ฐ์ฒด๋“ค

@GetMapping("/basic-objects")
public String basicObjects(HttpSession session) {
    session.setAttribute("sessionData", "Hello Session");
    return "thymeleaf/basic-objects";
}

@Component("helloBean")
static class HelloBean {
    public String hello(String data) {
        return "Hello " + data;
    }
}

[basic-objects.html]

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<h1>์‹ ๊ธฐ๋ณธ ๊ฐ์ฒด (Expression Basic Objects)</h1>
<ul>
  <li>request = <span th:text="${#request}"></span></li>
  <li>response = <span th:text="${#response}"></span></li>
  <li>session = <span th:text="${#session}"></span></li>
  <li>servletContext = <span th:text="${#servletContext}"></span></li>
  <li>locale = <span th:text="${#locale}"></span></li>
</ul>
<h1>ํŽธ์˜ ๊ฐ์ฒด</h1>
<ul>
  <li>Request Parameter = <span th:text="${param.paramData}"></span></li>
  <li>session = <span th:text="${session.sessionData}"></span></li>
  <li>spring bean = <span th:text="${@helloBean.hello('Spring!')}"></span></li>
</ul>


</body>
</html>

http://localhost:8080/thymeleaf/basic-objects?paramData=hello

 

 

โœ” ํŽธ์˜ ๊ฐ์ฒด

HTTP ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ ‘๊ทผ: ${param.name}

HTTP ์„ธ์…˜ ์ ‘๊ทผ: ${session.name}

์Šคํ”„๋ง ๋นˆ ์ ‘๊ทผ: ${@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 : ์•„์ด๋”” ์ฒ˜๋ฆฌ ๊ด€๋ จ ๊ธฐ๋Šฅ ์ œ๊ณต

 

- ๋‚˜์ค‘์— ํ•„์š”ํ•  ๋•Œ ์ง์ ‘ ์ฐพ์•„๋ณด๋Š” ๊ฒŒ ์ข‹์„ ๋“ฏ!

 

Tutorial: Using Thymeleaf

1 Introducing Thymeleaf 1.1 What is Thymeleaf? Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text. The main goal of Thymeleaf is to provide a

www.thymeleaf.org

 

 

โœ” ๋‚ ์งœ ํ‘œ์‹œ - temporals

[date.html]

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<h1>LocalDateTime</h1>
<ul>
  <li>default = <span th:text="${localDateTime}"></span></li>
  <li>yyyy-MM-dd HH:mm:ss = <span th:text="${#temporals.format(localDateTime, 'yyyy-MM-dd HH:mm:ss')}"></span></li>
</ul>
<h1>LocalDateTime - Utils</h1>
<ul>
  <li>${#temporals.day(localDateTime)} = <span th:text="${#temporals.day(localDateTime)}"></span></li>
  <li>${#temporals.month(localDateTime)} = <span th:text="${#temporals.month(localDateTime)}"></span></li>
  <li>${#temporals.monthName(localDateTime)} = <span th:text="${#temporals.monthName(localDateTime)}"></span></li>
  <li>${#temporals.monthNameShort(localDateTime)} = <span th:text="${#temporals.monthNameShort(localDateTime)}"></span></li>
  <li>${#temporals.year(localDateTime)} = <span th:text="${#temporals.year(localDateTime)}"></span></li>
  <li>${#temporals.dayOfWeek(localDateTime)} = <span th:text="${#temporals.dayOfWeek(localDateTime)}"></span></li>
  <li>${#temporals.dayOfWeekName(localDateTime)} = <span th:text="${#temporals.dayOfWeekName(localDateTime)}"></span></li>
  <li>${#temporals.dayOfWeekNameShort(localDateTime)} = <span th:text="${#temporals.dayOfWeekNameShort(localDateTime)}"></span></li>
  <li>${#temporals.hour(localDateTime)} = <span th:text="${#temporals.hour(localDateTime)}"></span></li>
  <li>${#temporals.minute(localDateTime)} = <span th:text="${#temporals.minute(localDateTime)}"></span></li>
  <li>${#temporals.second(localDateTime)} = <span th:text="${#temporals.second(localDateTime)}"></span></li>
  <li>${#temporals.nanosecond(localDateTime)} = <span th:text="${#temporals.nanosecond(localDateTime)}"></span></li>
</ul>
</body>
</html>

- ์ด๋ ‡๊ฒŒ ๋‚ ์งœ ํ‘œ์‹œ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค :D

 

 

โœ” URL ์ƒ์„ฑ

- ๋‹จ์ˆœํ•œ URL

: {@/hello}

-> /hello

 

- ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ

: @{/hello(param1=${param1}, param2={param2})}

์ด๋•Œ, model์— {"param1", "data1"} {"param2", "data2"} ๋„ฃ์€ ๊ฒฝ์šฐ

-> /hello?param1=data1&param2=data2

 

- ๊ฒฝ๋กœ ๋ณ€์ˆ˜

: @{/hello/{param1}/{param2}(param1=${param1}param2=${param2})}

-> /hello/data1/data2

 

- ๊ฒฝ๋กœ ๋ณ€์ˆ˜ + ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ

: @{/hello/{param1}(param1=${param1}, param2=${param2})}

-> /hello/data1?param2=data2

 

 

โœ” ๋ฆฌํ„ฐ๋Ÿด

- ์†Œ์Šค ์ฝ”๋“œ ์ƒ์—์„œ ๊ณ ์ •๋œ ๊ฐ’์„ ๋งํ•˜๋Š” ์šฉ์–ด

๋ฌธ์ž / ์ˆซ์ž / boolean / null

- ๋ฌธ์ž๋Š” ํ•ญ์ƒ ''์œผ๋กœ ๊ฐ์‹ธ์•ผ ํ•œ๋‹ค.

 

- ๊ทธ๋Ÿฌ๋‚˜, ๊ณต๋ฐฑ ์—†์ด ์ญ‰ ์ด์–ด์ง€๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ํ•˜๋‚˜์˜ ํ† ํฐ์œผ๋กœ ์ธ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์‹ธ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

- ๋‹น์—ฐํžˆ, ๊ณต๋ฐฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ''๋กœ ๊ฐ์‹ธ์•ผ ํ•œ๋‹ค.

th:text="hello" (o)th:text="'hello world'" (o)

 

- ๋ฆฌํ„ฐ๋Ÿด ๋Œ€์ฒด ๋ฌธ๋ฒ•.

: ''๋กœ ๊ฐ์‹ธ์ง€ ์•Š์•„๋„ ํ•œ ๋ฒˆ์— ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค!

<span th:text="|hello ${data}|">

- ๊ธฐ์กด์—๋Š” th:text="'hello ' + ${data}"๋กœ ์ž‘์„ฑํ–ˆ์–ด์•ผ ํ•˜์ง€๋งŒ, ||๋กœ ํ•œ ๋ฒˆ์— ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

โœ” ์—ฐ์‚ฐ

- ๋น„๊ต์—ฐ์‚ฐ: HTML ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์กฐ์‹ฌํ•˜๊ธฐ

> (gt), < (lt), >= (ge), <= (le), ! (not), == (eq), != (neq, ne)

 

- ?์„ ํ†ตํ•œ ๋‹คํ•ญ ์—ฐ์‚ฐ์ž๋„ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค

<li>(10 % 2 == 0) ? '์ง์ˆ˜':'ํ™€์ˆ˜' = <span th:text="(10 % 2 == 0)? '์ง์ˆ˜':'ํ™€์ˆ˜'"></span></li>

 

- ์—ฐ์‚ฐ ์ˆ˜ํ–‰ ์•ˆ ํ•จ

<li>${nullData}? :  _ = <span th:text="${nullData}?: _">๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.</span></li>

: _์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ํƒ€์ž„๋ฆฌํ”„์˜ ํƒœ๊ทธ ํšจ๊ณผ๊ฐ€ ๋ฌดํšจ๋œ๋‹ค. ${}์˜ ๊ฒฐ๊ณผ๊ฐ€ ์•„๋‹Œ '๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค'๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

 

 

โœ” ์†์„ฑ ๊ฐ’ ์„ค์ • - th:*

- th:*์„ ํ†ตํ•ด ์†์„ฑ์„ ์ง€์ •ํ•˜๋ฉด, ํƒ€์ž„๋ฆฌํ”„๋Š” ๊ธฐ์กด ์†์„ฑ์„ th:*๋กœ ์ง€์ •ํ•œ ์†์„ฑ์œผ๋กœ ๋Œ€์ฒดํ•œ๋‹ค.

- ์ด๋•Œ, ๊ธฐ์กด ์†์„ฑ์ด ์—†๋‹ค๋ฉด ์ƒˆ๋กœ ๋งŒ๋“ ๋‹ค.

<input type="text" name="mock" th:name="userA" />
-> <input type="text" name="userA" />

 

- th:attrappend : ์†์„ฑ ๊ฐ’์˜ ๋’ค์— ๊ฐ’ ์ถ”๊ฐ€

<input type="text" class="text" th:attrappend="class=' large'" />

-> <input class="text large">


- th:attrprepend : ์†์„ฑ ๊ฐ’์˜ ์•ž์— ๊ฐ’ ์ถ”๊ฐ€

<input type="text" class="text" th:attrprepend="class='large '" />

-> <input class="large text">


- th:classappend : class ์†์„ฑ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ถ”๊ฐ€

<input type="text" class="text" th:classappend="large" />

-> <input class="text large">

 

- ๊ธฐ์กด์˜ HTML์—์„œ๋Š” checked๋ผ๋Š” ์˜ต์…˜๋งŒ ์žˆ์œผ๋ฉด ์ฒดํฌ๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋ฅผ ๋ฐฉ์ง€ํ•ด๋ณด์ž. (T/F ์ฒ˜๋ฆฌํ•˜๊ธฐ)

- checked=false <input type="checkbox" name="active" checked="false" />

: false๋ผ๊ณ  ํ•ด๋„ ๋ฐ”๋กœ ์ฒดํฌ ํ‘œ์‹œ๊ฐ€ ๋˜์–ด๋ฒ„๋ฆฌ๋Š” ๊ฒƒ.

 

- checked o <input type="checkbox" name="active" th:checked="true" />
- checked x <input type="checkbox" name="active" th:checked="false" />

: th:checked๊ฐ€ false๋ผ๋ฉด ์•„์˜ˆ checked ์˜ต์…˜ ์ž์ฒด๋ฅผ ์ œ๊ฑฐํ•ด๋ฒ„๋ฆฐ๋‹ค.

 

โœ” ๋ฐ˜๋ณต๋ฌธ - th:each

<tr th:each="user : ${users}">

- users์— ์žˆ๋Š” ๊ฐ’์„ ํ•˜๋‚˜์”ฉ user์— ๋‹ด์•„์„œ ํƒœ๊ทธ๋ฅผ ๋ฐ˜๋ณต ์‹คํ–‰ํ•ด์ฃผ๊ธฐ.

- java.util.Iterable, java.util.Enmeration์„ ๊ตฌํ˜„๋งŒ ๋ชจ๋“  ๊ฐ์ฒด์— ๋Œ€ํ•ด์„œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

<tr th:each="user, userStat : ${users}">

- ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐ˜๋ณต์˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (์ƒ๋žต ์‹œ ์ง€์ •ํ•œ ๋ณ€์ˆ˜๋ช… + Stat ํ˜•ํƒœ)

- ๋ฐ˜๋ณต์˜ ์ƒํƒœ ํ™•์ธ ์‹œ ์ „์ฒด ์‚ฌ์ด์ฆˆ๋‚˜ ํ˜„์žฌ ๊ฐ์ฒด ๋“ฑ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

 

"${userStat.index}" : 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ์ผ์ข…์˜ ์ธ๋ฑ์Šค ๊ฐ’์„ ๋ณด์—ฌ์ค€๋‹ค.

count : 1๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ์ผ์ข…์˜ ์ธ๋ฑ์Šค ๊ฐ’

size : ์ „์ฒด ์‚ฌ์ด์ฆˆ

even : ์ง์ˆ˜ ์—ฌ๋ถ€ <boolean>

odd : ํ™€์ˆ˜ ์—ฌ๋ถ€ <boolean>

first : ์ฒ˜์Œ์ธ์ง€ <boolean>

last: ๋งˆ์ง€๋ง‰์ธ์ง€ <boolean>

current: ํ˜„์žฌ ๊ฐ’

 

 

โœ” ์กฐ๊ฑด๋ถ€ ํ‰๊ฐ€

th:if : if๋ฌธ, ๋งŒ์กฑํ•˜๋Š”์ง€ ํ™•์ธ

th:unless : if๋ฌธ์˜ ๋ฐ˜๋Œ€, ๋งŒ์กฑํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธ

- ๋‘˜ ๋ชจ๋‘ true์ผ ๊ฒฝ์šฐ ํƒœ๊ทธ ์ถœ๋ ฅ, false์ผ ๊ฒฝ์šฐ ํ•ด๋‹น ํƒœ๊ทธ๋Š” ์ถœ๋ ฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

th:switch, th:case : ์ž๋ฐ”์—์„œ์˜ switch-case๋ฌธ ๊ทธ๋Œ€๋กœ. th:case="*" -> ๋งŒ์กฑํ•˜๋Š” ์กฐ๊ฑด์ด ์—†์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋””ํดํŠธ ๊ฐ’.

 

 

โœ” ์ฃผ์„

- ํ‘œ์ค€ HTML ์ฃผ์„: <!-- -->

: ํƒ€์ž„๋ฆฌํ”„๊ฐ€ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ๋‚จ๊ฒจ๋‘”๋‹ค.

 

- ํƒ€์ž„๋ฆฌํ”„ ํŒŒ์„œ ์ฃผ์„ : <!-- /* */-->

: ํƒ€์ž„๋ฆฌํ”„์˜ ์ฃผ์„์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ Œ๋”๋ง์—์„œ ์ฃผ์„ ๋ถ€๋ถ„ ์ œ๊ฑฐ.

 

- ํƒ€์ž„๋ฆฌํ”„ ํ”„๋กœํ† ํƒ€์ž… ์ฃผ์„ : <!--/*/ /*/-->

: HTML ์ฃผ์„์ด๊ธฐ ๋•Œ๋ฌธ์— ์›น ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ Œ๋”๋ง X, ํƒ€์ž„๋ฆฌํ”„ ๋ Œ๋”๋ง ์‹œ์—๋Š” ์ •์ƒ ๋ Œ๋”๋ง.

: ์ฆ‰, HTML ํŒŒ์ผ์—์„œ๋Š” ์ฃผ์„, ํƒ€์ž„๋ฆฌํ”„์—์„œ๋Š” ๋ณด์ด๊ฒŒ ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

 

 

โœ” ๋ธ”๋ก - th:block

- ํƒ€์ž„๋ฆฌํ”„๋Š” ํƒœ๊ทธ ์•ˆ์— ์†์„ฑ์œผ๋กœ ๊ธฐ๋Šฅ์„ ์ •์˜ํ•˜๋‹ค ๋ณด๋‹ˆ๊นŒ, ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ๋ฌถ์–ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ๋‹ค.

- th:block์˜ ๊ฒฝ์šฐ ๋ Œ๋”๋ง๋  ๋•Œ ์ œ๊ฑฐ๋œ๋‹ค.

<th:block th:each="user : ${users}">
  <div>
    ์‚ฌ์šฉ์ž ์ด๋ฆ„1 <span th:text="${user.username}"></span>
    ์‚ฌ์šฉ์ž ๋‚˜์ด1 <span th:text="${user.age}"></span>
  </div>
  <div>
    ์š”์•ฝ <span th:text="${user.username} + ' / ' + ${user.age}"></span>
  </div>
</th:block>

- ์ด๋Ÿฐ ์‹์œผ๋กœ 2๊ฐœ์˜ div ํƒœ๊ทธ๋ฅผ ๋ฌถ์–ด์„œ ๋ฐ˜๋ณต๋ฌธ์„ ๋Œ๋ฆฌ๊ณ  ์‹ถ๋‹ค๋“ ์ง€... ๊ทธ๋Ÿด ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

 

 

โœ” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ธ๋ผ์ธ - <script th:inline="javascript">

- ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ํƒ€์ž„๋ฆฌํ”„๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

- ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ธ๋ผ์ธ ์‚ฌ์šฉ X

<script>
    var username = [[${user.username}]];
    var age = [[${user.age}]];
    var username2 = /*[[${user.username}]]*/ "test username";
    var user = [[${user}]];
</script>

- ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ธ๋ผ์ธ ์‚ฌ์šฉ O

<script th:inline="javascript">
    var username = [[${user.username}]];
    var age = [[${user.age}]];
    var username2 = /*[[${user.username}]]*/ "test username"; // ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋„ ๋„ค์ธ„๋Ÿด ํ…œํ”Œ๋ฆฟ ๊ฐ€๋Šฅ
    var user = [[${user}]];
</script>

- ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ธ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ

 var username = [[${user.username}]]; 

์—ฌ๊ธฐ์„œ var username = userA๋ผ๊ณ  ์ธ์‹์ด ๋œ๋‹ค. ์ฆ‰, userA๋ผ๋Š” ๋ณ€์ˆ˜ ์ž์ฒด๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ํ˜•ํƒœ๊ฐ€ ๋˜์–ด๋ฒ„๋ฆฐ๋‹ค.

-> ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด var username =  "[[${user.username}]]"; ์ด๋ ‡๊ฒŒ ์จ์•ผ ํ•œ๋‹ค. 

๋ฐ˜๋ฉด, ์ธ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด var username = "userA"๋ผ๊ณ  ๋‚˜์˜ค๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ž์—ด์ด ์ž˜ ๋“ค์–ด๊ฐ€๋Š” ๊ฑธ๋กœ ๋‚˜์˜จ๋‹ค.

 

- ๋˜ํ•œ, ๋‚ด์ถ”๋Ÿด ํ…œํ”Œ๋ฆฟ ๊ธฐ๋Šฅ์˜ ์ œ๊ณต ์œ ๋ฌด์—๋„ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

    var username2 = /*[[${user.username}]]*/ "test username";

์ธ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด var username2 = /*userA*/ "test username"; ์ด๋ ‡๊ฒŒ ๋‚˜์˜ค์ง€๋งŒ,

์ธ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด var username2 = "userA"๋ผ๊ณ  ๋‚˜์˜จ๋‹ค.

: ์ธ๋ผ์ธ x์ผ ๋•Œ๋Š” ์ •๋ง ๊ทธ๋Œ€๋กœ ํ•ด์„ํ•ด๋ฒ„๋ฆฌ์ง€๋งŒ, ์ธ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ Œ๋”๋ง ์‹œ ์ฃผ์„ ๋ถ€๋ถ„์„ ์ œ๊ฑฐํ•˜๊ณ  ๊ฐ’์ด ์ž…๋ ฅ๋œ๋‹ค.

 

- ๋งˆ์ง€๋ง‰์œผ๋กœ,  var user = [[${user}]]; ์ด ๋ถ€๋ถ„์ด๋‹ค.

์ธ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด var user = BasicController.User(username=userA, age=10);๋กœ ๋‚˜์˜ค์ง€๋งŒ,

์ธ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด var user = {"username":"userA","age":10};๋กœ ๋‚˜์˜จ๋‹ค. 

: ์ธ๋ผ์ธ x์ผ ๋•Œ๋Š” ๊ฐ์ฒด์˜ toString์ด, ์ธ๋ผ์ธ ์‚ฌ์šฉ ์‹œ์—๋Š” JSON์œผ๋กœ ๋ณ€ํ™˜ํ•œ ๊ฐ’์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

- ๋˜ํ•œ, ์ธ๋ผ์ธ ์‚ฌ์šฉ ์‹œ ๋ฌธ์ž ํƒ€์ž…์ด๋ฉด ์ž๋™์œผ๋กœ "์„ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ , "๋‚˜ '๊ฐ™์€ ๋ฌธ์ž๋Š” ์ž๋™์œผ๋กœ ์ด์Šค์ผ€์ดํ”„ ์ฒ˜๋ฆฌ๋„ ํ•ด์ค€๋‹ค! 

 

 

- ๋˜ํ•œ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ธ๋ผ์ธ์€ each๋ฅผ ํ†ตํ•ด ๋ฐ˜๋ณต๋ฌธ๋„ ์ง€์›ํ•œ๋‹ค.

<script th:inline="javascript">
    [# th:each="user, stat : ${users}"]
    var user[[${stat.count}]] = [[${user}]];
    [/]
</script>

<๊ฒฐ๊ณผ>

<script>
    var user1 = {"username":"userA","age":10};
    var user2 = {"username":"userB","age":20};
    var user3 = {"username":"userC","age":30};
</script>

 


| ํƒ€์ž„๋ฆฌํ”„ - ํ…œํ”Œ๋ฆฟ ์กฐ๊ฐ / ๋ ˆ์ด์•„์›ƒ

- ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์—์„œ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ์˜์—ญ๋“ค์— ๋Œ€ํ•ด ํ…œํ”Œ๋ฆฟ ์กฐ๊ฐ ๋ฐ ๋ ˆ์ด์•„์›ƒ์œผ๋กœ ๊ด€๋ฆฌํ•˜์ž.

@GetMapping("/fragment")
public String template() {
    return "template/fragment/fragmentMain";
}

 

[footer.html] - resources/templates/template/fragment/

<!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>

- 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>

- ์กฐ๊ฐ์— ๋Œ€ํ•œ ์‚ฝ์ž…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด th:insert, th:replace๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

- th:insert๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ˜„์žฌ ํƒœ๊ทธ์˜ ๋‚ด๋ถ€์— ์‚ฝ์ž…ํ•˜๊ฒŒ ๋œ๋‹ค.

- th:replace๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ˜„์žฌ ํƒœ๊ทธ๋ฅผ ๋Œ€์ฒดํ•ด๋ฒ„๋ฆฐ๋‹ค.

 

- ~{fragment์˜ ๊ฒฝ๋กœ :: ์ด๋ฆ„}์œผ๋กœ ์ ‘๊ทผํ•œ๋‹ค.

- ์ด๋•Œ, ์ฝ”๋“œ๊ฐ€ ๋‹จ์ˆœํ•˜๋ฉด ~{}์„ ์ƒ๋žตํ•  ์ˆ˜๋„ ์žˆ๋‹ค. (๊ทธ๋ž˜๋„ ์›ฌ๋งŒํ•˜๋ฉด ์จ์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค)

- ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ๋Š” ()์„ ํ†ตํ•ด ์ „๋‹ฌํ•œ๋‹ค.

 

 

- ์ด๋ฒˆ์—๋Š”, ์ฝ”๋“œ ์กฐ๊ฐ์„ ๋ ˆ์ด์•„์›ƒ์œผ๋กœ ๋„˜๊ฒจ๋ณด์ž.

@GetMapping("/layout")
public String layout() {
    return "template/layout/layoutMain";
}

 

[base.html] - resources/templates/template/layout

<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>

- head์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ถ€๋ถ„์— ๋Œ€ํ•ด ๋ฌถ์–ด๋‘์—ˆ๋‹ค. 

- th:fragment = "common_header (title, links)"

- th:replace๋กœ ๋ฐ›์•„์˜จ title, links ์‚ฌ์šฉ.

- th:replace="${title}"

 

[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>

<head th:replace="template/layout/base :: common_header(~{::title},~{::link})">

- ๊ธฐ๋ณธ์ ์œผ๋กœ th:replace๋ฅผ ์ ์šฉํ•˜์—ฌ, base.html์— ์žˆ๋Š” head๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ.

- ์ด๋•Œ, ๋‹จ์ˆœํžˆ base ๊ทธ ์ž์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์ปค์Šคํ…€์„ ํ•˜๊ธฐ ์œ„ํ•ด ํ˜„์žฌ ํŽ˜์ด์ง€์˜ ๊ฐ’์„ ์ „๋‹ฌํ•ด์ฃผ๋Š” ๊ฒƒ!

- ::title์€ ํ˜„์žฌ ํŽ˜์ด์ง€์˜ title ํƒœ๊ทธ๋“ค์„ ์ „๋‹ฌํ•œ๋‹ค. (ํƒœ๊ทธ ์ž์ฒด๊ฐ€ ์ „๋‹ฌ!)

- ::link๋Š” ํ˜„์žฌ ํŽ˜์ด์ง€์˜ link ํƒœ๊ทธ๋“ค์„ ์ „๋‹ฌํ•œ๋‹ค.

 

 

- ์กฐ๊ธˆ ๋” ์‘์šฉํ•ด๋ณด์ž.

@GetMapping("/layoutExtend")
public String layoutExtends() {
    return "template/layoutExtend/layoutExtendMain";
}

 

[layoutFile.html] - resources/templates/template/layoutExtend

<!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>

- th:fragment = "layout (title, content)"

- th:replace๋กœ ๋ฐ›์•„์˜จ title๊ณผ content ์‚ฌ์šฉ

- th:replace="${title}"

 

[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>

- ์›๋ฆฌ๋Š” ๋™์ผํ•˜๋‹ค.

th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title}, ~{::section})}

- ์ผ๋ถ€๊ฐ€ ์•„๋‹Œ, ํ†ต์œผ๋กœ ๊ต์ฒด๋ฅผ ์‹œ์ผœ๋ฒ„๋ฆฌ์ž๋Š” ๊ฒƒ.

- ํ˜„์žฌ ํŽ˜์ด์ง€์˜ title, section ํƒœ๊ทธ ์‚ฌ์šฉ

 

- ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ด์ „ ํฌ์ŠคํŒ…์—์„œ ์ง„ํ–‰ํ•˜์˜€๋˜ '์ƒํ’ˆ ๋“ฑ๋กํผ'์„ ์กฐ๊ธˆ ๋” ๋ฐœ์ „์‹œ์ผœ๋‚˜๊ฐ€๋ณด์ž.

Comments