타임리프(Thymeleaf)는 서버 측 Java 템플릿 엔진이다. HTML, XML, JavaScript, CSS 및 일반 텍스트를 처리하는 데 사용되고, 주로 웹 애플리케이션의 뷰를 생성하는 데 이용된다.
템플릿 엔진이란, 스프링 서버에서 데이터를 받아 HTML 페이지 상에 그 데이터를 넣어 보여주는 도구이다. HTML과 함께 템플릿 엔진을 위한 문법을 섞어 사용한다.
<h1 text=${이름}>
<p text=${나이}>
다음과 같이 작성시, 서버에서 이름, 나이라는 키로 데이터를 템플릿 엔진에 넘겨주고 템플릿 엔진은 이를 받아 HTML에 값을 적용한다.스프링은 타임리프를 권장하고 있다.
${...} : 변수의 값 표현식
#{...} : 속성 파일 값 표현식
@{...} : URL 표현식
*{...} : 선택한 변수의 표현식. th:object에서 선택한 객체에 접근
- th:text : 텍스트를 표현할 때 사용
ex. th:text=${person.name}
- th:each : 컬렉션을 반복할 때 사용
ex. th:each="person : ${persons}"
- th:if : 조건이 true인 때만 표시
ex. th:if="${person.age}>=20"
- th:unless : 조건이 false인 때만 표시
ex. th:unless="${person.age>=20}"
- th:href : 이동 경로
ex. th:href="@{/persons(id=${person.id})}"
- th:with : 변숫값으로 지정
ex. th:with="name=${prson.name}"
- th:object : 선택한 객체로 지정
ex. th:object="${person}"
// ExampleController.java
@Controller // 컨트롤러 명시적 표기
public class ExampleController {
@GetMapping("/thymeleaf/example")
public String thymeleafExample(Model model) { //뷰로 데이터를 넘겨주는 모델 객체
Person examplePerson = new Person();
examplePerson.setId(1L);
examplePerson.setName("홍길동");
examplePerson.setAge(11);
examplePerson.setHobbies(List.of("운동", "독서"));
model.addAttribute("person", examplePerson); // person 객체 저장
model.addAttribute("today", LocalDate.now());
return "example"; // example.html라는 뷰 조회
}
@Setter
@Getter
class Person {
private Long id;
private String name;
private int age;
private List<String> hobbies;
}
}
return "example";
Spring MVC 컨트롤러 메서드에서 뷰의 이름을 반환하는 구문이다. 이 구문은 컨트롤러가 처리한 요청에 대한 응답으로 보낼 뷰의 이름을 지정한다.
Spring MVC에서는 컨트롤러가 요청을 처리한 후에 뷰로 이동하여 사용자에게 결과를 표시해야한다. 이때 컨트롤러는 뷰의 이름을 반환하고, Spring은 해당 이름을 사용하여 resources/templates 디렉토리에서 적절한 뷰(html, jsp, ...)를 찾아서 렌더링하게 된다.
모델에는 "person", "today: 이렇게 두 키를 가진 데이터가 저장되어 있고, 컨트롤러는 모델을 통해 데이터를 설정하고, 모델은 뷸호 이 데이터를 전달해 키에 맞는 데이터를 뷰에서 조회할 수 있게된다.
즉, 모델은 컨트롤러와 뷰의 중간 다리 역할을 해주게 된다.
// main - resources - templates - example.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>타임리프 익히기</h1>
<p th:text="${#temporals.format(today, 'yyyy-MM-dd')}"></p>
<div th:object="${person}">
<p th:text="|이름 : *{name}|"></p>
<p th:text="|나이 : *{age}|"></p>
<p>취미</p>
<ul th:each="hobby : *{hobbies}">
<li th:text="${hobby}"></li>
<span th:if="${hobby == '운동'}">(대표 취미)</span>
</ul>
</div>
<a th:href="@{/api/articles/{id}(id=${person.id})}">글 보기</a>
</body>
</html>
html xmlns:th="http://www.thymeleaf.org"
Thymeleaf 태그 라이브러리를 해당 HTML 문서에서 사용할 수 있도록 선언한다.
temporals.format(today, 'yyyy-MM-dd')
LocalDate 타입의 날짜인 today를 yyyy-MM-dd 형식의 String 타입으로 포맷한다.
th:object="${person}"
모델에서 받은 객체 중 "person"이라는 키를 가진 객체의 데이터를 하위 태그에 지정한다. 하위 태그에서는 해당 객체의 값들을 사용할 수 있게된다.
*{...}
하위 태그에서 *{...}를 사용해 부모태그에 적용한 객체 값에 접근할 수 있다.
| 기호는 Thymeleaf 템플릿 엔진에서 문자열 리터럴을 표현하는 데 사용된다.
문자열 내에 변수를 포함하여 표현하기 위해서는 해당 기호를 문자열 양 끝에 사용해야한다.
th:each="hobby : *{hobbies}"
hobbies에 들어있는 객체의 개수만큼 hobby에 담아 반복 시행한다.
th:href="@{/api/articles/{id}(id=${person.id})}"
/api/articles/{id} URL에 매핑되는 컨트롤러가 실행되어 결국 해당 컨트롤러가 반환하는 뷰가 보여진다. id 값에는 모델에 추가된 person 객체의 id 속성값이 들어간다.
http://localhost:8080/thymeleaf/example에 접속하여 정상적으로 실행이 되는지 확인한다.
cf. 별도의 설정을 하지 않았으니 https가 아니라 http 요청으로 보내야된다.