개발/Spring MVC

스프링 MVC - @ModelAttribute, PRG, RedirectAttributes

Debin 2022. 1. 10.
반응형
본 게시글은 인프런 김영한 선생님 강의 스프링 MVC 1편을 완강하고 배운 것을 남기고자 적은 포스팅입니다.
(2022.08.07 수정) - 복습을 하면서, 기억할 부분 설명 추가.

 

강의 링크는 아래와 같습니다.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 원

www.inflearn.com

 

 

@ModelAttribute

우리는 저번에 @ModelAttribute에 대해 배워봤다. 그러나 이번에는 복습 겸 추가 내용을 남기려고 한다.

HTML FORM POST 방식을 통해 @RequestParam으로 변수를 하나하나 받아서 Item을 생성하는 과정은 불편했다.

이번에는 @ModelAttribute를 사용해서 한 번에 처리해보자. 코드는 아래와 같다.

/**
 * @ModelAttribute("item") Item item
 * model.addAttribute("item", item); 자동 추가
 *
 * @ModelAttribute name 생략 가능
 * 생략시 model에 저장되는 name은 클래스명 첫글자만 소문자로 등록 Item -> item
 * @ModelAttribute("item") Item item, ->  @ModelAttribute Item item
 */
@PostMapping("/add")
public String addItemV2(@ModelAttribute("item") Item item, Model model) {
   itemRepository.save(item);
   //model.addAttribute("item", item); //자동 추가, 생략 가능
   return "basic/item";
}

 

  • @ModelAttribute - 요청 파라미터 처리
    • @ModelAttribute는 Item 객체를 생성하고, 요청 파라미터의 값을 프로퍼티 접근법 (setXxx)으로 입력해준다.
  • @ModelAttribute - Model 추가
    • @ModelAttribute는 중요한 한 가지 기능이 더 있다.
    • 바로 모델(Model)에 @ModelAttribute로 지정한 객체를 자동으로 넣어준다.
    • 지금 코드를 보면 model.addAttribute("item", item)가 주석 처리되어 있어도 잘 동작하는 것을 확인할 수 있다.

모델에 데이터를 담을 때는 이름이 필요하다.

이름은 @ModelAttribute에 지정한 name(value) 속성을 사용한다.

만약 다음과 같이 @ModelAttribute의 이름을 다르게 지정하면 다른 이름으로 모델에 포함된다.

 

@ModelAttribute("hello") Item item 이름을 hello로 지정

model.addAttribute("hello", item); 모델에 hello 이름으로 저장

 

@ModelAttribute의 이름을 생략하면 모델에 저장될 때 클래스명을 사용한다. 이때 클래스의 첫 글자만 소문자로 변경해서 등록한다.

/**
 * @ModelAttribute 자체 생략 가능
 * model.addAttribute(item) 자동 추가
 */
@PostMapping("/add")
public String addItemV4(Item item) {
   itemRepository.save(item);
   return "basic/item";
}

@ModelAttribute 자체 생략도 가능하다. 대상 객체는 모델에 자동 등록된다. 

PRG POST/Redirect/GET

POST 방식을 통해 매핑된 컨트롤러가 뷰를 렌더링 한다고 가정해보자. 쉽게 이해를 도울 사진은 아래와 같다.

웹 브라우저의 새로 고침은 마지막에 서버에 전송한 데이터를 다시 전송한다.

상품 등록 폼에서 데이터를 입력하고 저장을 선택하면 POST /add + 상품 데이터를 서버로 전송한다.

이 상태에서 새로 고침을 또 선택하면 마지막에 전송한 POST /add + 상품 데이터를 서버로 다시 전송하게 된다.

즉 POST 방식으로 상품을 등록하고 새로 고침을 하면 ID만 다른 같은 상품이 등록되는 불상사가 발생한다.

 

어떻게 이를 해결할 수 있을까? 아래 이미지를 확인해보자.

 

바로 뷰를 렌더링 하지 않고 다른 URL로 Redirect 시키는 것이다.

브라우저의 새로 고침은 마지막에 서버에 전송한 데이터를 다시 전송한다.

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

웹 브라우저는 리다이렉트의 영향으로 상품 저장 후에 실제 상품 상세 화면으로 다시 이동한다.

따라서 마지막에 호출한 내용이 상품 상세 화면인 GET /items/{id}가 되는 것이다.

이후 새로고침을 해도 상품 상세 화면으로 이동하게 되므로 새로 고침 문제를 해결할 수 있다.

Redirect 

Redirect를 하도록 코드를 작성해보자.

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

이런 문제 해결 방식을 PRG Post/Redirect/Get 방식이라고 한다.

주의!!!

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

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

실행해보면 다음과 같은 리다이렉트 결과가 나온다. http://localhost:8080/basic/items/3? status=true

RedirectAttributes

RedirectAttributes를 사용하면 URL 인코딩도 해주고, pathVarible , 쿼리 파라미터까지 처리해준다.

 

  • redirect:/basic/items/{itemId}
    • pathVariable 바인딩: {itemId}
    • 나머지는 쿼리 파라미터로 처리:? status=true

이제 뷰 템플릿에서 if문을 사용해서 저장이 잘 되었다는 확인 메시지를 출력하면 된다.

 

이상으로 스프링 MVC 1편 포스팅을 마칩니다.

반응형

댓글