ACHO.pk devlog

[Springboot-쇼핑몰프로젝트] Thymeleaf 학습하기 본문

프레임워크/Springboot

[Springboot-쇼핑몰프로젝트] Thymeleaf 학습하기

Acho 2023. 2. 17. 22:10

1. Thymeleaf 소개

Thymeleaf는 Java 템플릿 엔진으로 가장 큰 장점은 natural templates이다. 서버 사이드 렌더링을 하지 않아도 Thymeleaf 문법을 포함하고 있는 html 파일을 브라우저에 띄워 정상적인 화면을 볼 수 있다.  

 

📚 템플릿 엔진

템플릿 양식과 특정 데이터 모델에 따른 입력 자료를 연결하여 결과 문서를 출력하는 소프트웨어 또는 소프트웨어 컴포넌트이다.

Thymeleaf는 서버 사이드 템플릿 엔진이며 서버에서 DB 혹은 API에서 가져온 데이터를 미리 정의된 템플릿에 넣어 HTML 문서를 만들어 클라이언트에 전달해주는 역할을 한다. HTML 코드로 템플릿을 만들어두고 동적으로 생성되는 부분만 템플릿의 특정 부분에 끼워 넣는 방식으로 동작한다고 보면 된다.

 

 

1-1. 웹 브라우저로 열어보기

thymeleafEx01.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
    <p th:text="${data}">Hello Thymeleaf!!</p>
</body>
</html>

Thymeleaf 문법이 추가되어도 html 파일이 깨지지 않고 정상적으로 출력됨을 확인할 수 있다. 

<html xmlns:th="http://www.thymeleaf.org">

Thymeleaf 문법을 사용하기 위해서 위와 같은 코드를 추가해준다. 

${data} 는 Controller의 model의 data라는 key 값에 담아준 값을 출력한다. 여기서 thymeleaf의 문법이 "th:text"이다.

 

 

 

1-2. 서버 사이드 렌더링을 통해 접근하기

controller > ThymeleafExController 생성 --> ex01

package com.shop.shop.controller;


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

@Controller
@RequestMapping(value="/thymeleaf")
public class ThymeleafExController {
    @GetMapping(value = "/ex01")
    public String thymeleafExample01(Model model){
        model.addAttribute("data", "타임리프 예제 입니다.");
        return "thymeleaf/thymeleafEx01";
    }
}

▹RequestMapping 어노테이션은 요청에 대해 어떤 Controller/메소드가 처리할 지를 Mapping한다. value 속성을 통헤 URL 값으로 매핑 조건을 부여한다.  GET 방식과 POST 방식을 모두 처리해준다.

▹GetMapping 어노테이션은 메서드를 요청할 때 GET 방식으로 명시하는 것으로 PostMapping 어노테이션과 반대되는 개념이다. 이 두 개의 어노테이션은 하나의 url로도 두 개 이상의 매핑을 처리할 수 있다.

@getMapping("/Board")
@PostMapping("/Board")

위 코드의 경우에는 "/thymeleaf/ex01"가 된다.

 

에러

ERROR 26844 --- [nio-8080-exec-4] org.thymeleaf.TemplateEngine             : [THYMELEAF][http-nio-8080-exec-4] Exception processing template "thymeleafEx/thymeleafEx01": Error resolving template [thymeleafEx/thymeleafEx01], template might not exist or might not be accessible by any of the configured Template Resolvers

폴더명과 Controller에 명시해준 경로가 달라서 생긴 에러임. 조심하자

 

 

2. Spring Boot Devtools

애플리케이션 개발 시 유용한 기능들을 제공하는 모듈로 이를 이용하면 개발 생산성을 향상시키는 데 도움을 준다.

크게 5가지의 기능을 제공하며 자동으로 어플리케이션을 재시작하여 브라우저에도 업데이트를 하는 역할을 한다.

  • Property Defaults
  • Automatic Restart
  • Live Reload
  • Global Settings
  • Remote Applications

