Thymeleaf Template Engine

์ด๊ด‘ํ›ˆยท2023๋…„ 6์›” 12์ผ
0

โœ… Thymeleaf Template Engine

๐ŸŒ Template Engine

๐Ÿ‘‰ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ผ์ข…์œผ๋กœ, HTML์˜ ๋‚ด์šฉ๋ฌผ์„ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š”๋ฐ ์ฃผ๋กœ ์‚ฌ์šฉ๋จ

โ†’ ์ฑ„์›Œ์ ธ์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์ด ์กด์žฌํ•˜๋Š” HTML์„ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ํ™œ์šฉ, ์ฑ„์›Œ์•ผํ•  ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณต๋ฐ›์œผ๋ฉด ๊ทธ ๋ถ€๋ถ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฑ„์›Œ๋„ฃ์€ ๋’ค, ์™„์„ฑ๋œ HTML์„ ๋Œ๋ ค์คŒ

  • ๋‹จ์ˆœํ•œ HTML์ด ์•„๋‹Œ Model์˜ ๋ณ€ํ™”์— ๋”ฐ๋ผ ๋‚˜ํƒ€๋‚˜๋Š” ๋ชจ์Šต์ด ๋‹ค๋ฅด๊ฒŒ ๋ณด์ด๋„๋ก ํ•ด์คŒ

๐ŸŒ Thymeleaf

๐Ÿ‘‰ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ Java ํ…œํ”Œ๋ฆฟ ์—”์ง„์œผ๋กœ, HTML, XML, JavaScript, CSS ๋“ฑ์˜ ๋งˆํฌ์—… ๋ฌธ์„œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋จ

๐Ÿ“Œ ์ผ๋ฐ˜์ ์œผ๋กœ Spring ํ”„๋ ˆ์ž„์›Œํฌ์™€ ํ†ตํ•ฉ๋˜์–ด ๋งŽ์ด ์‚ฌ์šฉ๋˜๋ฉฐ, Spring MVC์™€ ํ•จ๊ป˜ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ํ…œํ”Œ๋ฆฟ ์—”์ง„ ์ค‘ ํ•˜๋‚˜

1. Thymeleaf ์„ค์ •ํ•˜๊ธฐ

๐Ÿšง start.spring.io๋ฅผ ์ด์šฉํ•œ๋‹ค๋ฉด Dependencies์—์„œ Thymeleaf๋ฅผ ์ถ”๊ฐ€

๐Ÿšง Gradle๊ณผ Maven์— ๋”ฐ๋ผ ThymeleafViewResolver๋ฅผ ์ถ”๊ฐ€

  • Gradle - build.gradle
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
  • Maven - pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

๐Ÿ‘‰ ์œ„ ์„ค์ • ์ถ”๊ฐ€ ํ›„ ๋นŒ๋“œํ•˜๋ฉด Thymeleaf๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Œ

2. Thymeleaf ๋ฌธ๋ฒ•

๋Œ€๋ถ€๋ถ„์˜ html ์†์„ฑ์„ th:xxx๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ‘œํ˜„์„ค๋ช…์˜ˆ์ œ
@{ ... }URL ๋งํฌ ํ‘œํ˜„์‹th:href="@{/css/bootstrap.min.css}"
th:href="@{/{itemId}/edit(itemId=${item.id})}"
| ... |๋ฆฌํ„ฐ๋Ÿด ๋Œ€์ฒดth:text="|Hi ${user.name}!|"
( = th:text="'Hi '+${user.name}+'!'" )
${ ... }๋ณ€์ˆ˜th:text=${user.name}
[[${ โ€ฆ }]]๋ณ€์ˆ˜ ์ง์ ‘ ์ถœ๋ ฅ<tr th:each="item: ${items}">
โ€ƒ<td th:text="${item.price}">100</td>
</tr>
*{ ... }์„ ํƒ ๋ณ€์ˆ˜<tr th:object="${items}">
โ€ƒ<td th:text="*{price}">100</td>
</tr>
#{ ... }properties๊ฐ™์€ ์™ธ๋ถ€ ์ž์›์—์„œ
์ฝ”๋“œ์— ํ•ด๋‹นํ•˜๋Š” ๋ฌธ์ž์—ด get
th:text="#{member.register}"

3. Thymeleaf ์—ฐ์Šต

1) Today's Hits

