Spring Boot 3. Spring MVC & Thymeleaf

Spring Boot 3. Spring MVC & Thymeleaf


Thymeleaf : 실제 화면을 구성하도록 해줌 (JSP와 비슷)




1. Thymeleaf를 사용하는 프로젝트 생성


Spring Boot 프로젝트를 생성할 때 Dependencies 항목에서 Spring Boot, DevTools, Lombok, Spring Web과 더불어 Template Engines 항목에서 Thymeleaf 선택.







Thymeleaf를 사용할 때에는 변경 후에 만들어진 결과를 보관하지 않도록 설정하는 것이 편리

src -> mani -> resources -> application.properties 파일에 아래와 같이 작성

spring.thymeleaf.cache=false

=> Thymeleaf 파일을 수정하고 저장한 후에 브라우저에서 변경된 결과를 확인하기 위한 설정



- 컨트롤러

컨트롤러 클래스는 전반적인 동작 처리


* 예시

프로젝트 내에 controller 페키지 생성 -> SampleController 클래스 생성

SampleController.java

package com.example.ex3.controller;

import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/sample")
@Log4j2
public class SampleController {

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

@Controller : 해당 클래스가 컨트롤러 클래스임을 나타냄

@RequestMapping : 서버에서 요청하기 위함. () 안에는 요청하는 가상 디렉토리 명 작성.

@Log4j2 : Lombok의 기능으로 로그를 남기도록 해줌

@GetMapping : 서버에서 요청시 해당 메소드와 연결. () 안에는 요청하는 가상 디렉토리 명 작성.

log.info() : 로그 레벨이 INFO(애플리케이션의 상태, 이벤트에 대한 정보 등)인 로그를 기록하는 메소드


-> 브라우저에서 localhost:8080/sample/ex1을 입력하면 해당 클래스의 해당 메소드가 호출됨



- Thymeleaf 이용 HTML 작성

src -> main -> resources -> templates 폴더 안에 sample 폴더 생성 -> test1.html 파일 생성

(html 파일의 이름은 controller 클래스에 작성된 메소드의 @GetMapping() 안의 가상 디렉토리명과 일치해야 해당 페이지와 메소드 맵핑 가능)


* 예시

<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>

<h1 th:text="${'Hello World'}"></h1>

</body>
</html>

<html> 안의 xmlns 속성 : 없어도 되지만 있으면 좀더 코드의 완성을 도와줌

Thymeleaf의 기본 사용 방법은 기존의 속성 앞에 'th:'를 붙여주고 속성값을 지정

th:text : 해당 태그의 text 속성 지정

"${}" : {} 안에 변수명이나 직접 값을 입력해서 해당 값을 이용할 수 있도록 해줌


<실행결과>








Thymeleaf를 이용하면 기존의 HTML 구조를 그대로 두면서 필요한 동작이나 값을 추가할 수 있음





2. Thymeleaf의 기본 사용 방법


* DTO : Data Transfer Object. 값들이 저장된 객체, MVC 패턴에서 데이터 모델이 해당


* 예시

프로젝트 패키지 안에 dto 패키지를 생성하고 SampleDTO 클래스 생성







SampleDTO.java 에 아래와 같이 코드 작성

package com.example.ex3.dto;

import lombok.Builder;
import lombok.Data;
import java.time.LocalDateTime;

@Data
@Builder(toBuilder = true)
public class SampleDTO {

private Long sno;
private String first;
private String last;
private LocalDateTime regTime;

}

@Data : 해당 클래스가 데이터 클레스 임을 명시. Getter, Setter, toString, equals, hasCode등의 메소드 자동 생성

@Builder(toBuilder = true) : 객체를 생성할 수 있게 Builder() 메소드 제공

LocalDateTime : 현제 날짜와 시간을 받아오고 저장할 수 있는 타입



* 예시 - controller 클래스에서 data 클래스의 객체를 Model에 추가해서 전달

(Model : 데이터를 캡슐화 해서 처리하는데 사용되는 객체)


SampleController.java 에 아래와 같이 메소드 추가

@GetMapping({"/test2"})
public void testModel(Model model) {

// 전송할 객체 리스트 생성
List<SampleDTO> list = IntStream.rangeClosed(1, 10).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 : () 안에 가상 디렉토리 명을 작성할 때 {} 안에 작성하면 하나 이상의 URL을 지정할 수 있음

IntStream : int형 데이터를 처리하는데 특화된 기능들 제공

rangeClosed() : IntStream의 메소드 중에 하나로 () 안의 두 정수를 포함하는 int형 값에 대한 스트림 생성

asLongStream() : Stream 클래스의 메소드 중 하나로 해당 스트림의 요소를 Long 타입의 값으로 변환해서 새로운 LongStream을 생성

mapToObj() : IntStream, LongStream, DoubleStream과 같은 기본 타입을 요소로 가지는 스트림에서 요소를 다른 타입으로 변환하는 메소드

builder().build() : @Builder 어노테이션을 추가하면 제동되는 메소드로 builder() 와 build() 메소드 사이에 [필드 이름](필드 값) 형식으로 각 필드에 값을 대입해서 해당 클래스의 객체를 생성

collect(Collectors.toList()) : Collerctor 클래스의 메소드 중 하나. 스트림의 요소를 List로 수집.

model.addAttribute() : Spring MVC 에서 컨트롤러는 모델 객체에 데이터를 추가해서 데이터에 전달하는데 이때 모델 객체에 데이터를 추가하는 메소드. ( ) 안에 이름과 데이터를 순서대로 작성


=> SampleDTO 객체를 10개 생성해서 List에 추가하고 이를 Model에 'lsit'라는 이름으로 추가해서 해당 메소드를 호출하는 뷰에 전송




1) Thymeleaf 기본 사용 방법 - 반복문 처리


th:each 속성 이용

th:each = "[변수] : ${목록}"


목록의 값이 하나씩 변수에 대입되며 반복 (인핸스드 for문과 비슷)


* 예시

src -> main -> resources -> templates -> sample -> test2.html 파일 생성

아래와 같이 작성

<body>

<ul>
<li th:each="dto : ${list}">
[[${dto}]]
</li>
</ul>

</body>

[[ ]] : 인라인 표현식. [[ ]] 안의 내용을 코드에 추가


=> "list" 라는 이름으로 전달된 모델의 데이터를 반복적으로 변수 dto에 저장해서 화면에 출력


<실행결과>







- 반복문의 상태객체(state)

반복문에 부가적으로 사용할 수 있는 state객체가 있음

순번이나 인덱스 번호, 홀수 짝수등을 지정할 수 있음

반복문에서 데이터를 받아올 변수 다음에 , 다음에 상태 객체를 받아올 변수 작성(꼭 이름이 state가 아니어도 됨)

.count -> 1부터 시작, .index -> 0부터 시작


* 예시

<ul>
<li th:each = "dto, state : ${list}">
[[${state.index}]] --> [[${dto}]]
</li>
</ul>

=> state 변수에 상택개체을 받아와서 index 속성 이용

<실행결과>










2) Thymeleaf 기본 사용 방법 - 제어문 처리


