컨트롤러 뷰 템플릿 만들자.

// BasicItemController Class
package hello.itemservice.web.basic;
import hello.itemservice.domain.item.Item;
import hello.itemservice.domain.item.ItemRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.PostConstruct;
import java.util.List;
@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {
private final ItemRepository itemRepository;
@GetMapping
public String items(Model model) {
List<Item> items = itemRepository.findAll();
model.addAttribute("items", items);
return "basic/items";
}
/**
* 테스트용 데이터 추가
*/
@PostConstruct
public void init() {
itemRepository.save(new Item("itemA", 10000, 10));
itemRepository.save(new Item("itemb", 20000, 20));
}
}
thymeleaf 문법으로 동적으로 items.html 파일을 만들자.

아래와 같이 타임리프 문법으로 지정해주면 경로가 href ../css 가 아닌 css/~ 이렇게 나온다.
// items.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link th:href="@{/css/bootstrap.min.css}"
href="../css/bootstrap.min.css" rel="stylesheet">
</head>

상품등록도 아래와 같이 th:onclick ~ 작성해주면 반영이 잘 된다.
<div class="row">
<div class="col">
<button class="btn btn-primary float-end"
onclick="location.href='addForm.html'"
th:onclick="|location.href='@{/basic/items/add}'|"
type="button">상품 등록</button>
</div>
</div>


프로퍼티 접근법으로 작성을 해보면 아래 부분을 작성해보자.
<!-- 기존에 여기서 -->
<tr>
<td><a href="item.html">2</a></td>
<td><a href="item.html">테스트 상품2</a></td>
<td>20000</td>
<td>20</td>
</tr>
th 문법을 쓰자.
<!-- 이걸로 바꾼다. -->
<tbody>
<tr th:each="item : ${items}">
<td><a href="item.html" th:text="${item.id}">회원id</a></td>
<td><a href="item.html" th:text="${item.itemName}">테스트 상품1</a></td>
<td th:text="${item.price}">10000</td>
<td th:text="${item.quantity}">10</td>
</tr>
</tbody>

타임리프에서 아래문법 신경쓰자.
- @{
<tbody>
<tr th:each="item : ${items}">
<td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
<td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.itemName}">테스트 상품1</a></td>
<td th:text="${item.price}">10000</td>
<td th:text="${item.quantity}">10</td>
</tr>
</tbody>

basic package에 items.html 완성
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link th:href="@{/css/bootstrap.min.css}"
href="../css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>상품 목록</h2>
</div>
<div class="row">
<div class="col">
<button class="btn btn-primary float-end"
onclick="location.href='addForm.html'"
th:onclick="|location.href='@{/basic/items/add}'|"
type="button">상품 등록</button>
</div>
</div>
<hr class="my-4">
<div>
<table class="table">
<thead>
<tr><th>ID</th>
<th>상품명</th>
<th>가격</th>
<th>수량</th>
</tr>
</thead>
<tbody>
<tr th:each="item : ${items}">
<td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
<td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.itemName}">테스트 상품1</a></td>
<td th:text="${item.price}">10000</td>
<td th:text="${item.quantity}">10</td>
</tr>
</tbody>
</table>
</div>
</div> <!-- /container -->
</body>
</html>
리터럴 대체로 아래와 같이 해줄 수도 있다.
<tr th:each="item : ${items}">
<td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
<td><a href="item.html" th:href="@{|/basic/items/${item.id}|}" th:text="${item.itemName}">테스트 상품1</a></td>
<td th:text="${item.price}">10000</td>
<td th:text="${item.quantity}">10</td>
</tr>
타임리프는 화면 html의 모양을 그대로 살리면서 뷰 템플릿으로 렌더링 될 때만 조금씩 치환을 한다. 그래서 화면을 크게 깨트리지 않는다.
<tbody>
<tr th:each="item : ${items}">
<td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
<!-- 이 부분 변경, || 이용 -->
<td><a href="item.html" th:href="@{|/basic/items/${item.id}|}" th:text="${item.itemName}">테스트 상품1</a></td>
<td th:text="${item.price}">10000</td>
<td th:text="${item.quantity}">10</td>
</tr>
</tbody>
타임리프 간단히 알아보기
타임리프 사용 선언
<html xmlns:th="http://www.thymeleaf.org">
아래 내용을 기억하자
- 속성 변경 - th:href
- 타임리프 핵심 - 대부분의 HTML 속성을 th:xxx 로 변경할 수 있다
- URL 링크 표현식 - @{...}
- 속성 변경 - th:onclick - 상품 등록 폼으로 이동
- 리터럴 대체 - |...|
- 반복 출력 - th:each
- 변수 표현식 - ${...}
- 내용 변경 - th:text
- URL 링크 표현식2 - @{...}
- URL 링크 간단히
=> 타임리프는 순수 HTML을 그대로 유지하면서 뷰 템플릿도 사용할 수 있는 타임리프의 특징을 가진 네츄럴 템플릿이다.
<출처 김영한: 스프링 MVC 1편 - 벡앤드 웹 개발 핵심 기술>
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의
웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -
www.inflearn.com
'Spring > SpringMVC' 카테고리의 다른 글
상품 등록 처리 - @ModelAttribute (0) | 2022.05.04 |
---|---|
상품 상세, 상품 등록 폼 뷰 & 컨트롤러 (0) | 2022.05.03 |
스프링MVC 프로젝트 - 도메인 개발 & 상품 서비스 HTML (0) | 2022.05.03 |
요청 매핑 헨들러 어뎁터 구조 (0) | 2022.05.01 |
HTTP 응답 - HTTP API, 메시지 바디에 직접 입력 & HTTP 메시지 컨버터 (0) | 2022.05.01 |