공부/spring

0118 Spring boot / thymeleaf

삶은고구마 2024. 1. 18. 19:53

 

 

Spring boot 

dev tools

lombok

web

thymeleaf

jap[mybatis 대체]

validation

oracle

security

따로 톰캣 연결 안함

 

 

 

1.Spring boot 모듈 생성

공용 작업중이므로 본인 폴더 하위에 생성할 것.

 

 

 

2.주입할 의존을 키워드로 검색 해서 선택가능.

여기서 실수로 빼먹었다해도 build.gradle에서 추가할 수 있다.

 

3.구조

 

static : js css images

templates : html

 

static..단어 그대로 정적이란 뜻이다. 정적파일인 js css image들을 여기다 두면 된다.

반대로 동적인 파일은 웹페이지 등이 있다.

 

 

그리고 모듈 생성 후 , 클릭해보면 백지 상태인 application.properties라는 파일이 있는데

여기에 xml에 기술했던 설정들을 작성하면 된다. 

확장자 명은 yml 이나 yaml을 사용하자.

 

주의할 점은 들여쓰기.

server-port 속성이므로 들여쓰기를 해야한다 만약

server:

port: 8080 

이런식으로 작성하면 작동하지 않는다.

하단의 logging관련 설정도, 기본은 info이지만 com.sh.app 패키지에 한정해 debug 레벨부터 시작한다는 뜻.

#들여쓰기 주의 탭은 두개
#context-path 생략가능
#tomcat (container) 
server:
  port: 8080
  servlet:
    context-path: /spring

#logback(logging)
logging:
  level:
    root: info
    com.sh.app: debug

 

4.예제

package com.sh.app;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * getMapping에 아무것도 없을 때 = switch의 default = 문자열반환
 * @return
 */
@Controller
@Slf4j
public class HomeController {
    @GetMapping
    @ResponseBody //반환객체를 http응답메시지에 작성하라..
    public String home()
    {
        return "hello world!🎮🎨";
    }
}

 

 

 


Thymeleaf

-view template(뷰 템플릿)

-controller가 전달하는 데이터를 이용해 동적으로 화면을 구성해주는 역할.

-백엔드 서버에서 HTML을 동적으로 렌더링하는 용도로 사용한다.

-.html로 view작업을 진행한다.

 

 

 

1.Thymeleaf 모듈 생성

 

 

2.Thymeleaf  설정 

application.yml

server:
  port: 8080
  servlet:
    context-path: /thymeleaf

 

 

2.Thymeleaf  예제

-model
-modelmap
-modelandview 

controller->view로 값을 전달할 때  

model의 addAttribute 속성을 사용하면 된다.

 

기본:request에 저장

 

 model.addAttribute("flag",new Random().nextBoolean());
  model.addAttribute("greeting","hello, thymeleaf!");
        model.addAttribute("num",new Random().nextInt(10)+1);
        model.addAttribute("today", LocalDate.now());
        model.addAttribute("nongdamgom", 
                User.builder()
                        .id(777L)
                        .username("nongdamgom")
                        .password("pw1234")
                        .name("담곰이")
                        .enabled(true)
                        .createdAt(LocalDateTime.now())
                        
                        .build());

 

 

index.html

<title th:text="|Hello World!|">여기는안나와</title>

th:text가 우선순위가 높기 때문에 여기는안나와 텍스트는 출력되지 않고 Hello World!가 나온다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title th:text="|Hello World!|"></title>
</head>
<body>
    <h1 th:text="|띄어쓰기 하고싶으면 양쪽에 파이프라인을 붙이시오|"></h1>
    <ul>
        <li><a th:href="@{/basics.do?mode=kr&opt=red&opt=blue}" th:text="여기가우선순위">후순위</a></li>
        <li><a th:href="@{/inline.do}" th:text="inline작성"></a></li>
        <li><a th:href="@{/utilityObject.do}" th:text="utility객체"></a></li>
        <li><a th:href="@{/fragment.do}" th:text="fragment"></a></li>
        <li><a th:href="@{/layout.do}" th:text="Layout"></a></li>
    </ul>
</body>
</html>

 

1)사용자 입력값

 <li th:text="${param.mode}"></li>
    <li th:text="${param.opt}"></li>
    <li th:text="${param.opt[0]}"></li>
    <li th:text="${param.opt[1]}"></li>

 

2)속성가져오기

el과 유사하게 ${attributreName}을 사용하면 된다.

속성을 가져올 때엔 ${attributreName.필드값} 이렇게 가져오면 된다.

jsp랑 다르게 여긴 자동완성까지 된다 신기함.

그리고 속성 문자열을 표현하고싶으면 시작과 끝에 파이프라인(|)을 붙여주면 된다. 그렇지 않으면 오류 발생

+

한가지 드는 의문점

nongdamgom의 id,name등은 private값인데 어떻게 접근할 수 있지?

마치 필드같지만 getter를 사용해 호출하는것.

ex)

필드 변수명은 irm인데 getName,setName인 경우엔 user.irm이 아니라 user.name을 사용해야한다는것

private String irm;

public String getName(){}

