타임리프는 서버 사이드 Java 템플릿 엔진으로, 주로 스프링 프레임워크와 함께 사용된다.
이 템플릿 엔진은 HTML, XML, JavaScript, CSS를 렌더링 하는 데 사용되며, 특히 동적 웹 페이지의 개발에 용이하다.
HTML 문법에 통합되어 있기 때문에 개발자와 디자이너 간의 협업을 쉽게 해 준다는 특징이 있다.
타임리프 프로젝트 및 추가적인 내용은 위 글을 참고한다.
💡타임리프의 기본 문법
변수 표현
<p th:text="${message}">Default Message</p>
변수 표현은 ${...}를 사용하여 모델에서 전달된 데이터를 템플릿에서 출력하는 방법이다.
${message}는 모델에 담긴 데이터 중 message라는 속성을 참조하며, 해당 값으로 템플릿이 렌더링 된다.
텍스트 값 대체
<p th:text="'Hello, ' + ${username}">Guest</p>
th:text 속성을 사용하여 태그 내의 텍스트를 동적으로 대체할 수 있다.
${username}을 이용하여 'Hello, ' 다음에 사용자 이름이 동적으로 추가되어 출력된다.
반복문
<ul>
<li th:each="item : ${items}" th:text="${item}">Item</li>
</ul>
반복문은 th:each 속성을 사용하여 리스트나 배열과 같은 컬렉션의 요소를 반복적으로 처리할 수 있다.
${items}는 모델에 담긴 리스트를 참조하며, th:each를 통해 리스트의 각 요소를 순회하면서 출력한다.
조건문
<p th:if="${isUserLoggedIn}" th:text="'Welcome, ' + ${username}">Guest</p>
조건문은 th:if 속성을 사용하여 특정 조건에 따라 내용을 표시하거나 숨길 수 있다.
${isUserLoggedIn}은 모델에 담긴 데이터 중 isUserLoggedIn이라는 불리언 속성을 참조하며, 해당 조건에 따라 다른 메시지가 출력된다.
속성값 설정
<a th:href="@{'/items/' + ${itemId}}">Item Details</a>
th: 접두사를 사용하여 HTML 태그의 속성에 동적으로 값을 설정할 수 있다.
${itemId}는 모델에 담긴 데이터 중 itemId라는 속성을 참조하며, 이를 이용해 동적으로 링크의 href 속성을 설정한다.
💡타임리프의 특징
템플릿 재사용
<!-- 템플릿에서 fragment 정의 -->
<div th:fragment="header">Header Content</div>
<!-- fragment 재사용 -->
<div th:replace="fragments/header :: header"></div>
타임리프를 사용하면 템플릿 레이아웃을 통해 웹 페이지의 구조를 일관되게 유지할 수 있다.
여러 페이지에서 공통적으로 사용되는 header, footer, navigation 등을 하나의 템플릿으로 정의하고, 여러 페이지에서 재사용함으로써 코드의 중복을 방지하고 유지보수성을 높일 수 있다.
위 코드에서 th:fragment로 정의된 부분은 템플릿에서 사용될 프래그먼트로, 이를 다른 위치에서 th:replace를 통해 쉽게 재사용할 수 있다.
HTML 문법
<a th:href="@{/home}">Home</a>
타임리프는 HTML 문법과 통합되어 일반적인 HTML 문법을 그대로 사용할 수 있다.
위 코드에서 th:href를 사용하여 링크를 정의할 때 일반적인 HTML 문법을 그대로 사용하고 있다.
이와 같은 특징은 코드의 가독성을 높여주어 협업을 용이하게 한다.
데이터 바인딩
@Controller
public class MyController {
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("message", "Hello, Thymeleaf!");
return "hello";
}
}
스프링 부트 프로젝트에서는 타임리프를 기본적으로 지원하므로, 컨트롤러와의 데이터 바인딩이 간편하게 이루어진다.
위 코드에서 Model을 통해 데이터를 전달하면, 해당 데이터는 타임리프 템플릿에서 손쉽게 사용할 수 있다. 이는 웹 애플리케이션 개발 시 데이터 전달과 뷰 렌더링이 효율적으로 이루어지도록 도와준다.
💡국제화 및 메시지
다국어 메시지 출력
<p th:text="#{messages.welcome}">Welcome</p>
타임리프는 국제화(i18n)를 지원하여 웹 애플리케이션을 다국어로 제공할 수 있게 해 준다. 특히 메시지 처리를 통해 각 언어에 맞는 메시지를 동적으로 로드할 수 있다.
위 코드에서 #{messages.welcome}는 메세지 소스에서 해당 키(welcome)에 매핑된 메세지를 현재 설정된 언어에 따라 동적으로 출력한다. 이를 통해 사용자가 선호하는 언어로 메세지를 표시할 수 있다.
메세지 소스 통합
<p th:text="#{label.item}">Item</p>
스프링 프레임워크에서는 타임리프와 메세지 소스를 통합하여 다국어 지원을 보다 편리하게 제공하며, 메세지 파일에 정의된 내용을 타임리프에서 쉽게 활용할 수 있다.
위 코드에서 #{label.item}은 메세지 소스에서 item 키에 매핑된 메세지를 가져와 출력한다.
메세지 소스 설정
스프링에서는 MessageSource를 통해 메세지를 관리하며, 이를 타임리프와 함께 사용할 수 있다. 설정은 주로 스프링의 설정 파일인 application.properties 또는 application.yml에서 이루어진다.
# application.properties
# 메세지 파일이 위치한 경로 지정
spring.messages.basename=messages/messages
# 기본 언어 설정
spring.messages.default-locale=ko_KR
위의 설정에서 spring.messages.basename은 메세지 파일이 위치한 경로를 지정하고, spring.messages.default-locale는 기본 언어를 설정한다. 이를 통해 스프링은 해당 경로에서 메세지를 찾아 언어에 따라 적절한 메세지를 제공한다.
메세지 파일 작성
- messages.properties: 기본 메세지 파일
- messages_ko_KR.properties: 한국어 메세지 파일
- messages_en_US.properties: 영어 메세지 파일
메세지 파일은 각 언어별로 별도로 작성되며, 파일 이름은 위와 같은 규칙을 따른다.
메세지 파일은 키-값 쌍으로 이루어져 있다.
# messages_ko_KR.properties
messages.welcome=환영합니다!
label.item=항목
messages.welcome 및 label.item은 각각 다국어 메세지를 정의한 것이다.
다국어 메세지 적용
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.KOREA);
return slr;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
}
다국어 메세지를 적용하기 위해서는 먼저 사용자의 언어 설정을 식별하고, 이를 스프링에 전달해야 한다.
스프링에서는 LocaleResolver를 통해 이를 처리하며, 사용자의 언어 설정은 주로 세션, 쿠키, 요청 헤더 등을 통해 식별한다.
위의 설정에서는 SessionLocaleResolver를 사용하여 사용자의 언어 설정을 세션을 통해 관리하고 있다. 또한, LocaleChangeInterceptor를 등록하여 언어 변경 요청을 감지하고 이를 처리한다.
이렇게 설정된 환경에서는 타임리프에서 다국어 메세지를 자동으로 찾아서 적용하게 되며, 사용자의 언어 설정에 따라 각 언어에 맞는 메시지가 출력된다.
💡타임리프의 활용
템플릿 레이아웃과 구조
<!-- 기본 레이아웃 템플릿 -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>My Web App</title>
<!-- 추가적인 스타일시트 및 자바스크립트 파일 로드 -->
<link rel="stylesheet" th:href="@{/css/style.css}" />
<script th:src="@{/js/script.js}"></script>
</head>
<body>
<!-- header 영역 -->
<div th:replace="fragments/header :: header"></div>
<!-- content 영역 -->
<div th:replace="${content}"></div>
<!-- footer 영역 -->
<div th:replace="fragments/footer :: footer"></div>
</body>
</html>
타임리프를 사용하면 웹 애플리케이션의 템플릿 레이아웃을 정의하고 구조를 일관되게 유지할 수 있다.
이 구조를 통해 각 페이지의 내용이나 스타일, 스크립트의 변경이 필요한 경우 해당 부분만 수정하면 되므로 유지보수가 용이하다.
프로토타이핑 및 렌더링
<!-- 동적으로 데이터를 표현 -->
<p th:if="${user.isAdmin()}">Welcome, Admin!</p>
<p th:unless="${user.isAdmin()}">Hello, User!</p>
타임리프를 사용하면 동적으로 데이터를 표현하고 프로토타이핑을 효율적으로 수행할 수 있다. 또한, 조건문(th:if, th:unless)을 사용하여 특정 조건에 따라 다른 내용을 출력할 수 있다.
이를 통해 빠르게 초기 버전을 만들어보고, 동적으로 데이터를 처리하는 방법을 테스트할 수 있다.
자바 코드와의 통합
@Controller
public class MyController {
@GetMapping("/user/{id}")
public String getUserDetails(@PathVariable Long id, Model model) {
User user = userService.getUserById(id);
model.addAttribute("user", user);
return "userDetails";
}
}
스프링 프레임워크와 함께 사용되는 경우, 컨트롤러에서 모델에 데이터를 추가하고 해당 데이터를 템플릿에서 동적으로 활용할 수 있다.
위 예시에서는 getUserDetails 메서드에서 사용자의 정보를 가져와 모델에 추가한 후, userDetails 템플릿에서 해당 정보를 동적으로 표현한다.
타임리프를 사용하면 이와 같이 자바 코드와 템플릿 간에 효율적으로 데이터를 교환할 수 있다.