th:if ~ unless를 이용하거나 삼항 연산자 스타일 사용 가능

th:if 는 해당 조건이 참일 때, th:unless는 해당 조건이 거짓일 때

th:if(unless)="${ 여기에 조건식 작성 }"

if 와 unless는 하나의 묶음이 아닌 단독으로 처리됨


* 예시 -sno가 짝수만 출력

<ul>
<li th:each = "dto, state : ${list}" th:if="${dto.sno % 2 == 0}">
[[${dto}]]
</li>
</ul>

<실행결과>







* 예시 - sno가 3의 배수일 때만 다른 형식으로 출력

<ul>
<li th:each = "dto, state : ${list}">
<span th:if="${dto.sno % 3 == 0}" th:text="'---------' + ${dto.sno}"></span>

<span th:unless="${dto.sno % 3 == 0}" th:text="${dto.first}"></span>
</li>
</ul>

<실행결과>










- 삼항 연산자

th:[속성] = "${조건식} ? ${참일 때} : ${거짓일 때}"

거짓인 경우 없이 ? 뒤에 참인 경우만 작성할 수도 있음



* 예시 - sno가 3의 배수일 때만 다른 형식으로 출력(삼항 연산자 이용)

<ul>
<li th:each = "dto, state : ${list}"
th:text="${dto.sno % 3 == 0} ? ${'-------- ' + dto.sno} : ${dto.first}">
</li>
</ul>

<실행결과>




 






* 예시 - 3항 연산자를 이용해서 서로 다른 css 스타일 적용

<head>
<meta charset="UTF-8">
<title>Test2</title>

<style>
.target{background-color: blueviolet}
</style>

</head>
<body>

<ul>
<li th:each = "dto, state : ${list}"
th:class="${dto.sno % 2 == 0} ? ${'target'}"
th:text="${dto}">
</li>
</ul>

</body>

=> 조건이 참이면 해당 <li> 태그의 class가 'target'으로 지정되서 스타일이 적용됨

<실행결과>









3) Thymeleaf 기본 사용 방법 - inline 속성


javaScript 처리에 유용

리다이렉트하면서 전달한 파라미터를 javascript 코드로 받아올 수 있도록 해줌

HTML 파일에서 <script>코드의 th:inline을 javascript로 해주면 javascript 코드에서 전달된 데이터를 이용할 수 있음



* RedirectAttributes

