thymeleaf 접두사, 접미사 설정
미작성 시 기본값
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<p text=${member}></p>
<p text=${member.memberNo}</p>
th:object 속성과 같이 사용
<!-- member 객체의 필드 memberNo와 memberPw 등을 출력 -->
<div obejct="${member}">
<span text="*{memberNo}"></span>
<span text="*{memberId}"></span>
</div>
messages.properties
app.name=Board Project - boot
user.default.image=/images/user.png
html 파일
<p th:text="#{app.name}">프로젝트 이름</p>
<img th:src="#{user.default.image}" id="memberProfile">
<!-- 단순 url-->
<a href="@{/board}">단순 url</a>
<!-- 쿼리스트링 포함 url-->
<a href="@{/board(key=${key}, queyr=${query})}">쿼리스트링 포함</a>
<!-- PathVariable 포함 url-->
<a href="@{/board/{boardCode}/{boardNo}(boardCode=${boardCode}, boardNo=${boardNo})}">PathVar
<!-- request scope에 key="memberName" value="홍길동" 이 있을 경우-->
<p text="${memberName}">회원이름</p>
<input type="text" value="${memberName}">
<!-- 랜더링 결과 -->
<p>홍길동</p>
<input type="text" value="홍길동">
[[...]] / [(...)]
<!-- key="memberName" value="<b1>홍길동</b1>" 이 있을 경우-->
<h3> text 와 utext의 차이점 </h3>
<p text="${memberName}">회원이름</p>
<p utext="${memberName}">회원이름</p>
<h3> [[...]] 와 [(...)]의 차이점 </h3>
<p>[[${memberName}]]</p>
<p>[(${memberName})]</p>