public String setName(String irm(){}

 

property 접근방식 : 객체를따라가며 찾는거

OGNL property(Object Graph Navigation Lang)

-el

-mybatis

-bean:property 

-thymeleaf

 

 <li th:text="${greeting}"></li>
        <li th:text="${num}"></li>
        <li th:text="${today}"></li>
        <li th:text="${nongdamgom}"></li>
        <li>
            속성 가져오기1
            <ul>
                <li th:text="${nongdamgom.id}"></li>
                <li th:text="${nongdamgom.username}"></li>
                <li th:text="${nongdamgom.password}"></li>
                <li th:text="${nongdamgom.name}"></li>
                <li th:text="${nongdamgom.enabled}"></li>
                <li th:text="${nongdamgom.createdAt}"></li>
            </ul>
        </li>
         <li>
            속성 문자열 표현
            <ul>
                <li th:text="|안녕하세요 ${nongdamgom.name} 입니당|"></li>
            </ul>
        </li>

 

 

아스타로 값 가져오기

nongdamgom에 대한 id, username (앞에 * 기호 붙이기)

<li th:object="${nongdamgom}">
            속성 가져오기2
            <ul>
                <li th:text="*{id}"></li>
                <li th:text="*{username}"></li>
                <li>
                    <input type="checkbox" th:checked="*{enabled}">
                </li>
            </ul>
        </li>

 

 

 

 

 

3)분기처리

el과 다르게 eq ne가 없어서 !=로 처리했다.

<h2>분기처리</h2>
    <p th:if="${flag}" th:text="|flag가 true 입니다.|"></p>
    <p th:unless="${flag}" th:text="|flag가 false 입니다.|"></p>
    <p th:if="${nongdamgom != null}" th:text="|nongdamgom 존재하는 아이디 입니다|"></p>
    <!--switch-->
    <div th:switch="${num}">
        <p th:case="1" th:text="|1을 뽑았습니다..|"></p>
        <p th:case="2" th:text="|2을 뽑았습니다..|"></p>
        <p th:case="3" th:text="|3을 뽑았습니다..|"></p>
        <p th:case="4" th:text="|4을 뽑았습니다..|"></p>
        <p th:case="*" th:text="|꽝을 뽑았습니다..|"></p>
        <!--기본값은 * -->
    </div>

 

4)반복처리

<h2>반복처리</h2>
<table>
    <tr>
        <th>no</th>
        <th>id</th>
        <th>username</th>
        <th>name</th>
    </tr>
<!-- 꺼냈을때 사용할 각각의 변수 :반복객체  -->
<!--
    status
    -index : 0 based index
    -count : 1 based index
    -first : 첫번째 요소 여부
    -last : 마지막 요소 여부
    -odd : 홀수 여부
    -even : 짝수 여부
    -size :크기[전체수]
	index,count는 숫자타입이고 나머지는 boolean
   -->
    <tr th:each="user , status  : ${users}" th:style="${status.odd}?'background-color:pink'">
        <td th:text="${status.count}"></td>
        <td th:text="${user.id}"></td>
        <td th:text="${user.username}"></td>
        <td th:text="${user.name}"></td>
    </tr>
</table>

 

4)Utility Object

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf | Utility Object</title>
</head>
<body>
    <a href="https://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html">
        Basic Object | Utility Obejct</a>

    <h1>Utility Object</h1>
    <h2>#strings</h2>
    <ul>
        <li th:text="${#strings.isEmpty(name)}"></li>
        <li th:text="${#strings.contains('홍')}"></li>
        <li th:text="${#strings.startsWith('홍')}"></li>
        <li th:text="${#strings.replace('홍','고')}"></li>
    </ul>
    <h2>#lists</h2>
</body>
</html>

 

 

5)Layout

th의 fragment : 재사용 

->th include

 

layout의 fragment : 각 페이지마다 변하는것

->layout fragment

 

jsp에서 header / index / footer 로 영역을 나눈 것처럼 spring에서도 나눌 수 있다.

오늘 처음 익힌 방식이라 조금 헷갈리긴한데 익숙해진다면 jsp보다 활용도가 높을 것 같다.

 

아래는 page.html의 전체 구조다

 

 

<!DOCTYPE html>
<html
        xmlns:th="http://www.thymeleaf.org"
        xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
        layout:decorate="~{layout/default}">
<style layout:fragment="style">
    *{font-size:100px;}
    *{background-color: cornflowerblue}
</style>
<div layout:fragment="content">
    🐧🐧🐧🐧🐧🐧🐧🐧🐧
</div>
<script layout:fragment="script">
    console.log('👻👻👻👻👻👻👻👻👻👻👻👻👻');
</script>

<!-- layout:decorate="~{layout/default}" 페이지 뼈대-->

 

내부에 스타일태그를 작성해서 간단하게 폰트사이즈랑 배경색을 설정했다.

content엔 펭귄 아이콘을 출력, console.log는 유령을 출력한다.

html 속성에 decorate는 이 페이지의 뼈대를 의미한다. layout디렉토리의 default.html을 확인해보자.

 

 

layout-default.html

문서의 구조를 잡는 html이다.

헤더-section(content)-푸터

<!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>
<!-- 각 페이지의 style 태그로 대체   -->
    <style layout:fragment="style"></style>
</head>
<body>
<div id="container">
    <header th:include="~{fragments/header::header}"></header>


    <section>
        <!-- 각 페이지의 content 페이지로 대체되는 구역       -->
        <div layout:fragment="content"></div>
    </section>


    <footer th:include="~{fragments/footer::footer}"></footer>
</div>
<!-- 각 페이지의 script로 대체-->
<script layout:fragment="script"></script>
</body>
</html>

<!--
    문서의 구조를 잡는 html
-->

 

header

<!DOCTYPE html>
<html
        xmlns:th="httP://www.thymeleaf.org"
        xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<header th:fragment="header">
    <h2>Header</h2>
</header>

 

footer

<!DOCTYPE html>
<html
        xmlns:th="httP://www.thymeleaf.org"
        xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<footer th:fragment="footer">
    <h3>Footer</h3>
</footer>

 

 

고정적인 부분은 th:frg / 변동하는 부분은 layout:frg

 

 

전체 구조/파란색:고정/빨간색:커스텀되는 동적페이지