스프링 MVC에서 리다이렉트 시에 데이터를 전달하기 위한 인터페이스

메소드 addAttribute( [데이터 이름], [데이터 값] ) : 리다이렉트 시에 전달할 값 추가. 

메소드 addFlashAttribute( [데이터 이름], [데이터 값] ) : 리다이렉트 시에 일회성으로 데이터 전달

-> 리다이렉트된 페이지에서 데이터 이름을 이용해서 데이터 값을 받아볼 수 있음


메소드의 매개변수로 RedirectAttributes 타입의 객체를 지정하고 반환값을 String 타입으로 지정한 뒤 반환값을 "redirect:[리다이렉트 될 경로] 으로 지정



* 예시 

SampleController.java

@GetMapping({"/exInline"})
public String exInline(RedirectAttributes redirectAttributes) {
SampleDTO dto = SampleDTO.builder()
.sno(100L)
.first("Frist..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>
<h1 th:text="${result}"></h1>
<h1 th:text="${dto}"></h1>

<script th:inline="javascript">

var msg = [[${result}]]
var dto = [[${dto}]]

</script>
</body>


-> 브라우저에서 "/sample/exInline"으로 접속하면 exInline() 메소드가 실행되고 SampleDTO 객체를 생성해서 "result" 라는 이름의 문자열 데이터와 함께 리다이렉트 -> ex3.html 페이지로 리다이렉트 되고 전달된 데이터들을 'result'와 'dto'라는 이름으로 받아봄

<script> 의 th:inline을 javascript로 지정했기 때문에 전달된 데이터를 받아볼 수 있음


<실행결과>








-> 개발자도구에서 페이지의 소스를 보면 <script> 태그 안에 각 변수의 값으로 리다디렉트 하면서 전달받은 데이터가 저장된 것을 확인할 수 있음 (객체 타입은 JSON 형식으로 전달됨)




- th:block

HTML 파일에서 별도의 태그 없이 <th:block> 으로 사용할 수 있음

반복문 등을 별도로 처리할 때에 많이 사용


* 예시

<ul>
<th:block th:each="dto : ${list}">
<li th:text="${dto.sno %3 == 0} ? ${dto.sno} : ${dto.first}"></li>
</th:block>
</ul>

<실행결과>













4) Thymeleaf 기본 사용 방법 - 링크 처리

@{} 을 이용해서 링크 사용

파라미터를 전달해야 하는 상황에서 좀더 가독성 좋은 코드를 작성할 수 있음

a 태그의 th:href 속성에 @{}를 이용해서 링크 전달 가능



* 예시 

SampleController.java -> testModel() 메소드에 맵핑할 가상 디렉토리 추가 

(/testLink로 접근해도 testMethod 호출)

@GetMapping({"/test2", "/testLink"})
public void testModel(Model model) {
                .....
}

testLink.html

<ul>

<li th:each="dto : ${list}">
<a th:href="@{/sample/testView}">[[${dto.first}]]</a>
</li>

</ul>

<실행결과>








-> 링크가 생성되고 href 속성이 지정됨



- 파라미터 추가하기

링크 끝에 () 를 추가하고  [변수 이름] = ${값} 작성


* 예시

<ul>

<li th:each="dto : ${list}">
<a th:href="@{/sample/testView(sno = ${dto.sno})}">[[${dto.first}]]</a>
</li>

</ul>

<실행결과>








- path 추가하기

링크 끝에 /{ [변수] }( [변수] = ${값} ) 작성


* 예시

<ul>

<li th:each="dto : ${list}">
<a th:href="@{/sample/testView/{sno}(sno = ${dto.sno})}">[[${dto.first}]]</a>
</li>

</ul>

<실행결과>










3. Thymeleaf의 기본 객체와 LocalDateTime


Thyneleaf 에는 내부적으로 여러 종류의 기본 객체가 있음

(문자나 숫자, 웹에서 사용되는 파라미터, request, response, session 등)

숫자나 날짜 처리를 위해 #numbers나 #temporals 객체를 별도의 설정 없이 사용할 수 있음


* 예시 - #numbers를 이용해서 정수 자리수를 5로 지정

<ul>

<li th:each="dto : ${list}">
[[${#numbers.formatInteger(dto.sno, 5)}]]
</li>

</ul>

<실행결과>













* 예시 - #temporals 객체를 이용해 날짜 처리

<ul>

<li th:each="dto : ${list}">
[[${dto.sno}]] --- [[${#temporals.format(dto.regTime, 'yyyy/MM/dd')}]]
</li>

</ul>

<실행결과>

















댓글

이 블로그의 인기 게시물

Spring Boot 6. 계시판 프로젝트

Spring Boot 2. Maria 데이터베이스 & Spring Data JPA

Django 10. DB 연동