빙응의 공부 블로그

[Spring]타임리프(Thymeleaf)에 대해 알아보자! 2편 본문

Spring/개인공부_이론

[Spring]타임리프(Thymeleaf)에 대해 알아보자! 2편

빙응이 2024. 1. 21. 17:52

 

해당 포스팅은 전편 타임리프 1편의 추가 부분이다.!

[Spring]타임리프(Thymeleaf)에 대해 알아보자! (tistory.com)

 

[Spring]타임리프(Thymeleaf)에 대해 알아보자!

📝타임리프(Thymeleaf) 타임리프는 컨트롤러가 전달하는 데이터를 이용해 동적으로 화면을 만들어주는 뷰 템플릿 엔진이다. 특징 서버 상에서 동작하지 않아도 HTML 파일의 내용을 바로 확인이 가

quddnd.tistory.com

📝타임리프 기본 객체 2

타임리프는 다음과 같은 객체 접근을 지원한다.

  • Request
  • Response
  • Session
  • ServletContext
  • Locale
  • Bean
실습 컨트롤러 
@GetMapping("/basic-objects")
public String basicObjects(Model model, HttpServletRequest request, 
HttpServletResponse response, HttpSession session) {
 session.setAttribute("sessionData", "Hello Session"); //세션 생성 
 model.addAttribute("request", request); //요청
 model.addAttribute("response", response); //응답 
 model.addAttribute("servletContext", request.getServletContext());
 return "basic/basic-objects";
}
@Component("helloBean")
static class HelloBean {
 public String hello(String data) {
 return "Hello " + data;
실습 HTML
<h1>식 기본 객체 (Expression Basic Objects)</h1>
<ul>
 <li>request = <span th:text="${request}"></span></li>
 <li>response = <span th:text="${response}"></span></li>
 <li>session = <span th:text="${session}"></span></li> //세션 직접 접근 
 <li>servletContext = <span th:text="${servletContext}"></span></li>
 <li>locale = <span th:text="${#locale}"></span></li> //Locale 직접 접근 
</ul>
<h1>편의 객체</h1>
<ul>
 <li>Request Parameter = <span th:text="${param.paramData}"></span></li> //파라미터로 값을 받을 수 있다.
 <li>session = <span th:text="${session.sessionData}"></span></li> 
 <li>spring bean = <span th:text="${@helloBean.hello('Spring!')}"></span></li> //빈 직접 접근 가능

 

📝타임리프 유틸리티 객체와 날짜 

자바 8의 날짜 

타임리프는 자바8 날짜인 LocalDate, LocalDateTime, Instant 를 사용하려면 추가 라이브러리가 필요하다. 

스프링 부트 타임리프를 사용하면 해당 라이브러리가 자동으로 추가된다. 

 

사용 예시 

<ul>
  <li>default = <span th:text="${localDateTime}"></span></li>
  <li>yyyy-MM-dd HH:mm:ss = <span th:text="${#temporals.format(localDateTime,
'yyyy-MM-dd HH:mm:ss')}"></span></li>
</ul>
<h1>LocalDateTime - Utils</h1>
<ul>
  <li>${#temporals.day(localDateTime)} = <span th:text="${#temporals.day(localDateTime)}"></span></li>
  <li>${#temporals.month(localDateTime)} = <span th:text="${#temporals.month(localDateTime)}"></span></li>
  <li>${#temporals.monthName(localDateTime)} = <span th:text="${#temporals.monthName(localDateTime)}"></span></li>
  <li>${#temporals.monthNameShort(localDateTime)} = <span th:text="${#temporals.monthNameShort(localDateTime)}"></span></li>
  <li>${#temporals.year(localDateTime)} = <span th:text="${#temporals.year(localDateTime)}"></span></li>
  <li>${#temporals.dayOfWeek(localDateTime)} = <span th:text="${#temporals.dayOfWeek(localDateTime)}"></span></li>
  <li>${#temporals.dayOfWeekName(localDateTime)} = <span th:text="${#temporals.dayOfWeekName(localDateTime)}"></span></li>
  <li>${#temporals.dayOfWeekNameShort(localDateTime)} = <span th:text="${#temporals.dayOfWeekNameShort(localDateTime)}"></span></li>
  <li>${#temporals.hour(localDateTime)} = <span th:text="${#temporals.hour(localDateTime)}"></span></li>
  <li>${#temporals.minute(localDateTime)} = <span th:text="${#temporals.minute(localDateTime)}"></span></li>
  <li>${#temporals.second(localDateTime)} = <span th:text="${#temporals.second(localDateTime)}"></span></li>
  <li>${#temporals.nanosecond(localDateTime)} = <span th:text="${#temporals.nanosecond(localDateTime)}"></span></li>
</ul>

 

📝타임리프 URL 링크의 세부식 

타임리프에서 URL을 만들 때 방법이 여러가지이다. 

 

쿼리 파라미터 생성 

/hello?param1=data1&param2=data2 

이런식으로 쿼리 파라미터 URL을 구성할 수 있다.

  <li><a th:href="@{/hello(param1=${param1}, param2=${param2})}">hello query param</a></li>

 

Path 생성 

/hello/data1/data2

이런식으로 경로 URL을 구성할 수 있다. 

  <li><a th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}">path variable</a></li>

 

 

📝타임리프 - 자바스크립트 인라인

타임리프는 자바스크립트에서 타임리프를 편리하게 사용할 수 있도록 기능을 제공한다. 

<script th:inline="javascript">

<!-- 자바스크립트 인라인 사용 전 -->
<script>
    var username = [[${user.username}]];
    var age = [[${user.age}]];
    //자바스크립트 내추럴 템플릿
    var username2 = /*[[${user.username}]]*/ "test username";
    //객체
    var user = [[${user}]];
</script>
<!-- 자바스크립트 인라인 사용 후 -->
<script th:inline="javascript">
    var username = [[${user.username}]];
    var age = [[${user.age}]];
    //자바스크립트 내추럴 템플릿
    var username2 = /*[[${user.username}]]*/ "test username";
    //객체
    var user = [[${user}]];
</script>

위 코드는 타임리프를 스크립트에 그대로 렌더링 시에 오류가 생긴다. 그렇기에 인라인을 사용을 안하면 스크립트 타입에 대한 추가 처리가 필요하다. 

th:inline은 이러한 것을 도와주는 타임리프의 기능이다. 

 

자바스크립트 인라인 each

자바스크립트 인라인은 each를 지원한다.

<!-- 자바스크립트 인라인 each -->
<script th:inline="javascript">
 [# th:each="user, stat : ${users}"]
 var user[[${stat.count}]] = [[${user}]];
 [/]
</script

 

참고! 타임리프의 자바스크립트 인라인 기능을 사용하면 객체를 JSON으로 자동 변환해준다. 

 

 

📝타임리프 - 템플릿

웹 페이지를 개발할 때는 공통 영역이 많이 있다. 예를 들어서 상단 영역이나 하단 영역, 좌측 카테고리 등등 여러 페이지에서 함께 사용하는 영역들이 있다. 이런 부분을 코드를 복사해서 사용한다면 여러 페이지를 수정해야 하므로 타임리프는 템플릿 조각과 레이아웃 기능을 지원한다. 

 

템플릿 조각 

우리가 재사용할 영역을 의미한다. 

<footer th:fragment="copy">
</footer>
프래그먼트를 지정하는 부분으로 재사용할 범위를 지정하는데 사용한다. 

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<footer th:fragment="copy">
 푸터 자리 입니다.
</footer>
<footer th:fragment="copyParam (param1, param2)">
 <p>파라미터 자리 입니다.</p>
 <p th:text="${param1}"></p>
 <p th:text="${param2}"></p>
</footer>
</body>
</html>

 

렌더링 페이지
<h2>부분 포함 insert</h2>
<div th:insert="~{template/fragment/footer :: copy}"></div>
<h2>부분 포함 replace</h2>
<div th:replace="~{template/fragment/footer :: copy}"></div>
<h2>부분 포함 단순 표현식</h2>
<div th:replace="template/fragment/footer :: copy"></div>
<h1>파라미터 사용</h1>
<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></ div>

th:insert : 해당 부분에 추가하는 방식이다. 
th:replace : 해당 부분을 교체하는 방식이다. 
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>
<h1>부분 포함</h1>
<h2>부분 포함 insert</h2>
<div th:insert="~{template/fragment/footer :: copy}"></div>
<h2>부분 포함 replace</h2>
<div th:replace="~{template/fragment/footer :: copy}"></div>
<h2>부분 포함 단순 표현식</h2>
<div th:replace="template/fragment/footer :: copy"></div>
<h1>파라미터 사용</h1>
<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></div>
</body>
</html>
  • 해당 코드는 프래그먼트를 추가하고, 교체하고, 파라미터를 전달하는 방식이다. 

 

📝타임리프 - 템플릿 레이아웃 

이전에는 일부 코드 조각을 가지고와서 사용했다면, 이번에는 개념을 더 확장해 코드 조각을 레이아웃에 넘겨서 사용하는 방법이다. 

 

만약 <head> 부분을 공통으로 사용한다고 해보자! 

공통으로 사용하는 부분은 타이틀과 링크이다.

그러나 각 페이지마다 필요한 정보를 추가해서 사용하고 싶다면 다음과 같이 사용하면 된다. 

공통 사용 코드 조각 

해당 코드는 변경하는 코드를 지정할 수 있다.

<head th:fragment="common_header(title,links)">
    <title th:replace="${title}">레이아웃 타이틀</title>
    <th:block th:replace="${links}" />
</head>

<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="common_header(title,links)">
  <title th:replace="${title}">레이아웃 타이틀</title>
  <!-- 공통 -->
  <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}">
  <link rel="shortcut icon" th:href="@{/images/favicon.ico}">
  <script type="text/javascript" th:src="@{/sh/scripts/codebase.js}"></script>
  <!-- 추가 -->
  <th:block th:replace="${links}" />
</head>

 

렌더링 페이지 
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="template/layout/base :: common_header(~{::title},~{::link})">
 <title>메인 타이틀</title>
 <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
 <link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">
</head>
<body>
메인 컨텐츠
</body>
</html>

해당 렌더링 페이지는 위 공통 코드로 인해 이렇게 바뀌게 된다.

<!DOCTYPE html>
<html>
<head>
<title>메인 타이틀</title>
<!-- 공통 -->
<link rel="stylesheet" type="text/css" media="all" href="/css/awesomeapp.css">
<link rel="shortcut icon" href="/images/favicon.ico">
<script type="text/javascript" src="/sh/scripts/codebase.js"></script>
<!-- 추가 -->
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/themes/smoothness/jquery-ui.css">
</head>
<body>
메인 컨텐츠
</body>
</html>
  • 쉽게 이야기하면 레이아웃 개념을 두고, 그 레이아웃에 필요한 코드 조각을 전달해서 완성하는 방법이다.

 

📝타임리프 - 템플릿 레이아웃2

이번에는 <html> 전체에 적용해보자 

 

이번에 바꿀 것은 타이틀과 내용이다! 

공통 코드 조각 
<!DOCTYPE html>
<html th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org">
<head>
 <title th:replace="${title}">레이아웃 타이틀</title>
</head>
<body>
<h1>레이아웃 H1</h1>
<div th:replace="${content}">
 <p>레이아웃 컨텐츠</p>
</div>
<footer>
 레이아웃 푸터
</footer>
</body>
</html>
렌더링 페이지 
<!DOCTYPE html>
<html th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title}, ~{::section})}"
 xmlns:th="http://www.thymeleaf.org">
<head>
 <title>메인 페이지 타이틀</title>
</head>
<body>
 <section>
  <p>메인 페이지 컨텐츠</p>
  <div>메인 페이지 포함 내용</div>
 </section>
</body>
</html>

 

 

변경한 것은 다음과 같다 .

<!DOCTYPE html>
<html>
<head>
  <title>메인 페이지 타이틀</title>
</head>
<body>
  <h1>레이아웃 H1</h1>
  <section>
    <p>메인 페이지 컨텐츠</p>
    <div>메인 페이지 포함 내용</div>
  </section>
  <footer>
    레이아웃 푸터
  </footer>
</body>
</html>

 

공통 코드 조각을 보면 기본 레이아웃을 가지고 있어 이 레이아웃 파일을 기본으로 하고 여기에 필요한 내용을 전달해서 부분부분 변경하는 것으로 이해하면 된다.