pom.xml에 spring-boot-devtools 의존성을 추가해준후 "Reload All Maven Projects"을 클릭하여 의존성을 받아온다.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
</dependency>

 

2-1. Automaticc Restart 적용하기

2-2. Live Reload 적용하기

2-3. Property Defaults 적용하기

 

 

 

3. Thymeleaf 예제 진행하기

 dto 패키지를 생성 후 뷰 영역에서 사용할 ItemDto 클래스를 생성한다. Dto를 생성하는 이유는 데이터를 주고 받을 때 Entity 클래스 자체를 반환하면 안되고 데이터 전달용 객체(Data Transfer Object)를 생성해서 사용해야 한다.

 

📚Dto 와 Entity 차이

Dto는 계층 간 데이터 교환을 위한 객체이다. DB에서 데이터를 얻어 Service나 Controller 등으로 데이터를 보낼 때 사용하는 객체를 의미한다. getter/setter 메서드만을 갖는다. 데이터를 담고 있다는 점에서 엔티티 객체와 비슷하지만 데이터 전달이 목적이므로 읽고, 쓰는 것이 모두 허용되고, 일회성으로 사용되는 성격이 강하다.

Entity는 실제 DB의 테이블과 1:1 매핑되는 클래스이다. DB의 테이블 내에 존재하는 컬러만을 필드로 가져야한다. Entity 클래스는 상속을 받거나 구현체여서는 안된다.

 

📚Dto 와 Entity 클래스를 분리하는 이유

View Layer와 DB Later의 역할을 철저히 분리하기 위해서이다. 테이블과 매핑되는 Entity 클래스가 변경되면 여러 클래스에 영향을 끼치게 된다. 분리하는 이유를 크게 4가지로 나눈다.

  • 관심사의 분리
  • Validation 로직 및 불필요한 코드 등과의 분리
  • API 스펙의 유지
  • API 스펙의 파악이 용이

더 자세한 내용은 추가적으로 공부해야겠다.

Dto 클래스

package com.shop.shop.dto;

import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;

@Getter
@Setter
public class ItemDto {
    private Long id;

    private String itemNm;

    private Integer price;

    private String itemDetail;

    private String sellStatCd;

    private LocalDateTime regTime;

    private LocalDateTime updateTime;
}

ItemDto 객체를 하나 생성 후 모델에 데이터를 담아서 뷰에 전달한다.

 

 

3-1. th:text 예제

Controller 클래스 --> ex02

package com.shop.shop.controller;


import com.shop.shop.dto.ItemDto;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.time.LocalDateTime;

@Controller
@RequestMapping(value="/thymeleaf")
public class ThymeleafExController {
    @GetMapping(value = "/ex01")
    public String thymeleafExample01(Model model){
        model.addAttribute("data", "타임리프 예제 입니다.");
        return "thymeleaf/thymeleafEx01";
    }

    @GetMapping(value = "/ex02")
    public String thymeleafExample02(Model model){
        ItemDto itemDto = new ItemDto();
        itemDto.setItemDetail("상품 상세 설명");
        itemDto.setItemNm("테스트 상품1");
        itemDto.setPrice(10000);
        itemDto.setRegTime(LocalDateTime.now());

        model.addAttribute("itemDto", itemDto);
        return "thymeleaf/thymeleafEx02";
    }
}

▹new 생성자를 이용해 itemDto 객체를 하나 생성 후 모델에 데이터를 담아서 뷰에 전달한다.

▹addAttribute() 함수로 데이터를 저장하여 반환할 경로에 전달한다.

 

 

thymeleafEx02.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>상품 데이터 출력 예제</h1>
    <div>
        상품명 : <span th:text="${itemDto.itemNm}"></span>
    </div>
    <div>
        상품상세설명 : <span th:text="${itemDto.itemDetail}"></span>
    </div>
    <div>
        상품등록일 : <span th:text="${itemDto.regTime}"></span>
    </div>
    <div>
        상품가격 : <span th:text="${itemDto.price}"></span>
    </div>
