본문 바로가기
Spring/Boot

스프링부트 thymeleaf 정리하기

by dyddyd0 2024. 8. 22.
Thymeleaf 란 :
서버사이드 템플릿 엔진으로, 자바기반 웹 애플리케이션에서 HTML, XML, JavaScript, CSS를 생성하는 데 사용된다. (jsp의 템플릿 엔진 jstl과 비슷한 개념. Model에 담긴 데이터를 뷰로 전달받아 타임리프 템플릿에서 렌더링함.)

 

• Thymeleaf layout은 웹 애플리케이션의 일관된 레이아웃을 유지하기 위해 템플릿을 모듈화 하고 재사용할 수 있게 하며, 레이아웃 템플릿을 통해 공통된 구조를 정의하고, 각 페이지별로 변경되는 부분만 별도로 관리할 수 있다.

 

레이아웃의 기본 파일 위치는 : src/main/resources/templates 에 위치한다.

 

 

Thymeleaf의 특징:

  • EL 표기법 사용 - ${}
    <p> 안녕하세요, ${name}님! </p>
  • URL 표현 - @{}
    <a href="@{/home}"> Home </a>
  • 속성 수정자 - th:attr
    <a th:href="@{/user/{id}(id=${user.id})}"> 사용자 프로필 </a>
  • for each처럼 사용하는 반복문 - th:each 구문으로 반복 처리 한다.

-예제코드-

<ul>
      <li th:each="user : ${users}">
          <span th:text="${user.name}">이름</span>
      </li>
</ul>

th:each의 범위는 th:each를 선언한 li 태그이며,

user.name이라고 지정했는데, user는 th:each에서 사용할 변수를 정의한 것이고,

th:text="${user.name}"은 foreach구문 안쪽에 코드라고 생각할 수 있다. -> ${users}의 name으로 지정한 속성값을 가리킴 

 

  • th:if와 th:unless 구문으로 조건식을 처리.

-예제코드-

<div th:if="${user != null}">
    <p>사용자가 로그인했습니다.</p>
</div>
<div th:unless="${user != null}">
    <p>사용자가 로그인하지 않았습니다.</p>
</div>

th:if는 조건문이며 조건에 해당하면 렌더링을 하고,

th:unless는 조건에 해당하지 않으면 렌더링을 한다.

따라서 위 코드로 보면,

th:if="${user!= null}" 유저가 null이 아니면 사용자가 로그인했습니다.

th:unless="${user!= null}" 유저가 null이면 사용자가 로그인하지 않았습니다.

라는 p 태그를 보여준다.

 

  • th:fragment: Thymeleaf에서 템플릿의 일부분을 정의하고 재사용할 수 있도록 하는 속성

-예제코드-

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <body>
        <div th:fragment="header">
            <header>
                <h1>My Application Header</h1>
            </header>
        </div>

        <div th:fragment="footer">
            <footer>
                <p>My Application Footer</p>
            </footer>
        </div>
    </body>
    </html>

위 코드는 th:fragment라는 속성을 이용해 div 태그의 내용을 각각 header와 footer라는 이름의 조각으로 만들겠다.

라는 의미이며, 각각 header와 footer로 재사용할 수 있다.

 

  • th:fragment로 만든 프레그먼트를 포함할 때는 th:insert, th:replace, th:include를 사용한다.
    • th:insert: 프래그먼트를 현재 요소 내에 삽입.
    • th:replace: 현재 요소를 프래그먼트로 교체.
    • th:include: 프래그먼트의 내용을 현재 요소 내에 포함.

기본적으로 태그 내부에 작성하지만, jstl처럼 태그 밖에 작성하고 싶다면 th:block을 이용해 작성해 준다.

 

 

Thymeleaf를 사용하기 위해서는 다음 의존성이 필요하다.

build.gradle 의 dependency 부분에 추가해주자~~

 

 

html 문서에서 타임리프와 레이아웃을 사용하기 위해 다음 내용을 포함시킨다.

<html lang="en"
    xmlns:th="http://www.thymeleaf.org"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">

 

 

위에서 fragment 속성을 활용해 보자.

우선,

헤더로 공통으로 사용할 헤더 태그를 다음과 같이 header라는 이름으로 조각을 만들 수 있음.

 

