스프링 검색기능 개발

안석우(문과대학 철학)·2024년 2월 20일

스프링

목록 보기
9/15

위와 같이 회원명과 주문상태(Order,Cancel)에 따라 주문을 검색할 수 있는 기능을 개발하려 한다.

  • 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> <div>
        <form th:object="${orderSearch}" class="form-inline">
            <div class="form-group mb-2">
                <input type="text" th:field="*{memberName}" class="form- control" 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(jpabook2.jpashop2.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>
  • Controller 코드
@Controller
@RequiredArgsConstructor
public class OrderController {
    private final OrderService orderService;
    private final MemberService memberService;
    private final ItemService itemService;

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

        return "order/orderList";
    }

    @PostMapping("/orders/{orderId}/cancel")
    public String cancelOrder(@PathVariable("orderId") Long orderId){
        orderService.cancelOrder(orderId);
        return "redirect:/orders";
    }
}
  • OrderSearch
@Getter @Setter
public class OrderSearch {
    private String memberName;
    private OrderStatus orderStatus;
}
  • 화면의 경로는 /orders다.

검색창 부분

<form th:object="${orderSearch}" class="form-inline">
            <div class="form-group mb-2">
                <input type="text" th:field="*{memberName}" class="form- control" 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(jpabook2.jpashop2.domain.OrderStatus).values()}"
                            th:value="${status}"
                            th:text="${status}">option
                    </option>
                </select>
            </div>
            <button type="submit" class="btn btn-primary mb-2">검색</button> </form>

처음에 get요청으로 검색페이지로 이동하면 orders에는 모든 order가 다 담겨서 넘어오고 orderSearch라는 타임리프 커맨드 객체가 함께 넘어온다(th:object="${orderSearch}").
이 때 orderSearch는 memberName과 orderStatus가 모두 null이다.
따라서 모든 order이 보여진다.

이 때, 이름이나 오더의 상태를 선택해서 검색을 누르면

form태그의 action과 method속성이 지정되어있지 않기 때문에 디폴트 옵션인 action은 /orders(페이지에 들어오는 루트가 /orders니깐)로 method는 get으로 http요청이 날아간다. 이 때는 orderSearch 커맨드 객체의 memberName이나 orderStatus가 값이 채워져있고, 이와 일치하는 값들만 orders에 들어와서 화면에 보여진다.

  • 취소
<td>
    <a th:if="${item.status.name() == 'ORDER'}" href="#"
                  th:href="'javascript:cancel('+${item.id}+')'"
                       class="btn btn-danger">CANCEL</a>
</td>

에 의해서 item의 상테가 ORDER이면 취소버튼을 보여준다.

취소버튼을 누르면

function cancel(id) {
        var form = document.createElement("form");
        form.setAttribute("method", "post");
        form.setAttribute("action", "/orders/" + id + "/cancel");
        document.body.appendChild(form);
        form.submit();
    }

함수가 호출되고 cancel함수가 method와 action을 각각 post와 /orders/id/cancel로 바꿔놨기 때문에 form이 제출되면서

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

함수가 호출되어 해당 order가 취소되고, 다시 orders페이지로 리디렉션시켜준다.

0개의 댓글