</body>
</html>

전달받은 itemDto 객체를 th:text를 이용하여 출력한다.

 

 

3-2. th:each예제

여러 개의 데이터를 가지고 있는 컬렉션 데이터를 출력하는 방법에 대해 알아보자

Controller 클래스 --> ex03

package com.shop.shop.controller;


import com.shop.shop.dto.ItemDto;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Controller
@RequestMapping(value="/thymeleaf")
public class ThymeleafExController {
    @GetMapping(value = "/ex01")
    public String thymeleafExample01(Model model){
        model.addAttribute("data", "타임리프 예제 입니다.");
        return "thymeleaf/thymeleafEx01";
    }

    @GetMapping(value = "/ex02")
    public String thymeleafExample02(Model model){
        ItemDto itemDto = new ItemDto();
        itemDto.setItemDetail("상품 상세 설명");
        itemDto.setItemNm("테스트 상품1");
        itemDto.setPrice(10000);
        itemDto.setRegTime(LocalDateTime.now());

        model.addAttribute("itemDto", itemDto);
        return "thymeleaf/thymeleafEx02";
    }

    @GetMapping(value = "/ex03")
    public String thymeleafExample03(Model model){

        List<ItemDto> itemDtoList = new ArrayList<>();

        for(int i=1;i<=10;i++){

            ItemDto itemDto = new ItemDto();
            itemDto.setItemDetail("상품 상세 설명"+i);
            itemDto.setItemNm("테스트 상품" + i);
            itemDto.setPrice(1000*i);
            itemDto.setRegTime(LocalDateTime.now());

            itemDtoList.add(itemDto);
        }

        model.addAttribute("itemDtoList", itemDtoList);
        return "thymeleaf/thymeleafEx03";
    }
}

▹반복문을 통해 화면에서 출력할 10개의 itemDto 객체를 만들어서 itemDtoList에 넣어준다.

▹화면에 출력할 itemDtoList를 model에 담아서 View에 전달한다.

 

 

thymeleafEx03.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>상품 리스트 출력 예제</h1>

<table border="1">
    <thead>
    <tr>
        <td>순번</td>
        <td>상품명</td>
        <td>상품설명</td>
        <td>가격</td>
        <td>상품등록일</td>
    </tr>
    </thead>
    <tbody>
    <tr th:each="itemDto, status: ${itemDtoList}">
        <td th:text="${status.index}"></td>
        <td th:text="${itemDto.itemNm}"></td>
        <td th:text="${itemDto.itemDetail}"></td>
        <td th:text="${itemDto.price}"></td>
        <td th:text="${itemDto.regTime}"></td>
    </tr>
    </tbody>
</table>

</body>
</html>

▹th:each를 이용하면 자바의 for문처럼 반복문을 사용할 수 있다.전달받은 itemDtoList에 있는 데이터를 하나씩 꺼내와서 itemDto에 담아준다. status에는 현재 반복에 대한 상태 데이터가 존재하며, 변수명은 status 대신 다른 것을 사용해도 된다.

▹현재 순회하고 있는 데이터의 인덱스를 출력한다.

 

이렇게 테이블 형태로 데이터가 출력된다.

 

 

3-3. th:if, th:unless 예제

조건문에 대해 알아보자

Controller 클래스

package com.shop.shop.controller;


import com.shop.shop.dto.ItemDto;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Controller
@RequestMapping(value="/thymeleaf")
public class ThymeleafExController {
    @GetMapping(value = "/ex01")
    public String thymeleafExample01(Model model){
        model.addAttribute("data", "타임리프 예제 입니다.");
        return "thymeleaf/thymeleafEx01";
    }

