백엔드/Spring

[Spring] 타임리프 실습

happy_life 2022. 7. 26. 15:28

목차

1. 타임리프 문법

2. 관련 클래스

3. html, css

 

타임리프 문법

1) 타임리프 사용 선언

<html xmlns:th="http://www.thymeleaf.org">

 

2) 타임리프 속성 변경

th:href="@{/css/bootstrap.min.css}" // 타임리프 속성 변경

href="../css/bootstrap.min.css" // 기존

 타임리프 뷰 템플릿을 거치게 되면 서버렌더링을 통해 원래 값을 th:xxx로 변경하게 된다. 

 

3) URL 링크 표현식 - @{...}

th:href="@{/css/bootstrap.min.css}"

타임리프는 URL링크 사용시 @{...}를 사용한다. 이를 링크 표현식이라고 한다.

 

 

4) 상품 등록 폼으로 이동

속성 변경 th:onclick

onclick="location.href='addForm.html'" // 기존
th:onclick="|location.href='@{/basic/items/add}'|" // 타임리프

 

5) 리터럴 대체 - |...|

타임리프에서 문자와 표현식 등은 분리되어 있기 때문에 아래와 같이 더해서 사용해야 한다.

<span th:text="'Welcome to our application, ' + ${user.name} + '!'">

하지만 리터럴을 사용하면 아래와 같이 편하게 사용할 수 있다.

<span th:text="|Welcome to our application, ${user.name}!|">

 

6) 반복 출력 - th:each

 

<tr th:each="item : ${items}">

모델에 포함된 items 커렉션 데이터가 item변수에 하나씩 포함되고, 반복문 <tr> 태그 안에서 item 변수를 사용할 수 있다.

 

 

7) 변수 표현식- ${...}

<td th:text="${item.price}">10000</td>

모델에 포함된 값이나, 타임리프 변수로 선언된 값을 조회할 수 있다.

 

 

8) 내용 변경 - th:text

<td th:text="${item.price}">10000</td>

내용의 값을 text의 값으로 변경한다.

 

9) URL 링크 표현식2 - @{...}

<td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" // 링크 표현식
 
<td><a href="item.html" th:href="@{|/basic/items/${item.id}|}" // 간단히

 

 

관련 클래스

 

1. Item

@Data
public class Item {

    private Long id;
    private String itemName;
    private Integer price;
    private Integer quantity;

    public Item() {
    }

    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    }
}

추가 설명

1. @Data 어노테이션 쓰는거 위험하긴 함

 

 

2. ItemRepository

@Repository
public class ItemRepository {

    private static final Map<Long, Item> store = new HashMap<>(); //static
    private static long sequence = 0L; // static


    public Item save(Item item) {
        item.setId(++sequence);
        store.put(item.getId(), item);
        return item;
    }

    public Item findById(Long id) {
        return store.get(id);
    }

    public List<Item> findAll() {
        return new ArrayList<>(store.values());
    }

    public void update(Long itemId, Item updateParam) {
        Item findItem = findById(itemId);
        findItem.setItemName(updateParam.getItemName());
        findItem.setPrice(updateParam.getPrice());
        findItem.setQuantity(updateParam.getQuantity());
    }

    public void clearStore() {
        store.clear();
    }
}

추가 설명

1. update때 DTO를 사용하기도 하나, 편의상 위와 같이 코드를 작성함.

 

 

3. BasicItemController

@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {

    private final ItemRepository itemRepository;

//    @Autowired
//    public BasicItemController(ItemRepository itemRepository) {
//        this.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));
    }
}

 

추가 설명

1. @RequiredArgsConstructor가 있으면 주석 처리된 부분과 같은 코드가 있는 것과 같다.

 

2. @Autowired를 통해 스프링 Bean에 있는 ItemRepository 의존성 주입받는다.

 

 

 

html, css

 

1. CSS

CSS는 bootstrap.min.css를 사용하였음

 

 

2. HTML

타임리프를 사용하였음 위치는 baslc/items임

 

<!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/${item.id}|}" th:text="${item.itemName}">상품명</a></td>
                <td th:text="${item.price}">10000</td>
                <td th:text="${item.quantity}">10</td>
            </tr>

            </tbody>
        </table>
    </div>
</div> <!-- /container -->
</body>
</html>

 

 

결과

 

 

 

 

 

 

본 포스팅은 김영한님 인프런 강의내용을 바탕으로 복습을 위해 작성하였습니다. 강의를 통해 배운 개념을 바탕으로 추가적으로 공부한 부분과 간단한 코드 예제를 작성하였습니다. 코드 전체를 복사한 것이 아니라 임의로 수정하거나 생략하였습니다.