... 기존 코드 생략 ...
@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.setItemImgIds(itemImgDtoList);
return itemFormDto;
}
① 상품 데이터를 읽어오는 트랜잭션을 읽기 전용으로 설정. 이럴 경우 JPA가 더티체킹(변경감지)을 수행하지 않아 성능을 향상시킬 수 있음.
② 해당 상품의 이미지를 조회. 등록순으로 가지고 오기 위해서 상품 이미지 아이디 오름순으로 가져옴.
③ 조회한 ItemImg 엔티티를 ItemImgDto 객체로 만들어서 리스트에 추가
④ 상품 아이디를 통해 상품 엔티티를 조회함. 존재하지 않을 때는 EntityNotFoundException 을 발생시킴.
@RequestMapping(value = "/admin/item/{itemId}", method = RequestMethod.GET)
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";
}
① 조회한 상품 데이터를 모델에 담아서 뷰로 전달
② 상품 엔티티가 존재하지 않을 경우 에러메시지를 담아서 상품 등록 페이지로 이동
... 기존 소스 생략 ...
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.save() 로직을 호출하지 않는다는 것. savedItemImg 엔티티는 현재 영속 상태이므로 데이터를 변경하는 것만으로 변경 감지 기능이 동작하면서 트랜잭션이 끝날 때 update 쿼리가 실행됨. 엔티티가 영속 상태여야 함!
... 이전 코드 생략 ...
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();
}
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.getItemImgIdList();
//이미지 등록
for (int i = 0; i < itemImgFileList.size(); i++) {
itemImgService.updateItemImg(itemImgIds.get(i), itemImgFileList.get(i));
}
return item.getId();
}
① 상품 등록 화면으로부터 전달 받은 상품 아이디를 이용하여 상품 엔티티를 조회함.
② 상품 등록 화면으로부터 전달 받은 ItemFormDto를 통해 상품 엔티티를 업데이트함.
③ 상품 이미지 아이디 리스트를 조회함.
④ 상품 이미지를 업데이트하기 위해서 updateItemImg()메서드에 상품 이미지 아이디와 상품 이미지 파일 정보를 파라미터로 전달함.
@RequestMapping(value = "/admin/item/{itemId}", method = RequestMethod.POST)
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.updateItem(itemFormDto, itemImgFileList);
}
catch (Exception e) {
model.addAttribute("errorMessage", "상품 수정 중 에러가 발생했습니다.");
return "item/itemForm";
}
return "redirect:/";
}
① 상품 수정 로직을 호출함.
참고문헌 & 강의자료
변구훈, 스프링부트 쇼핑몰 프로젝트 with JPA, 로드북
(스마트혼합)자바&파이썬 빅데이터 웹UI콘텐츠 개발, 부산IT교육센터