Web/MVC

EP9. PRG (Post/Redirect/Get) 패턴

 

 

 

 

상품등록과 같은 POST 요청을 보내고 나서 Redirect 처리를 안해주면 새로고침 시 POST 요청이 또 나갈 수 있다.

왜냐하면 새로고침은 마지막 요청을 다시 보내기 때문이다.

 

 

 

 

이 문제를 어떻게 해결할까?

 

상품 저장 후에 뷰 템플릿으로 이동하는 것이 아니라, 상품 상세 화면으로 리다이렉트를 호출해주면 된다.

 

    @PostMapping("/add")
    public String addItemV5(Item item) {
        itemRepository.save(item);
        return "redirect:/basic/items/" + item.getId();
    }

 

 

이렇게, POST 요청 후에 RedirectGET 요청을 보내는 것이 PRG 패턴이다.

 

 

 

 

하지만 위 코드에서도 문제가 있다.

URL을 인코딩 하지 않고 사용하는것은 위험할 수 있다.

그래서 RedirectAttributes를 사용해야 한다.

 

 

 

RedirectAttributes

 

코드를 먼저 보겠다.

    @PostMapping("/add")
    public String addItemV6(Item item, RedirectAttributes redirectAttributes) {

        Item savedItem = itemRepository.save(item);
        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);

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

컨트롤러에서 RedirectAttributes redirectAttributes 로 매개변수를 받아온다.

redirectAttributes.addAttribute("itemId", savedItem.getId()); 는 PathVariable을 지정할 수 있고

redirectAttributes.addAttribute("status", true); 이것과 같이 값을 지정하지 않은 것들은 쿼리파라미터로 넘어가게된다. (ex. /basic/items/1?status=true)

추가로 URL 인코딩까지 자동으로 해준다.

 

 

추가 요구사항

상품등록이 성공했으면 "저장되었습니다"라는 메세지를 보여달라는 요구사항이 추가되었다.

 

사실 위에서 status를 true로 쿼리파라미터로 보낸 이유가 있다.

 

RedirectAttributes와 타임리프의 param을 이용해서 해결할 수 있다.

<h2 th:if="${param.status}" th:text="'저장 완료'"></h2>

 

타임리프에서는 RedirectAttributes의 쿼리파라미터를 param으로 그냥 읽어낼 수 있다.

그래서 th:if="${param.status}" 는 th:if=true 와 같고, true 이므로 th:text="'저장 완료'" 가 실행된다.