백엔드/Spring

[Spring] 상품 상세, 등록폼, 등록 처리, 상품 수정

happy_life 2022. 7. 28. 15:09

목차

1. 상품 상세

2. 상품 등록 폼

3. 상품 등록 처리(PRG)

4. 상품 수정 폼

5. 상품 수정

 

 

 

도메인

Item.class

package spring.mvc.web.domain;

import lombok.Data;

@Data
public class Item {
    private long id;
    private String itemName;
    private Integer price;
    private Integer quantity;

    public Item() {

    }

    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    }
}

Book.class

package spring.mvc.web.domain;

import lombok.Data;

@Data
public class Book extends Item {
    public String dataType;

    public Book(String itemName, Integer price, Integer quantity, String dataType) {
        super(itemName, price, quantity);
        this.dataType = dataType;
    }

}

 

 

상품 상세

 

상품 상세페이지 만들기

 

과정) 상품 클릭시 basic/items/{item.id}로 이동 ->  핸들러가 모델에 데이터를 담고 basic/item으로 뷰 이동

 

basic/items.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link th:href="@{/css/bootstrap.css}"
          href="../css/bootstrap.css" rel="stylesheet">
</head>
<body>

<div class="container" style="max-width: 600px">
    <div class="py-3 bg-primary text-center text-white">
        <h2>Steady Kim Shop</h2>
    </div>
    <div class="py-2 text-center">
        <h3>상품 목록</h3>
    </div>
    <div class="row">
        <div class="col">
            <button class="btn btn-secondary float-end"
                    onclick="location.href='addForm.html'"
                    th:onclick="|location.href='@{/basic/items/add}'|"
                    type="button">상품
                등록</button>
        </div>
    </div>
    <hr class="my-4">
    <div>
        <table class="table">
            <thead>
            <tr>
                <th>ID</th>
                <th>상품명</th>
                <th>품목</th>
                <th>가격</th>
                <th>수량</th>
            </tr>
            </thead>
            <tbody>
            <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.dataType}">아이템 종류</a></td>
                <td th:text="${item.price}">10000</td>
                <td th:text="${item.quantity}">10</td>
            </tr>

            </tbody>
        </table>
    </div>
</div> <!-- /container -->
</body>
</html>

 

1. 클릭시 basic/items/{item.id}로 이동하기 위해 th:href를 사용하였다.

한편, th:text를 통해 모델로 받은 item객체의 값들을 활용해 매핑해고 있다.

<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>

 

2. 클릭하면 basic/items/{item.id}로 url 요청이 가는데 이를 핸들링 하기 위해 아래의 컨트롤러가 존재한다. model에 데이터를 담는다.

    @GetMapping("{itemId}")
    public String item(@PathVariable long itemId, Model model) {
        Item foundItem = itemRepository.findById(itemId);
        model.addAttribute("item", foundItem);

        return "basic/item";
    }

1. @PathVariable을 통해 {itemId}를 받는다.

2. 받은 itemId를 키로 foundItem을 찾는다.

3. model에 담아 basic/item으로 뷰 dispatch한다.

 

 

 

basic/item.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link th:href="@{/css/bootstrap.css}"
          href="../css/bootstrap.css" rel="stylesheet">
</head>
<body>
<!--상부 컨테이너-->
<div class="container" style="max-width: 600px">
    <div class="py-3 bg-primary text-center text-white">
        <h2>Steady Kim Shop</h2>
    </div>

    <div class="py-2 text-center">
        <h3>상품 상세 </h3>
    </div>
    <!-- 상품 상세 내용-->
    <div class="text-center" >
        <label class="bg-secondary text-white" for="itemId" style="width: 300px">상품 ID</label>
        <p id="itemId" name="itemId" th:text="${item.id}">1</p>

        <label class="bg-secondary text-white" for="itemName" style="width: 300px">상품 이름</label>
        <p id="itemName" name="itemName" th:text="${item.itemName}">itemName</p>

        <label class="bg-secondary text-white" for="dataType" style="width: 300px">품목</label>
        <p id="dataType" name="dataType" th:text="${item.dataType}">품목</p>

        <label class="bg-secondary text-white" for="itemPrice" style="width: 300px">가격</label>
        <p id="itemPrice" name="itemPrice" th:text="${item.price}">1</p>

        <label class="bg-secondary text-white" for="itemQuantity" style="width: 300px">수량</label>
        <p id="itemQuantity" name="itemQuantity" th:text="${item.quantity}">수량</p>
    </div>
    <hr class="my-4">
    <div class="row">
        <div class="col text-center">
            <button class="w-50 btn btn-primary btn-lg"
                    th:onclick="|location.href='@{/basic/items/{itemId}/edit(itemId=${item.id})}'|"
                    type="button">상품 수정</button>
        </div>
        <div class="col">
            <button class="w-50 btn btn-secondary btn-lg"
                    th:onclick="|location.href='@{/basic/items}'|"
                    type="button">목록으로</button>
        </div>
    </div>
