상품 수정하기 기능 구현

jihan kong·2023년 2월 22일
0
post-thumbnail
post-custom-banner

등록한 상품 정보를 볼 수 있는 상품 상세 페이지 및 상품 데이터 수정

상품을 등록하는 기능을 구현했다. 그러나 등록된 상품은 항상 수정이 가능하여야 할 것이다. 즉, 수정 기능을 구현해야한다. 기능을 만들기 위해 해야할 것들을 생각해보았다.

⚙️ Item update logic ⚙️

상품 이미지를 어떤 방식으로 조회할지에 대한 아이디어, ItemController 에서 조회한 상품을 통해 어떻게 수정 페이지에 들어가게끔 할 것인지에 대한 고민이 있었다.
(ItemService 단에서 ItemFormDto 를 주입 받아 등록된 상품들을 조회하는 메서드를 만들고, ItemController 에서는 ItemService 에서 만들어진 조회데이터로 model에 담아 view로 전달하게끔 하는 과정이 필요)

일단은 먼저 등록된 상품을 불러와야했고, 이를 위해 메소드를 ItemService 에 추가했다.

ItemService

package com.shop.service;

// ..import 생략

@Service
@Transactional
@RequiredArgsConstructor
public class ItemService {

    @Transactional(readOnly = true)
    public ItemFormDto getItemDtl(Long itemId){
        List<ItemImg> itemImgList = itemImgRepository.findByItemIdOrderByIdAsc(itemId);
        List<ItemImgDto> itemImgDtoList = new ArrayList<>();
        for (ItemImg itemImg : itemImgList) {
            ItemImgDto itemImgDto = ItemImgDto.of(itemImg);
            itemImgDtoList.add(itemImgDto);
        }

        Item item = itemRepository.findById(itemId)
                .orElseThrow(EntityNotFoundException::new);
        ItemFormDto itemFormDto = ItemFormDto.of(item);
        itemFormDto.setItemImgDtoList(itemImgDtoList);
        return itemFormDto;
    }
}
  • 상품 데이터를 읽어오는 트랜잭션을 읽기 전용으로 설정
    (JPA가 더티체킹을 수행하지 않아서 성능을 향상 시킬 수 있다)
  • 상품의 이미지를 아이디 오름차순으로 조회하고 조회한 ItemImg 엔티티를 ItemImgDto 객체로 만들어서 리스트에 추가하였다
  • 상품의 아이디를 통해 상품 엔티티를 조회하고 존재하지 않을 때는 EntityNotFoundException 을 발생시키도록 했다.

다음은, 상품 수정 페이지로 진입하기 위한 ItemController 클래스 코딩 작업이다.

ItemController

    @GetMapping(value = "/admin/item/{itemId}")
    public String itemDtl(@PathVariable("itemId") Long itemId, Model model) {

        try {
            ItemFormDto itemFormDto = itemService.getItemDtl(itemId);
            model.addAttribute("itemFormDto", itemFormDto);
        } catch (EntityNotFoundException e) {
            model.addAttribute("errorMessage", "존재하지 않는 상품 입니다.");
            model.addAttribute("itemFormDto", new ItemFormDto());
            return "item/itemForm";
        }

        return"item/itemForm";
    }
  • 조회한 상품 데이터를 모델에 담아서 뷰로 전달하였다.
  • 상품 엔티티가 존재하지 않을 경우 에러메시지를 담아서 상품 등록 페이지로 이동

ItemImgService

상품을 수정할 때, 이미지 수정도 같이 진행되어야한다. 이미지 수정 기능을 위해 ItemImgService 클래스에 코드를 추가했다.

ItemImgService.java

@Service
@RequiredArgsConstructor
@Transactional
public class ItemImgService {
    
    // ..기존 코드 생략
    
