본문 바로가기
JAVA Spring

스프링 MVC - 웹페이지 만들기(3)

by ppirae 2022. 4. 16.

상품 등록 처리 - @ModelAttribute

상품 등록 폼은 다음 방식으로 서버에 데이터를 전달한다.

  • POST - HTML Form
  • content-type: application/x-www-form-urlencoded
  • 메시지 바디에 쿼리 파리미터 형식으로 전달 itemName=itemA&price=10000&quantity=10
  • 예) 회원 가입, 상품 주문, HTML Form 사용

 

V1은 요청 파라미터 형식을 처리해야 하므로 @RequestParam 을 사용하자

addItemV1 - BasicItemController에 추가 (@RequestParam)

  • 먼저 @RequestParam String itemName : itemName 요청 파라미터 데이터를 해당 변수에 받는다.
  • Item 객체를 생성하고 itemRepository 를 통해서 저장한다.
  • 저장된 item 을 모델에 담아서 뷰에 전달한다.

 

@RequestParam 으로 변수를 하나하나 받아서 Item 을 생성하는 과정은 불편했다.

V2 부터는 @ModelAttrubute를 사용하자

addItemV2 - 상품 등록 처리 - ModelAttribute (@ModelAttribute)

@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 이름으로 저장

 

addItemV3 - 상품 등록 처리 - ModelAttribute 이름 생략

@ModelAttribute 의 이름을 생략할 수 있다.

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

예) @ModelAttribute 클래스명 모델에 자동 추가되는 이름

  • Item -> item
  • HelloWorld -> helloWorld

addItemV4 - 상품 등록 처리 - ModelAttribute 전체 생략

@ModelAttribute 자체도 생략가능하다. 대상 객체는 모델에 자동 등록된다. 나머지 사항은 기존과 동일하다.


상품 수정

수정에 필요한 정보를 조회하고, 수정용 폼 뷰를 호출한다.

리다이렉트

상품 수정은 마지막에 뷰 템플릿을 호출하는 대신에 상품 상세 화면으로 이동하도록 리다이렉트를 호출한다.

  • 스프링은 redirect:/... 으로 편리하게 리다이렉트를 지원한다.
  • redirect:/basic/items/{itemId}"
    • 컨트롤러에 매핑된 @PathVariable 의 값은 redirect 에도 사용 할 수 있다.
    • redirect:/basic/items/{itemId} -> {itemId} 는 @PathVariable Long itemId 의 값을 그대로 사용한다.

PRG Post/Redirect/Get

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

상품 등록을 완료하고 웹 브라우저의 새로고침 버튼을 클릭해보자.

상품이 계속해서 중복 등록되는 것을 확인할 수 있다.

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

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

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

그래서 내용은 같고, ID만 다른 상품 데이터가 계속 쌓이게 된다.

 

POST, Redirect GET

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

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

웹 브라우저는 리다이렉트의 영향으로 상품 저장 후에 실제 상품 상세 화면으로 다시 이동한다. 따라서 마지막에 호출한 내용이 상품 상세 화면인 GET /items/{id} 가 되는 것이다.

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


RedirectAttributes

상품을 저장하고 상품 상세 화면으로 리다이렉트 한 것 까지는 좋았다. 그런데 고객 입장에서 저장이 잘 된 것인지 안 된 것인지 확신이 들지 않는다. 그래서 저장이 잘 되었으면 상품 상세 화면에 "저장되었습니다"라는 메시지를 보여달라는 요구사항이 왔다.

 

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

실행해보면 다음과 같은 리다이렉트 결과가 나온다.

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

 

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

  • redirect:/basic/items/{itemId}
    • pathVariable 바인딩: {itemId}
    • 나머지는 쿼리 파라미터로 처리: ?status=true
  • th:if : 해당 조건이 참이면 실행
  • ${param.status} : 타임리프에서 쿼리 파라미터를 편리하게 조회하는 기능
    • 원래는 컨트롤러에서 모델에 직접 담고 값을 꺼내야 한다. 그런데 쿼리 파라미터는 자주 사용해서 타임리프에서 직접 지원한다.

 

뷰 템플릿에 메시지를 추가하고 실행해보면 "저장 완료" 라는 메시지가 나오는 것을 확인할 수 있다.

물론 상품 목록에서 상품 상세로 이동한 경우에는 해당 메시지가 출력되지 않는다.


인프런 김영한님의 스프링 MVC 1편을 듣고 쓴 글입니다.

https://inf.run/cd9z

 

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

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

www.inflearn.com

 

댓글