    @GetMapping(value = "/ex02")
    public String thymeleafExample02(Model model){
        ItemDto itemDto = new ItemDto();
        itemDto.setItemDetail("상품 상세 설명");
        itemDto.setItemNm("테스트 상품1");
        itemDto.setPrice(10000);
        itemDto.setRegTime(LocalDateTime.now());

        model.addAttribute("itemDto", itemDto);
        return "thymeleaf/thymeleafEx02";
    }

    @GetMapping(value = "/ex03")
    public String thymeleafExample03(Model model){

        List<ItemDto> itemDtoList = new ArrayList<>();

        for(int i=1;i<=10;i++){

            ItemDto itemDto = new ItemDto();
            itemDto.setItemDetail("상품 상세 설명"+i);
            itemDto.setItemNm("테스트 상품" + i);
            itemDto.setPrice(1000*i);
            itemDto.setRegTime(LocalDateTime.now());

            itemDtoList.add(itemDto);
        }

        model.addAttribute("itemDtoList", itemDtoList);
        return "thymeleaf/thymeleafEx03";
    }

    @GetMapping(value = "/ex04")
    public String thymeleafExample04(Model model){

        List<ItemDto> itemDtoList = new ArrayList<>();

        for(int i=1;i<=10;i++){

            ItemDto itemDto = new ItemDto();
            itemDto.setItemDetail("상품 상세 설명"+i);
            itemDto.setItemNm("테스트 상품" + i);
            itemDto.setPrice(1000*i);
            itemDto.setRegTime(LocalDateTime.now());

            itemDtoList.add(itemDto);
        }

        model.addAttribute("itemDtoList", itemDtoList);
        return "thymeleaf/thymeleafEx04";
    }
}

▹상품 데이터 10개를 넣어서 뷰에 전달한다.

 

 

thymeleafEx04.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>상품 리스트 출력 예제</h1>

<table border="1">
    <thead>
    <tr>
        <td>순번</td>
        <td>상품명</td>
        <td>상품설명</td>
        <td>가격</td>
        <td>상품등록일</td>
    </tr>
    </thead>
    <tbody>
    <tr th:each="itemDto, status: ${itemDtoList}">
        <td th:if="${status.even}" th:text="짝수"></td>
        <td th:unless="${status.even}" th:text="홀수"></td>
        <td th:text="${itemDto.itemNm}"></td>
        <td th:text="${itemDto.itemDetail}"></td>
        <td th:text="${itemDto.price}"></td>
        <td th:text="${itemDto.regTime}"></td>
    </tr>
    </tbody>
</table>

</body>
</html>

▹status에는 현재 반복에 대한 정보가 존재한다. 인덱스가 짝수일 경우 status.even은 true가 된다. 즉, 현재 인덱스가 짝수라면 순번에 "짝수"를 출력한다.

▹현재 인덱스가 홀수일 경우, 순번에 "홀수"를 출력한다.

 

 

 

 

 

3-4. th:switch, th:case 예제

switch문에 대해 알아보자. 여러 개의 조건을 처리해야 할 때 사용하면 된다.

thymeleafEx04.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>상품 리스트 출력 예제</h1>

<table border="1">
    <thead>
    <tr>
        <td>순번</td>
        <td>상품명</td>
        <td>상품설명</td>
        <td>가격</td>
        <td>상품등록일</td>
    </tr>
    </thead>
    <tbody>
    <tr th:each="itemDto, status: ${itemDtoList}">
        <td th:switch="${status.even}">
            <span th:case=true>짝수</span>
            <span th:case=false>홀수</span>
        </td>
        <td th:text="${itemDto.itemNm}"></td>
        <td th:text="${itemDto.itemDetail}"></td>
        <td th:text="${itemDto.price}"></td>
        <td th:text="${itemDto.regTime}"></td>
    </tr>
    </tbody>
</table>

</body>
</html>

▹${stauts.even} 값이 true일 경우는 "짝수"를 출력하고, false일 경우는 홀수이므로 "홀수"를 출력한다.

 

 

 

 

