프로그래밍/spring boot

[스프링부트] 실전! 스프링 부트와 JPA 활용1 #7 웹 계층 개발(5)

aSpring 2023. 11. 13. 09:45
728x90
728x90
※ 본 포스팅은 김영한 강사님의 인프런 '실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발' 강의를 들으며 작성한 수강일지 입니다.

 

 

 

| 웹 계층 개발

1. 홈 화면과 레이아웃
2. 회원 등록
3. 회원 목록 조회
4. 상품 등록
5. 상품 목록
6. 상품 수정
7. 변경 감지와 병합(merge)
8. 상품 주문
9. 주문 목록으로 검색, 취소
10. 다음으로

 


8. 상품 주문

OrderController

package jpabook.jpashop.controller;

import jpabook.jpashop.domain.Member;
import jpabook.jpashop.domain.item.Item;
import jpabook.jpashop.service.ItemService;
import jpabook.jpashop.service.MemberService;
import jpabook.jpashop.service.OrderService;
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;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Controller
@RequiredArgsConstructor
public class OrderController {

    private final OrderService orderService;
    private final MemberService memberService;
    private final ItemService itemService;

    @GetMapping("/order")
    public String createForm(Model model) {

        List<Member> members = memberService.findMembers(); // 모든 멤버 가져옴
        List<Item> items = itemService.findItems(); // 모든 아이템들 가져와서

        // model에 담아서 orderForm에 넘김
        model.addAttribute("members", members);
        model.addAttribute("items", items);

        return "order/orderForm";
    }

    @PostMapping("/order")
    public String order(@RequestParam("memberId") Long memberId,
                        @RequestParam("itemId") Long itemId,
                        @RequestParam("count") int count) {

        orderService.order(memberId, itemId, count);
        return "redirect:/orders";
    }
}

 

주문 폼 이동

  • 메인 화면에서 상품 주문을 선택하면 /order 를 GET 방식으로 호출
  • OrderController 의 createForm() 메서드
  • 주문 화면에는 주문할 고객정보와 상품 정보가 필요하므로 model 객체에 담아서 뷰에 넘겨줌

 

주문 실행

  • 주문할 회원과 상품 그리고 수량을 선택해서 Submit 버튼을 누르면 /order URL을 POST 방식으로 호출
  • 컨트롤러의 order() 메서드를 실행
  • 이 메서드는 고객 식별자( memberId ), 주문할 상품 식별자( itemId ), 수량( count ) 정보를 받아서 주문 서 비스에 주문을 요청
  • 주문이 끝나면 상품 주문 내역이 있는 /orders URL로 리다이렉트

 

order/orderForm

<!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 role="form" action="/order" method="post">
    <div class="form-group">
      <label for="member">주문회원</label>
      <select name="memberId" id="member" class="form-control">
        <option value="">회원선택</option>
        <option th:each="member : ${members}"
                th:value="${member.id}"
                th:text="${member.name}" />
      </select>
    </div>
    <div class="form-group">
      <label for="item">상품명</label>
      <select name="itemId" id="item" class="form-control">
        <option value="">상품선택</option>
        <option th:each="item : ${items}"
                th:value="${item.id}"
                th:text="${item.name}" />
      </select>
    </div>
    <div class="form-group">
      <label for="count">주문수량</label>
      <input type="number" name="count" class="form-control" id="count"
             placeholder="주문 수량을 입력하세요">
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
  </form>
  <br/>
  <div th:replace="fragments/footer :: footer" />
</div> <!-- /container -->
</body>
</html>

 


9. 주문 목록으로 검색, 취소

 

OrderController

@GetMapping("/orders")
public String orderList(@ModelAttribute("orderSearch") OrderSearch orderSearch, Model model) {
    List<Order> orders = orderService.findOrders(orderSearch);
    model.addAttribute("orders", orders);

    return "order/orderList";
}

 

OrderService

 public List<Order> findOrders(OrderSearch orderSearch) {
    return orderRepository.findAllByString(orderSearch);
}

 

 

order/orderList

<!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>
    <div>
      <form th:object="${orderSearch}" class="form-inline">
        <div class="form-group mb-2">
          <input type="text" th:field="*{memberName}" class="formcontrol" placeholder="회원명"/>
        </div>
        <div class="form-group mx-sm-1 mb-2">
          <select th:field="*{orderStatus}" class="form-control">
            <option value="">주문상태</option>
            <option th:each=
                            "status : ${T(jpabook.jpashop.domain.OrderStatus).values()}"
                    th:value="${status}"
                    th:text="${status}">option
            </option>
          </select>
        </div>
        <button type="submit" class="btn btn-primary mb-2">검색</button>
      </form>
    </div>
    <table class="table table-striped">
      <thead>
      <tr>
        <th>#</th>
        <th>회원명</th>
        <th>대표상품 이름</th>
        <th>대표상품 주문가격</th>
        <th>대표상품 주문수량</th>
        <th>상태</th>
        <th>일시</th>
        <th></th>
      </tr>
      </thead>
      <tbody>
      <tr th:each="item : ${orders}">
        <td th:text="${item.id}"></td>
        <td th:text="${item.member.name}"></td>
        <td th:text="${item.orderItems[0].item.name}"></td>
        <td th:text="${item.orderItems[0].orderPrice}"></td>
        <td th:text="${item.orderItems[0].count}"></td>
        <td th:text="${item.status}"></td>
        <td th:text="${item.orderDate}"></td>
        <td>
          <a th:if="${item.status.name() == 'ORDER'}" href="#"
             th:href="'javascript:cancel('+${item.id}+')'"
             class="btn btn-danger">CANCEL</a>
        </td>
      </tr>
      </tbody>
    </table>
  </div>
  <div th:replace="fragments/footer :: footer"/>
</div> <!-- /container -->
</body>
<script>
  function cancel(id) {
    var form = document.createElement("form");
    form.setAttribute("method", "post");
    form.setAttribute("action", "/orders/" + id + "/cancel");
    document.body.appendChild(form);
    form.submit();
  }
</script>
</html>

 

 

 

주문 취소

OrderController.java

@PostMapping("/orders/{orderId}/cancel")
public String cancelOrder(@PathVariable("orderId") Long orderId) {
    orderService.cancelOrder(orderId);
    return "redirect:/orders";
}

- 주문 시 재고 수량 감소, 주문 취소 시 다시 그만큼 재고 수량 증가하는 것까지 확인해보고, 검색도 해보기!


10. 다음으로

- API 만들 것 : 과거에는 화면 만드는 정도로 끝나는 경우가 많았지만 요즘에는 SPA, react, vuejs... API로 통신해야 하는 경우가 많고 app과 교신, 사내 시스템들끼리 api로 통신해야 하는 경우가 많아서 JPA를 가지고 어떻게 api잘 설계하고 만들어내는지와 이걸로 CRUD하는 것들, 성능 최적화 부분들을 설명할 예정

728x90
728x90