2025-05-09
Thymeleaf๋ HTML/XML ๋ฌธ๋ฒ์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ์๋ฒ ์ฌ์ด๋ ํ ํ๋ฆฟ ์์ง์ ๋๋ค. Spring Boot์์ ์ฐ๋์ฑ์ด ๋ฐ์ด๋ View Layer ๊ตฌ์ฑ์ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
@ModelAttribute
์ ํจ๊ป ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ฒด๋ก ์ฝ๊ฒ ์ ๋ฌ ๊ฐ๋ฅimplementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
spring:
thymeleaf:
prefix: classpath:/templates/
view-names: th/* # th/๋ก ์์ํ๋ view๋ thymeleaf๋ก ์ฒ๋ฆฌ
suffix: .html
mode: HTML5
cache: false
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp # JSP ํผ์ฉ ์ ์ค์
โ ViewResolver ์ฐ์ ์์๋ฅผ ๋ช ํํ ์ค์ ํด ์ถฉ๋ ๋ฐฉ์ง
test1.html
)<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- ๊ธฐ๋ณธ ๋ฐ์ดํฐ ์ถ๋ ฅ -->
NAME : <span th:text="${name}"></span> <hr/>
MEMO : <span th:text="${memo}"></span> <hr/>
MEMO.ID : <span th:text="${memo.id}"></span> <hr/>
MEMO.TEXT : <span th:text="${memo.text}"></span> <hr/>
MEMO.WRITER : <span th:text="${memo.writer}"></span> <hr/>
<!-- ์กฐ๊ฑด๋ฌธ ์ฒ๋ฆฌ -->
<th:block th:if="${isAuth}">
<div>๋ก๊ทธ์ธ ์ํ์
๋๋ค</div>
</th:block>
<th:block th:unless="${isAuth}">
<div>๋ก๊ทธ์์ ์ํ์
๋๋ค</div>
</th:block>
<hr/>
<!-- ๋ฐ๋ณต๋ฌธ ์ฒ๋ฆฌ -->
<th:block>
<div th:each="memo : ${memoList}">
<span th:text="${memo.id}"></span> :
<span th:text="${memo.text}"></span>
</div>
</th:block>
<hr/>
<!-- ํ๋ผ๋ฏธํฐ ์ ๋ฌ ๋ฐฉ์ -->
<a th:href="@{/th/param1(id=${memo.id},text='aaa',writer='bbb')}">์ด๋ํ๊ธฐ</a> |
<a th:href="@{/th/param2/{id}/{text}/{writer}(id=${memo.id},text='aaa',writer='bbb')}">์ด๋ํ๊ธฐ2</a>
<!-- JavaScript ๋ณ์ ๋ฐ์ธ๋ฉ -->
<script th:inline="javascript">
const name = [[ ${name} ]];
const memo = [[ ${memo} ]];
const memoList = [[ ${memoList} ]];
console.log('name', name);
console.log('memo', memo);
console.log('memoList', memoList);
</script>
</body>
</html>
th:text
: ๋ชจ๋ธ ๊ฐ ์ถ๋ ฅth:if
, th:unless
: ์กฐ๊ฑด ๋ถ๊ธฐ ์ฒ๋ฆฌth:each
: ๋ฐ๋ณต๋ฌธth:href
: URL ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉth:inline="javascript"
: JS ๋ด์ ์๋ฒ ๋ฐ์ดํฐ ์ฃผ์
๊ฐ๋ฅThymeleafTestController.java
)@Controller
@Slf4j
@RequestMapping("/th")
public class ThymeleafTestController {
@Autowired
private MemoRepository memoRepository;
@GetMapping("/test1")
public void test1(Model model){
log.info("GET /th/test1....");
// ๋ฌธ์์ด ๊ฐ ์ ๋ฌ
model.addAttribute("name", "hong");
// DTO ๊ฐ์ฒด ์์ฑ ๋ฐ ์ฃผ์
MemoDto memo = new MemoDto();
memo.setId(111);
memo.setText("aaa");
memo.setWriter("aaa@naver.com");
model.addAttribute("memo", memo);
// ๋ก๊ทธ์ธ ์ฌ๋ถ ๊ฐ
model.addAttribute("isAuth", false);
// ์ ์ฒด ๋ฉ๋ชจ ๋ฆฌ์คํธ ์ ๋ฌ
List<Memo> memoList = memoRepository.findAll();
model.addAttribute("memoList", memoList);
}
// ์ฟผ๋ฆฌ์คํธ๋ง ํ๋ผ๋ฏธํฐ ์๋ ๋ฐ์ธ๋ฉ
@GetMapping("/param1")
public void param1(@ModelAttribute MemoDto memoDto){
log.info("GET /th/param1..." + memoDto);
}
// PathVariable ๋ฐ์ธ๋ฉ๋ @ModelAttribute๋ก ์์ง ๊ฐ๋ฅ
@GetMapping("/param2/{id}/{text}/{writer}")
public void param2(@ModelAttribute MemoDto memoDto){
log.info("GET /th/param2..." + memoDto);
}
// ๋จ์ ํ์ด์ง ์ด๋
@GetMapping("/test2")
public void test2(){
log.info("GET /th/test2...");
}
}
Model
๊ฐ์ฒด๋ก HTML์ ๋ฐ์ดํฐ ์ ๋ฌ@ModelAttribute
๋ก ํ๋ผ๋ฏธํฐ ์๋ ๋งคํvoid
๋ฆฌํด ์ ์์ฒญ ๊ฒฝ๋ก์ ๋์ผํ ํ
ํ๋ฆฟ(.html) ์๋ ํธ์ถ๋จ