[스프링 MVC 1편] 7 - (4) 상품 등록, 수정, Redirect
* 스프링 입문 = window, 스프링 MVC 1편 = Mac 으로 진행합니다
* 섹션7 부터는 자바 17 버전으로 진행합니다
* 진도 : 섹션7 - (7) ~ (11)
* : 자바 클래스명, : 코드, : 단축키
1. 상품 등록
1) 컨트롤러 추가
[ java/hello/itemservice/web/basic/BasicItemController ]
@GetMapping("/add")
public String addForm(){
return "basic/addForm";
}
@PostMapping ("/add")
public String save(@ModelAttribute("item") Item item){
itemRepository.save(item);
return "basic/item";
}
url 경로는 같으나 방식을 다르게 함으로서 Get 타입은 등록하는 창, Post 타입은 등록 완료 창
< 변경 과정 _ 포스트 6-(3) 참고 >
1단계_@RequestParam 사용
@PostMapping("/add")
public String addItemV1(@RequestParam String itemName,
@RequestParam int price,
@RequestParam Integer quantity,
Model model) {
Item item = new Item();
item.setItemName(itemName);
item.setPrice(price);
item.setQuantity(quantity);
itemRepository.save(item);
model.addAttribute("item", item);
return "basic/item";
}
- 요청파라미터 조회 (request.getParameter()와 같은 기능)
- model 객체 생성
- item 객체 생성
- itemRepository에 저장
- 저장된 item을 모델에 담아서 뷰에 전달
2단계_@ModelAttribute 사용
@PostMapping("/add")
public String addItemV2(@ModelAttribute("item") Item item, Model model) {
itemRepository.save(item);
return "basic/item";
}
- @ModelAttribute
- Item 객체 자동 생성 가능
- model 객체 생성 / 모델에 item 넣어주는 model.addAtribute 기능 수행 가능
3단계_@ModelAttribute 사용
@PostMapping("/add")
public String addItemV3(Item item) {
itemRepository.save(item);
return "basic/item";
}
- @ModelAttribute("name")에서 이름 생략 가능
- 클래스명(=Item)에 따라서 앞글자만 소문자로 바꿔(=item) 이름 자동으로 만들어준다
- @ModelAttribute 전체 생략 가능
2) 뷰 화면 타임리프로 만들기
- [resources/templates/basic/addForm]에서 타임리프 영역 수정하기 (강의 참고)
<form action="item.html" th:action method="post">
url이 같아서 th:action에 별도의 경로 추가 없이 진행하고 방식만 달리해서 전송한다
( = action에 값이 없으면 현재 URL에 데이터 전송 )
th:onclick="|location.href='@{/basic/items}'|"
취소를 누르면 원래 목록으로 돌아갈 수 있게 설정
2. 상품 수정
1) 컨트롤러 추가
[ java/hello/itemservice/web/basic/BasicItemController ]
@GetMapping("/{itemId}/edit")
public String editForm(@PathVariable("itemId") Long itemId, Model model) {
Item item = itemRepository.findById(itemId);
model.addAttribute("item", item);
return "basic/editForm";
}
@PostMapping ("/{itemId}/edit")
public String edit(@PathVariable("itemId") Long itemId, @ModelAttribute Item item) {
itemRepository.update(itemId, item);
return "redirect:/basic/items/{itemId}";
}
url 경로는 같으나 방식을 다르게 함으로서 Get 타입은 수정하는 창, Post 타입은 수정 완료 창
상품 수정은 마지막에 뷰 템플릿을 호출하는 대신에 상품 상세 화면으로 이동하도록 리다이렉트를 호출한다
(@PathVariable 의 값은 redirect 에도 사용 가능)
2) 뷰 화면 타임리프로 만들기
- [resources/templates/basic/editForm]에서 타임리프 영역 수정하기 (강의 참고)
<form action="item.html" th:action method="post">
url이 같아서 th:action에 별도의 경로 추가 없이 진행하고 방식만 달리해서 전송한다
( = action에 값이 없으면 현재 URL에 데이터 전송 )
th:onclick="|location.href='@{/basic/items/{itemId}(itemId=${item.id})}'|"
취소를 누르면 이전 상품상세 페이지로 돌아갈 수 있게 설정
th:value="${item.id}"
th:value="${item.itemName}"
th:value="${item.price}"
th:value="${item.quantity}"
-
모델에 있는 item 정보를 획득하고 프로퍼티 접근법으로 출력
3. Redirect를 사용하는 이유 (PRG)
< 동작과정 >
사용자가 상품 등록 버튼을 누른다 → 상품 등록화면을 보여준다 (Get)
사용자가 정보를 입력하고 상품 저장을 누른다 → 상품 데이터를 서버로 전송하고 저장된 화면(상품 상세)을 보여준다 (Post)
이때 새로고침 버튼을 누른다면 마지막에 전송한 데이터를 서버로 보내게 된다
즉 아이디만 다르고 같은 정보가 계속해서 저장된다
< 리다이렉트를 사용하면 >
사용자가 상품 등록 버튼을 누른다 → 상품 등록화면을 보여준다 (Get)
사용자가 정보를 입력하고 상품 저장을 누른다 → 리다이렉트로 URI 바꾼 다음 저장된 화면(상품 상세)을 보여준다 (Post)
이렇게 되면 마지막 데이터는 상품저장이 아닌 상품 상세가 되므로 새로고침 문제를 해결할 수 있다
1) 컨트롤러 수정
[ java/hello/itemservice/web/basic/BasicItemController ]
@PostMapping ("/add")
public String save(@ModelAttribute("item") Item item){
itemRepository.save(item);
return "redirect:/basic/items/" + item.getId();
}
4. RedirectAttributes
상품등록 할 때 저장완료라는 글을 출력하고 싶다 어떻게 해야할까
1) 컨트롤러 수정
[ java/hello/itemservice/web/basic/BasicItemController ]
@PostMapping("/add")
public String save(Item item, RedirectAttributes redirectAttributes) {
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/basic/items/{itemId}";
}
반환값이 items이니까 찾아가보면 items 클래스에서 List<item> 사용 → item 클래스 찾아가기 → 해당 클래스 뷰 찾아가기 → basic/item.html에서 조건 코드 추가하기
2) 뷰 화면 수정하기
- [resources/templates/basic/item]에서 타임리프 영역 수정하기 (강의 참고)
<h2 th:if="${param.status}" th:text="저장완료"></h2>
파라미터값 조건이 참이면 출력하기
실행해보면 다음과 같은 리다이렉트 결과가 나온다
http://localhost:8080/basic/items/3?status=true