다음 코드는 fragment 폴더의 header.html이다.

<html lang="en"
  xmlns:th="http://www.thymeleaf.org">
<body>
    <header th:fragment="header" class="container">
        <nav class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
            <button type="button" class="btn btn-outline-light btn-lg text-secondary" onclick="location.href='/'">홈</button>
            <div class="collapse navbar-collapse justify-content-end" id="navbarSupportedContent">
                <ul class="navbar-nav mr-auto">
                    <li class="nav-item">
                        <a class="nav-link" href="board/free-list.html">자유게시판</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="board/notice-list.html">공지사항</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="user/login.html">로그인</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="user/join.html">회원가입</a>
                    </li>
                </ul>
            </div>
        </nav>
    </header>

 

조각낸 header를 불러올 때, 다음과 같이 ~{조각 경로 :: 조각 명}으로 지정해 주어야 됨

(물론 th를 사용하려면 다음과 같이 타임리프 namespace를 추가해야 된다.
<html lang="en"
  xmlns:th="http://www.thymeleaf.org">)

다음은 layout1.html 코드이다.

<body>
    <div class="wrapper">

        <header th:replace="~{/fragments/header :: header}"></header>

        <main layout:fragment="content"></main>

        <footer th:replace="~{/fragments/footer :: footer}"></footer>

    </div>
</body>

코드를 간략하게 설명해 보자면,

<header 태그를  th:replace = 대체해 주겠다.

각각의 경로에서 header와 footer라는 조각을 가져옴.

 

layout:fragment :

index.html에서 다음 레이아웃을 이용해서 꾸며주겠다고 선언한 느낌임→

<html…

layout:decorate="~{/layouts/layout1}">

<!DOCTYPE html>
<html lang="en"
  xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
  layout:decorate="~{/layouts/layout1}">
<body>
    <main layout:fragment="content" class="container d-flex justify-content-center my-5 py-5">
        <h2 class="my-5 py-5">게시판 홈</h2>
    </main>
</body>
</html>

index.html과 layout1.html을 보면 각각

<main layout:fragment="content" class="container d-flex justify-content-center my-5 py-5">

<main layout:fragment="content"></main>

에서 서로 매핑된다.

 

  • th:insert는 현재 태그를 유지하며 템플릿 조각을 가져옴
  • th:replace는 현재 태그 자리에 템플릿 조각으로 대체함

+

 

ModelAndView 객체로 값 넘겨주어 타임리프로 보여주기

 

package com.bit.springboard.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/member")
public class MemberController {
//    (@ResponseBody 가 포함 안된)@Controller 를 사용해서 Controller bean 객체를 생성했을 때는
//    String 값을 리턴했을 때 ViewResolver 가 동작했지만,
//    (@ResponseBody 가 포함된)@RestController 에서 String 값을 리턴하면,
//    ViewResolver 가 동작하지 않고 String 값을 그대로 리턴한다.
//    @RestController 에서 화면을 리턴하기 위해서는 ModelAndView 객체를 리턴해 주어야됨.

    @GetMapping("/join")
    public String joinView(){
        return "member/join";
    } // @Controller 에서는 이와같이 사용했지만, @RestController 에서 사용하면 스트링값 그대로 화면에 나온다.

}

@Controller에서는 이와 같이 사용했지만, @RestController에서 사용하면 스트링값 그대로 화면에 나온다.

 

 

@RestController에서는 다음과 같이 화면을 이동함

  @GetMapping("/join")
  public ModelAndView joinView(){
      ModelAndView mav = new ModelAndView();
      mav.addObject("name", "model객체의 key값으로 가져온 Value");
      mav.setViewName("member/join"); // 찾아갈 화면의 이름 지정해주기
//        mav.setViewName("templates/member/join.html");
//        application.properties 에서 설정한 prefix와 suffix 가 붙어 위와 같이 동작하는거다.

      return mav;
  }

 

<- 사용 th:text=${name} 결과->

 

반응형

'Spring > Boot' 카테고리의 다른 글

스프링부트 응답 메시지 보내기  (0) 2024.09.01
스프링부트 ResponseEntity<T>  (0) 2024.08.17
스프링부트 RESTful Api  (0) 2024.08.15