◉ 사전지식 : 타임리프
- 타임리프 : 템플릿 엔진
- 템플릿 엔진 : 스프링 서버에서 데이터를 받아 우리가 보는 웹 페이지 즉, HTML 상에 그 데이터를 넣어 보여주는 도구
단, 템플릿 엔진의 경우, HTML과 함께 템플릿 엔진을 위한 문법을 섞어 사용해야 함
- 템플릿 엔진(Template Engine)
• 지정된 템플릿 양식과 데이터가 합쳐져 HTML 문서를 출력하는 소프트웨어로, 웹 사이트를 어떤 형태로 만들지 도와주는 양식
• 서버 사이드 템플릿 엔진과 클라이언트 사이드 템플릿 엔진으로 분류됨
① 서버 사이드 템플릿 엔진 (Server Side Template Engine)
- 서버에서 DB 혹은 API에서 가져온 데이터를 미리 정의된 Template에 넣어 HTML를 그려서 클라이언트에 전달해주는 역할
- 대표적인 서버 사이드 템플릿 엔진 : Thymeleaf, JSP, Freemarker
② 클라이언트 사이드 템플릿 엔진 (Client Side Template)
- HTML 형태로 코드를 작성할 수 있으며, 동적으로 DOM를 그리게 해주는 역할
- 데이터를 받아서 DOM 객체에 동적으로 그려주는 프로세스를 담당
- 대표적인 클라이언트 사이드 템플릿 엔진 : Mustache, Squirrelly, Handlebars
• 보통 Java에서 웹 개발 시 JSP를 이용하여 진행
JSP 사용 시, <% %> 형태의 스크립트릿을 사용하여 개발함 → 스크립트릿의 경우, HTML과 혼재되어 유지 보수의 어려움이 있음
따라서, Spring boot에서는 JSP가 아닌 Thymeleaf 사용을 권장함
1. 템플릿 엔진 개념 잡기
- 간단한 템플릿 문법을 위한 예
<h1 text=${ 이름 } >
<p text=${ 나이 } >
- 서버에서 보내준 데이터 예
: 서버에서 이름, 나이라는 키로 데이터를 템플릿 엔진에 넘겨주면, 템플릿 엔진은 HTML에 값을 적용함
{
이름 : “구름”
나이 : 10
}
• 값이 달라질 경우, 그때 그때 화면에 반영되므로 동적인 웹 페이지가 생성 가능
- 타임리프 표현식과 문법
▪︎ 표현식 : 전달받은 데이터를 사용자들이 볼 수 있는 뷰로 만들기 위해 사용됨
표현식 | 설명 |
${ ... } | 변수의 값 표현식 |
#{ ... } | 속성 파일 값 표현식 |
@{ ... } | URL 표현식 |
*{ ... } | 선택한 변수의 표현식 th:object에서 선택한 객체에 접근 |
▪︎ 문법
표현식 | 설명 | 예제 |
th:text | 텍스트를 표현할 때 사용 | th:text=${ person.name } |
th:each | 컬렉션을 반복할 때 사용 | th:each="person : ${ persons }" |
th:if | 조건이 true인 때만 표시 | th:if="${ person.age } >= 20" |
th:unless | 조건이 false인 때만 표시 | th:unless="${ person.age } >= 20" |
th:href | 이동 경로 | th:href="@{ /person(id=${ person.id })}" |
th:with | 변수값으로 지정 | th:with="name=${ person.name }" |
th:object | 선택한 객체로 지정 | th:object="${ person }" |
※ 뷰 페이지를 작업할 때 사용하면 좋은 확장프로그램 : LiveReload++
- 이클립스에서 작업한 내용 저장 시, 웹 브라우저가 자동으로 갱신되도록 해주는 플러그인
- 서버 실행 후, 확장 프로그램 클릭하여 새로고침해주면 자동으로 실행됨
2. 타임리프 사용을 위한 의존성 추가하기
1) 새로운 Spring Starter Project 생성 : HiThymeleaf
- 프로젝트 생성 시, 의존성 추가
2) 타임리프 사용을 위한 의존성 추가하기
- build.gradle 파일에 의존성 추가 → Snippets에 업데이트해놓기
※ build.gradle 파일 수정 후, 반드시 Refresh Gradle Project 해주어야 반영됨
dependencies {
// * MVC 개발 라이브러리
// MVC 환경 개발에 필요한 필수 라이브러리
implementation 'org.springframework.boot:spring-boot-starter-web'
// 타임리프를 뷰 템플릿으로 사용 시 필요
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
// * 데이터베이스를 다루는 기술 ( JPA / MyBatis / JDBC TEMPLATE )
// JDBC Template 방식 기술로 개발할 때 필요
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
// JPA 방식 기술로 개발 시 필요
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// 순수 JDBC 기술로 개발 시 필요
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
// 한국에서 가장 많이 사용하고 있는 데이터베이스 기술
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.2'
// * 실행 시 필요한 데이터베이스 JDBC 드라이버
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
runtimeOnly 'com.oracle.database.jdbc:ojdbc8'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
// * 개발할 때 소스 자동 생성 실행 시 필요한 라이브러리
annotationProcessor 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// * 테스트 라이브러리
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.2'
}
3) 타임리프 문법 익히기용 컨트롤러 작성하기
- '/thymeleaf/example' GET 요청이 오면, 특정 데이터를 HTML로 넘겨주는 모델 객체에 추가하는 컨트롤러 메서드 작성
▪︎ ExampleController.java ( controller패키지 )
package org.choongang.ewha.hithymeleaf.controller;
import java.time.LocalDate;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.Getter;
import lombok.Setter;
@Controller // 컨트롤러라는 것을 명시적으로 표시
public class ExampleController {
@GetMapping("/thymeleaf/example")
public String thymeleafExample(Model model) {
// * Model 객체 : HTML 쪽으로 값을 넘겨주는 객체
// -> 따로 생성할 필요 없이 인자로 선언하기만 하면 스프링이 알아서 만들어줌
Person examplePerson = new Person();
examplePerson.setId(1L);
examplePerson.setName("홍길동");
examplePerson.setAge(11);
examplePerson.setHobbies(List.of("운동", "독서"));
// * List의 of() 메서드 : 변경불가한 list 객체를 생성
// -> List.of()로 생성된 list의 각 요소는 변경 불가능
// 변경할 경우, UnsupportedOperationException 발생
model.addAttribute("person", examplePerson); // person 객체 저장
model.addAttribute("today", LocalDate.now());
return "example"; // example.html 뷰 조회
}
// * 내부클래스 : Controller 클래스 내에 Person 클래스 존재
// -> has a 관계
@Setter
@Getter
class Person{
private Long id;
private String name;
private int age;
private List<String> hobbies;
}
}
• Model
- HTML 쪽으로 값을 넘겨주는 객체
→ 따로 생성할 필요 없이 인자로 선언하기만 하면 스프링이 알아서 만들어줌
- org.springframework.ui.Model ( MVC 패턴의 Model 아님 )
- UI용 화면과 화면 사이 또는 화면과 controller 사이에 임시 데이터를 저장하기 위한 버퍼나 캐쉬같은 임시 메모리 공간
• addAttribute( ) 메서드
- Model 객체에 값을 저장
• List의 of() 메서드
- 변경불가한 list 객체를 생성
→ List.of()로 생성된 list의 각 요소는 변경 불가능
변경할 경우, UnsupportedOperationException 발생
• @Controller
- 해당 클래스가 '컨트롤러'임을 명시하는 목적
- 스프링 부트가 컨트롤러의 이 애너테이션을 보고, resource/templates 디렉토리에서 '반환하는 값의 이름을 가진 뷰의 파일'을 찾은 다음, 웹 브라우저에서 해당 파일을 보여줌
• 모델의 역할 : 컨트롤러와 뷰의 중간다리 역할
- 예제에 따르면, 현재 이 모델의 경우 두 종류의 키('person', 'today')를 가진 데이터가 저장됨
- 컨트롤러 : model.addAttribute( ) 메서드를 통해 모델에 데이터 설정
→ 뷰에서 사용할 수 있게 데이터 전달
4) 뷰 작성하기
▪︎ Example.html ( src/main/resources/templates )
<!DOCTYPE html>
<html xmlns="http://www.thymeleaf.org">
// * 타임리프 사용 선언
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>타임리프 익히기</h1>
<!-- LocalDate를 yyyy-MM-dd 포맷으로 변경 -->
<p th:text="${#temporals.format(today,'yyyy-MM-dd')}"></p>
<div th:object="${ person }">
<!--
# person을 선택한 객체로 지정
- 멤버변수를 여러 개 가진 자료의 경우, 출력 시 객체명을 매번 붙여주어야 함
- 태그 방식에서는 보기 불편함
-> 타임리프의 경우, 객체는 한 번만 th:object에 대입하여 하위 태그에 지정
-> 하위 태그에서는 *{ ... }를 사용해 해당 객체에 접근
# th:object 속성의 범위 : 시작태그<>와 끝태그</ >의 사이
-> 일종의 객체의 루프와 유사한 느낌이라고 생각하면 됨
-->
<p th:text="|이름 : *{ name }|"></p>
<p th:text="|나이 : *{ age }|"></p>
<p>취미</p>
<!-- List<String> hobbies : th:each(컬렉션을 반복할 때 이용) -->
<ul th:each="hobby : *{ hobbies }">
<li th:text="${ hobby }"></li>
<!-- 반복 대상이 운동이라면, '대표 취미'라는 표시 추가 -->
<span th:if="${ hobby == '운동' }">(대표 취미)</span>
</ul>
</div>
<!-- 1번 블로그 글을 보러 이동 : 네비게이션 메뉴(<a>태그) 만들기 -->
<a th:href="@{ /api/articles/{id}(id=${person.id})}">글 보기</a>
</body>
</html>
• #temporals.format( ) 메서드
- LocalDate 타입인 오늘 날짜를 'yyyy-MM-dd' 형식의 String 타입으로 포매팅
• th:object - 선택한 객체로 지정
*{ } - 선택한 변수의 표현식
th:object에서 선택한 객체에 접근
th:object를 사용해 모델에서 받은 객체 중 "person"이라는 키를 가진 객체의 데이터를 하위태그에 지정
→ 하위태그에서는 *{ ... }를 사용해 부모 태그에 적용한 객체 값에 접근 가능
: person.name의 경우, *{ name }와 동일한 의미 ( 코드의 반복을 줄여줌 )
5) 뷰 테스트하기
▪︎ 실행결과
'백엔드 > Spring Boot' 카테고리의 다른 글
타임리프 (0) | 2023.08.04 |
---|---|
Thymeleaf (0) | 2023.08.02 |
6. 블로그 기획하고 API 만들기 (3) - 블로그 글 작성을 위한 API 구현❸ (1) | 2023.07.31 |
6. 블로그 기획하고 API 만들기 (3) - 블로그 글 작성을 위한 API 구현❷ (0) | 2023.07.27 |
6. 블로그 기획하고 API 만들기 (3) - 블로그 글 작성을 위한 API 구현❶ (0) | 2023.07.26 |