본문 바로가기

spring

PRG Post/Redirect/Get

사실 지금까지 진행한 상품 등록 처리 컨트롤러는 심각한 문제가 있다.

상품 등록한 컨트롤러를 보게 되면

@PostMapping("/add")
public String addSaveV4(Item item){
    itemRepository.save(item);
    return "basic/item";
}

폼에서 Item 객체타입으로 값들이 전달되서 저장되고 ModelAttribute는 안보이지만 model에 담겨 뷰템플릿으로 가는 코드이다. 단순히 한번의 등록으로 끝난다면 문제는 없지만 등록한 페이지에서 새로고침을 하게 되면 문제가 생긴다.

이유는 저장한 뒤 사이트의 주소를 보게 되면 여전히 add에 머물러있게 되고 새로고침을 하게 되면 등록한 주소와 내용 값들이 다시 호출이 되어 새로고침을 누를 때마다 상품이 등록되기 때문이다.

출처 : 김영한 MVC 1편

새로고침이란 마지막에 서버에 전송한 요청을 다시 실행하는 것이므로, post 방식의 상품 등록이 계속 요청되는 것이다.

그렇기 때문에 Redirect를 사용하면 된다.

출처 : 김영한 MVC 1편

post 방식의 상품등록이 되면 return으로 redirect 등록한 상품의 상세보기 페이지로 이동하게 되면 요청한 매핑의 마지막 값으로 상품 상세보기 페이지가 되면서 새로고침을 해도 중복되는 상품등록이 되지 않는 것이다.

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

※ 주의

> "redirect:/basic/items/" + item.getId() redirect에서 +item.getId() 처럼 URL에 변수를 더해서 사용하는 것은 URL 인코딩이 안되기 때문에 위험하다. 그러므로 RedirectAttributes 를 사용하자.

 

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}";
}

같은 상품저장 POST매핑의 모습이지만 RedirectAttributes라는게 추가 되었다.

RedirectAttributes로 저장된 값은 return에 redirect의 변수로 사용이 가능하고, 사용되지 않은 등록된 값은 쿼리파라미터로 매핑주소에 추가되어 이동하게 된다.

리다이렉트 할 때 간단히 status=true 를 추가해보자. 그리고 뷰 템플릿에서 이 값이 있으면, 저장되었습니다. 라는 메시지를 출력해보자.

http://localhost:8080/basic/items/3?status=true

redirect:/basic/items/{itemId}

> pathVariable 바인딩: {itemId}

> 나머지는 쿼리 파라미터로 처리: ?status=true

 

resources/templates/basic/item.html

간단하게 param으로 status의 값이 잇다면 간단한 문구가 보이게 추가해보자.

<div class="container">
<div class="py-5 text-center">
<h2>상품 상세</h2>
</div>
<!-- 추가 -->
<h2 th:if="${param.status}" th:text="'저장 완료!'"></h2>

맨 아래에 th:if를 통해 param의 status의 값을 확인하고 문구가 보이게 만들어봤다.

th:if : 해당 조건이 참이면 실행

> ${param.status} : 타임리프에서 쿼리 파라미터를 편리하게 조회하는 기능

 

뷰 템플릿에 메시지를 추가하고 실행해보면 "저장 완료!" 라는 메시지가 나오는 것을 확인할 수 있다. 물론 상품 목록에서 상품 상세로 이동한 경우에는 해당 메시지가 출력되지 않는다.

'spring' 카테고리의 다른 글

타임리프 - 기본 기능 (2)  (0) 2023.04.10
타임리프 - 기본 기능 (1)  (0) 2023.04.10
간단한 사이트 만들기  (0) 2023.04.05
요청 매핑 헨들러 어뎁터 구조  (0) 2023.04.04
HTTP 메시지 컨버터  (0) 2023.04.04