3-5. th:href 예제

Thymeleaf에서 링크를 처리하는 문법으로 th:href 가 있다.

 

링크의 종류

  • Absolute URL : http:// 또는 https://로 시작
  • Context-relative URL :  애플리케이션의 서버 내부를 이동하는 방법으로 상대적인 URL을 입력한다. 상대경로는 URL의 프로토콜이나 호스트 이름을 지정하지 않는다.

 

Controller 클래스 --> ex05

package com.shop.shop.controller;


import com.shop.shop.dto.ItemDto;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Controller
@RequestMapping(value="/thymeleaf")
public class ThymeleafExController {
    @GetMapping(value = "/ex01")
    public String thymeleafExample01(Model model){
        model.addAttribute("data", "타임리프 예제 입니다.");
        return "thymeleaf/thymeleafEx01";
    }

    @GetMapping(value = "/ex02")
    public String thymeleafExample02(Model model){
        ItemDto itemDto = new ItemDto();
        itemDto.setItemDetail("상품 상세 설명");
        itemDto.setItemNm("테스트 상품1");
        itemDto.setPrice(10000);
        itemDto.setRegTime(LocalDateTime.now());

        model.addAttribute("itemDto", itemDto);
        return "thymeleaf/thymeleafEx02";
    }

    @GetMapping(value = "/ex03")
    public String thymeleafExample03(Model model){

        List<ItemDto> itemDtoList = new ArrayList<>();

        for(int i=1;i<=10;i++){

            ItemDto itemDto = new ItemDto();
            itemDto.setItemDetail("상품 상세 설명"+i);
            itemDto.setItemNm("테스트 상품" + i);
            itemDto.setPrice(1000*i);
            itemDto.setRegTime(LocalDateTime.now());

            itemDtoList.add(itemDto);
        }

        model.addAttribute("itemDtoList", itemDtoList);
        return "thymeleaf/thymeleafEx03";
    }

    @GetMapping(value = "/ex04")
    public String thymeleafExample04(Model model){

        List<ItemDto> itemDtoList = new ArrayList<>();

        for(int i=1;i<=10;i++){

            ItemDto itemDto = new ItemDto();
            itemDto.setItemDetail("상품 상세 설명"+i);
            itemDto.setItemNm("테스트 상품" + i);
            itemDto.setPrice(1000*i);
            itemDto.setRegTime(LocalDateTime.now());

            itemDtoList.add(itemDto);
        }

        model.addAttribute("itemDtoList", itemDtoList);
        return "thymeleaf/thymeleafEx04";
    }

    @GetMapping(value = "/ex05")
    public String thymeleafExample05(){
        return "thymeleaf/thymeleafEx05";
    }
}

 

 

thymeleafEx05.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Thymeleaf 링크처리 예제 페이지</h1>
    <div>
        <a th:href="@{/thymeleaf/ex01}">예제1 페이지 이동</a>
    </div>
    <div>
        <a th:href="@{https://www.thymeleaf.org/}">thymeleaf 공식 페이지 이동</a>
    </div>
</body>
</html>

▹클릭 시 이전에 작생했던 예제 1 페이지로 이동하며 "th:href=@{이동할 경로}" 형태로 입력한다. 

▹thymeleaf 공식 페이지로 이동한다. 애플리케이션 외부의 사이트에 접근하는 절대 경로로 입력한다.

 

 

 

해당 링크로 이동 시 파라미터값을 전달하는 것도 해보자.

thymeleafEx05.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Thymeleaf 링크처리 예제 페이지</h1>
    <div>
        <a th:href="@{/thymeleaf/ex01}">예제1 페이지 이동</a>
    </div>
    <div>
        <a th:href="@{https://www.thymeleaf.org/}">thymeleaf 공식 페이지 이동</a>
    </div>
    <div>
        <a th:href="@{/thymeleaf/ex06(param1 = '파라미터 데이터1', param2 = '파라미터 데이터2')}">thymeleaf 파라미터 전달</a>
    </div>