</div> <!--/container -->
</body>
</html>

1. item의 속성들이 동적으로 mapping된다.

 

상품 등록 폼

 

상품등록폼

 

과정) 상품 등록 클릭시 basic/items/add 이동 -> 컨트롤러가 addForm.html로 뷰 이동

 

1. 상품 등록 클릭시 basic/items/add 로 가도록 설계한다.

<button class="btn btn-secondary float-end"
            onclick="location.href='addForm.html'"
            th:onclick="|location.href='@{/basic/items/add}'|"
            type="button">상품 등록</button>

 

2. 해당 url을 받는 컨트롤러를 생성한다. basic/addForm으로 이동한다.

@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {

    @GetMapping("/add")
    public String addForm() {
        return "basic/addForm";
 }
}

 

basic/addForm.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link th:href="@{/css/bootstrap.css}"
          href="../css/bootstrap.css" rel="stylesheet">
</head>
<body>
<!--상부 컨테이너-->
<div class="container" style="max-width: 600px">
    <div class="py-3 bg-primary text-center text-white">
        <h2>Steady Kim Shop</h2>
    </div>

    <div class="py-2 text-center">
        <h3>상품 등록 </h3>
    </div>

    <!-- 상품 상세 내용-->
    <div class="text-center">
        <h5 class="mb-3">상품 입력</h5>
        <form th:action method="post">
            <div class="my-3">
                <label form="itemName">상품명</label>
                <input type="text" id="itemName" name="itemName" placeholder="이름을 입력하세요">
            </div>
            <div class="my-3">
                <label form="price">가격</label>
                <input type="text" id="price" name="price" placeholder="가격을 입력하세요">
            </div>
            <div class="my-3">
                <label form="quantity">수량</label>
                <input type="text" id="quantity" name="quantity" placeholder="수량을 입력하세요">
            </div>

            <hr class="my-4">
            <div class="row">
                <div class="col text-center">
                    <button class="w-50 btn btn-primary btn-lg"
                            th:onclick="|location.href='@{/basic/items/add)}'|"
                            type="submit">상품 등록</button>
                </div>
                <div class="col text-center">
                    <button class="w-50 btn btn-secondary btn-lg"
                            th:onclick="|location.href='@{/basic/items}'|"
                            type="button">취소</button>
                </div>
            </div>
        </form>
    </div>
</div> <!--/container -->
</body>
</html>

 

 

 

 

상품 등록 처리

 

상품 등록

 

과정) 상품 등록 클릭 같은 url로 post요청 -> 같은 Url을 Post Controller가 핸들링 -> 상품 상세페이지로 redirect 이동

 

 

 

1) 상품 등록 form이 있는 addForm.html의 일부 발췌

<form th:action method="post">
    <div class="my-3">
        <label form="itemName">상품명</label>
        <input type="text" id="itemName" name="itemName" placeholder="이름을 입력하세요">
    </div>
    <div class="my-3">
        <label form="price">가격</label>
        <input type="text" id="price" name="price" placeholder="가격을 입력하세요">
    </div>
    <div class="my-3">
        <label form="quantity">수량</label>
        <input type="text" id="quantity" name="quantity" placeholder="수량을 입력하세요">
    </div>

    <hr class="my-4">
    <div class="row">
        <div class="col text-center">
            <button class="w-50 btn btn-primary btn-lg"
                    th:onclick="|location.href='@{/basic/items/add)}'|"
                    type="submit">상품 등록</button>
        </div>
        <div class="col text-center">
            <button class="w-50 btn btn-secondary btn-lg"
                    th:onclick="|location.href='@{/basic/items}'|"
                    type="button">취소</button>
        </div>
    </div>
</form>

 

 

basic/addForm.html 에 상품 등록 관련 코드 

<form th:action method="post">

같은 url에 POST요청을 보낸다.

 

 

2)  RequestParam 사용한 POST Controller

    @PostMapping("/add")
    public String addItem(@RequestParam("itemName") String itemName,
                          @RequestParam("price") Integer itemPrice,
                          @RequestParam("quantity") Integer itemQuantity,
                          RedirectAttributes redirectAttributes) {

        Book book = new Book(itemName, itemPrice, itemQuantity, ItemName.BOOK);
        Item savedItem = itemRepository.save(book);

        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);

        return "redirect:/basic/items/{itemId}";
    }

 

1. post에 받은 데이터를 @RequestParam을 통해 받는다.

2. basic/items/{itemId}로 redirect한다.

 

한편 ModelAttribute도 가능한데, 특징은 아래와 같다.

 

