Jin's Dev Story

[스프링 부트 쇼핑몰 프로젝트 with JPA] 7. 상품 수정 본문

Web & Android/스프링 부트 쇼핑몰 프로젝트 with JPA

[스프링 부트 쇼핑몰 프로젝트 with JPA] 7. 상품 수정

woojin._. 2023. 10. 16. 18:16
이 내용은 스프링 부트 쇼핑몰 프로젝트 with JPA 책을 학습한 내용입니다.

1. 상품 조회

  • 상품을 수정하려면 해당 상품을 불러와야 함
  • 따라서, ItemService 에 상품 조회 메소드 추가 (조회 기능이므로 읽기 전용으로 불러옴)
  • item 엔티티와 img 정보 엔티티를 itemFormDto 객체로 변환 후 반환하는 조회 기능
// 아이템 수정
    public ItemFormDto getItemDetail(Long itemId) {

        List<ItemImg> itemImgList = itemImgRepository.findByItemIdOrderByIdAsc(itemId);
        List<ItemImgDto> itemImgDtoList = new ArrayList<>();

        for (ItemImg itemImg : itemImgList) {
            ItemImgDto itemImgDto = ItemImgDto.of(itemImg); // 엔티티를 dto로 변환
            itemImgDtoList.add(itemImgDto); // dto를 추가해서 리스트 생성(웹사이트에 들고가기 위해서)
        }

        Item item = itemRepository.findById(itemId).orElseThrow(EntityNotFoundException::new);

        ItemFormDto itemFormDto = ItemFormDto.of(item);
        itemFormDto.setItemImgDtoList(itemImgDtoList);

        return itemFormDto;

    }

2. 상품 수정 페이지 Controller

  • 상품 등록 페이지를 동일하게 사용 ("저장" 버튼을 "수정" 버튼으로 출력)
  • 수정 대상 상품의 Id 값을 포함한 Get URL 요청으로 상품 수정 페이지를 요청
  • 해당 상품을 조회한 뒤 itemFormDto 객체를 기반으로 상품 수정 페이지 생성 및 반환
@GetMapping("/admin/item/{itemId}")
    public String itemDetail(@PathVariable("itemId")Long itemId, Model model) {

        try {
            ItemFormDto itemFormDto = itemService.getItemDetail(itemId);
            model.addAttribute("itemFormDto", itemFormDto); // itemForm.html에서 itemFormDto로 받기 때문에
        } catch (EntityNotFoundException E) {
            model.addAttribute("errorMessage", "존재하지 않는 상품입니다.");
            model.addAttribute("itemFormDto", new ItemFormDto());
            return "item/itemForm";
        }

        return "item/itemForm";

    }
  • 상품 수정 페이지
  • /admin/item/{상품 id}

3. ItemImgService 수정

  • 상품 이미지를 수정한 경우, 기존의 이미지 정보 객체를 불러옴 (조회)
  • 기존 이미지 파일이 존재한다면 삭제 (존재하지 않는다면 이미지를 추가한 것)
  • 수정한 이미지 파일을 fileService.uploadFile() 메소드를 통해 업로드
  • itemImgRepository.save() 가 아닌 savedItemImg.updateItemImg() 메소드로 객체를 수정
// 이미지 수정
    public void updateItemImg(Long ItemImgId, MultipartFile itemImgFile) throws IOException {
        // itemImgFile이 빈게 아니면
        if(!itemImgFile.isEmpty()) {
            ItemImg itemImg = itemImgRepository.findById(ItemImgId).orElseThrow(EntityNotFoundException::new);

            // 이미지 파일이 존재하는 경우
            if(!StringUtils.isEmpty(itemImg.getImgName())) {
                fileService.deleteFile(itemImgLocation + "/" + itemImg.getImgName());
            }

            String oriName = itemImgFile.getOriginalFilename();
            String imgName = fileService.uploadFile(itemImgLocation, oriName, itemImgFile.getBytes());
            String imgUrl = "/images/item/" + imgName;

            itemImg.updateItemImg(oriName, imgName, imgUrl);

        }
    }