</body>
</html>

▹전달할 매개변수를 입력한 경로 끝에 "key=value" 구조로 입력한다. 전달할 매개변수 param1, param2에는 각각 "파라미터 데이터1", "파라미터 데이터2"를 데이터로 입력한다.

 

Controller 클래스 --> ex06

package com.shop.shop.controller;


import com.shop.shop.dto.ItemDto;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Controller
@RequestMapping(value="/thymeleaf")
public class ThymeleafExController {
    @GetMapping(value = "/ex01")
    public String thymeleafExample01(Model model){
        model.addAttribute("data", "타임리프 예제 입니다.");
        return "thymeleaf/thymeleafEx01";
    }

    @GetMapping(value = "/ex02")
    public String thymeleafExample02(Model model){
        ItemDto itemDto = new ItemDto();
        itemDto.setItemDetail("상품 상세 설명");
        itemDto.setItemNm("테스트 상품1");
        itemDto.setPrice(10000);
        itemDto.setRegTime(LocalDateTime.now());

        model.addAttribute("itemDto", itemDto);
        return "thymeleaf/thymeleafEx02";
    }

    @GetMapping(value = "/ex03")
    public String thymeleafExample03(Model model){

        List<ItemDto> itemDtoList = new ArrayList<>();

        for(int i=1;i<=10;i++){

            ItemDto itemDto = new ItemDto();
            itemDto.setItemDetail("상품 상세 설명"+i);
            itemDto.setItemNm("테스트 상품" + i);
            itemDto.setPrice(1000*i);
            itemDto.setRegTime(LocalDateTime.now());

            itemDtoList.add(itemDto);
        }

        model.addAttribute("itemDtoList", itemDtoList);
        return "thymeleaf/thymeleafEx03";
    }

    @GetMapping(value = "/ex04")
    public String thymeleafExample04(Model model){

        List<ItemDto> itemDtoList = new ArrayList<>();

        for(int i=1;i<=10;i++){

            ItemDto itemDto = new ItemDto();
            itemDto.setItemDetail("상품 상세 설명"+i);
            itemDto.setItemNm("테스트 상품" + i);
            itemDto.setPrice(1000*i);
            itemDto.setRegTime(LocalDateTime.now());

            itemDtoList.add(itemDto);
        }

        model.addAttribute("itemDtoList", itemDtoList);
        return "thymeleaf/thymeleafEx04";
    }

    @GetMapping(value = "/ex05")
    public String thymeleafExample05(){
        return "thymeleaf/thymeleafEx05";
    }

    @GetMapping(value = "/ex06")
    public String thymeleafExample06(String param1, String param2, Model model){
        model.addAttribute("param1", param1);
        model.addAttribute("param2", param2);
        return "thymeleaf/thymeleafEx06";
    }
}

▹전달했던 매개변수와 같은 이름의 String 변수 param1, param2를 파라미터로 설정하면 자동으로 뎅터가 바인딩된다. 매개변수를 model에 담아서 View로 전달한다.

 

 

thymeleafEx06.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>파라미터 전달 예제</h1>
    <div th:text="${param1}"></div>
    <div th:text="${param2}"></div>
</body>
</html>

url 뒤에는 전달하는 파라미터 값이 노출된다.

 

 

4. Thymeleaf 페이지 레이아웃

보통 웹사이트를 만들 때 header, footer, menu 등 공통적인 페이지 구성 요소들이 있다. Thymeleaf의 페이지 레이아웃 기능을 사용한다면 공통 요소 관리를 쉽게 할 수 있다.

 

Thymeleaf Layout dialect dependency 추가하기

<dependency>
   <groupId>nz.net.ultraq.thymeleaf</groupId>
   <artifactId>thymeleaf-layout-dialect</artifactId>
   <version>3.1.0</version>
