
ํ์ ๋ฆฌํ์ ํน์ง์ ์๋์ ๊ฐ์ต๋๋ค.
- *.html ํ์ฅ์๋ฅผ ์ฌ์ฉํ๋ค.
- ๋ณ๋์ ๋ ์ด์์ ํ๋ ์์ํฌ์ ๋์ ์์ด ๋ ์ด์์์ ๊ด๋ฆฌํ ์ ์๋ค.
- ์คํฌ๋ฆฝํธ๋ฆฟ์ด ์๋ HTML ๋ฌธ๋ฒ์ผ๋ก JAVA ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
์์ฐ์ฑ ํ๋์ ์์ฒญ๋๊ฒ ๊ณต์ ๋ค์ธ ๋๋์ด ๋ฉ๋๋ค.
ํ์ ๋ฆฌํ์์๋ JSP์ ์คํฌ๋ฆฝํธ๋ฆฟ์ ์ฌ์ฉํ ์ ์๊ณ , ๋์ ๊ฐ์ ๊ธฐ๋ฅ์ ํ๋ ${}๊ณผ ๊ฐ์ ํํ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํ์ง๋ง ์คํฌ๋ฆฝํธ๋ฆฟ๊ณผ๋ ๋ค๋ฅด๊ฒ HTML ์ฝ๋์ ์ฌ๋ฏธ์ฑ์ ํฌ๊ฒ ํด์น์ง ์์ต๋๋ค.
๊ฐ์คํ๊ณ , ๊ทธ๋ผ ์ด thymeleaf๋ฅผ Spring Boot ํ๋ก์ ํธ์์ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ์์๋ณด๊ฒ ์ต๋๋ค.
1. Thymeleaf prefix, suffix ์ ์
๋จผ์ , Thymeleaf ํ์ผ์ ์ด๋์ ๊ด๋ฆฌํ ๊ฒ์ธ์ง application.properties์ ์ ์ํด์ผ ํฉ๋๋ค.
์๋์ ๋ด์ฉ์ ์ถ๊ฐํฉ๋๋ค.
# ์ ์ ๋ฆฌ์์ค์ ๋ณํ๊ฐ ์์ ๋ ๋ฐ๋ก ๋ฐ์ํ๋ค.
spring.devtools.livereload.enabled=true
# thymeleaf ์ฐธ์กฐ ๊ฒฝ๋ก
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
# thymeleaf์ ๋ํ ์บ์๋ฅผ ๋จ๊ธฐ์ง ์๋๋ค. cache=false ์ค์ (์ด์์๋ true)
spring.thymeleaf.cache=false
# templates ๋๋ ํ ๋ฆฌ์ ํ์ผ์ด ์๋์ง ์๋์ง ์ฒดํฌ, ์์ผ๋ฉด ์๋ฌ๋ฅผ ๋ฐ์์ํจ๋ค.
spring.thymeleaf.check-template-location=true
์ค์ ์ ๋ณด๋ฉด ํด๋์ค ํจ์ค templates/๋ผ๊ณ ์ ์ํ๋๋ฐ, ์ด์ ๋ถํฐ๋ ์ด templates์์ ํ์๋ฆฌํ๋ฅผ ๊ด๋ฆฌํ ๊ฒ์
๋๋ค.
๊ทธ๋ฆฌ๊ณ suffix๋ก๋ html ํ์ฅ์ ์ง์ ํด, ์ปจํธ๋กค๋ฌ์์ ํ์๋ฆฌํ ๋ทฐ๋ฅผ ํธ์ถํ ๋ ํ์ฅ์๋ฅผ ๋ถ์ด์ง ์์๋ ์ธ์ํ๋๋ก ํฉ๋๋ค.
๊ทธ ์ธ์๋ ๊ฐ๋ฐ ์์ ํ์ํ ์์ํ ์ค์ ์
๋๋ค.
2. ๋ ์ด์์ ์ ์

