상품등록 후 새로고침하면 중복등록이 되는 문제가 발생

 

 

[실제 상품을 등록한 뷰 화면]

 

위처럼 상품 등록한 상태에서 새로고침을 누른다면 상품ID는 계속 올라가고 상품이 계속 등록되는 이슈가 생긴다.

 

 

 

[상품등록 POST - BasicItemController ]

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

 

  • 전체 흐름
    • 실제 상품등록
    • 상품 상세 뷰로 뷰템플릿(basic/item)을 호출 - 끝
    • 상품 등록 (POST / add) URL 이 유지되어있는 상태
    • 새로고침하면 계속 POST / add 행위가 지속된다.
    • 새로고침 시 마지막 행위가 다시 요청되기 때문에 상품이 중복저장이 되는 이슈가 발생한다. 
  •  

 

 

 

 

 

문제 해결 방법은 리다이렉트! 

 

 

POST ▶ Redirect ▶ GET

실제 상품을 등록하고 뷰 템플릿으로 호출하는게 아니라 상품 상세화면으로 리다이렉트를 하면된다.

그렇게 하면 상품 등록 후 상품 상세 화면으로 다시 이동해서 (리다이렉트) 마지막에 호출한 GET /items/{id} 이 된다.

 

  • 전체 흐름 
    • 실제 상품등록 POST/ add
    • 상품 상세 화면으로 리다이렉트 Redirect items/{itemId} 호출 http://localhost:8080/basic/items/3
    • 웹 브라우저가 상품 상세를 새로 요청 GET /items/{id} 
    • 새로고침을 해도 GET /items/{id} 상품 상세 화면으로 이동
    • 문제 해결 

 

 

 

[상품등록 POST redirect - BasicItemController ]

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

 

※ 주의

+item.getId() 처럼 URL에 변수를 더해서 사용하는 것은 URL 인코딩이 안되기 때문에 위험

 

 

 

 

RedirectAttributes

RedirectAttributes 을 사용하여 URL 인코딩 문제 해결과 상품이 실제로 등록이 됐을때 "저장되었습니다." 메세지가 나오도록 해보자 

@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 는 리다이렉트할 때 모델에 데이터를 전달할 수 있고 파라미터에 itemIdstatus 를 붙여주는 역할이다. 

  • basic/items/1?status=true

 

 

 

이제 저장완료 메세지를 만들어보자

 

리다이렉트  redirect:/basic/items/{itemId}  ▶ 최종 basic/item 뷰 템플릿을 호출한다. 

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

    private final ItemRepository itemRepository;

    //상품 상세
    @GetMapping("/{itemId}")
    public String item(@PathVariable Long itemId, Model model){
        Item item = itemRepository.findById(itemId);
        model.addAttribute("item", item);
        return "basic/item";
    }
    
    ....

 

 

 

 

뷰템플릿

resources/templates/basic/item.html 

상품 상세

<div class="container">
    <div class="py-5 text-center">
        <h2>상품 상세</h2>
    </div>

    <!-- -->
    <h2 th:if="${param.status}" th:text="'저장 완료'"></h2>
    
    ...
  • th:if 해당 조건이 참일 때
  • ${param.status} : 파라미터 값을 조회할 수 있는 기
  • 참이면 '저장완료' 가 나온다.

 

 

 

상품 실제 등록시 '저장 완료' 메세지를 확인할 수 있다. 

반응형
LIST

+ Recent posts