    public void updateItemImg(Long itemImgId, MultipartFile itemImgFile) throws Exception {
        if(!itemImgFile.isEmpty()) {
            ItemImg savedItemImg = itemImgRepository.findById(itemImgId)
            		.orElseThrow(EntityNotFoundException::new);

        // 기존 이미지 파일 삭제
        if(!StringUtils.isEmpty(savedItemImg.getImgName())) {
                fileService.deleteFile(itemImgLocation + "/" + savedItemImg.getImgName());
            }

            String oriImgName = itemImgFile.getOriginalFilename();
            String imgName = fileService.uploadFile(itemImgLocation, oriImgName, itemImgFile.getBytes());
            String imgUrl = "/images/item/" + imgName;
            savedItemImg.updateItemImg(oriImgName, imgName, imgUrl);
        }
    }
}
  • 상품 이미지 아이디를 이용하여 기존에 저장했던 상품 이미지 엔티티를 조회
  • 기존에 등록된 상품 이미지 파일이 있을 경우 해당 파일을 삭제
  • 업데이트한 상품 이미지 파일을 업로드
  • 변경된 상품 이미지 정보를 세팅 (savedItemImg.updateItemImg(oriImgName, imgName, imgUrl);)

구현하면서 알게된 것❓
-> 변경된 상품 이미지 정보를 세팅할 때는 ItemImgRepository.save() 로직을 호출하지 않는다. savedItemImg Entity는 현재 영속 상태이므로 데이터를 변경하는 것만으로 변경감지 기능이 동작하여 트랜잭션이 끝날 때 update 쿼리가 실행되기 때문이다. (Entity가 영속 상태일 때만 가능)


상품 업데이트 로직 구현

본격적으로 상품을 업데이트하는 로직을 구현하기 위해 첫번째로,
Item class에 상품 데이터를 업데이트하는 로직을 만들었다.

Item.java

package com.shop.entity;

// import 생략

@Entity                                             
@Table(name="item")                                     
@Getter
@Setter
@ToString
public class Item {

	// ..기존 코드 생략
    
    public void updateItem(ItemFormDto itemFormDto) {
        this.itemNm = itemFormDto.getItemNm();
        this.price = itemFormDto.getPrice();
        this.stockNumber = itemFormDto.getStockNumber();
        this.itemDetail = itemFormDto.getItemDetail();
        this.itemSellStatus = itemFormDto.getItemSellStatus();
    }
}

상품을 업데이트할 때도 마찬가지로 변경 감지 기능이 동작한다.

ItemService.java

@Service
@Transactional
@RequiredArgsConstructor
public class ItemService {
    
    public Long updateItem(ItemFormDto itemFormDto, List<MultipartFile> itemImgFileList) throws Exception{
    
        //상품 수정
        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();
    }
}
  • 상품 등록 화면으로부터 전달 받은 상품 아이디를 이용해 상품 엔티티 조회
  • 마찬가지로 상품 등록 화면으로부터 전달 받은 ItemFormDto 를 통해 상품 엔티티 업데이트
  • 상품 이미지 아이디 리스트 조회
  • 상품 이미지를 업데이트하기 위해 updateItemImg() 메소드에 상품 이미지 아이디와 상품 이미지 파일 정보를 파라미터로 전달

마지막으로 상품을 수정하는 URL을 ItemController 클래스에 추가했다.

ItemController.java

package com.shop.controller;

// ..import 생략

@Controller
@RequiredArgsConstructor
public class ItemController {
    
    // 코드 생략
    
    @PostMapping(value = "/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.saveItem(itemFormDto, itemImgFileList);
        } catch (Exception e) {
            model.addAttribute("errorMessage", "상품 수정 중 에러가 발생하였습니다.");
            return "item/itemForm";
        }

        return "redirect:/";
    }
}

느낀점💡

지금까지 상품을 등록하고 수정하는 기능을 구현했다. Entity 구현부터 Service단과 Controller단, 트랜잭션, 매핑관계 등등...을 모두 신경쓰다보니 할게 정말 많았다.😥 솔직히 혼자서 구현하기란 어려웠다. 그러나, 구글링과 도서들을 참고하여 만들다보니 비교적 쉽게 구현할 수 있었다. 무엇보다 구현이 잘되고 동작하는 것을 보니 나름 뿌듯했다. 여기서 그치지 않고 더욱 다양한 기능을 추가해 나만의 웹사이트를 구축해볼 생각이다.

profile
학습하며 도전하는 것을 즐기는 개발자
post-custom-banner

0개의 댓글