Thymeleaf
= 자바 기반 웹 프레임워크에서 매우 유용하게 쓰이는 템플릿 엔진
= HTML 파일을 그대로 유지하면서 동적인 데이터를 바인딩
- HTML 친화적 : Thymeleaf 템플릿은 확장명이 .html, 서버에서 동적 데이터 주입할 때만 달라짐
- 서버 사이드 렌더링 : 동적 웹 페이지 제공 가능
- 특정 파일이나 요청을 보낼 때는 @, 변수를 꺼낼 때는 $ 사용


th:text
= 서버에서 저장된 텍스트 출력
→ 출력 데이터 내 tag 포함되어 있어도 text로 출력
→ null이나 빈문자는 표현 X, 숫자 또는 날짜도 텍스트로 출력
→ 객체의 경우 toString()이나 멤버변수의 getter() 값 출력
th:utext
= 서버에서 저장된 텍스트에 tag 포함 시, tag를 rendering 하여 출력
@Controller
public class ThymeleafController {
@GetMapping("/display/text")
public String text(Model model) {
// 문자 출력을 위한 데이터 준비
String korean = "대한민국 ~~ *♥";
String english = "Hello, everyone!!!";
String tag = "<marquee>돌이 굴러가유~</marquee>";
// 숫자 출력을 위한 데이터 준비
int age = 30;
double pi = Math.PI;
// URL 출력을 위한 데이터 준비
String url="https://naver.com";
// 빈 데이터와 NULL 데이터 준비
String nullData = null;
String emptyData = "";
model.addAttribute("korean", korean);
model.addAttribute("english", english);
model.addAttribute("tag", tag);
model.addAttribute("age", age);
model.addAttribute("pi", pi);
model.addAttribute("url", url);
model.addAttribute("nullData", nullData);
model.addAttribute("emptyData", emptyData);
return "thyme_text";
}
<h2>Thymeleaf text 출력</h2>
<div>
<a th:href="@{/}">홈으로</a>
</div>
<h3>1. 문자 출력</h3>
<p>한글 출력: <span th:text="${korean}">한글</span></p>
<p>영문 출력: <span th:text="${english}">영문</span></p>
<p>태그 출력: <span th:text="${tag}">태그</span></p>
<p>정수 출력: <span th:text="${age}">정수</span></p>
<p>실수 출력: <span th:text="${pi}">실수</span></p>
<p>URL 출력: <span th:text="${url}">실수</span></p>
<br>
<p>태그 출력: <span th:utext="${tag}">태그</span></p>
<p>URL 출력: <a th:href="${url}" th:text="${url}">네이버</a></p>
<hr>
<h3>2. 태그의 Inner 위치에서 Thymeleaf 문법을 사용하면...</h3>
<p>한글 출력: [[${korean}]] </p>
<p>영문 출력: [[${english}]] </p>
<hr>
<h3>3. 빈 데이터 출력(아무것도 출력되지 않음)</h3>
<p>null 출력: <span th:text="${nullData}">null</span></p>
<p>빈 문자 출력: <span th:text="${emptyData}">빈 문자</span></p>
<marquee> 태그가 붙은 tag는 th:utext 사용할 경우 작동

1. 객체 출력
th:objext: 서버에서 저장된 객체값 출력
@GetMapping("/display/condition")
public String condition(Model model) {
// 일반 객체
Friend friend = new Friend("홍길동", 25, "010-1234-1111", LocalDate.of(2003, 12, 5), true);
<p th:text="${friend}">객체</p>
model.addAttribute("friend", friend);

2. 각각의 데이터 출력
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class Friend {
private String username;
private Integer age;
private String phone;
private LocalDate birthday;
private Boolean active;
}
<h3>2. 각각의 데이터로 출력</h3>
<p th:text="${friend.username}">이름</p>
<p th:text="${friend.age} + 10">나이</p>
<p th:text="${friend.phone}">전화번호</p>
<p th:text="${friend.birthday}">생년월일</p>
<p th:text="${friend.active} ? '외향적' : '내향적'">성향</p>

3. Object 단위 데이터 출력
<h2>3. Object 단위 데이터로 출력</h2>
<div th:object="${friend}">
<p th:text="*{username}">이름</p>
<p th:text="*{age} + 10">나이</p>
<p th:text="*{phone}">전화번호</p>
<p th:text="*{birthday}">생년월일</p>
<p th:text="*{active} ? '외향적' : '내향적'">성향</p>
</div>

4. List 데이터 출력
// Iterable 데이터
List<String> list = Arrays.asList("사과", "배", "딸기", "복숭아", "포도", "오렌지");
model.addAttribute("list", list);
<h2>4. List에 들어있는 데이터 출력</h2>
<p>개수: [[${list.size()}]]</p>
<div th:each="item : ${list}">
<span th:text="${item}"></span>
</div>

5. Map에 들어 있는 데이터 출력
// Map 데이터
Map<Integer, Friend> map = new HashMap<>();
map.put(10, new Friend("손오공", 25, "010", LocalDate.of(2000, 12, 25), true));
map.put(20, new Friend("저팔계", 30, "011", LocalDate.of(1994, 10, 1), false));
map.put(30, new Friend("사오정", 21, "019", LocalDate.of(2003, 1, 5), true));
model.addAttribute("map", map);
<h2>5. Map에 들어있는 데이터 출력</h2>
<p>개수: [[${map.size()}]]</p>
<p>10번 데이터: [[${map[10]}]]</p>
<h3>Map 정보 전체 순회</h3>
<ul th:each="f : ${map}">
<li>번호: [[${f.key}]]</li>
<li>이름: [[${f.value.username}]]</li>
<li>나이: [[${f.value.age}]]</li>
<li>전화번호: [[${f.value.phone}]]</li>
<li>성향: [[${f.value.active} ? '외향적' : '내성적']]</li>
</ul>

5. 숫자 정보 전체 순회
List<Integer> nList = new ArrayList<>();
for(int i=1; i<=20; ++i)
nList.add(i*3);
model.addAttribute("nList", nlist);
<h3>6. 숫자 정보 전체 순회</h3>
<div th:each="n, status : ${nList}">
<span th:if="${status.count % 3 == 0}" style="color:red;">[[${status.count}]] : *****</span>
<span th:unless="${status.count % 3 == 0}">----------</span>
</div>

관련 Attribute :
th:href,th:src,th:action등 외부 URL 사용 태그
- @{...}과 함께 사용
<img>,<a>,<form>태그의 attribute와 동일
1. 이미지 URL
<a href=".../index.html" th:href="@{/}">
<img th:src="@{/images/logo.png}" alt="첫화면">
</a>
2. 쿼리 String 전송
<a th:href="@{/display/sendOne(username=Gildong, age=23}">
= localhost:8080/display/sendOne?username=Gildong&age=23 과 동일
3. 요청 URL로 form data 전송
<form th:action="@{/display/sendVO}" method="POST">

- 정수 :
#numbers.formatInteger- 실수 :
#numbers.formatDecimal- 백분율 :
#numbers.formatPercent(값, 0, n)=>소숫점 n자리 표현- 통화 기호:
#numbers.formatCurrency()
<h2>기본 객체 다루기(숫자)</h2>
<ul>
<li>Integer(기본): <span th:text="${intNum}"></span></li>
<li>Integer 10자리: <span th:text="${#numbers.formatInteger(intNum, 10)}"></span></li>
<li>Integer POINT: <span th:text="${#numbers.formatInteger(intNum, 3, 'POINT')}"></span></li>
<li>Integer COMMA: <span th:text="${#numbers.formatInteger(intNum, 3, 'COMMA')}"></span></li>
<li>Integer NONE: <span th:text="${#numbers.formatInteger(intNum, 3, 'NONE')}"></span></li>
<li>Integer 3자리: <span th:text="${#numbers.formatInteger(intNum, 3)}"></span></li>
<li>----------------------</li>
<li>Double(기본): <span th:text="${doubleNum}"></span></li>
<li>Double(소수 2자리): <span th:text="${#numbers.formatDecimal(doubleNum, 3, 2)}"></span></li>
<li>Double(천단위 콤마, 소수 2자리): <span th:text="${#numbers.formatDecimal(doubleNum, 3, 'COMMA', 2, 'POINT')}"></span></li>
<li>Double(천단위 공백, 소수 3자리): <span th:text="${#numbers.formatDecimal(doubleNum, 3, 'WHITESPACE', 3, 'POINT')}"></span></li>
<li>----------------------</li>
<li>Percent(기본): <span th:text="${percent}"></span></li>
<li>Percent(백분율, 2자리): <span th:text="${#numbers.formatPercent(percent, 0, 2)}"></span></li>
<li>----------------------</li>
<li>Money: <span th:text="${money}"></span></li>
<li>Money(통화기호): <span th:text="${#numbers.formatCurrency(money)}"></span></li>
</ul>

<li><a th:href="@{/display/receive(name=홍길동, age=35)}"></a></li>
@GetMapping("/display/receive")
public String receive(
@RequestParam(name="name", defaultValue="모모") String name,
@RequestParam(age="age", defaultValue="23") int age
){
System.out.println(name+", "+age)
return "index";
