상품 수정하기

진크·2022년 3월 2일
0
post-thumbnail

ItemService 메소드 추가

등록된 상품을 불러오는 메소드를 추가합니다.

package me.jincrates.gobook.service;

//...기존 임포트 생략
import me.jincrates.gobook.web.dto.ItemImgDto;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.EntityNotFoundException;
import java.util.ArrayList;
import java.util.List;

@RequiredArgsConstructor
@Transactional
@Service
public class ItemService {

    //..기존 코드 생략

    @Transactional(readOnly = true)
    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);
            itemImgDtoList.add(itemImgDto);
        }

        Item item = itemRepository.findById(itemId).orElseThrow(EntityNotFoundException::new);
        ItemFormDto itemFormDto = ItemFormDto.of(item);
        itemFormDto.setItemImgDtoList(itemImgDtoList);

        return itemFormDto;
    }
}
  • @Transactional(readOnly = true) : 상품 데이터를 읽어오는 트랜잭션을 읽기 전용으로 설정합니다. 이럴 경우 JPA가 더티체킹(변경감지)을 수행하지 않아서 성능을 향상 시킬 수 있습니다.

ItemController 코드 추가

상품 수정 페이지로 진입하기 위해서 ItemController 클래스에 코드를 추가하겠습니다.

package me.jincrates.gobook.web;

//...기존 임포트 생략

import javax.persistence.EntityNotFoundException;
import javax.validation.Valid;
import java.util.List;

@RequiredArgsConstructor
@Controller
public class ItemController {

		//...기존 코드 생략

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

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

        return "item/itemForm";
    }
}

ItemImgService 수정

상품 이미지 데이터를 수정할 때는 변경감지 기능을 사용하겠습니다.

package me.jincrates.gobook.service;

//..기존 임포트 생략

import javax.persistence.EntityNotFoundException;

@RequiredArgsConstructor
@Transactional
@Service
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);
        }
    }
}
  • 상품 이미지를 수정한 경우 상품 이미지를 업데이트 합니다.
  • itemImgRepository.findById(itemImgId) : 상품 이미지 아이디를 이용하여 기존에 저장했던 상품 이미지 엔티티를 조회합니다.
  • !StringUtils.isEmpty(savedItemImg.getImgName()) : 기존에 등록된 상품 이미지 파일이 있을 경우 해당 파일을 삭제합니다.
  • fileService.uploadFile(itemImgLocation, oriImgName, itemImgFile.getBytes()) : 업데이트한 상품 이미지 파일을 업로드합니다.
  • savedItemImg.updateItemImg(oriImgName, imgName, imgUrl) : 변경된 상품 이미지 정보를 셋팅해줍니다. 여기서 중요한 점은 상품 등록 때처럼 itemImgRepository.save() 로직을 호출하지 않는다는 것입니다. savedItemImg 엔티티는 현재 영속 상태이므로 데이터를 변경하는 것만으로 변경 감지 기능이 동작하여 트랜잭션이 끝날 때 update 쿼리가 실행됩니다. 여기서 중요한 것은 엔티티가 영속 상태여야 한다는 것입니다.

Item 엔티티 수정

이제 상품을 업데이트하는 로직을 구현하겠습니다. 먼저 Item클래스에 상품 데이터를 업데이트하는 로직을 만들겠습니다. 엔티티 클래스에 비즈니스 로직을 추가한다면 조금 더 객체지향적으로 코딩을 할 수 있고, 코드를 재활용할 수 있습니다. 또한 데이터 변경 포인트를 한군데에서 관리할 수 있습니다.

package me.jincrates.gobook.domain.items;

//..기존 임포트 생략

@Getter @ToString
@NoArgsConstructor
@Table(name = "item")
@Entity
public class Item extends BaseEntity {

    //...코드 생략

    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 수정

상품을 업데이트할 때도 마찬가지로 변경 감지 기능을 사용합니다.

package me.jincrates.gobook.service;

//...기존 임포트 생략

@RequiredArgsConstructor
@Transactional
@Service
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, max = itemImgFileList.size(); i < max; i++) {
            itemImgService.updateItemImg(itemImgIds.get(i), itemImgFileList.get(i));
        }
        
        return item.getId();
    }
}
  • item.updateItem(itemFormDto) : 상품 등록 화면으로부터 전달 받은 ItemFormDto를 통해서 상품 엔티티를 업데이트 합니다.

ItemController 수정

상품을 수정하는 URL을 추가하겠습니다. 상품 등록 때 추가했던 코드와 거의 비슷합니다.

package me.jincrates.gobook.web;

//..기존 임포트 생략

@RequiredArgsConstructor
@Controller
public class ItemController {

    //..코드 생략

    @PostMapping(value = "/admin/item/{itemId}")
    public String itemUpdate(@Valid ItemFormDto itemFormDto, BindingResult bindingResult
            , @RequestParam("itemImgFile") List<MultipartFile> itemImgFileList, Model model) {

        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:/";
    }
}

실제 테스트

상품이 정상적으로 수정되는지 확인하려고 하였으나....수정한 만큼 이미지 리스트가 쌓이네요....
하하 어쩐지 잘풀리더라ㅎㅎㅎ 어디가 잘못된건지 찾고 오겠습니다.

profile
철학있는 개발자 - 내가 무지하다는 것을 인정할 때 비로소 배움이 시작된다.

0개의 댓글