ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백견불야일타] 3장 Thymeleaf 학습하기
    SpringBoot/쇼핑몰 프로젝트 with JPA 2022. 8. 26. 01:41
    • 미리 정의된 템플릿을 만들고 동적으로 HTML 페이지를 만들어서 클라이언트에 전달하는 방식
    • 요청이 올 때마다 서버에서 새로운 HTML 페이지를 만들어 주기 때문에 서버 사이드 렌더링 방식이라고 함
    • 서버 사이드 템플릿 엔진으로는 Thymeleaf, JSP, Freemarker, Groovy, Mustache 가 있음

     

    thymeleafEx01.html

    <!DOCTYPE html>
    <!-- thymeleaf 문법을 사용하기 위해서 추가 <-->
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!-- ThymeleafExController의 model의 data라는 key 값에 담아준 값을 출력 <-->
    <p th:text="${data}">Hello Thymelaf!!</p>
    </body>
    </html>

    th:text="${data}" - Thymeleaf 문법

     

     

    ThymeleafExController.java

    package com.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
    // 클라이언트 요청에 대해서 어떤 컨트롤러가 처리할지 매핑하는 어노테이션
    // url에 "/thymeleaf" 경로로 오는 요청을 ThymeleafExController가 처리하도록 함
    @RequestMapping(value = "/thymeleaf")
    public class ThymeleafExController {
    
        @GetMapping(value = "/ex01")
        public String thymeleafExample01(Model model) {
            // model 객체를 이용해 뷰에 전달한 데이터를 key, value 구조로 넣어줌
            model.addAttribute("data", "타임리프 예제 입니다.");
            // templates 폴더를 기준으로 뷰의 위치와 이름(thymeleafEx01.html)을 반환
            return "thymeleafEx/thymeleafEx01";
        }
    }

    Hello Thymeleaf!! 대신 타임리프 예제 입니다 라는 문구가 나타남

     

    • 이것이 Thymeleaf가 지향하는 'natural templates' 
    • 디자이너 또는 퍼블리셔는 자신이 작업한 내용을 html 파일로 바로 열어서 확인 가능하며, 개발자는 html 파일을 받아서 html 태그 안에 thymeleaf 문법을 추가하는 것만으로 동적으로 html 파일을 생성할 수 있음
    • JSP는 html파일을 다시 JSP로 변경할 때 실수할 확률도 높고 많은 시간이 걸림

     

     

     

    Spring Boot Devtools

    • 애플리케이션 개발 시 유용한 기능들을 제공하는 모듈
    • Automati Restart : classpath에 있는 파일이 변경될 때마다 애플리케이션을 자동으로 재시작해줌
    • Live Reload: 정적 자원(html, css, js) 수정 시 새로 고침 없이 바로 적용
    • Property Defaults: Thymeleaf는 기본적으로 성능을 향상시키기 위해서 캐싱 기능을 사용함. 하지만 개발하는 과정에서 캐싱 기능을 사용한다면 수정한 소스가 제대로 반영되지 않을 수 있기 때문에 cache의 기본값을 false로 설정할 수 있음

    pom.xml

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

    spring-boot-devtools 의존성 추가

     

    2021.02 버전부터 compiler.automake.allow.when.app.running 이 없기 때문에 File - setting - Build, Execution, Deployment - compiler 를 열고 Build project automatically 체크 후 OK

     

     

    application.properties 

    #Live Reload 기능 활성화
    spring.devtools.livereload.enabled=true
    
    #Thymeleaf cache 사용 중지
    spring.thymeleaf.cache = false

     

     

     

     

     

    Thymeleaf 예제 

     

    th:text 예제

     

    com.shop.dto.ItemDto

    package com.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;
        
    }

    데이터를 주고받을 때는 Entity 클래스 자체를 반환하면 안 되고 데이터 전달용 객체(DTO)를 생성해서 사용해야 함.

    데이터베이스의 설계를 외부에 노출할 필요도 없으며, 요청과 응답 객체가 항상 엔티티와 같지 않기 때문.

     

     

    com.shop.controller.ThymeleafExController.java

    @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 "thymeleafEx/thymeleafEx02";
        }

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

     

     

    resources/templates/thymeleafEx/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를 이용하여 출력

     

     

     

     

    th:each 예제

    여러 개의 데이터를 가지고 있는 컬렉션 데이터를 화면에 출력

     

    com.shop.controller.ThymeleafExController.java

    @GetMapping(value = "/ex03")
        public String thymeleafExample03(Model model){
    
            List<ItemDto> itemDtoList = new ArrayList<>();
    
            // 화면에 출력할 10개의 itemDto 객체를 만들어서 itemDtoList에 넣어줌
            for(int i=1; i<=10; i++){
    
                ItemDto itemDto = new ItemDto();
                itemDto.setItemDetail("상품 상세 설명" + i);
                itemDto.setItemNm("테스트 상품1" + i);
                itemDto.setPrice(1000*i);
                itemDto.setRegTime(LocalDateTime.now());
    
                itemDtoList.add(itemDto);
            }
    
            //화면에서 출력할 itemDtoList를 model에 담아서 View에 전달
            model.addAttribute("itemDtoList", itemDtoList);
            return "thymeleafEx/thymeleafEx02";
        }

     

     

     

    resources/templates/thymeleafEx/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 대신 다른 것을 사용해도 됨
    • <td th:text="${status.index}"></td> - 현재 순회하고 있는 데이터의 인덱스 출력

     

     

     

     

     

    th:if, th:unless 예제

    순번이 짝수이면 '짝수', 짝수가 아니면 '홀수' 를 출력( java에서 if else 조건 처리)

     

     

    com.shop.controller.ThymeleafExController.java

    @GetMapping(value = "/ex04")
        public String thymeleafExample04(Model model){
    
            List<ItemDto> itemDtoList = new ArrayList<>();
    
            // 화면에 출력할 10개의 itemDto 객체를 만들어서 itemDtoList에 넣어줌
            for(int i=1; i<=10; i++){
    
                ItemDto itemDto = new ItemDto();
                itemDto.setItemDetail("상품 상세 설명" + i);
                itemDto.setItemNm("테스트 상품1" + i);
                itemDto.setPrice(1000*i);
                itemDto.setRegTime(LocalDateTime.now());
    
                itemDtoList.add(itemDto);
            }
    
            //화면에서 출력할 itemDtoList를 model에 담아서 View에 전달
            model.addAttribute("itemDtoList", itemDtoList);
            return "thymeleafEx/thymeleafEx04";
        }

     

    resources/templates/thymeleafEx/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:if="${status.even}" th:text="짝수"></td>
                    <td th:unless="${status.even}" th:text="홀수"></td>
                    <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>
    • <td th:if="${status.even}" th:text="짝수"></td>  -> status에는 현재 반복에 대한 정보가 존재한다. 인덱스가 짝수일 경우 status.even은 true가 되고 순번에 '짝수' 출력
    • <td th:unless="${status.even}" th:text="홀수"></td> -> 현재 인덱스가 짝수가 아닐 경우 '홀수' 출력

     

     

     

     

     

    th:swtich, th:case 예제

    여러개의 조건 처리

     

     

    resources/templates/thymeleafEx/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>

     

     

     

     

    th:href 예제

    • 링크 처리 문법
    • 'Absolute URL' - 이동할 서버의 URL을 입력 , 'http://' or 'https://' 로 시작
    • 'Context-relative URL' - 가장 많이 사용되는 형식, 우리가 실행하는 애플리케이션의 서버 내부를 이동하는 방법
    • 웹 애플리케이션 루트에 상대적인 URL을 입력, 상대경로는 URL의 프로토콜이나 호스트 이름을 지정하지 않는다.

     

    com.shop.controller.ThymeleafExController.java

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

     

    resources/templates/thymeleafEx/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>
    • <a th:href="@{/thymeleaf/ex01}">예제 1페이지 이동</a> -> "th:href=@{이동할 경로}" SpringBoot 에서는 애플리케이션의 루트가 "/"이다. 만약 애플리케이션의 루트가 "/shop" 으로 지정했다면 html파일에 생성되는 이동 경로는 "/shop/thymeleaf/ex01" 이다.
    • <a th:href="@{https://www.thymeleaf.org/}">thymeleaf 공홈 이동</a> -> 절대 경로 입력

     

     

     

     

    resources/templates/thymeleafEx/thymeleafEx05.html

    <div>
            <a th:href="@{/thymeleaf/ex06(param1 = '파라미터 데이터1', param2 = '파라미터 데이터2')}">thymeleaf 파라미터 전달</a>
    </div>
    • 해당 링크로 이동시 파라미터 값 전달해야 하는 경우 처리
    • 전달할 매개변수를 입력한 결오 끝에 "(key=value)" 구조로 입력, 전달할 매개 변수 param1, param2

     

     

     

    com.shop.controller.ThymeleafExController.java

    @GetMapping(value = "/ex06")
        public String thymeleafExample06(String param1, String param2, Model model){
            model.addAttribute("param1", param1);
            model.addAttribute("param2", param2);
            return "thymeleafEx/thymeleafEx06";
    }
    • 전달했던 매개 변수와 같은 이름의 String 변수 param1, param2를 파라미터로 설정하면 자동으로 데이터가 바인딩됨
    • 매개 변수를 model에 담아서 View로 전달

     

     

    resources/templates/thymeleafEx/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>
    • 전달받은 매개 변수 값을 출력

     

     

     

     

     

     

     

    Thymeleaf 페이지 레이아웃

    • 웹사이트의 header, footer, menu 등 공통적인 페이지 구성 요소들이 있는데 이런 영역들을 각각의 페이지마다 같은 소스코드를 넣는다면 변경이 일어날 때 마다 이를 포함하고 있는 모든 페이지를 수정해야 할 것이다. Thymeleaf 페이지 레이아웃 기능을 사용한다면 공통 요소 관리를 쉽게 할 수 있다.

     

    pom.xml

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

    Thymeleaf Layout Dialect 의존성 추가

    • 하나의 레이아웃을 여러 페이지에 똑같이 적용 가능
    • 공통적으로 적용되는 레이아웃을 미리 만들어놓고 현재 작성 중인 페이지만 레이아웃에 끼워넣으면 됨

     

     

    resource/templates/fragments/footer.html

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    
        <div th:fragment="footer">
            footer 영역입니다.
        </div>
    
    </html>
    • 다른 페이지에 포함시킬 영역을 th:fragment로 선언. footer 영역을 fragment로 만듬

     

     

    resource/templates/fragments/header.html

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    
        <div th:fragment="header">
            header 영역입니다.
        </div>
    
    </html>
    • 다른 페이지에 포함시킬 영역을 th:fragment로 선언. header 영역을 fragment로 만듬

     

     

    resource/templates/layouts/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>
    • xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">  layout 기능 사용을 위해서 layout 네임스페이스 추가
    • <div th:replace="fragments/header::header"></div>  th:replace 속성은 해당 속성이 선언된 html 태그를 다른 html 파일로 치환하는 것으로 이해. fragments 폴더 아래의 header.html 파일의 "th:fragment=header" 영역을 가지고 옴
    • <div layout:fragment="content"> layout에서 변경되는 영역을 fragment로 설정. 앞으로 쇼핑몰을 만들면서 만들 페이지는 이 영역에 들어감
    • <div th:replace="fragments/footer::footer"></div> header 영역과 마찬가지로 fragments 폴더 아래의 footer.html 파일의 th:fragment="footer" 영역을 가지고 옴.

     

     

    resources/templates/thymeleafEx/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>
    • layout:decorate="~{layouts/layout1}"> layouts 폴더 아래에 있는 layout1.html 파일을 적용하기 위해서 네임스페이스 추가
    • <div layout:fragment="content"> layout1.html 파일의 <div layout:fragment="content"> 영역에 들어가는 영역

     

     

    com.shop.controller.ThymeleafExController.java

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

     

     

    • thymeleafEx07.html 파일에 따로 header 영역과 footer 영역을 지정하지 않았지만 작성한 내용이 layout1.html 파일에 포함돼 출력됨
    • 이런식으로 공통 영역은 레이아웃으로 만들어 놓고 작성하는 페이지의 content만 변경하면 공통으로 들어가는 내용들을 쉽게 관리할 수 있음

     

     

     

     

     

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

    내비게이션 바(상단의 웹 페이지 이동) 와 footer(하단의 해당 기업의 주소, 전화번호, 이메일 등의 정보)영역 만들기

     

    BootStrap

    • 트위터에서 만든 오픈소스로 웹사이트를 쉽게 만들 수 있게 도와주는 HTML, CSS, JS 프레임워크

    BootStrap CDN

    • Contents Delivery Network 는 물리적으로 멀리 떨어져 있는 사용자에게 콘텐츠를 좀 더 빠르게 제공하기 위한 서비스로 예를 들어 한국에서 미국 서버에 있는 css, javascript, 이미지 등의 리소스를 받기 위해서는 시간 지연이 발생하는데 한국에 같은 소스를 제공해주는 서버가 있다면 물리적 거리가 가깝기 때문에 좀 더 빠르게 받을 수 있다. 즉 일종의 캐시 서버를 두어서 컨텐츠를 빠르게 받을 수 있도록 하는 서비스

     

     

     

    resource/templates/layouts/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">
    
        <!-- 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">
    
        </div>
    
        <div th:replace="fragments/footer::footer"></div>
    
    </body>
    </html>

     

     

     

    resource/templates/fragments/header.html

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org"
          xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
    
    <div th:fragment="header">
        <nav class="navbar navbar-expand-sm bg-primary navbar-dark">
            <button class="navbar-toggler" type="button" data-toggle="collapse"
                    data-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03"
                    aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <a class="navbar-brand" href="/">Shop</a>
    
            <div class="collapse navbar-collapse" id="navbarTogglerDemo03">
                <ul class="navbar-nav mr-auto mt-2 mt-lg-0">
                    <li class="nav-item" sec:authorize="hasAnyAuthority('ROLE_ADMIN')">
                        <a class="nav-link" href="/admin/item/new">상품 등록</a>
                    </li>
                    <li class="nav-item" sec:authorize="hasAnyAuthority('ROLE_ADMIN')">
                        <a class="nav-link" href="/admin/items">상품 관리</a>
                    </li>
                    <li class="nav-item" sec:authorize="isAuthenticated()">
                        <a class="nav-link" href="/cart">장바구니</a>
                    </li>
                    <li class="nav-item" sec:authorize="isAuthenticated()">
                        <a class="nav-link" href="/orders">구매이력</a>
                    </li>
                    <li class="nav-item" sec:authorize="isAnonymous()">
                        <a class="nav-link" href="/members/login">로그인</a>
                    </li>
                    <li class="nav-item" sec:authorize="isAuthenticated()">
                        <a class="nav-link" href="/members/logout">로그아웃</a>
                    </li>
                </ul>
                <form class="form-inline my-2 my-lg-0" th:action="@{/}" method="get">
                    <input name="searchQuery" class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
                    <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
                </form>
            </div>
        </nav>
    </div>
    
    </html>
    • https://getbootstrap.com/ 방문 후 Navbar 코드 Header 영역에 추가후 쇼핑몰에 맞게 수정

     

     

     

    resource/templates/fragments/footer.html

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    
        <div class="footer" th:fragment="footer">
            <footer class="page-footer font-small cyan darken-3">
                <div class="footer-copyright text-center py-3">
                    2022 Shopping Mall Example WebSite
                </div>
            </footer>
        </div>
    </html>

     

     

    resources/static/css/layout1.css

    html {
        position: relative;
        min-height: 100%;
        margin: 0;
    }
    body {
        min-height: 100%;
    }
    .footer {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        padding: 15px 0;
        text-align: center;
    }
    .content{
        margin-bottom:100px;
        margin-top: 50px;
        margin-left: 200px;
        margin-right: 200px;
    }
    • footer 영역이 하단에 고정될 수 있도록 css 작성

     

     

    resource/templates/layouts/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>
    • <link th:href="@{/css/layout1.css}" rel="stylesheet"> , <div layout:fragment="content" class="content"> 추가 및 수정하여 CSS와 HTML 파일 연결 

     

     

     

    댓글

Designed by Tistory.