์ข์ ๋ฐฑ์๋ ๊ฐ๋ฐ์๊ฐ ๋๋ ค๋ฉด, JSP๋ ํ์๋ฆฌํ๋ SSR ๋ ๋๋ง ๊ธฐ์ ์ค ํ ๊ฐ์ง ์ ๋๋ ๋ฅ์ํ๊ฒ ๋ค๋ฃฐ ์ ์์ด์ผ ํ๋ค.
๊ทธ ์ค์์๋ ์คํ๋ง๊ณผ ํตํฉํ์ฌ ๋ค์ํ ๊ธฐ๋ฅ์ ํธ๋ฆฌํ๊ฒ ์ง์ํ๋ View ํ ํ๋ฆฟ ํ์๋ฆฌํ์ ๊ฐ๋ ์ ๊ฐ๋จํ ์์๋ณด๊ณ , ์ค์ ๋์ํ๋ ๊ธฐ๋ฅ ์์ฃผ๋ก ๊ณต๋ถํด๋ณด์.
- ๊ณต์ ์ฌ์ดํธ: https://www.thymeleaf.org/
- ๊ณต์ ๋ฉ๋ด์ผ - ๊ธฐ๋ณธ๊ธฐ๋ฅ: https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
- ๊ณต์ ๋ฉ๋ด์ผ - ์คํ๋ง ํตํฉ: https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html
- ์๋ฒ ์ฌ์ด๋ HTML ๋ ๋๋ง (SSR)
- ๋ค์ธ๋ด ํ ํ๋ฆฟ
- ์คํ๋ง ํตํฉ ์ง์
ํ์๋ฆฌํ๋ ๋ฐฑ์๋ ์๋ฒ์์ HTML์ ๋์ ์ผ๋ก ๋ ๋๋ง ํ๋ ์ฉ๋๋ก ์ฌ์ฉ๋๋ค
ํ์๋ฆฌํ๋ ์์ HTML์ ์ต๋ํ ์ ์งํ๋ ํน์ง์ด ์๋ค.
ํ์๋ฆฌํ๋ก ์์ฑํ ํ์ผ์ HTML์ ์ ์งํ๊ธฐ ๋๋ฌธ์ ์น ๋ธ๋ผ์ฐ์ ์์ ํ์ผ์ ์ง์ ์ด์ด๋ ๋ด์ฉ์ ํ์ธํ ์ ์๊ณ , ๋ทฐ ํ ํ๋ฆฟ์ ๊ฑฐ์น๋ฉด ๋์ ์ผ๋ก ๋ณ๊ฒฝ๋ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์๋ค.
JSP๋ฅผ ํฌํจํ ๋ค๋ฅธ ๋ทฐ ํ ํ๋ฆฟ๋ค์ ํด๋น ํ์ผ์ ์ด๋ฉด, JSP ํ์ผ ์์ฒด๋ฅผ ์น ๋ธ๋ผ์ฐ์ ์์ ๊ทธ๋๋ก ์ด์ด๋ณด๋ฉด JSP ์์ค์ฝ๋์ HTML์ด ๋ค์ฃฝ๋ฐ์ฃฝ ์์ฌ ์น ๋ธ๋ผ์ฐ์ ์์ ์ ์์ ์ธ HTML ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์๋ค. ์ค์ง ์๋ฒ๋ฅผ ํตํด์ JSP๊ฐ ๋ ๋๋ง ๋๊ณ HTML ์๋ต ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์์ผ ํ๋ฉด์ ํ์ธํ ์ ์๋ค.
๋ฐ๋ฉด์ ํ์๋ฆฌํ๋ก ์์ฑ๋ ํ์ผ์ ํด๋น ํ์ผ์ ๊ทธ๋๋ก ์น ๋ธ๋ผ์ฐ์ ์์ ์ด์ด๋ ์ ์์ ์ธ HTML ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์๋ค. ๋ฌผ๋ก ์ด ๊ฒฝ์ฐ ๋์ ์ผ๋ก ๊ฒฐ๊ณผ๊ฐ ๋ ๋๋ง ๋์ง๋ ์์ง๋ง, ํ์ผ๋ง ์ด์ด๋ HTML ๋งํฌ์ ๊ฒฐ๊ณผ๊ฐ ์ด๋ป๊ฒ ๋๋์ง ๋ฐ๋ก ํ์ธํ ์ ์๋ค.
์ด๋ ๊ฒ ์์ HTML์ ๊ทธ๋๋ก ์ ์งํ๋ฉด์ ๋ทฐ ํ ํ๋ฆฟ๋ ์ฌ์ฉํ ์ ์๋ ํ์๋ฆฌํ์ ํน์ง์ ๋ค์ธ๋ด ํ ํ๋ฆฟ(natural templates)์ด๋ผ ํ๋ค.
ํ์๋ฆฌํ๋ ์คํ๋ง๊ณผ ์์ฐ์ค๋ฝ๊ฒ ํตํฉ๋๊ณ , ์คํ๋ง์ ๋ค์ํ ๊ธฐ๋ฅ์ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ์ง์ํ๋ค.
- ํ์๋ฆฌํ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ค์ ์ ์ธ์ ์ถ๊ฐํ๋ค.
<html xmlns:th ="http://www.thymeleaf.org">
๊ธฐ๋ณธ ํํ์: https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#standard-expression-syntax
ํ์๋ฆฌํ์ ๊ฐ์ฅ ๊ธฐ๋ณธ ๊ธฐ๋ฅ์ธ ํ ์คํธ๋ฅผ ์ถ๋ ฅํ๋ ๊ธฐ๋ฅ์ด๋ค.
ํ์๋ฆฌํ๋ ๊ธฐ๋ณธ์ ์ผ๋ก HTML ํ๊ทธ์ ์์ฑ์ ๊ธฐ๋ฅ์ ์ ์ํด์ ๋์ํ๋ค.
HTML์ ์ฝํ
์ธ ์ ๋ฐ์ดํฐ๋ฅผ ์ถ๋ ฅํ ๋๋ ๋ค์๊ณผ ๊ฐ์ด th:text๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
<span th:text="${data}">
HTML ํ๊ทธ์ ์์ฑ์ด ์๋๋ผ HTML ์ฝํ ์ธ ์์ญ์์์ ์ง์ ๋ฐ์ดํฐ๋ฅผ ์ถ๋ ฅํ๊ณ ์ถ์ผ๋ฉด ๋ค์๊ณผ ๊ฐ์ด [[...]]๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
package hello.thymeleaf.basic;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/basic")
public class BasicController {
@GetMapping("text-basic")
public String textBasic(Model model) {
model.addAttribute("data", "Hello Spring!");
return "basic/text-basic";
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>์ปจํ
์ธ ์ ๋ฐ์ดํฐ ์ถ๋ ฅํ๊ธฐ</h1>
<ul>
<li>th:text ์ฌ์ฉ <span th:text="${data}"></span></li>
<li>์ปจํ
์ธ ์์์ ์ง์ ์ถ๋ ฅํ๊ธฐ = [[${data}]]</li>
</ul>
</body>
</html>
๊ฐ๋จํ๊ฒ Hello Spring ๋ฌธ์ฅ์ thymeleaf๋ฅผ ์ด์ฉํด์ ์ถ๋ ฅ์์ผ๋ณด์๋ค.
HTML ๋ฌธ์๋ <,> ๊ฐ์ ํน์ ๋ฌธ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ ์๋๋ค.
๋ฐ๋ผ์ ๋ทฐ ํ
ํ๋ฆฟ์ผ๋ก HTML ํ๋ฉด์ ์์ฑํ ๋๋ ์ถ๋ ฅํ๋ ๋ฐ์ดํฐ์ ์ด๋ฌํ ํน์ ๋ฌธ์๊ฐ ์๋ ๊ฒ์ ์ฃผ์ํด์ ์ฌ์ฉํด์ผ ํ๋ค.
model.addAttribute("data", "Hello <b>Spring!</b>");
์ Hello Spring! ๋ฌธ์ฅ ์ค ํ๊ทธ๋ฅผ ์ฌ์ฉํด์ Spring! ์ด๋ผ๋ ๋จ์ด๊ฐ ์งํ๊ฒ ๋์ค๋๋ก ์ฝ๋๋ฅผ ์์ ํด๋ณด์๋ค.
๋ด๊ฐ ๊ธฐ๋ํ๋ ๊ฒฐ๊ณผ๋ Spring! ๋จ์ด๊ฐ ์งํ๊ฒ ๋์ค๋ ๊ฒ์ด์์ง๋ง, ํ๊ทธ๊ฐ ๊ทธ๋๋ก ๋ธ๋ผ์ฐ์ ์์ ๋ณด์ด๋ ์์ค์ฝ๋๋ ์ด์ํ ๋ฌธ์๋ค์ด ์์ฌ์๋ ๊ฒ์ ๋ณผ ์ ์์๋ค.
- ์น ๋ธ๋ผ์ฐ์ ๋ < ๋ฅผ HTML ํ๊ทธ์ ์์์ผ๋ก ์ธ์ํ๋ค.
- ๋ฐ๋ผ์ < ๋ฅผ ํ๊ทธ์ ์์์ด ์๋๋ผ ๋ฌธ์๋ก ํํํ ์ ์๋ ๋ฐฉ๋ฒ์ด ํ์ํ๋ฐ ์ด ๊ฒ์ HTML ์ํฐํฐ๋ผ ํ๋ค.
- ๊ทธ๋ฆฌ๊ณ ์ด๋ ๊ฒ HTML์์ ์ฌ์ฉํ๋ ํน์๋ฌธ์๋ฅผ HTML ์ํฐํฐ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ ์ด์ค์ผ์ดํ(escape)๋ผ ํ๋ค.
- ๊ทธ๋ฆฌ๊ณ ํ์๋ฆฌํ๊ฐ ์ ๊ณตํ๋ th:text, [[...]] ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ด์ค์ผ์ดํ(escape)๋ฅผ ์ ๊ณตํ๋ค.
- < -> <
- < -> >
- ๊ธฐํ ์ ๋ง์ HTML ์ํฐํฐ๊ฐ ์๋ค.
ํ์๋ฆฌํ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ด์ค์ผ์ดํ๋ฅผ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ฅ์ ์ํ์ง ์์๋๋
- th:text -> th:utext
- [[...]] -> [(...)]
๋ก ๋ฐ๊ฟ์ฃผ๋ฉด ๋๋ค.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<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>
- ์ค์ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๋ค ๋ณด๋ฉด escape๋ฅผ ์ฌ์ฉํ์ง ์์์ HTML์ด ์ ์ ๋ ๋๋ง ๋์ง ์๋ ์๋ง์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
- escape๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ํ๊ณ , ๊ผญ ํ์ํ ๋๋ง unescape๋ฅผ ์ฌ์ฉํ์!
ํ์๋ฆฌํ์์ ๋ณ์๋ฅผ ์ฌ์ฉํ ๋๋ ๋ณ์ ํํ์์ ์ฌ์ฉํ๋ค.
- ๋ณ์ ํํ์: ${...}
์ด ๋ณ์ ํํ์์๋ ์คํ๋ง EL์ด๋ผ๋ ์คํ๋ง์ด ์ ๊ณตํ๋ ํํ์์ ์ฌ์ฉํ ์ ์๋ค.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>SpringEL ํํ์</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>${users[0].username} = <span th:text="${users[0].username}"></span></li>
<li>${users[0]['username']} = <span th:text="${users[0]['username']}"></span></li>
<li>${users[0].getUsername()} = <span th:text="${users[0].getUsername()}"></span></li>
</ul>
<ul>Map
<li>${userMap['userA'].username} = <span th:text="${userMap['userA'].username}"></span></li>
<li>${userMap['userA']['username']} = <span th:text="${userMap['userA']['username']}"></span></li>
<li>${userMap['userA'].getUsername()} = <span th:text="${userMap['userA'].getUsername()}"></span></li>
</ul>
</body>
</html>
th:with๋ฅผ ์ฌ์ฉํ๋ฉด ์ง์ญ ๋ณ์๋ฅผ ์ ์ธํด์ ์ฌ์ฉํ ์ ์๋ค. ์ง์ญ ๋ณ์๋ ์ ์ธํ ํ๊ทธ ์์์๋ง ์ฌ์ฉ๊ฐ๋ฅํ๋ค.
<h1>์ง์ญ ๋ณ์ - (th:with)</h1>
<div th:with="first=${users[0]}">
<p>์ฒ์ ์ฌ๋์ ์ด๋ฆ์ <span th:text="${first.username}"></span></p>
</div>
ํ์ ๋ฆฌํ๋ ๊ธฐ๋ณธ ๊ฐ์ฒด๋ค์ ์ ๊ณตํ๋ค.
- ${#request}
- ${#response}
- ${#session}
- ${#servletContext}
- ${#locale}
๊ทธ๋ฐ๋ฐ #request๋ HttpServletRequest ๊ฐ์ฒด๊ฐ ๊ทธ๋๋ก ์ ๊ณต๋๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ค๋ฉด
request.getParameter("data")์ฒ๋ผ ๋ถํธํ๊ฒ ์ ๊ทผํด์ผ ํ๋ค.
์ด๋ฐ ์ ์ ํด๊ฒฐํ๊ธฐ ์ํด ํธ์ ๊ฐ์ฒด๋ ์ ๊ณตํ๋ค.
-HTTP ์์ฒญ ํ๋ผ๋ฏธํฐ ์ ๊ทผ: param
-ex)
@GetMapping("/basic-objects")
public String basicObjects(HttpSession session) {
session.setAttribute("sessionData", "Hello Session");
return "basic/basic-objects";
}
@Component("helloBean")
static class HelloBean {
public String hello(String data) {
return "Hello" + data;
}
}
<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>
ํ์๋ฆฌํ๋ ๋ฌธ์, ์ซ์, ๋ ์ง URI๋ฑ์ ํธ๋ฆฌํ๊ฒ ๋ค๋ฃจ๋ ๋ค์ํ ์ ํธ๋ฆฌํฐ ๊ฐ์ฒด๋ค์ ์ ๊ณตํ๋ค.
ํ์๋ฆฌํ ์ ํธ๋ฆฌํฐ ๊ฐ์ฒด๋ค
- #message : ๋ฉ์์ง, ๊ตญ์ ํ ์ฒ๋ฆฌ
- #uris : URI ์ด์ค์ผ์ดํ ์ง์
- #dates : java.util.Date ์์ ์ง์
- #calendars : java.util.Calendar ์์ ์ง์
- #temporals : ์๋ฐ8 ๋ ์ง ์์ ์ง์
- #numbers : ์ซ์ ์์ ์ง์
- #strings : ๋ฌธ์ ๊ด๋ จ ํธ์ ๊ธฐ๋ฅ
- #objects : ๊ฐ์ฒด ๊ด๋ จ ๊ธฐ๋ฅ ์ ๊ณต
- #bools : boolean ๊ด๋ จ ๊ธฐ๋ฅ ์ ๊ณต
- #arrays : ๋ฐฐ์ด ๊ด๋ จ ๊ธฐ๋ฅ ์ ๊ณต
- #lists , #sets , #maps : ์ปฌ๋ ์ ๊ด๋ จ ๊ธฐ๋ฅ ์ ๊ณต
- #ids : ์์ด๋ ์ฒ๋ฆฌ ๊ด๋ จ ๊ธฐ๋ฅ ์ ๊ณต, ๋ค์์ ์ค๋ช
ํ์๋ฆฌํ ์ ํธ๋ฆฌํฐ ๊ฐ์ฒด
์ ํธ๋ฆฌํฐ ๊ฐ์ฒด ์์
์ด๋ฐ ์ ํธ๋ฆฌํฐ ๊ฐ์ฒด๋ค์ ๋๋ต ์ด๋ฐ ๊ฒ์ด ์๋ค ์์๋๊ณ , ํ์ํ ๋ ์ฐพ์์ ์ฌ์ฉํ์!
ํ์๋ฆฌํ์์ ์๋ฐ8 ๋ ์ง์ธ LocalDate, LocalDateTime, Instant๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ถ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํ๋ฐ,
์คํ๋ง ๋ถํธ ํ์๋ฆฌํ๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋์ผ๋ก ์ถ๊ฐ๋๊ณ ํตํฉ๋๋ค.
ํ์๋ฆฌํ ์๋ฐ8 ๋ ์ง ์ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
thymeleaf-extras-java8time
์๋ฐ8 ๋ ์ง์ฉ ์ ํธ๋ฆฌํฐ ๊ฐ์ฒด
#temporals
@GetMapping("/date")
public String data(Model model) {
model.addAttribute("localDateTime", LocalDateTime.now());
return "basic/date";
}
<span th:text="${#temporals.format(localDateTime, 'yyyy-MM-dd HH:mm:ss')}"></span>
ํ์๋ฆฌํ์์ URL์ ์์ฑํ ๋๋ @{...} ๋ฌธ๋ฒ์ ์ฌ์ฉํ๋ฉด ๋๋ค.
@GetMapping("/link")
public String link(Model model) {
model.addAttribute("param1", "data1");
model.addAttribute("param2", "data2");
return "basic/link";
}
<li><a th:href="@{/hello}">basic url</a></li>
<!--http://localhost:8080/hello-->
<li><a th:href="@{/hello(param1=${param1}, param2=${param2})}">hello query param</a></li>
<!--http://localhost:8080/hello?param1=data1¶m2=data2-->
<li><a th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}">path variable</a></li>
<!--http://localhost:8080/hello/data1/data2-->
<li><a th:href="@{/hello/{param1}(param1=${param1}, param2=${param2})}">path variable + query parameter</a></li>
<!--http://localhost:8080/hello/data1?param2=data2-->
๋ฆฌํฐ๋ด์ ์์ค ์ฝ๋์์ ๊ณ ์ ๋ ๊ฐ์ ๋งํ๋ ์ฉ์ด์ด๋ค.
ํ์๋ฆฌํ๋ ๋ค์๊ณผ ๊ฐ์ ๋ฆฌํฐ๋ด์ด ์๋ค.
- ๋ฌธ์: 'hello'
- ์ซ์: 10
- ๋ถ๋ฆฐ: true, false
- null: null
ํ์๋ฆฌํ์์ ๋ฌธ์ ๋ฆฌํฐ๋ด์ ํญ์ ์์ ๋ฐ์ดํ๋ก ๊ฐ์ธ์ผ ํ๋ค.
๊ทธ๋ฐ๋ฐ ๋ฌธ์๋ฅผ ํญ์ '๋ก ๊ฐ์ธ๋ ๊ฒ์ ๋๋ฌด ๊ท์ฐฎ์ ์ผ์ด๋ค.
๊ณต๋ฐฑ ์์ด ์ญ ์ด์ด์ง๋ค๋ฉด ํ๋์ ์๋ฏธ์๋ ํ ํฐ์ผ๋ก ์ธ์งํด์ ๋ค์๊ณผ ๊ฐ์ด ์์ ๋ฐ์ดํ๋ฅผ ์๋ตํ ์ ์๋ค.
๋ฃฐ: A-Z, a-z, 0-9, [], ., -, _
์ค๋ฅ
<span th:text="hello world!"></span>
๋ฌธ์ ๋ฆฌํฐ๋ด์ ์์น์ '๋ก ๊ฐ์ธ์ผ ํ๋ค. ์ค๊ฐ์ ๊ณต๋ฐฑ์ด ์์ด์ ํ๋์ ํ ํฐ์ผ๋ก๋ ์ธ์๋์ง ์๋๋ค.
์์
<span th:text="'hello world!'"></span>
<li>'hello' + ' world!' = <span th:text="'hello' + ' world!'"></span></li> <!--hello world!-->
<li>'hello world!' = <span th:text="'hello world!'"></span></li> <!--hello world!-->
<li>'hello ' + ${data} = <span th:text="'hello ' + ${data}"></span></li> <!--hello Spring-->
<span th:text="|hello $(data)|"> <!--hello Spring-->
ํ์๋ฆฌํ ์ฐ์ฐ์ ์๋ฐ์ ํฌ๊ฒ ๋ค๋ฅด์ง ์๋ค. HTML ์์์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ HTML ์ํฐํฐ๋ฅผ ์ฌ์ฉํ๋ ๋ถ๋ถ๋ง ์ฃผ์ํ์
- ๋น๊ต์ฐ์ฐ: HTML ์ํฐํฐ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ๋ถ๋ถ์ ์ฃผ์ํ์,
- > (gt), < (lt), >= (ge), <= (le), ! (not), == (eq), != (neq, ne)
<li>1 > 10 = <span th:text="1 > 10"></span></li>
<li>1 gt 10 = <span th:text="1 gt 10"></span></li>
<li>1 >= 10 = <span th:text="1 >= 10"></span></li>
<li>1 ge 10 = <span th:text="1 ge 10"></span></li>
<li>1 == 10 = <span th:text="1 == 10"></span></li>
<li>1 != 10 = <span th:text="1 != 10"></span></li>
- ์กฐ๊ฑด์: ์๋ฐ์ ์กฐ๊ฑด์๊ณ ์ ์ฌํ๋ค.
<li>(10 % 2 == 0)? '์ง์':'ํ์' = <span th:text="(10 % 2 == 0)? '์ง์':'ํ์'"></span></li>
- Elvis ์ฐ์ฐ์: ์กฐ๊ฑด์์ ํธ์ ๋ฒ์
<li>${data}?: '๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค.' = <span th:text="${data}?: '๋ฐ์ดํฐ๊ฐ์์ต๋๋ค.'"></span></li> <!--Spring -->
<li>${nullData}?: '๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค.' = <span th:text="${nullData}?: '๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค.'"></span></li> <!--๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค-->
- No- Operation: _ ์ธ ๊ฒฝ์ฐ ๋ง์น ํ์๋ฆฌํ๊ฐ ์คํ๋์ง ์๋ ๊ฒ ์ฒ๋ผ ๋์ํ๋ค.
์ด ๊ฒ์ ์ ์ฌ์ฉํ๋ฉด HTML์ ๋ด์ฉ ๊ทธ๋๋ก ํ์ฉํ ์ ์๋ค. ๋ง์ง๋ง ์๋ฅผ ๋ณด๋ฉด ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค. ๋ถ๋ถ์ด ๊ทธ๋๋ก ์ถ๋ ฅ๋๋ค.
<li>${data}?: _ = <span th:text="${data}?: _">๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค.</span></li> <!--Spring-->
<li>${nullData}?: _ = <span th:text="${nullData}?: _">๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค.</span></li> <!--๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค-->
ํ์๋ฆฌํ์์ ๋ฐ๋ณต์ th:each๋ฅผ ์ฌ์ฉํ๋ค.
@GetMapping("/each")
public String each(Model model) {
addUsers(model);
return "basic/each";
}
private void addUsers(Model model) {
List<User> list = new ArrayList<>();
list.add(new User("userA", 10));
list.add(new User("userB", 20));
list.add(new User("userC", 30));
model.addAttribute("users", list);
}
<h1>๊ธฐ๋ณธ ํ
์ด๋ธ</h1>
<table border="1">
<tr>
<th>username</th>
<th>age</th>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
</tr>
</table>
<tr th:each="user, userStat : ${user}">
๋ฐ๋ณต์ ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ฅผ ์ค์ ํด์ ๋ฐ๋ณต์ ์ํ๋ฅผ ํ์ธ ํ ์ ์๋ค.
๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ ์๋ต ๊ฐ๋ฅํ๋ฐ, ์๋ตํ๋ฉด ์ง์ ํ ๋ณ์๋ช
(user) + Stat์ด ๋๋ค.
<h1>๋ฐ๋ณต ์ํ ์ ์ง</h1>
<table border="1">
<tr>
<th>count</th>
<th>username</th>
<th>age</th>
<th>etc</th>
</tr>
<tr th:each="user, userStat : ${users}">
<td th:text="${userStat.count}">username</td>
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
<td>
index = <span th:text="${userStat.index}"></span>
count = <span th:text="${userStat.count}"></span>
size = <span th:text="${userStat.size}"></span>
even? = <span th:text="${userStat.even}"></span>
odd? = <span th:text="${userStat.odd}"></span>
first? = <span th:text="${userStat.first}"></span>
last? = <span th:text="${userStat.last}"></span>
current = <span th:text="${userStat.current}"></span>
</td>
</tr>
</table>
ํ์๋ฆฌํ์ ์กฐ๊ฑด์ if, unless
ํ์๋ฆฌํ๋ ํด๋น ์กฐ๊ฑด์ด ๋ง์ง ์์ผ๋ฉด ํ๊ทธ ์์ฒด๋ฅผ ๋ ๋๋งํ์ง ์๋๋ค.
<h1>if, unless</h1>
<table border="1">
<tr>
<th>count</th>
<th>username</th>
<th>age</th>
</tr>
<tr th:each="user, userStat : ${users}">
<td th:text="${userStat.count}">1</td>
<td th:text="${user.username}">username</td>
<td>
<span th:text="${user.age}">0</span>
<span th:text="'๋ฏธ์ฑ๋
์'" th:if="${user.age lt 20}"></span>
<span th:text="'๋ฏธ์ฑ๋
์'" th:unless="${user.age ge 20}"></span>
</td>
</tr>
</table>
* ์ ๋ง์กฑํ๋ ์กฐ๊ฑด์ด ์์ ๋ ์ฌ์ฉํ๋ ๋ํดํธ์ด๋ค.
<h1>switch</h1>
<table border="1">
<tr>
<th>count</th>
<th>username</th>
<th>age</th>
</tr>
<tr th:each="user, userStat : ${users}">
<td th:text="${userStat.count}">1</td>
<td th:text="${user.username}">username</td>
<td th:switch="${user.age}">
<span th:case="10">10์ด</span>
<span th:case="20">20์ด</span>
<span th:case="*">๊ธฐํ</span>
</td>
</tr>
</table>
@GetMapping("/comments")
public String comments(Model model) {
model.addAttribute("data", "Spring!");
return "basic/comments";
}
<h1>์์</h1>
<span th:text="${data}">html data</span>
<h1>1. ํ์ค HTML ์ฃผ์</h1>
<!--
<span th:text="${data}">html data</span>
-->
<h1>2. ํ์๋ฆฌํ ํ์ ์ฃผ์</h1>
<!--/* [[${data}]] */-->
<!--/*-->
<span th:text="${data}">html data</span>
<!--*/-->
<h1>3. ํ์๋ฆฌํ ํ๋กํ ํ์
์ฃผ์</h1>
<!--/*/
<span th:text="${data}">html data</span>
/*/-->
1. ํ์ค HTML ์ฃผ์
์๋ฐ์คํฌ๋ฆฝํธ์ ํ์ค HTML ์ฃผ์์ ํ์๋ฆฌํ๊ฐ ๋ ๋๋ง ํ์ง ์๊ณ , ๊ทธ๋๋ก ๋จ๊ฒจ๋๋ค.
2. ํ์๋ฆฌํ ํ์ ์ฃผ์
ํ์๋ฆฌํ ํ์ ์ฃผ์์ ํ์๋ฆฌํ์ ์ง์ง ์ฃผ์์ด๋ค. ๋ ๋๋ง์์ ์ฃผ์ ๋ถ๋ถ์ ์ ๊ฑฐํ๋ค.
3. ํ์๋ฆฌํ ํ๋กํ ํ์
์ฃผ์
ํ์๋ฆฌํ ํ๋กํ ํ์
์ ์ฝ๊ฐ ํน์ดํ๋ฐ, HTML ์ฃผ์์ ์ฝ๊ฐ์ ๊ตฌ๋ฌธ์ ๋ํ๋ค.
HTML ํ์ผ์ ์น ๋ธ๋ผ์ฐ์ ์์ ๊ทธ๋๋ก ์ด์ด๋ณด๋ฉด HTML ์ฃผ์์ด๊ธฐ ๋๋ฌธ์ ์ด ๋ถ๋ถ์ด ์น ๋ธ๋ผ์ฐ์ ๊ฐ ๋ ๋๋ง ํ์ง ์๋๋ค.
ํ์๋ฆฌํ ๋ ๋๋ง์ ๊ฑฐ์น๋ฉด ์ด ๋ถ๋ถ์ด ์ ์ ๋ ๋๋ง ๋๋ค.
์ฝ๊ฒ ์ด์ผ๊ธฐํด์ HTML ํ์ผ์ ๊ทธ๋๋ก ์ด์ด๋ณด๋ฉด ์ฃผ์์ฒ๋ฆฌ๊ฐ ๋์ง๋ง, ํ์๋ฆฌํ๋ฅผ ๋ ๋๋ง ํ ๊ฒฝ์ฐ์๋ง ๋ณด์ด๋ ๊ธฐ๋ฅ์ด๋ค.
th:block์ HTML ํ๊ทธ๊ฐ ์๋ ํ์๋ฆฌํ์ ์ ์ผํ ์์ฒด ํ๊ทธ๋ค.
<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>
ํ์๋ฆฌํ๋ ์๋ฐ์คํฌ๋ฆฝํธ์์ ํ์๋ฆฌํ๋ฅผ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ธ๋ผ์ธ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค
<script th:inline="javascript">
@GetMapping("/javascript")
public String javascript(Model model) {
model.addAttribute("user", new User("userA", 10));
addUsers(model);
return "basic/javascript";
}
<!-- ์๋ฐ์คํฌ๋ฆฝํธ ์ธ๋ผ์ธ ์ฌ์ฉ ์ -->
<script>
var username = [[${user.username}]];
var age = [[${user.age}]];
//์๋ฐ์คํฌ๋ฆฝํธ ๋ด์ถ๋ด ํ
ํ๋ฆฟ
var username2 = /*[[${user.username}]]*/ "test username";
//๊ฐ์ฒด
var user = [[${user}]];
</script>
<!-- ์๋ฐ์คํฌ๋ฆฝํธ ์ธ๋ผ์ธ ์ฌ์ฉ ํ -->
<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;
- ์ธ๋ผ์ธ ์ฌ์ฉ ํ -> var username = "userA";
์ธ๋ผ์ธ ์ฌ์ฉ ์ ๋ ๋๋ง ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ณ , "userA" ๋์ userA ๋ผ๋ ๋ณ์ ์ด๋ฆ์ด ๊ทธ๋๋ก ๋จ์์๋ค.
๋ค์ ์ผ๋ก ๋์ค๋ ์ซ์ age์ ๊ฒฝ์ฐ์๋ "๊ฐ ํ์ ์๊ธฐ๋๋ฌธ์ ์ ์ ๋ ๋๋ง ๋๋ค.
์ธ๋ผ์ธ ์ฌ์ฉ ํ ๋ ๋๋ง ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ๋ฌธ์ ํ์
์ธ ๊ฒฝ์ฐ " ๋ฅผ ํฌํจํด์ค๋ค.
์ถ๊ฐ๋ก ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ฌธ์ ๊ฐ ๋ ์ ์๋ ๋ฌธ์๊ฐ ํฌํจ๋์ด ์์ผ๋ฉด ์ด์ค์ผ์ดํ ์ฒ๋ฆฌ๋ ํด์ค๋ค.
ํ์๋ฆฌํ๋ HTML ํ์ผ์ ์ง์ ์ด์ด๋ ๋์ํ๋ ๋ด์ถ๋ด ํ
ํ๋ฆฟ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด ์ฃผ์์ ํ์ฉํด์ ์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋ค.
- var username2 = /*[[${user.username}]]*/ "test username";
- ์ธ๋ผ์ธ ์ฌ์ฉ ์ -> var username2 = /*userA*/ "test username";
- ์ธ๋ผ์ธ ์ฌ์ฉ ํ -> var username2 = "userA";
์ธ๋ผ์ธ ์ฌ์ฉ ์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์ ๋ง ๊ทธ๋๋ก ์ถ๋ ฅํ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ธ๋ผ์ธ์ ์ฌ์ฉํ๋ฉด ์ฃผ์ ๋ถ๋ถ์ ์ ๊ฑฐ๋๊ณ , ๊ธฐ๋ํ๋๋๋ก "userA"๋ง ์ ํํ ์ถ๋ ฅ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
ํ์๋ฆฌํ์ ์๋ฐ์คํฌ๋ฆฝํธ ์ธ๋ผ์ธ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด๋ฅผ JSON์ผ๋ก ์๋์ผ๋ก ๋ณํํด์ค๋ค.
- var user = [[${user}]];
- ์ธ๋ผ์ธ ์ฌ์ฉ ์ -> var user = BasicController.User(username=userA, age=10);
- ์ธ๋ผ์ธ ์ฌ์ฉ ํ -> var user = {"username":"userA", "age":10};
์ธ๋ผ์ธ ์ฌ์ฉ ์ ์ ๊ฐ์ฒด์ toString()์ด ํธ์ถ๋ ๊ฐ์ด๋ค.
์ธ๋ผ์ธ ์ฌ์ฉ ํ๋ ๊ฐ์ฒด๋ฅผ JSON์ผ๋ก ๋ณํ ํด์ค๋ค.
์น ํ์ด์ง๋ฅผ ๊ฐ๋ฐํ ๋๋ ๊ณตํต ์์ญ์ด ๋ง์ด ์๋ค. ์ด๋ฐ ์์ญ๋ค์ ์ฝ๋๋ฅผ ๋ณต์ฌํด์ ์ฌ์ฉํ๋ค๋ฉด ๋ณ๊ฒฝ์ ์ฌ๋ฌ ํ์ด์ง๋ฅผ
๋ค ์์ ํด์ผ ํ๋ฏ๋ก ์๋นํ ๋นํจ์จ ์ ์ด๋ค. ํ์๋ฆฌํ๋ ์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํ
ํ๋ฆฟ ์กฐ๊ฐ๊ณผ ๋ ์ด์์ ๊ธฐ๋ฅ์ ์ง์ํ๋ค.
@Controller
@RequestMapping("/template")
public class TemplateController {
@GetMapping("/fragment")
public String template() {
return "template/fragment/fragmentMain";
}
}
<!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>
<!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>
ํ ํ๋ฆฟ ์กฐ๊ฐ์ ๋ฌด์๋ณด๋ค๋ ์ง์ ์คํ์ ํด๋ด์ผ ์ด๋ป๊ฒ ๋๋๊ฑด์ง ์ดํด๊ฐ ๋๋ค.
์ฐ์ GetMapping์ ๋ฆฌํด์ fragmentMain.html๋ก ์์ผ์ฃผ๋๋ฐ,
footer.html ํ
ํ๋ฆฟ์ ์๋ th:fragment="copy" ๋ถ๋ถ์ด
fragment.html ~{template/fragment/footer :: copy} ๋ก ์ด๋ํ ๊ฒ์ ๋ณผ ์ ์๋ค.
๊ทธ ์ค์์๋ th:insert ๋ฅผ ์ฌ์ฉํ ๋ถ๋ถ์ ํ์ฌ ํ๊ทธ์ธ div ๋ด๋ถ์ footer ํ๊ทธ๋ฅผ ์ถ๊ฐํ์๊ณ .
th:replace๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ฌ ํ๊ทธ์ธ div๋ฅผ ๋์ฒดํ๋ค.
~{...}๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์์น์ด์ง๋ง ํ ํ๋ฆฟ ์กฐ๊ฐ์ ์ฌ์ฉํ๋ ์ฝ๋๊ฐ ๋จ์ํ๋ฉด ์ด ๋ถ๋ถ์ ์๋ต ํ ์๋ ์๋ค.
๊ทธ๋ฆฌ๊ณ ๋น์ฐํ ํ๋ผ๋ฏธํฐ๋ ๋์ ์ผ๋ก ์กฐ๊ฐ์ ๋ ๋๋ง ํ ์ ์๋ค.
์ฝ๋ ์กฐ๊ฐ์ ๋ ์ด์์์ ๋๊ฒจ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์.
์๋ฅผ ๋ค์ด <head>์ ๊ณตํต์ผ๋ก ์ฌ์ฉํ๋ css, javascript ๊ฐ์ ์ ๋ณด๋ค์ด ์๋๋ฐ ์ด๋ฐ ๊ณตํต ์ ๋ณด๋ค์ ํ ๊ณณ์ ๋ชจ์๋๊ณ , ๊ณตํต์ผ๋ก ์ฌ์ฉํ์ง๋ง
๊ฐ ํ์ด์ง๋ง๋ค ํ์ํ ์ ๋ณด๋ฅผ ๋ ์ถ๊ฐํด์ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ๋๋ค.
@GetMapping("layout")
public String layout() {
return "template/layout/layoutMain";
}
<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>
<!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>
- common_header(
{::title},{::link}) ์ค์- ::title์ ํ์ฌ ํ์ด์ง์ title ํ๊ทธ๋ค์ ์ ๋ฌํ๋ค.
- ::link๋ ํ์ฌ ํ์ด์ง์ link ํ๊ทธ๋ค์ ์ ๋ฌํ๋ค.
๋ ์ด์์ ๊ฐ๋ ์ ๋๊ณ , ๊ทธ ๋ ์ด์์์ ํ์ํ ์ฝ๋ ์กฐ๊ฐ์ ์ ๋ฌํด์ ์์ฑํ๋ ๊ฒ์ผ๋ก ์ดํดํ๋ฉด ๋๋ค.
๋ ์ด์์ ๊ฐ๋ ์ <html> ์ ์ฒด์ ์ ์ฉํ ์๋ ์๋ค.
์ฌ์ดํธ 100ํ์ด์ง์ ๋ชจ์์ด ๋ค ๋๊ฐ์์ผํ๊ณ , title๊ณผ replace๋ง ๋ฐ๊พธ๊ณ ์ถ์ผ๋ฉด?
@GetMapping("/layoutExtend")
public String layoutExtend() {
return "template/layoutExtend/layoutExtendMain";
}
<!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>
<!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>
GetMapping์ ๋ฆฌํด๊ฐ์ผ๋ก layoutExtendMain์ด ์คํ์ด ๋๊ณ layoutExtendMain์ html์์ฒด๋ฅผ layoutFile๋ก th:replace ์ํจ๋ค.
layoutFile.html ์ ๊ธฐ๋ณธ ๋ ์ด์์์ด ๋๊ณ title๊ณผ section ํ๊ทธ๊ฐ ๋์ด๊ฐ๋ค.
๋ ์ด์์์ ์ฐ๊ฑฐ๋ ์ฌ์ดํธ๊ฐ ์์ผ๋ฉด ์กฐ๊ฐ์กฐ๊ฐ ๋ฃ๊ฑฐ๋ ๋ณดํต ๋ ๊ฐ์ง ์ค์ ์ ํ์ ํ๋ค.
ํ์ด์ง๊ฐ ๋ง์ด ์์๋๋ ๋ ์ด์์ ๋์ fragment๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๋ ๊ด์ฐฎ๋ค.
ํ์ง๋ง ํ์ด์ง๊ฐ ๋ง์์ง๊ณ ๊ด๋ฆฌ๊ฐ ์ค์ํ ๊ฒ ๊ฐ์ผ๋ฉด layout์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.