@Controller
public class MvcController {
	private int hitCount = 0;
    
    @RequestMapping("/hits")
    public String hits(Model model) {
    	model.addAttribute("hits", ++hitCount);
        return "hits";
    }
}
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Hits</title>
</head>
<body>
	<!-- ์ƒˆ๋กœ๊ณ ์นจํ•  ๋•Œ๋งˆ๋‹ค hits๊ฐ€ ์ฆ๊ฐ€ํ•œ๋‹ค. -->
  <p>Today's Hits: [[${hits}]]</p>
</body>
</html>

๐Ÿšง ๊ฒฐ๊ณผ

2) Lotto

@Controller
public class MvcController {
	@RequestMapping("/lotto")
    public String lotto(Model model) {
    	List<Integer> listOfNums = new ArrayList<>();
        // ๋žœ๋ค ๋ฐ›์•„์„œ 6๋ฒˆ ์ถœ๋ ฅ โ†’ listOfNums์— ๋‹ด๊ธฐ
        for (int i = 0; i < 6; i++) {
        	listOfNums.add((int)(Math.random()*46)); // ์ •์ˆ˜๋กœ 0<random<46 ๋ฒ”์œ„๋ฅผ ์ •ํ•จ
        }
        model.addAttribute("listOfNums",listOfNums);
        return "lotto";
    }
}
<!-- lotto.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Lotto</title>
</head>
<body>
    <span th:each="item: ${listOfNums}">[[${item}]] - </span>
    <div>
        <a href="/hits">๋’ค๋กœ๊ฐ€๊ธฐ</a>
        <a href="/lotto">๋‹ค์‹œํ•˜๊ธฐ</a>
    </div>
</body>
</html>

๐Ÿšง ๊ฒฐ๊ณผ

(๋ฒ”์œ„๋ฅผ 0~99๋กœ ์ง€์ •ํ–ˆ์„๋•Œ ์ด๋ฏธ์ง€)

3) History of Lotto

@Controller
public class MvcController {
	// listOfLotto ๋ฌธ์ž์—ด ๋ฐฐ์—ด ์ƒ์„ฑ
    private List<String> listOfLotto = new ArrayList<>();
    
    @RequestMapping("/lotto")
    	public String lotto(Model model) {
        // lotto ๋ถˆ๋Ÿฌ์˜ฌ๋•Œ๋งˆ๋‹ค listOfNums ์ดˆ๊ธฐํ™”
        List<Integer> listOfNums = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
        	listOfNums.add((int)(Math.random()*46));
        }
        listOfLotto.add(listOfNums.toString());
        model.addAttribute("listOfNums", listOfNums);
        return "lotto";
    }
    
    @RequestMapping("/history")
    public String history(Model model) {
    	// ์šฐ์„  listOfLotto๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ์ฒดํฌ
        boolean isHistory;
        if (!listOfLotto.isEmpty()) isHistory = true;
        else isHistory = false;
        // ๊ทธํ›„ ์†์„ฑ ๋„˜๊ฒจ์ฃผ๊ธฐ
        model.addAttribute("listOfLotto", listOfLotto);
        model.addAttribute("isHistory", isHistory);
        return "history";
    }
}
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>History</title>
</head>
<body>
  <div>
    <h2>Lotto List</h2>
		<!-- isHistory bool ๊ฐ’์— ๋”ฐ๋ผ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅด๋‹ค. -->
    <div th:if="${isHistory}">
    <p th:each="item: ${listOfLotto}">[[${item}]]</p>
    </div>
    <div th:unless="${isHistory}"><p>์•„์ง ๊ธฐ๋ก์ด ์—†์Šต๋‹ˆ๋‹ค.</p></div>
  </div>
    <a href="/hits">๋Œ์•„๊ฐ€๊ธฐ</a>
</body>
</html>

๐Ÿšง ๊ฒฐ๊ณผ

(๋žœ๋ค์˜ ๋ฒ”์œ„๊ฐ€ 0~99๋กœ ๋œ ์ด๋ฏธ์ง€)
profile
์›ƒ์œผ๋ฉฐ ์ผํ•  ๋•Œ, ์‹œ๋„ˆ์ง€๊ฐ€ ๋ฐฐ๊ฐ€ ๋œ๋‹ค๊ณ  ๋ฏฟ๋Š” ๊ฐœ๋ฐœ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€