<!-- request scope에 key="memberName" value="홍길동" 이 있을 경우-->
<p text="|이름 : ${memberName} 님|">회원이름</p>
<!-- 랜더링 결과 -->
<p>이름 : 홍길동 님</p>
<ul with="num=100, name1=#{app.name}, name2=${memberName}">
<li text="${num}">num</li>
<li text="${name1}">name1</li>
<li text="${name2}">name2</li>
</ul>
<th:block th:if="${session.loginMember == null}">
<a href="/">메인 페이지</a> | <a href="/member/login">로그인</a>
</th:block>
<th:block unless="${session.loginMember == null}">
<label for="header-menu-toggle"> 닉네임
<i class="fa-solid fa-caret-down"></i>
</label> <input type="checkbox" id="header-menu-toggle">
<div id="header-menu">
<a href="/member/info">내정보</a> <a href="/member/logout">로그아웃</a>
</div>
</th:block>
<!-- if 조건식에 값만 작성한 경우 (있으면 true, 없으면 false)-->
<th:block unless="${session.loginMember}">
로그인 x
</th:block>
<th:block if="${session.loginMember}">
로그인 O
</th:block>
<th:block switch="${num}">
<p th:case="100">A</p>
<p th:case="200">B</p>
<p th:case="*">C</p>
</th:block>
<h3>삼항 연산자</h3>
<p text="${memberName} ? ${memberName} : '데이터가 없습니다'">삼항 연산자</p>
<h3>Elvis 연산자</h3>
<p text="${memberName} ?: '데이터가 없습니다'">Elvis 연산자</p>
<p th:text="${std} ?: '학생 데이터 없음'"></p>
<!-- std.toString() 한 결과 값 나옴 -->
<!-- Student(studentNo=67890, name=잠만보, age=22) -->
값이 없을 경우 Thymelaef가 실행이 안된 것 만듦
html 태그 내부에 작성된 값이 그대로 출력됨
조건식의 값이 없을 경우 (== null)
타임리프 코드를 해석하지 않는 연산자
타임리프 코드 해석 X
-> 일반 HTML 태그로 동작
-> HTML 태그 사이 내용(content)이 화면에 출력
<h3>No-Operation</h3>
<p text="${memberName222} ?: _">데이터가 없습니다</p>
<!-- 랜더링 결과 -->
<h3>No-Operation</h3>
<p>데이터가 없습니다</p>
<p th:text="${std} ?: _">학생 데이터 없음</p>
<!-- Student(studentNo=67890, name=잠만보, age=22) -->
<!-- 학생 데이터 있으니까 타임리프 코드 해석해서 p 태그 내용 없어지고 std.toString 나옴 -->
<h4>th:each 사용</h4>
<ul>
<th:block th:each="fruit : ${fruitList}">
<li th:text="${fruit}">과일명</li>
</th:block>
</ul>
HTML 화면
Controller에서 fruitList 값 사과, 딸기, 바나나로 setting 해놓음
List<String> fruitList = new ArrayList<>();
fruitList.add("사과");
fruitList.add("딸기");
fruitList.add("바나나");
model.addAttribute("fruitList", fruitList);
Model 객체 이용
Model 객체는 Spring 에서 사용하는 데이터 전달용 객체 (request scope)
[templates/fragments/common.html]
<nav fragment="nav"> <!-- 해당 요소에 nav라는 조각 이름을 지정-->
<ul>
<li><a href="#">공지사항</a></li>
<li><a href="#">자유 게시판</a></li>
<li><a href="#">질문 게시판</a></li>
<li><a href="#">FAQ</a></li>
<li><a href="#">1:1문의</a></li>
<li><a href="/chatting">채팅</a></li>
</ul>
</nav>
<!-- 해당 요소를 조각으로 지정된 속성으로 변경-->
<div insert="~{fragments/commons :: nav}"></div>
<!-- 랜더링 결과 -->
<!-- div 요소 안에 nav라는 이름의 조각이 삽입됨 -->
<div>
<nav>
<ul>
<li><a href="#">공지사항</a></li>
<li><a href="#">자유 게시판</a></li>
<li><a href="#">질문 게시판</a></li>
<li><a href="#">FAQ</a></li>
<li><a href="#">1:1문의</a></li>
<li><a href="/chatting">채팅</a></li>
</ul>
</nav>
</div>
<!-- 해당 요소를 조각으로 지정된 속성으로 변경-->
<div replace="~{fragments/commons :: nav}"></div>
<!-- 랜더링 결과 -->
<!-- div 요소가 nav라는 이름의 조각으로 변환됨 -->
<nav>
<ul>
<li><a href="#">공지사항</a></li>
<li><a href="#">자유 게시판</a></li>
<li><a href="#">질문 게시판</a></li>
<li><a href="#">FAQ</a></li>
<li><a href="#">1:1문의</a></li>
<li><a href="/chatting">채팅</a></li>
</ul>
</nav>
[templates/common/main.html]
<!-- common/header.html의 모든 내용을 읽어와 th:block 태그와 바꿈 -->
<th:block replace="~{common/header}"></th:block>
<!-- common/footer.html의 모든 내용을 읽어와 th:block 태그와 바꿈 -->
<th:block replace="~{common/footer}"></th:block>
// message에 100 이라는 값이 저장되어 있을 경우
// message2에 "abc" 이라는 값이 저장되어 있을 경우
<script th:inline="javascript">
const message = [[${message}]];
const message2 = /*[[${message2}]]*/ "값";
</script>
// 랜더링 결과
// message 가 100으로 치환됨
<script th:inline="javascript">
const message = 100;
const message2 = "abc";
// HTML을 직접 열었을 때
const message2 = "값";
</script>
<p th:text=${member}></p>
<p th:text=${member.memberNo}</p>
th:classappend : 클래스를 동적으로 추가
<!-- child-comment 클래스 추가 -->
<li class="comment-row" classappend="child-comment">
<!-- 랜더링 결과 -->
<li class="comment-row child-comment">
<!-- 조건이 true일 경우 child-comment 클래스 추가 -->
<li class="comment-row" classappend="${comment.parentNo} != 0 ? child-comment">
<!-- 랜더링 결과 -->
<!-- true인 경우 -->
<li class="comment-row child-comment">
<!-- false인 경우 -->
<li class="comment-row">
객체가 null인지 판별해서 null이 아닌 경우에 수행