src/main/reslources์ templates ํจํค์ง ์์ ๋ทฐ ํ์ผ์ ์์ฑํฉ๋๋ค.
์ฐธ๊ณ ๋ก ์๋ ์คํํฑ ํด๋์๋ js, css๋ฑ๊ณผ ๊ฐ์ด ๋ณํ์ง ์๋ ํ์ผ๋ค์ ๊ด๋ฆฌํฉ๋๋ค.
๋จผ์ ๋ค๋ฅธ view๋ค์ด ๊ณต์ ํ ๋ ์ด์์์ ์ ์ํ๊ฒ ์ต๋๋ค.

templates ํจํค์ง ์์ layout์ด๋ผ๋ ํจํค์ง๋ฅผ ๋ง๋ค๊ณ , ๊ทธ ์์ default_layour.html์ด๋ผ๋ ํ์ผ์ ์์ฑํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ default_layout.html์ ๋ด์ฉ์ ์ง์ฐ๊ณ ์๋์ ๋ด์ฉ์ ์
๋ ฅํฉ๋๋ค.
<html lang="ko"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<!--/* ์ด๊ณณ์ ๊ฐ view๊ฐ ์์นํฉ๋๋ค. */-->
<th:block layout:fragment="head"></th:block>
<div>
<div layout:fragment="header"></div>
<div layout:fragment="content"></div>
<div layout:fragment="footer"></div>
</div>
</html>
๋ ์ด์์์ head, header, content, footer๋ก ์ด๋ฃจ์ด์ง๋๋ก ๊ตฌํํฉ๋๋ค.
head์๋ title ํ๊ทธ, css ๋ฑ์ ํฌํจํ ์์ ์
๋๋ค.
์ฌ๊ธฐ์ html ํ๊ทธ์ xmlns ์์ฑ์ ์ฃผ๋ชฉํด์ฃผ์ธ์.
xmlns์ ์ ์๊ฐ ์์ผ๋ฉด ํ์๋ฆฌํ ๋ฌธ๋ฒ์ ์ฌ์ฉํ ์ ์์ผ๋ ๋ฐ๋์ ๋ฃ์ด์ค๋๋ค.
์ด๊ฒ์ผ๋ก ๋ ์ด์์ ์ ์๋ ์๋ฃ๋์์ต๋๋ค.
๊ธฐ์กด์ Spring์์์ tiles ํ๋ ์์ํฌ ๊ฐ์ ๋ณต์กํ ์ ์ฐจ๊ฐ ํ์ํ์ง ์์ต๋๋ค.
์ด์ ๊ณตํต์ผ๋ก ์ฌ์ฉ๋ header์ footer ํ์ผ์ ์ ์ํ๊ฒ ์ต๋๋ค.
3. ๊ณตํต ๋ ์ด์์ ์์ ์ ์
2๋ฒ์์ ๋ ์ด์์์ ์ ์ํ ๋ header์ footer๋ฅผ ์ฝ์
ํ๋ ๊ตฌ๋ฌธ์ด ์์์ต๋๋ค.
๋ณธ ์์ ์์๋ header์ footer ํ์ผ์ templates์ fragmants ํจํค์ง์์ ๊ด๋ฆฌํ๊ฒ ์ต๋๋ค.

templates ํจํค์ง์ fragments ํจํค์ง๋ฅผ ์์ฑํ๊ณ header.html, footer.html ํ์ผ ์์ฑ ํ ์๋์ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
# header.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<div class="header">
<h2>Header</h2>
</div>
</html>
# footer.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<div class="footer">
<h2>Footer</h2>
</div>
</html>
4. content ์์ฑ

