상품상세 메소드
BasicItemController에 상품상세를 보는 url매핑한 메소드를 만들어준다.
@GetMapping("/{itemId}") //아이템 상세보기
public String item(@PathVariable long itemId, Model model) {
Item item = itemRepository.findById(itemId);
model.addAttribute("item", item);
return "basic/item";
}
상품상세 페이지를 타임리프가 동작하게끔 수정해보자.
<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">
<style>
기본적으로 추가해줄것해주고 테스트해본다.
화면은 나오지만 값에 대한 렌더링이 되지않았으므로 고정된 기본값(value)이 나오는것이다.
타임리프를 통해 value에 렌더링될때 데이터에 대한 값들이 들어가게 수정해보자
<div>
<label for="itemId">상품 ID</label>
<input type="text" id="itemId" name="itemId" class="form-control"
value="1" th:value="${item.id}" readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="form-control"
value="상품A" th:value="${item.itemName}" readonly>
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control"
value="10000" th:value="${item.price}" readonly>
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="form-control"
value="10" th:value="${item.quantity}" readonly>
</div>
이렇게 해주면 된다. 렌더링할때 모델이 item이라는 속성이름에 item객체라는 속성값이 담겨서 넘어올테니까
그 데이터를 이용하는것이다.
확인해보면 상품번호2번에 대한 값으로 잘바뀌어있는것을 확인할 수 있다.
상품수정 버튼 타임리프 적용
<button class="w-100 btn btn-primary btn-lg"
onclick="location.href='editForm.html'"
th:onclick="|location.href='@{/basic/items/{itemId}/edit(itemId=${item.id})}'|"
type="button">상품 수정</button>
Pathvariable을 문법을 이용해서 수정하였다.
th:onclick="|location.href='@{|/basic/items/${itemId}/edit|}'|"
이렇게 사용해도 똑같이 동작한다.! ( 리터럴 대체를 잘사용해야한다. 일반 문자열과 '내용 '을 합치기위해 제일 겉부분에 ||(리터럴대체)문법이 들어갔고 ' '안에 경로가 들어가면서 ${}라는 변수표현식을 사용하기위해 ||가 또한번 사용되었다)
"목록으로" 버튼 타임리프 적용
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='items.html'"
th:onclick="|location.href='@{/basic/items}'|"
type="button">목록으로</button>
</div>
잘동작함을 확인하였다
상품등록폼
@GetMapping("/add") // 상품 등록 폼으로 이동
public String addForm() {
return "basic/addForm";
}
GetMapping을 이용하여 해당 url요청이 왔을때 상품등록폼 화면으로 이동하게끔하는 메소드 추가.
상품등록버튼 타임리프 적용
<form action="item.html" th:action="/basic/item/add" method="post">
<div>
form태그에서 action부분을 추가해주면되는데 "/basic/item/add"로 해주면
서버주소 + "/basic/item/add" 가 되므로 localhost:8080/basic/item/add가 될것이다. (POST방식으로)
그러면 저장을 위한 메소드를 추가해주자.
@PostMapping("/add") // 상품 저장메소드 , 같은 url이지만 Method가 다르므로 구분이 된다.
public String save() {
return "basic/addForm";
}
url은 같지만 HttpMethod가 다르므로 구분되어 동작할것이다.
하지만 현재 GET방식으로 localhost:8080/basic/item/add이란 url를 호출해서 상품등록폼화면에 온것이고
form의 action에서 "/basic/item/add"를 설정하면 결국 같은 url이지만 method만 다른것이니까
form의 action을 다음과 같이 수정할 수 있다.
<form action="item.html" th:action method="post">
뷰가 렌더링될때 th:action으로 치환이 될텐데 아무값도 없으므로 접근한 url그 자체가 될것이다.
취소버튼 타임리프 적용
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='items.html'"
th:onclick="|location.href='@{/basic/items}'|"
type="button">취소</button>
</div>
취소를 누르면 items 템플릿이 동작하도록 하였다.
만약에 /basic/items가 아닌 basic/items라고 입력했을경우
현재 경로 + basic/items인 url를 호출해버린다.
/로 시작해야 서버주소뒤에 붙어서 만든 url를 호출한다.
서버주소 + /basic/items
참고(/reasources/static 안에 들어있는 정적리소스들은 http://localhost:8080/html/items.html와 같이 주소를 입력하면 페이지를 보여주는데 http://localhost:8080/basic/items.html 이런식으로 타임리프가 적용된 html를 열어보려고 하면 화이트라벨 에러페이지를 보여준다. resources 아래 template 폴더안의 파일은 클라이언트가 직접접근 불가능하다.
war를 선택했을때 생성되는 webapp 폴더 아래 web-inf와 같이 보안폴더 개념이다.)
상품등록 처리 -@ModelAttribute
@RequestParam
@ModelAttribute를 사용하기전에
HTML Form은 메시지바디에 쿼리 파라미터형식으로 오므로 @Requestparam을 사용해서 처리하는것도 해보자.
@PostMapping("/add") // 상품 저장메소드 , 같은 url이지만 Method가 다르므로 구분이 된다.
public String save(
@RequestParam String itemName,
@RequestParam int price,
@RequestParam Integer quantity,
Model model) {
Item item = new Item();
item.setItemName(itemName);
item.setPrice(price);
item.setQuantity(quantity);
itemRepository.save(item);
model.addAttribute("item", item);
return "basic/item";
}
@RequestParam을 이용해 파라미터값을 가져오고, Item객체를 생성해서 값을 넣은후 저장하고
모델에 아이템객체를 넣고, 아이템상세화면을 렌더링하면 된다.
잘 동작하는것을 확인할 수 있다.
@ModelAttribute 사용
@PostMapping("/add")
public String addItemV2(@ModelAttribute Item item ,Model model) {
itemRepository.save(item);
model.addAttribute("item", item);
return "basic/item";
}
@ModelAttribute를 이용하여 파라미터로 들어오는 데이터를 객체로 변환할 수 있다.
잘동작하는것을 확인하였음
@ModelAttribute 사용 + 숨겨진기능
@ModelAttribute의 숨겨진기능
@PostMapping("/add")
public String addItemV3(@ModelAttribute("item")Item item ,Model model) {
itemRepository.save(item);
return "basic/item";
}
@ModelAttribute("속성이름")으로 하면 Model객체안에 addAttribute로 데이터를 넣는과정을 없애도된다.
보통 객체는 모델에 담기니까 @ModelAttribute("속성이름")으로 바로 Model담기도록 할 수 있다.
@ModelAttribute("item")Item item
이 명령어 한줄이
model.addAttribute("item", item);
를 대체한다. "item2"로 바꾸면 속성이름도 item2로 들어간다.(하지만 item2로 바꾸면 안된다. -> 뷰템플릿에서 사용하는 데이터명에 맞게 적어줘야한다)
잘동작하는것을 확인하였음
@ModelAttribute 사용 + 이름생략 + Model 생략
@PostMapping("/add")
public String addItemV4(@ModelAttribute Item item) {
itemRepository.save(item);
return "basic/item";
}
@ModelAttribute name 생략 가능
model.addAttribute(item); 자동 추가, 생략 가능
생략시 model에 저장되는 name은 클래스명 첫글자만 소문자로 등록 Item -> item
모델에 데이터를 넣을때 필요한 속성이름이 생략가능하다.
생락하면 클래스명의 맨앞글자만 소문자로 바뀌어서 등록한다.
model.addAttribute("item", item);
이 자동으로 진행된다는것!
@ModelAttribute는 Model에 객체를 자동으로 넣어주기때문에, Model 객체를 파라미터로 받아올 필요가없다.
(@ModelAttribute가 스프링프레임워크에게 모델을 받아서 알아서 데이터를 등록해준다!)
설명에 보면 @ModelAttiribute를 이용하여 모델의 속성에 접근하거나 만약 없다면 객체화 할수 있다고한다.
모델에 접근해서 파라미터를 이용해서 변환시킨 객체를 속성에 추가할수 있다는것같다.
@ModelAttribute 생략
@ModelAttribute도 생략이 가능하다. 대상 객체는 모델에 자동 등록된다
@PostMapping("/add")
public String addItemV5(Item item) {
itemRepository.save(item);
return "basic/item";
}
객체를 item이라는 이름으로 모델에 담겨지게된다
'인프런 > 스프링 MVC 1편' 카테고리의 다른 글
끝)리다이렉트(RedirectAttributes),PRG 패턴(Post/Redirect/Get) (0) | 2023.01.30 |
---|---|
17)상품 도메인 개발,부트스트랩,타임리프 적용 (0) | 2023.01.27 |
16)스프링 MVC(웹페이지 만들기,웹 퍼블리셔,웹 프론트앤드) (0) | 2023.01.27 |
15)HTTP 메시지 컨버터 , RequestMappingHandlerAdapter 구조 (0) | 2023.01.26 |
14)HTTP 응답 문자(v1~v3) JSON(v1~v2) ,@RestController (0) | 2023.01.26 |
댓글