package jpabook.jpashop.web;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class BookForm {
private Long id;
private String name;
private int price;
private int stockQuantity;
private String author;
private String isbn;
}
package jpabook.jpashop.web;
import jpabook.jpashop.domain.item.Book;
import jpabook.jpashop.service.ItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
@RequiredArgsConstructor
public class ItemController {
private final ItemService itemService;
@GetMapping(value = "/items/new")
public String createForm(Model model){
model.addAttribute("form", new BookForm());
return "items/createItemForm";
}
@PostMapping(value = "/items/new")
public String create(BookForm form){
Book book = new Book();
book.setName(form.getName());
book.setPrice(form.getPrice());
book.setStockQuantity(form.getStockQuantity());
book.setAuthor(form.getAuthor());
book.setIsbn(form.getIsbn());
itemService.saveItem(book);
return "redirect:/items";
}
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header" />
<body>
<div class="container">
<div th:replace="fragments/bodyHeader :: bodyHeader"/>
<form th:action="@{/items/new}" th:object="${form}" method="post">
<div class="form-group">
<label th:for="name">상품명</label>
<input type="text" th:field="*{name}" class="form-control"
placeholder="이름을 입력하세요">
</div>
<div class="form-group">
<label th:for="price">가격</label>
<input type="number" th:field="*{price}" class="form-control"
placeholder="가격을 입력하세요">
</div>
<div class="form-group">
<label th:for="stockQuantity">수량</label>
<input type="number" th:field="*{stockQuantity}" class="formcontrol" placeholder="수량을 입력하세요">
</div>
<div class="form-group">
<label th:for="author">저자</label>
<input type="text" th:field="*{author}" class="form-control"
placeholder="저자를 입력하세요">
</div>
<div class="form-group">
<label th:for="isbn">ISBN</label>
<input type="text" th:field="*{isbn}" class="form-control"
placeholder="ISBN을 입력하세요">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<br/>
<div th:replace="fragments/footer :: footer" />
</div> <!-- /container -->
</body>
</html>
createForm
에서 빈 폼이라도 넘겨주는 이유
- 상품 등록 폼에서 데이터를 입력하고
submit
버튼을 클릭하면/items/new
를 POST 방식으로 요청- 상품 저장이 끝나면 상품 목록 화면(
redirect:/items
)으로 리다이렉트
...
public class ItemController {
...
/**
* 상품 목록
*/
@GetMapping(value = "items")
public String list(Model model){
List<Item> items = itemService.findItems();
model.addAttribute("items", items);
return "items/itemList";
}
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header" />
<body>
<div class="container">
<div th:replace="fragments/bodyHeader :: bodyHeader"/>
<div>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>상품명</th>
<th>가격</th>
<th>재고수량</th>
<th></th>
</tr>
</thead>
<tbody>
<tr th:each="item : ${items}">
<td th:text="${item.id}"></td>
<td th:text="${item.name}"></td>
<td th:text="${item.price}"></td>
<td th:text="${item.stockQuantity}"></td>
<td>
<a href="#" th:href="@{/items/{id}/edit (id=${item.id})}"
class="btn btn-primary" role="button">수정</a>
</td>
</tr>
</tbody>
</table>
</div>
<div th:replace="fragments/footer :: footer"/>
</div> <!-- /container -->
</body>
</html>
model
에 담아둔 상품 목록인items
를 꺼내서 상품 정보를 출력
...
@Controller
@RequiredArgsConstructor
public class ItemController {
...
/**
* 상품 수정 폼
*/
@GetMapping(value = "/items/{itemId}/edit")
public String updateItemForm(@PathVariable("itemId") Long itemId, Model model){
Book item = (Book) itemService.findOne(itemId);
BookForm form = new BookForm();
form.setId(item.getId());
form.setName(item.getName());
form.setPrice(item.getPrice());
form.setStockQuantity(item.getStockQuantity());
form.setAuthor(item.getAuthor());
form.setIsbn(item.getIsbn());
model.addAttribute("form", form);
return "items/updateItemForm";
}
/**
* 상품 수정
*/
@PostMapping(value = "/items/{itemId}/edit")
public String updateItem(@ModelAttribute("form") BookForm form){
Book book = new Book();
book.setId(form.getId());
book.setName(form.getName());
book.setPrice(form.getPrice());
book.setStockQuantity(form.getStockQuantity());
book.setAuthor(form.getAuthor());
book.setIsbn(form.getIsbn());
itemService.saveItem(book);
return "redirect:/items";
}
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header" />
<body>
<div class="container">
<div th:replace="fragments/bodyHeader :: bodyHeader"/>
<form th:object="${form}" method="post">
<!-- id -->
<input type="hidden" th:field="*{id}" />
<div class="form-group">
<label th:for="name">상품명</label>
<input type="text" th:field="*{name}" class="form-control"
placeholder="이름을 입력하세요" />
</div>
<div class="form-group">
<label th:for="price">가격</label>
<input type="number" th:field="*{price}" class="form-control"
placeholder="가격을 입력하세요" />
</div>
<div class="form-group">
<label th:for="stockQuantity">수량</label>
<input type="number" th:field="*{stockQuantity}" class="form-
control" placeholder="수량을 입력하세요" />
</div>
<div class="form-group">
<label th:for="author">저자</label>
<input type="text" th:field="*{author}" class="form-control"
placeholder="저자를 입력하세요" />
</div>
<div class="form-group">
<label th:for="isbn">ISBN</label>
<input type="text" th:field="*{isbn}" class="form-control"
placeholder="ISBN을 입력하세요" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<div th:replace="fragments/footer :: footer" />
</div> <!-- /container -->
</body>
</html>
/items/{itemId}/edit
URL을 GET 방식으로 요청updateItemForm()
메서드를 실행하는데, 해당 메서드는 temService.findOne(itemId)
를 호출해서 수정할 상품을 조회함items/updateItemForm
)에 전달상품 수정 폼 HTML에는 상품의 id(hidden), 상품명, 가격, 수량 정보가 있음
상품 수정 폼에서 정보를 수정하고 Submit
버튼을 선택
/items/{itemId}/edit
URL을 POST 방식으로 요청하고 updateItem()
메서드를 실행
이때 컨트롤러에 파라미터로 넘어온 item
엔티티 인스턴스는 현재 준영속 상태임
준영속 엔티티는 영속성 엔티티가 관리하지 않는 엔티티를 말함
package jpabook.jpashop.domain.item;
...
@Entity
@DiscriminatorValue("B")
@Getter @Setter
public class Book extends Item {
private String author;
private String isbn;
}
@DiscriminatorValue("B")
어노테이션을 활용하여 구현했기 때문에 Dtype 값으로 B가 자동 저장이 됨