작성자 없음
작성자 정보가 삭제된 글입니다.
작성
·
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
위 코드가 동작하면, 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, "과자"]를 순회하는 동작이 진행됩니다.
감사합니다.
itemId는 Item의 id로 세팅되는 타임리프 문법 이라는 말씀에 힌트를 얻어
이름이 넘어가는게 아니라면 어떻게 매칭되는걸까 계속계속 생각해보다
{} 이안에 이름을보고 매칭이 되는게 아니라 단순히 /{} 만을 보고 매칭되는게 아닐까 라는 생각에 /{itemId} 를 /{sample} 로 바꿔보았더니 작동하는것을확인하였고 이어서
/{itemId} 과 /{sample} 로 맵핑된 두 메소드를 만들어 테스트 해보니 에러가 뜨는것을 확인하였습니다.
이게 제대로 이해한게 맞는지 모르겠지만 /{} 의 형태를 보고 매칭 시키는것 같다는 결론에 도달했습니다.
늦은밤까지
도움 정말 감사합니다!^^
답변 정말 감사합니다.
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 에서 컨트롤러 안 메소드로 들어가는 원리가 이해가 안되네요