공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.
이번 포스팅에서는 JPA를 활용한 웹 계층 개발 중 회원 목록 조회, 상품 등록, 상품 수정 기능을 다루어 본다. 각 기능별로 컨트롤러와 HTML 코드를 살펴보며, 주요한 부분들을 설명한다.
회원 목록 조회
memberController 수정
회원 목록 조회는 MemberController에서 회원 목록을 가져와 이를 화면에 출력하는 과정이다. memberService를 통해 데이터베이스에서 회원 목록을 조회하고, 조회된 데이터를 모델에 담아 뷰로 전달한다. 뷰에서는 Thymeleaf를 사용해 테이블 형태로 회원 정보를 출력한다.
@GetMapping("/members")
public String list(Model model) {
List<Member> members = memberService.findMembers();
model.addAttribute("members", members);
return "members/memberList";
}
- @GetMapping("/members")으로 회원 목록을 조회하는 요청을 처리하며, memberService.findMembers()로 회원 리스트를 가져와 모델에 담아 반환한다.
memberList.html 추가
<!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="member : ${members}">
<td th:text="${member.id}"></td>
<td th:text="${member.name}"></td>
<td th:text="${member.address?.city}"></td>
<td th:text="${member.address?.street}"></td>
<td th:text="${member.address?.zipcode}"></td>
</tr>
</tbody>
</table>
</div>
<div th:replace="fragments/footer :: footer" />
</div> <!-- /container -->
</body>
</html>
- Thymeleaf의 th:each를 사용해 회원 데이터를 반복 출력하며, 각 회원의 이름, 도시, 주소 등을 테이블로 보여준다.
상품 등록
상품 등록 기능은 사용자가 폼을 통해 입력한 상품 정보를 BookForm 객체로 받아, 이를 데이터베이스에 저장하는 과정이다. 상품 등록 페이지에서 입력한 정보를 ItemController에서 처리하고, Book 엔티티로 변환한 뒤 저장하는 흐름으로 구현된다.
BookForm 추가
package jpabook.jpashop.controller;
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;
}
- BookForm은 상품 등록 폼에서 입력받은 데이터를 담는 DTO(Data Transfer Object) 역할을 한다. 이 객체는 상품 등록 및 수정을 위한 필드(이름, 가격, 재고 수량, 저자, ISBN)를 가지고 있어 사용자 입력을 쉽게 관리할 수 있다.
ItemController 추가
package jpabook.jpashop.controller;
import jpabook.jpashop.domain.item.Book;
import jpabook.jpashop.domain.item.Item;
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.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class ItemController {
private final ItemService itemService;
@GetMapping("/items/new")
public String createFrom(Model model) {
model.addAttribute("form", new BookForm());
return "items/createItemForm";
}
@PostMapping("/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";
}
}
- @GetMapping("/items/new)로 상품 등록 페이지를 표시하며, 빈 BookForm객체를 모델에 담아 전달한다.
- 이후@PostMapping("/items/new)에서는 폼에서 전달된 데이터를 Book엔티티로 변환하여 itemService.saveItem(book)`을 통해 데이터베이스에 저장한다.
createitemForm.html 추가
<!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="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>
<br/>
<div th:replace="fragments/footer :: footer"/>
</div> <!-- /container -->
</body>
</html>
- 사용자가 상품명, 가격, 수량, 저자, ISBN 정보를 입력할 수 있도록 폼을 구성하며, 입력된 데이터를 서버로 전송한다.
상품 목록
상품 목록 조회는 등록된 모든 상품을 화면에 표시하는 기능이다. ItemController에서 상품 리스트를 가져와 뷰에 전달하고, HTML 템플릿에서는 테이블 형식으로 상품을 출력한다.
itemController 수정
package jpabook.jpashop.web;
@Controller
@RequiredArgsConstructor
public class ItemController {
private final ItemService itemService;
/**
* 상품 목록
*/
@GetMapping(value = "/items")
public String list(Model model) {
List<Item> items = itemService.findItems();
model.addAttribute("items", items);
return "items/itemList";
}
}
- @GetMapping("/items")을 통해 상품 목록 페이지를 요청받고, itemService.findItems()를 호출해 모든 상품 리스트를 가져온다.
- 이 데이터를 model에 담아 뷰로 전달하여 목록을 화면에 출력한다.
itemList.html 추가
<!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>
- Thymeleaf의 th:each를 사용해 상품 리스트를 테이블로 출력하며, 상품명, 가격, 재고 수량 등을 사용자에게 보여준다.
- 각 상품 옆에는 수정 버튼을 제공하여, 상품 수정 페이지로 이동할 수 있도록 한다.
상품 수정
상품 수정 기능은 기존에 등록된 상품의 정보를 수정하는 기능이다. 사용자는 상품 수정 폼에서 수정할 정보를 입력하고, 수정된 데이터를 서버에 제출하면, 해당 상품의 정보가 업데이트된다.
ItemController 수정
package jpabook.jpashop.web;
import jpabook.jpashop.domain.item.Book;
import jpabook.jpashop.domain.item.Item;
import jpabook.jpashop.service.ItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class ItemController {
/**
* 상품 수정 폼
*/
@GetMapping("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("items/{itemId}/edit")
public String updateItem(@PathVariable("itemId") String itemId, @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";
}
}
- 사용자가 수정 버튼을 클릭하면 /items/{itemId}/edit URL로 GET 요청이 발생하고, updateItemForm() 메서드가 실행되어 수정할 상품 정보를 조회한 후 수정 폼에 전달한다.
- 수정된 내용을 입력하고 Submit 버튼을 누르면 /items/{itemId}/edit로 POST 요청이 보내진다.
- 이때 전달된 상품은 준영속 상태이므로, 변경 감지가 동작하지 않아 직접 새로운 Book 객체를 생성하여 수정된 데이터를 저장한다.
- 수정이 완료되면 상품 목록으로 리다이렉트된다.
updateItemFrom.html 추가
<!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}" th:action="@{/items/{itemId}/edit(itemId=${form.id})}" 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>
- 상품 수정 폼에서는 기존 상품 정보가 미리 입력된 상태로 제공되며, 사용자가 정보를 수정한 후 제출하면 수정된 데이터를 서버로 전송한다.
'BackEnd > JPA' 카테고리의 다른 글
[JPA] 웹 계층 개발(4) (0) | 2024.10.05 |
---|---|
[JPA] 웹 계층 개발(3) (0) | 2024.10.05 |
[JPA] 웹 계층 개발(1) (2) | 2024.10.04 |
[JPA] 주문 도메인 개발 (3) | 2024.10.03 |
[JPA] 상품 도메인 개발 (0) | 2024.10.03 |