타임리프(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>
태그와 유사한 속성이다.::
을 기준으로 앞에는 조각이 있는 경로를 뒤에는 조각의 이름을 넣어준다.insert
88와 다르게 완전하게 대체한다. <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을 이용하여 원하는 범위에 대해 시퀀스를 생성해준다.