인프런 커뮤니티 질문&답변

작성자 없음

작성자 정보가 삭제된 글입니다.

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술

상품 상세

@PathVariable 이 어떻게 매칭되는지 모르겠습니다..

작성

·

1K

0


[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오) 네
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 네
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)

[질문 내용]
여기에 질문 내용을 남겨주세요.

<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>
package hello.itemservice.web.basic;


import hello.itemservice.domain.item.Item;
import hello.itemservice.domain.item.ItemRepository;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

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";
    }

    @GetMapping("/{itemId}")
    public String item(@PathVariable Long itemId, Model model) {
        Item item = itemRepository.findById(itemId);
        model.addAttribute("item", item);
        return "basic/item";
    }

    /**
     * 테스트용 데이터 추가
     */
    @PostConstruct
    public void init() {
        itemRepository.save(new Item("itemA", 10000, 10));
        itemRepository.save(new Item("itemB", 20000, 20));
    }
}

 

 

여기서

"@{/basic/items/{itemId}(itemId=${item.id})}"

{itemId} 이 변수명? 키값? 같은게 넘어가서 @RequestMapping("/basic/items") 컨트롤러로 넘어가고 @GetMapping("/{itemId}") 이쪽으로 들어가는거 로이해했는데요

"@{|/basic/items/${item.id}|}"

리터럴 대체는 item.id 이렇게 이름이 넘어가는 거 같은데 여기선 변수명? 같은 매칭될만한게 안보이는데 어떻게 알고 찾아 들어가는건가요?

 

 

 

 

 

 

답변 1

1

안녕하세요. C베로님, 공식 서포터즈 OMG입니다.

image

위 코드가 동작하면, ItemRepository에서 Item 전체를 조회하여 items 페이지로 이동하게 됩니다.

model에 "items",로 조회 아이템이 담기고 있죠?

여기서 데이터는

[1번-사과, 2번-과자, 3번-음료] 를 불러왔다고 가장하겠습니다.

(자바 코드로 설명 드리면

items.get(0) = [1L, "사과"] ==> item.get(0).getId() = 1L, item.get(0).getItemName() = "사과"

items.get(1) = [2L, "과자"]

items.get(2) = [3L, "음료"]

)

 

그리고 items.html 페이지에선 아래와 같은 코드가 실행됩니다.

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

(2) <td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>

(3) <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>

여기서 (1)을 보시면 items를 각각 하나씩 순회하기 위해 item이라는 이름으로 지정합니다.

그리고 순차적으로 돌면서 (2), (3)에 값이 세팅이 됩니다.

(2)에는 1이라는 값이 <a> 태그가 적용되어 링크가 세팅되고 링크는 basic/items/{itemId}인데 itemId는 Item의 id로 세팅되는 타임리프 문법을 사용하여 Item.id(1L)가 세팅됩니다.

 

질문 남기신 내용 (3)의 경우에도 동일합니다.

링크는 해당 아이템의 id가 세팅되며,

<td><a href="item.html" th:href="@{|/basic/items/${item.id}|}"

 

<td> 상품명 </td> 사이에는 item.itemName인 사과가 들어가게 됩니다.

th:text="${item.itemName}">상품명</a></td>

이후 다음 아이템인 [2L, "과자"]를 순회하는 동작이 진행됩니다.

 


감사합니다.

답변 정말 감사합니다.

2번 이나 3번을 누르면 다시 /basic/items 로 맵핑된 컨트롤러로 넘어가자나요?

이후 {itemId} 로 매칭되어

@GetMapping("/{itemId}")

public String item(@PathVariable Long itemId, Model model) {

Item item = itemRepository.findById(itemId);

model.addAttribute("item", item);

return "basic/item";

}

이 메소드로 들어가는게 아닌가요? 2번은 {itemId} 이거로 찾아 매칭되는건줄알았는데

${item.id} 가 들어가는거라면

바로위의 메소드는 무엇을 보고 찾아들어가는건가요? 어떤원리로 찾아들어가는건가요?

thml 에서 컨트롤러 안 메소드로 들어가는 원리가 이해가 안되네요

 

 

 

 

 

 

itemId는 Item의 id로 세팅되는 타임리프 문법 이라는 말씀에 힌트를 얻어

이름이 넘어가는게 아니라면 어떻게 매칭되는걸까 계속계속 생각해보다

{} 이안에 이름을보고 매칭이 되는게 아니라 단순히 /{} 만을 보고 매칭되는게 아닐까 라는 생각에 /{itemId} 를 /{sample} 로 바꿔보았더니 작동하는것을확인하였고 이어서

/{itemId} 과 /{sample} 로 맵핑된 두 메소드를 만들어 테스트 해보니 에러가 뜨는것을 확인하였습니다.

이게 제대로 이해한게 맞는지 모르겠지만 /{} 의 형태를 보고 매칭 시키는것 같다는 결론에 도달했습니다.

늦은밤까지

도움 정말 감사합니다!^^

 

 

 

 

 

${item.id} 는 결국 Long타입의 정수형이니까 Long타입의 정수를 @PathVariable로 받는 item() 메서드뿐이니까 그렇게 들어가는거 아닐까요 ?

작성자 없음

작성자 정보가 삭제된 글입니다.

질문하기