타임리프(Thymeleaf)는View Templete Engine으로 JSP, Freemarkerd와 같이 서버에서 클라이언트에게 응답할 브라우저 화면을 만들어주는 역할을 한다.
타임리프의 주 목표는 템플릿을 만들 때 유지관리가 쉽도록 하는 것이다. 이를 위해 디자인 프토로타입으로 사용되는 템플릿에 영향을 미치지 않는 방식인
Natural Templates을 기반으로 한다. Natural Templates은기존 HTML 코드와 구조를 변경하지 않고 덧붙이는 방식이다.
👉 코드를 변경하지 않기 때문에 디자인 팀과 개발 팀간의 협업이 편해진다.
👉 JSP와 달리 Servlet Code로 변환되지 않기 때문에 비즈니스 로직과 분리되어 오로지 View에 집중할 수 있다.
👉 서버상에서 동작하지 않아도 되기 때문에 서버 동작 없이 화면을 확인할 수 있다. 때문에 더미 데이터를 넣고 화면 디자인 및 테스트에 용이하다.
위와같은 타임리프 장점 때문에 Spring에서도 Spring Boot와 타임리프를 함께 사용하는 것을 권장하고 있다. Spring Boot에서는 JSP 사용 시 호환 및 환경설정에 어려움이 많기 때문이다. 반대로 타임리프는 간편하게 Dependency 추가 작업으로 사용할 수 있다.
Maven은 pom.xml에, Gradle은 build.gradle에 타임리프의 dependency를 추가해준다.
👉 Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
👉 Gradle
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${name}">Name</h1>
</body>
</html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div th:text="${data}"></div>
<body>
<a th:hrf="@{/boardListPage?currentPageNum={page}}"></a>
</body>
<a> 태그의 href 속성과 동일하다. <div th:with=”userId=${number}” th:text=”${usesrId}”>
th:with를 이용하여 새로운 변수값을 생성할 수 있다. <input type="text" id="userId" th:value="${userId} + '의 이름은 ${userName}"/>
👉 예시
<html lang="ko" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{board/layout/basic}">
👉 의존성
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
xmlns:layout은 타임리프의 레이아웃 기능을 사용하기 위한 선언이다. 레이아웃을 적용시킬 HTML 파일에 해당 선언을한다. 그리고 해당 페이지에 th:fagment로 조각한 공통 영역을 가져와서 삽입해준다. <html lagn="ko"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<body>
//전체 레이아웃
<th:block th:fragment="footerFragment">
</th:block>
</body>
</html>
<body>
<footer th:fragment="footerFragment">
<p>안녕하세요</p>
</footer>
</body>
fragment가 바로 공통 영역을 정의하여 코드를 정리해준다.th:replace"[파일경로 :: 조각 이름]"을 통해 삽입한다.<body>
<div th:replace="~{/common/footer :: footerFragment}"></div>
</body>
<include> 태그와 유사한 속성이다.::을 기준으로 앞에는 조각이 있는 경로를 뒤에는 조각의 이름을 넣어준다.insert88와 다르게 완전하게 대체한다. <body>
<div th:insert="~{/common/footer :: footerFragment}"></div>
</body>
insert는 태그 내로 조각을 삽입하는 방법이다. replace는 완전하게 대체하기 때문에 replace 태그 가 입력된 <div>가 사라지고 fragment로 조각화한 코드가 완전히 대체된다. insert는 insert가 입력된 <div> 안에 fragment를 삽입하는 개념이기 때문에 <div>안에 조각화한 코드가 삽입된다.👉 대표예시
<body>
<form th:action="@{/join}" th:object="${joinForm}" method="post">
<input type="text" id="userId" th:field="*{userId}" >
<input type="password" id="userPw" th:field="*{userPw}" >
</form>
</body>
<form> 태그 사용시, 해당 경로로 요청을 보낼 때 사용한다. <form> 태그에서 데이터를 보내기 위해 Submit을 할 때 데이터가 th:object 속성을 통해 object에 지정한 객체에 값을 담아 넘긴다. 이때 값을 th:field속성과 함꼐 사용하여 넘긴다. th:object속성과 함께 th:field를 이용해서 HTML 태그에 멤버 변수를 매핑할 수 있다.th:field을 이용한 사용자 입력 필드는 id, name, value 속성 값이 자동으로 매핑된다. th:if="${}", th:unless="${}"<span th:if="${userNum} == 1"></span>
<span th:unless="${userNum} == 2"></span>
if와 else를 뜻한다. th:unless는 일반적인 언어의 else 문과는 달리 th:if에 들어가는 조건과 동일한 조건을 지정해야 한다.<body>
<li th:each="pageButton" : ${#numbers.sequece(paging.firstPage, paging.lastPage)}></li>
</body>
<c:foreach> 그리고 JAVA의 반복문 중 for문을 뜻한다.<th:block th:switch="${userNum}">
<span th:case="1">권한1</span>
<span th:case="2">권한2</span>
</th:block>
switch-case문과 동일하다. th:block으로 설정하고 그 안에 코드를 작성한다. #numbers라는 숫자 포맷 메소드를 지원한다. #numbers에는 다양한 메소드들이 존재하는데 가장 많이 사용하는 것이 #numbers.sequece이다. #numbers.sequece 메소드는 start, end, step을 이용하여 원하는 범위에 대해 시퀀스를 생성해준다.