[스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술] 07. 스프링 MVC - 웹 페이지 만들기

Turtle·2024년 6월 29일
0
post-thumbnail

🙄요구사항 분석

  • ✔️상품 도메인 모델
    • 상품 ID
    • 상품명
    • 가격
    • 수량
  • ✔️상품 관리 기능
    • 상품 목록
    • 상품 상세
    • 상품 등록
    • 상품 수정
    • (상품 삭제)
  • ✔️서비스 제공 흐름

🙄상품 목록 - 타임 리프

✔️타임리프

  1. 순수 HTML 파일을 웹 브라우저에서 열어도 내용을 확인할 수 있고 서버를 통해 뷰 템플릿을 거치면 동적으로 변경된 결과를 확인할 수 있다. JSP의 경우 웹 브라우저에서 열면 JSP 소스코드와 HTML이 뒤죽박죽되어 정상적인 확인이 불가능하다. 오직 서버를 통해서 JSP를 열 수 있다.
  2. 순수 HTML을 그대로 유지하면서 뷰 템플릿도 사용할 수 있는 타임리프의 특징을 네츄럴 템플릿이라고 한다.

🙄PRG Post/Redirect/Get

웹 브라우저의 새로 고침은 마지막에 서버에 전송한 데이터를 다시 전송하게끔 한다.
상품 등록 폼에서 데이터를 입력하고 저장을 선택하면 POST /add + 상품 데이터를 서버로 전송한다. 이 상태에서 새로 고침을 하면 마지막에 전송한 POST /add + 상품 데이터를 서버로 다시 전송하게 된다. 그래서 내용은 같은데 ID만 다른 상품 데이터가 계속 저장되는 문제가 발생한다.

✔️POST, Redirect GET

웹 브라우저의 새로 고침은 마지막에 서버에 전송한 데이터를 다시 전송하게끔 한다. 새로 고침 문제를 해결하려면 상품 저장 후 뷰 템플릿으로 이동하는 것이 아니라 상품 상세 화면으로 리다이렉트를 호출해주면 된다. 웹 브라우저는 리다이렉트의 영향으로 상품 저장 후에 실제 상품 상세 화면으로 다시 이동한다. 따라서 마지막에 호출한 내용이 상품 상세 화면인 GET /items/{id}가 되는 것이다.
이런 리다이렉트를 지원하는 속성으로 RedirectAttributes()이 있다.

🙄RedirectAttributes

상품을 저장하고 상품 상세 화면으로 이동할 수 있도록 RedirectAttributes를 사용한다.

🙄BasicItemController 전체 코드

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

	private final ItemRepository itemRepository;

	public BasicItemController(ItemRepository itemRepository) {
		this.itemRepository = itemRepository;
	}

	// 상품 전체 조회
	@GetMapping()
	public String items(Model model) {
		List<Item> items = itemRepository.findAll();
		model.addAttribute("items", items);
		return "basic/items";
	}

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

	// 상품 추가 뷰
	@GetMapping("/add")
	public String addItem() {
		return "basic/addForm";
	}

	// 실질적인 상품 추가가 되도록...
	@PostMapping("/add")
	public String save(@ModelAttribute(name = "item") Item item, RedirectAttributes redirectAttributes) {
		Item savedItem = itemRepository.save(item);
		redirectAttributes.addAttribute("itemId", savedItem.getId());
		redirectAttributes.addAttribute("status", true);
		return "redirect:/basic/items/{itemId}";
	}

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

	// 실질적인 상품 수정이 되도록...
	// HTML Form의 경우 PATCH를 지원하지 않기 때문에 @PostMapping을 사용
	@PostMapping("/{itemId}/edit")
	public String edit(@PathVariable(name = "itemId") Long itemId, @ModelAttribute(name = "item") Item item) {
		itemRepository.update(itemId, item);
		return "redirect:/basic/items/{itemId}";
	}

	@PostConstruct
	public void init() {
		itemRepository.save(new Item("itemA", 1000, 1));
		itemRepository.save(new Item("itemA", 1000, 2));
	}
}

0개의 댓글