WEB/Back-end

Thymeleaf 기본(SpringBoot)

최새벽 2024. 7. 30. 14:17

Thymeleaf

타임리프도 JSP처럼 서버에서 결과를 만들어 브라우저로 전송

사용하기 위해 application.properties에서 spring.thymeleaf.cache=false로 설정

타임리프에서 에러가 나면 스크롤을 내려 중앙부분을 보면 확인할 수 있음

 

 

특징

타임리프는 속성으로 되어있기 때문에 그냥 html로 열면 퍼블리셔가 화면에 코딩한 그대로 화면에서 볼 수 있음 (서버에서 받아와야하는 값들 알 수 없음)

JSP는 확장자가 JSP라서 이런거 못함

 

 

기본 설정(DTO, Controller)

// SampleDTO
@Data // JPA할 때 무한 참조가 일어날 수 있으므로 사용에 유의
@Builder(toBuilder = true)
public class SampleDTO {
    private Long sno;
    private String first;
    private String last;
    private LocalDateTime regTime;
}


// SampleController
@GetMapping("/ex2")
public void exModel(Model model){
    List<SampleDTO> list = IntStream.rangeClosed(1,20).asLongStream().mapToObj(i -> {
        SampleDTO dto = SampleDTO.builder()
                .sno(i)
                .first("First.."+i)
                .last("Last.."+i)
                .regTime(LocalDateTime.now())
                .build();
        return dto;
    }).collect(Collectors.toList());
    model.addAttribute("list", list);
}

* 참고: 자바에서 중괄호 나오면 배열 ((@Getmapping("/ex2", "/ex3") 하면 두 url모두 접근 가능함)

 

 

반복문

state를 통해 인덱스 번호를 부여하는 것도 가능함

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--  반복문  -->
    <ul>
        <li th:each="dto: ${list}">
            [[${dto}]]    <!--    대괄호 2겹: 그대로 인라인으로 출력, 객체 하나씩 출력        -->
            <a th:text="${dto}"></a>   <!--    태그 포함하여 출력       -->
        </li>
    </ul>
</body>
</html>

 

 

제어문

if를 통한 조건문이 사용이 가능하며, 이외에 unless를 통한 else처리, 삼항연산자 등을 이용할 수 있음

- 예시: 5의 배수에만 빨간 배경

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .target{
            background-color: red;
        }
    </style>
</head>
<body>
    <ul>
        <li th:each="dto, state: ${list}" th:class="${dto.sno % 5 == 0} ? 'target'"  th:text="${dto}" > <!-- state를 통해서 인덱스 번호 붙여주기, 조건문 부여 -->
            [[${state.index}]] [[${dto}]]
        </li>
    </ul>
</body>
</html>

 

 

inline 속성

- SampleController 中

@GetMapping("/exInline")
public String exInline(RedirectAttributes redirectAttributes) {
    SampleDTO dto = SampleDTO.builder()
            .sno(100L)
            .first("First.."+100)
            .last("Last.."+100)
            .regTime(LocalDateTime.now())
            .build();
    redirectAttributes.addFlashAttribute("result", "success");
    redirectAttributes.addFlashAttribute("dto", dto);

    return "redirect:/sample/ex3";
}

@GetMapping("/ex3")
public void ex3() {
    log.info("ex3");
}

- ex3.html

<body>
<!--1-->
    <h1 th:text="${result}"></h1>
    <h1 th:text="${dto}"></h1>

<!--2-->
    <script th:inline="javascript">
        var msg = [[${result}]];
        var dto = [[${dto}]];
    </script>

<!--3-->
    <script>
        var msg = '[[${result}]]';
        var dto = '[[${dto}]]';
    </script>
</body>

- 출력

- 타임리프를 활용할 경우 javascript 코드에 model처럼 속성을 넣을 수 있음

- 자바 스크립트와 서버에서 변수는 완전히 별개임. 서버 입장에서는 result라는 값을 그저 타임리프를 통해 출력하는 것.

- 따라서 원래대로라면 2번에서 따옴표 없이 사용할 경우 에러가 나야함

- 그러나 'th:inline="${result}"'를 통해 inline javascript 속성을 주었기 때문에 웹의 개발자 도구에서 보면 자동으로 따옴표가 생겨있음을 볼 수 있음

- 2번에서 객체는 원래 DTO 객체 형태 그대로 출력이 되어야하나, inline을 부여했기 때문에 js 객체 형태로 출력이 됨

 

 

링크 처리

@{}를 통해서 링크를 부여할 수 있음. 

 

- SampleController

    @GetMapping({"/ex2", "/exLink"}) // 배열을 통해 여러개 mapping이 가능함
    public void exModel(Model model){
        List<SampleDTO> list = IntStream.rangeClosed(1,20).asLongStream().mapToObj(i -> {
            SampleDTO dto = SampleDTO.builder()
                    .sno(i)
                    .first("First.."+i)
                    .last("Last.."+i)
                    .regTime(LocalDateTime.now())
                    .price(12345)
                    .build();
            return dto;
        }).collect(Collectors.toList());
        model.addAttribute("list", list);
    }

 

- exLink.html

    <li th:each="dto:${list}">
		<!-- 파라미터 여러개면 콤마를 통해 여러개 활용 가능-->
        <a th:href="@{/sample/exView(sno=${dto.sno}, first=${dto.first})}">
            [[${dto}]]
        </a>
    </li>

 

 

포맷팅

<!--   화면에 나타나는 글자를 모두 5자리로 만들어야할 때 다음과 같이 작성      -->
[[${#numbers.formatInteger(dto.sno, 5)}]]
<!-- 가격 세자리마다 콤마 직어주기          -->
[[${#numbers.formatInteger(dto.price,3,'COMMA')}]]
<!--  날짜 포맷팅 해주기, 옛날에는 dependency 추가했어야했는데 이제는 추가 없이 활용 가능함       -->
[[${#temporals.format(dto.regTime, 'yyyy/MM/dd')}]]

 

 

html 태그가 서버에서 넘어오는 내용에 담겼을 경우

- 타임리프는 별도의 확장자가 없으며 속성으로 구성되어 있기 때문에 그냥 html로 열면 퍼블리셔가 화면에 코딩한 내용을 그대로 볼 수 있음

- JSP는 확장자가 JSP이므로 html자체로 열 수 없음

- 타임리프를 활용하면 서버에서 받아와야하는 값을 알 수 없음

<h1 th:text="${'Hello World'}"></h1>
<h2 th:text="${name}">이순신</h2>  <!--name값이 홍길동이므로 화면에 홍길동이라 나옴 -->

<th:block th:text="${content}"></th:block> <!--html 글자 그대로 찍힘-->
[[${content}]]

<th:block th:utext="${content}"></th:block> <!--html 형식이 적용되어 출력됨 -->
[(${content})]

 

 

주석

<!--html 주석은 개발자 도구에서 볼 수 있음 -->
<!--/* 타임리프 주석은 개발자 도구에서 안보임 */-->