클래스 이름에서 앞글자 대문자를 소문자로 한다. Item -> item

 

@ModelAttribute는 요청 파라미터를 처리하기도 하고, Model에 자동으로 객체를 추가하는 처리도 한다.

 

 

 

상품 수정 폼

 

상품수정폼

 

과정) 상품 수정 클릭시 ->basic/items/{itemId}/edit으로 이동 -> Controller가 basic/editForm 뿌려줌

 

 

 1) basic/item.html의 일부분

    <div class="row">
        <div class="col text-center">
            <button class="w-50 btn btn-primary btn-lg"
                    th:onclick="|location.href='@{/basic/items/{itemId}/edit(itemId=${item.id})}'|"
                    type="button">상품 수정</button>
        </div>
        <div class="col text-center" >
            <button class="w-50 btn btn-secondary btn-lg"
                    th:onclick="|location.href='@{/basic/items}'|"
                    type="button">목록으로</button>
        </div>
    </div>

1. 기존에 item.html로 뷰 이동을 할 때 item 객체의 정보를 가지고 있었으므로, 수정에서도 그 정보인 itemId를 활용한다.

 

 

2) 상품 수정 폼 이동 Controller

    @GetMapping("/{itemId}/edit")
    public String editForm(@PathVariable("itemId") long id, Model model) {
        Item foundItem = itemRepository.findById(id);

        model.addAttribute("item", foundItem);
        return "basic/editForm";
    }

 

 

3) editForm.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link th:href="@{/css/bootstrap.css}"
          href="../css/bootstrap.css" rel="stylesheet">
</head>
<body>
<!--상부 컨테이너-->
<div class="container" style="max-width: 600px">
    <div class="py-3 bg-primary text-center text-white">
        <h2>Steady Kim Shop</h2>
    </div>

    <div class="py-2 text-center">
        <h3>상품 수정 </h3>
    </div>

    <!-- 상품 상세 내용-->
    <div class="text-center">
        <h5 class="mb-3">상품 입력</h5>
        <form th:action method="post">
            <div class="my-3">
                <label form="id">상품ID</label>
                <input style="color: #9e9e9e" type="text" id="id" name="id" th:value="${item.id}" readonly>
            </div>

            <div class="my-3">
                <label form="itemName">상품명</label>
                <input type="text" id="itemName" name="itemName" th:value="${item.itemName}">
            </div>
            <div class="my-3">
                <label form="price">가격</label>
                <input type="text" id="price" name="price" th:value="${item.price}">
            </div>
            <div class="my-3">
                <label form="quantity">수량</label>
                <input type="text" id="quantity" name="quantity" th:value="${item.quantity}">
            </div>

            <hr class="my-4">
            <div class="row">
                <div class="col text-center">
                    <button class="w-50 btn btn-primary btn-lg" type="submit">저장</button>
                </div>
                <div class="col text-center">
                    <button class="w-50 btn btn-secondary btn-lg"
                            th:onclick="|location.href='@{/basic/items/{itemId}(itemId=${item.id})}'|"
                            type="button">목록으로</button>
                </div>
            </div>
        </form>
    </div>
</div><!--/상부 컨테이너-->
</body>
</html>

1. 상품 수정폼으로 이동시 th:value를 활용하여 넘어온 데이터의 속성들을 매핑해준다.

 

 

상품 수정 

 

상품 수정

 

과정) 저장버튼 누르면 -> Post로 같은 url에 데이터를 넘긴다. -> Post Controller가 받아서 수정 로직을 실행하고, basic/items/{itemId}로 redirect 이동한다.

 

 

1) 저장버튼

<form action="item.html" th:action method="post">
<button class="w-100 btn btn-primary btn-lg" type="submit">저장</button>
</form>

1저장버튼 누르면 -> Post로 같은 url에 item 객체 데이터를 넘긴다. 

 

 

2) PostController

@PostMapping("/{itemId}/edit")
public String edit(@PathVariable("itemId") long itemId,
                   @RequestParam("itemName") String itemName,
                   @RequestParam("price") Integer itemPrice,
                   @RequestParam("quantity") Integer itemQuantity,
                   Model model) {


    Book book = new Book(itemName, itemPrice, itemQuantity, ItemName.BOOK);

    itemRepository.update(itemId, book);

    return "redirect:/basic/items/{itemId}";
}

1. Post Controller가 받아서 수정 로직을 실행하고, basic/items/{itemId}로 redirect 이동한다.

 

 

 

 

 

본 포스팅은 김영한님 인프런 강의내용을 바탕으로 복습을 위해 작성하였습니다. 강의를 통해 배운 개념을 바탕으로 추가적으로 공부한 부분과 간단한 코드 예제를 작성하였습니다. 코드 전체를 복사한 것이 아니라 임의로 수정하거나 생략하였습니다.