</dependency>

 

footer.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <div th:fragment="footer">
    footer 영역입니다.
    </div>
</html>

 

 

header.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <div th:fragment="header">
    header 영역입니다.
    </div>
</html>

 

layout1.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <th:block layout:fragment="script"></th:block>
    <th:block layout:fragment="css"></th:block>

</head>
<body>

    <div th:replace="fragments/header::header"></div>

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

    <div th:replace="fragments/footer::footer"></div>

</body>
</html>

 

thymeleafEx07.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout=http://www.ultraq.net.nz/thymeleaf/layout
      layout:decorate="~{layouts/layout1}">

<div layout:fragment="content">
    본문 영역 입니다.
</div>

</html>

 

Controller --> ex07

package com.shop.shop.controller;


import com.shop.shop.dto.ItemDto;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Controller
@RequestMapping(value="/thymeleaf")
public class ThymeleafExController {
    @GetMapping(value = "/ex01")
    public String thymeleafExample01(Model model){
        model.addAttribute("data", "타임리프 예제 입니다.");
        return "thymeleaf/thymeleafEx01";
    }

    @GetMapping(value = "/ex02")
    public String thymeleafExample02(Model model){
        ItemDto itemDto = new ItemDto();
        itemDto.setItemDetail("상품 상세 설명");
        itemDto.setItemNm("테스트 상품1");
        itemDto.setPrice(10000);
        itemDto.setRegTime(LocalDateTime.now());

        model.addAttribute("itemDto", itemDto);
        return "thymeleaf/thymeleafEx02";
    }

    @GetMapping(value = "/ex03")
    public String thymeleafExample03(Model model){

        List<ItemDto> itemDtoList = new ArrayList<>();

        for(int i=1;i<=10;i++){

            ItemDto itemDto = new ItemDto();
            itemDto.setItemDetail("상품 상세 설명"+i);
            itemDto.setItemNm("테스트 상품" + i);
            itemDto.setPrice(1000*i);
            itemDto.setRegTime(LocalDateTime.now());

            itemDtoList.add(itemDto);
        }

        model.addAttribute("itemDtoList", itemDtoList);
        return "thymeleaf/thymeleafEx03";
    }

    @GetMapping(value = "/ex04")
    public String thymeleafExample04(Model model){

        List<ItemDto> itemDtoList = new ArrayList<>();

        for(int i=1;i<=10;i++){

            ItemDto itemDto = new ItemDto();
            itemDto.setItemDetail("상품 상세 설명"+i);
            itemDto.setItemNm("테스트 상품" + i);
            itemDto.setPrice(1000*i);
            itemDto.setRegTime(LocalDateTime.now());

            itemDtoList.add(itemDto);
        }

        model.addAttribute("itemDtoList", itemDtoList);
        return "thymeleaf/thymeleafEx04";
    }

    @GetMapping(value = "/ex05")
    public String thymeleafExample05(){
        return "thymeleaf/thymeleafEx05";
    }

    @GetMapping(value = "/ex06")
    public String thymeleafExample06(String param1, String param2, Model model){
        model.addAttribute("param1", param1);
        model.addAttribute("param2", param2);
        return "thymeleaf/thymeleafEx06";
    }

    @GetMapping(value = "/ex07")
    public String thymeleafExample07(){
        return "thymeleafEx/thymeleafEx07";
    }
}

 

5. 부트스트랩으로 header, footer 영역 수정하기 

layout1.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <!-- CSS only -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <link th:href="@{/css/layout1.css}" rel="stylesheet">

    <!-- JS, Popper.js, and jQuery -->
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

    <th:block layout:fragment="script"></th:block>
    <th:block layout:fragment="css"></th:block>

</head>
<body>

<div th:replace="fragments/header::header"></div>

<div layout:fragment="content" class="content">

</div>

<div th:replace="fragments/footer::footer"></div>

</body>
</html>

 

 

 

 

Comments