• 상품 수정 페이지에서 기존 이미지 파일을 수정하지 않았다면 "null" 객체로 넘어옴 (상품 이미지 라벨에는 이름이 표시되어 있지만 파일이 등록된 것은 아님)

4. 상품 업데이트 로직

  • Item Entity 클래스에 업데이트 로직 생성
  • 엔티티 클래스에 로직을 추가한다면 좀 더 객체지향적이고 코드 재활용이 가능, 또한 변경 포인트를 한군데에서 관리할 수 있음
public void updateItem(ItemFormDto itemFormDto) {
        this.itemNm = itemFormDto.getItemNm();
        this.price = itemFormDto.getPrice();
        this.stockNumber = itemFormDto.getStockNumber();
        this.itemDetail = itemFormDto.getItemDetail();
        this.itemSellStatus = ItemSellStatus.valueOf(itemFormDto.getItemSellStatus());

    }

5. ItemService 수정

  • 상품 Id 를 이용하여 기존의 상품 Entity 객체를 불러온 뒤, Post 입력값으로 들어온 상품 정보로 수정
  • itemImgService.updateItemImg() 메소드를 이용하여 상품 이미지 수정
public Long updateItem(ItemFormDto itemFormDto, List<MultipartFile> itemImgFileList) throws IOException {

        // 상품 수정
        Item item = itemRepository.findById(itemFormDto.getId()).orElseThrow(EntityNotFoundException::new);
        item.updateItem(itemFormDto);

        List<Long> itemImgIds = itemFormDto.getItemImgIds();

        // 이미지 수정
        for (int i = 0; i < itemImgFileList.size(); i++) {
            itemImgService.updateItemImg(itemImgIds.get(i), itemImgFileList.get(i));
        }

        // 수정 후 어떤 아이템인지 아이템의 아이디를 알려줌
        return item.getId();
    }

6. 상품 수정 Controller

  • 상품 등록 Controller와 거의 동일 (itemService. saveItem -> updateItem)
// 아이템 수정 후 할 일
    @PostMapping("/admin/item/{itemId}")
    public String itemUpdate(@Valid ItemFormDto itemFormDto, BindingResult bindingResult
            , Model model, @RequestParam("itemImgFile") List<MultipartFile> itemImgFileList) {

        if(bindingResult.hasErrors()) {
            return "item/itemForm";
        }

        if(itemImgFileList.get(0).isEmpty() && itemFormDto.getId() == null) {
            model.addAttribute("errorMessage", "첫 번째 상품 이미지는 필수입니다.");
            return "item/itemForm";
        }

        try {
            itemService.updateItem(itemFormDto, itemImgFileList);
        } catch (IOException e) {
            model.addAttribute("errorMessage", "상품 수정 중에 오류가 발생했습니다.");
            return "item/itemForm";
        }

        // 홈으로 리턴
        return "redirect:/";
    }

7. 상품 등록 동작 과정

  • 상품 등록은 save() 메소드만을 수행
  • 상품 수정은 조회 -> update() 메소드를 수행 (변경 감지 이용)

① "ADMIN" 권한을 가진 아이디로 상품 수정 페이지 Get 요청 ("/admin/item/{itemId}")

② Item Controller 에서 itemService.getItemDtl(itemId) 수행하여 해당 상품 조회

③ Item Controller 에서 상품 수정 페이지 반환하면서 해당 상품 Dto 객체 넘김

④ 상품 수정 페이지에서 수정한 후 "수정" (POST 요청)

⑤ Item Controller 에서 입력값을 검증하고 itemService.updateItem() 메소드를 수행

   - 이 때, 파라미터는 입력받은 itemFormDto 객체와 이미지 정보를 담고있는 itemImgFileList 를 넘김   

⑥ itemService 에서 Item 객체를 조회하여 불러온 뒤 item.updateItem(itemFormDto) 수행

⑦ itemService 에서 itemImgService.updateItemImg() 메소드 수행

  - 이 때, 파라미터는 "상품 이미지의 id", "상품 이미지 파일"   

⑧ itemImgService 에서 기존 이미지 파일 삭제 후 savedItemImg.updateItemImg () 수행