templates์ content๋ผ๋ ํจํค์ง๋ฅผ ๋ง๋ค๊ณ ๊ทธ ์์ home.html ํ์ผ์ ์์ฑํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์๋์ ๋ด์ฉ์ ์์ฑํฉ๋๋ค.
# home.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/default_layout}">
<th:block layout:fragment="head">
<title>Spring Boot</title>
<!--/* css */-->
<link th:href="@{/css/common.css}" rel="stylesheet" />
</th:block>
<body>
<th:block layout:fragment="header" th:include="@{/fragments/header}"></th:block>
<div layout:fragment="content" class="content">
<h2>This is Content</h2>
</div>
<th:block layout:fragment="footer" th:include="@{/fragments/footer}"></th:block>
</body>
</html>
์ ์ฝ๋์์ ๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ์ html ํ๊ทธ์ layout:decorate ์์์
๋๋ค.
๋ ์ด์์ ์์ค์ฝ๋๋ฅผ ์ด๋ค ๊ฒ์ผ๋ก ์ง์ ํ ๊ฒ์ธ์ง๋ฅผ ์ ์ํ๋ ์์๋ก, ๋ณธ ์์ ์์ ์ฌ์ฉํ๋ ๋ ์ด์์ ํ์ผ์ layout ํด๋์ defaout_layout ํ์ผ์ด๋ฏ๋ก layout/default_layout์ด๋ผ ์ ์ํฉ๋๋ค.
๋ ์ด์์์์ ์ ์ํ head, header, content, footer์ ๋ํ ์ ์๋ฅผ <th:block layout:fragment="์์ ๋ช
"></th:block> ํํ๋ก ์์ฑํฉ๋๋ค.
header์ footer๋ fragments์์ ์ ์ํ ํ์ผ๋ค์ inlcude ํ๊ณ ์์ต๋๋ค.
์ด์ ์ปจํธ๋กค๋ฌ์์ home.html๋ฅผ ์์ฒญํ๋ฉด default_layout.html์์ ์ ์ํ ํํ๋ก view๊ฐ ๋ ๋๋ง๋์ด ๋ธ๋ผ์ฐ์ ์ ์ถ๋ ฅ๋ฉ๋๋ค.
๊ทธ์ ์, ์์ ์์ ์ ์ํ ๊ฐ ๋ ์ด์์ ์์๋ค์ ๊ตฌ๋ณํ๊ธฐ ์ฝ๊ฒ ๊ฐ๋จํ css ํ์ผ์ ์ถ๊ฐํ๋๋ก ํ๊ฒ ์ต๋๋ค.

static ํด๋์ css ํด๋๋ฅผ ์์ฑํ๊ณ common.css๋ผ๋ ์ด๋ฆ์ ํ์ผ์ ์์ฑํ๊ณ ์๋์ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
body, html {
height: 100%;
}
.header {
background-color: Gray;
height: 20%
}
.content {
height:60%;
}
.footer {
background-color: yellow;
height: 20%
}
5. Controller ์์
์ด์ ํฌ์คํ
์์ ์์ฑํ HomeController์ ๋ด์ฉ์ ์๋์ ๊ฐ์ด ์์ ํฉ๋๋ค.
// HomeController.java
@Controller
public class HomeController {
@RequestMapping(value = "/home", method=RequestMethod.GET)
public String goHome(HttpServletRequest request) {
return "content/home";
}
}
ํ์ด์ง๋ฅผ ํ์ํ ๊ฒ์ด๋ฏ๋ก ์ด์ ํฌ์คํ
์์ ์์ฑ๋์ด์๋ @ResponseBody ์ด๋
ธํ
์ด์
์ ์ ๊ฑฐํด์ฃผ๊ณ goHome ๋ฉ์๋์์ return ๊ฐ์ผ๋ก "content/home"์ ์ง์ ํ์ต๋๋ค.
์ด๋ application.properties์์ ํ๋ฆฌํฝ์ค๋ก ์ง์ ํ ํด๋์ค ํจ์ค templates์์ content ์์ home.html์ ๋ฐํํ๊ฒ ๋ค๋ ์๋ฏธ์
๋๋ค.
์ด์ localhost:8080/home์ผ๋ก ์ ์ํ๋ฉด ์๋์ ๊ฐ์ ํ๋ฉด์ ์ถ๋ ฅํ๊ฒ ๋ฉ๋๋ค.

6. Controller์์ ๊ฐ์ ๋ฐ์ Thymeleaf์ ํ์ฑ ํ๊ธฐ
๋ณธ ํฌ์คํ
์์๋ thymeleaf์ ๋ชจ๋ ํํ์์ ๋ค ๋ค๋ฃจ์ง๋ ๋ชปํ๊ณ , ์ปจํธ๋กค๋ฌ์์ ๋ณด๋ด์ค๋ list ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ณต๋ฌธ์ ์ฌ์ฉํด์ ํ์ด์ง์ ํ์ฑ ํด์ฃผ๋ ์์
๊น์ง ํด ๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ , ์ปจํธ๋กค๋ฌ๋ฅผ ์์ ํด์ ๊ฐ๋จํ ๋ฐ์ดํฐ๋ฅผ ์ค๋นํ๊ฒ ์ต๋๋ค.
//HomeController.java
@Controller
public class HomeController {
@RequestMapping(value = "/home", method=RequestMethod.GET)
public ModelAndView goHome(HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
List<String> resultList = new ArrayList<String>();
resultList.add("AAA");
resultList.add("BBB");
resultList.add("CCC");
resultList.add("DDD");
resultList.add("EEE");
resultList.add("FFF");
mav.addObject("resultList",resultList);
mav.setViewName("content/home");
return mav;
}
}
๋ฐ์ดํฐ์ ๋ทฐ ์ ๋ณด๋ฅผ ๊ฐ์ด ๋ฐํํด์ฃผ์ด์ผ ํ๋ฏ๋ก ๊ธฐ์กด์ goHome ๋ฉ์๋์ ๋ฐํํ์ String์์ ModelAndView๋ก ๋ฐ๊ฟ์ค๋๋ค.
๊ทธ๋ฆฌ๊ณ List <String> ํ์
์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณต์๊ฐ ์ถ๊ฐํด์ฃผ๊ณ ModelAndView ๊ฐ์ฒด์ ๋ด์ ๋ฐํํฉ๋๋ค.
์ด์ home.html ํ์ผ์ ์ด๊ณ ์๋์ ๊ฐ์ด ์์ ํด์ค๋๋ค.
# home.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/default_layout}">
<th:block layout:fragment="head">
<title>Spring Boot</title>
<!--/* ์ด ์์ญ์ ๊ณตํต์ผ๋ก ์ฌ์ฉํ css, js library๋ฅผ ์ ์ธํ๋ค. */-->
<link th:href="@{/css/common.css}" rel="stylesheet" />
</th:block>
<body>
<th:block layout:fragment="header" th:include="@{/fragments/header}"></th:block>
<div layout:fragment="content" class="content">
<h2>This is Content</h2>
<hr>
<!-- ์๋์ ์ฝ๋๋ฅผ ์ถ๊ฐ ํฉ๋๋ค.-->
<table border="1">
<tr>
<th>TEXT</th>
</tr>
<th:block th:each="rl : ${resultList}">
<tr>
<td th:text="${ rl }"></td>
</tr>
</th:block>
</table>
</div>
<th:block layout:fragment="footer" th:include="@{/fragments/footer}"></th:block>
</body>
</html>
ํ์๋ฆฌํ์์๋ th:each๋ฅผ ์ด์ฉํด ๋ฐ๋ณต ๊ฐ๋ฅํ ๋ณ์๋ฅผ ์ํํ๋ ๊ฒ์ด ๊ฐ๋ฅํฉ๋๋ค. JSTL์์์ c:foreach์ ๋์ผํ ์ญํ ์ ํ์ง๋ง, ํ์๋ฆฌํ์์๋ ๋ฐ๋ณต๋ฌธ์ html ํ๊ทธ์ ์ง์ ์ฌ์ฉํ ์ ์๋ค๋ ํน์ง์ด ์์ต๋๋ค.
์ด์ localhost:8080/home์ผ๋ก ์ ์ํด ๋ฐ์ดํฐ๋ฅผ ์ ๋๋ก ๋ฐ์์ค๊ณ ์๋์ง ํ์ธํฉ๋๋ค.

์ปจํธ๋กค๋ฌ์์ ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ ์ ์์ ์ผ๋ก ์ถ๋ ฅํด ์ฃผ๊ณ ์์ต๋๋ค.