일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 멋쟁이사자처럼10기
- 백엔드
- 멋사10기
- 멋사 합격
- 멋사 서류평가
- 깃허브
- 멋쟁이사자처럼
- 웹동아리
- 알림봇
- 기사 제목 크롤링
- 멋사 10기
- 멋사 면접
- 멋사 서류
- 멋쟁이 사자처럼
- 파이썬 크롤링
- 디스코드봇
- 파이썬
- 멋사12
- 멋쟁이사자처럼 서류
- 코딩동아리
- API
- 멋쟁이사자처럼11기
- IT동아리
- django
- 멋쟁이사자처럼대학
- 멋사
- 크롤링
- ㅏㄴ
- discord
- 멋사11기
- Today
- Total
ACHO.pk devlog
[Springboot] 상품 수정하기 본문
1. 상품 수정하기
상품 정보를 볼 수 있는 상품 상세 페이지와 상품 데이터를 수정해보자.
상품을 등록한 다음 해당 상품 아이디를 이용해서 상품 수정 페이지에 진입한다.
service > ItemService.java
package com.shop.shop.service;
import com.shop.shop.dto.ItemFormDto;
import com.shop.shop.dto.ItemImgDto;
import com.shop.shop.entity.Item;
import com.shop.shop.entity.ItemImg;
import com.shop.shop.repository.ItemImgRepository;
import com.shop.shop.repository.ItemRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.persistence.EntityNotFoundException;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
@Transactional
@RequiredArgsConstructor
public class ItemService {
private final ItemRepository itemRepository;
private final ItemImgService itemImgService;
private final ItemImgRepository itemImgRepository;
public Long saveItem(ItemFormDto itemFormDto, List<MultipartFile> itemImgFileList) throws Exception{
//상품 등록
Item item = itemFormDto.createItem();
itemRepository.save(item);
//이미지 등록
for(int i=0;i<itemImgFileList.size();i++){
ItemImg itemImg = new ItemImg();
itemImg.setItem(item);
if(i == 0)
itemImg.setRepimgYn("Y");
else
itemImg.setRepimgYn("N");
itemImgService.saveItemImg(itemImg, itemImgFileList.get(i));
}
return item.getId();
}
@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가 더티체킹을 수행하지 않아서 서능을 향상 시킬 수 있다.
@Transactional(readOnly = true)
📚 더디체킹이란?
▹해당 상품의 이미지를 조회한다. 등록 순으로 가지고 오기 위해 상품 이미지 아이디 오름차순으로 가지고 온다.
List<ItemImg> itemImgList = itemImgRepository.findByItemIdOrderByIdAsc(itemId);
▹조회한 ItemImg 엔티티를 ItemImgDto 객체로 만들어서 리스트에 추가한다.
for (ItemImg itemImg : itemImgList) {
▹상품의 아이디를 통해 상품 엔티티를 조회한다. 존재하지 않을 때는 EntityNotFoundException을 발생시킨다.
Item item = itemRepository.findById(itemId)
상품 수정 페이지로 진입하기 위해서 ItemController 클래스에 코드를 추가해야한다.
🔔 실무에서는 등록 수정을 할 때 서버에 전달하는 데이터가 많이 다르기 때문에 보통 등록용 페이지와 수정용 페이지를 나눠서 개발한다 !!
package com.shop.shop.controller;
import com.shop.shop.dto.ItemFormDto;
import com.shop.shop.service.ItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.persistence.EntityNotFoundException;
import javax.validation.Valid;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class ItemController {
private final ItemService itemService;
@GetMapping(value = "/admin/item/new")
public String itemForm(Model model){
model.addAttribute("itemFormDto", new ItemFormDto());
return "item/itemForm";
}
@PostMapping(value = "/admin/item/new")
public String itemNew(@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:/";
}
@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";
}
}
▹조회한 상품 데이터를 모델에 담아서 뷰로 전달한다.
try {
ItemFormDto itemFormDto = itemService.getItemDtl(itemId);
▹상품 엔티티가 존재하지 않을 경우 에러메시지를 담아서 상품 등록 페이지로 이동한다.
catch(EntityNotFoundException e){
상품 이미지 수정을 위해서 ItemImgService 클래스를 수정하자. 상품 이미지 데이터를 수정할 때는 변경감지 기능을 사용한다.
ItemImgService .java
package com.shop.shop.service;
import com.shop.shop.entity.ItemImg;
import com.shop.shop.repository.ItemImgRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.thymeleaf.util.StringUtils;
import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;
@Service
@RequiredArgsConstructor
@Transactional
public class ItemImgService {
@Value("${itemImgLocation}")
private String itemImgLocation;
private final ItemImgRepository itemImgRepository;
private final FileService fileService;
public void saveItemImg(ItemImg itemImg, MultipartFile itemImgFile) throws Exception{
String oriImgName = itemImgFile.getOriginalFilename();
String imgName = "";
String imgUrl = "";
//파일 업로드
if(!StringUtils.isEmpty(oriImgName)){
imgName = fileService.uploadFile(itemImgLocation, oriImgName,
itemImgFile.getBytes());
imgUrl = "/images/item/" + imgName;
}
//상품 이미지 정보 저장
itemImg.updateItemImg(oriImgName, imgName, imgUrl);
itemImgRepository.save(itemImg);
}
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);
}
}
}
▹상품 이미지를 수정한 경우 상품 이미지를 업데이트한다.
if(!itemImgFile.isEmpty()){
▹상품 이미지 아이디를 이용하여 기존에 저장했던 상품 이미지 엔티티를 조회한다.
ItemImg savedItemImg = itemImgRepository.findById(itemImgId)
▹기존에 등록된 상품 이미지 파일이 있을 경우 해당 파일을 삭제한다.
if(!StringUtils.isEmpty(savedItemImg.getImgName())) {
▹업데이트한 상품 이미지 파일을 업로드한다.
String imgName = fileService.uploadFile(itemImgLocation, oriImgName, itemImgFile.getBytes());
▹변경된 상품 이미지 정보를 세팅해준다. 여기서 중요한 점은 상품 등록 때처럼 itemImgRepository.save() 로직을 호출하지 않는다는 것이다. savedItemImg 엔티티는 현재 영속 상태이므로 데이터를 변경하는 것만으로 변경 감지 기능이 동작하여 트랜잭션이 끝날 떄 update 쿼리가 실행된다. 여기서 중요한 것은 엔티티가 영속 상태여야 한다.
savedItemImg.updateItemImg(oriImgName, imgName, imgUrl);
상품을 업데이트 하는 로직을 구현해보자. 먼저 Item 클래스에 상품 데이터를 업데이트하는 로직을 만들어야 한다.
entity > Item.java
package com.shop.shop.entity;
import com.shop.shop.constant.ItemSellStatus;
import com.shop.shop.dto.ItemFormDto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name="item")
@Getter
@Setter
@ToString
public class Item {
@Id
@Column(name="item_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id; //상품 코드
@Column(nullable = false, length = 50)
private String itemNm; //상품명
@Column(name="price", nullable = false)
private int price; //가격
@Column(nullable = false)
private int stockNumber; //재고수량
@Lob
@Column(nullable = false)
private String itemDetail; //상품 상세 설명
@Enumerated(EnumType.STRING)
private ItemSellStatus itemSellStatus; //상품 판매 상태
private LocalDateTime regTime; //등록 시간
private LocalDateTime updateTime; //수정 시간
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();
}
}
상품을 업데이트할 때도 변경 감지 기능을 사용한다.
service > ItemService.java
package com.shop.shop.service;
import com.shop.shop.dto.ItemFormDto;
import com.shop.shop.dto.ItemImgDto;
import com.shop.shop.entity.Item;
import com.shop.shop.entity.ItemImg;
import com.shop.shop.repository.ItemImgRepository;
import com.shop.shop.repository.ItemRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.persistence.EntityNotFoundException;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
@Transactional
@RequiredArgsConstructor
public class ItemService {
private final ItemRepository itemRepository;
private final ItemImgService itemImgService;
private final ItemImgRepository itemImgRepository;
public Long saveItem(ItemFormDto itemFormDto, List<MultipartFile> itemImgFileList) throws Exception{
//상품 등록
Item item = itemFormDto.createItem();
itemRepository.save(item);
//이미지 등록
for(int i=0;i<itemImgFileList.size();i++){
ItemImg itemImg = new ItemImg();
itemImg.setItem(item);
if(i == 0)
itemImg.setRepimgYn("Y");
else
itemImg.setRepimgYn("N");
itemImgService.saveItemImg(itemImg, itemImgFileList.get(i));
}
return item.getId();
}
@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;
}
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();
}
}
▹상품 등록 화면으로부터 전달 받은 상품 아이디를 이용하여 상품 엔티티를 조회한다.
Item item = itemRepository.findById(itemFormDto.getId())
▹상품 등록 화면으로부터 전달 받은 ItemFormDto를 통해 상품 엔티티를 업데이트한다.
item.updateItem(itemFormDto);
▹상품 이미지 아이디 리스트를 조회한다.
List<Long> itemImgIds = itemFormDto.getItemImgIds();
▹상품 이미지를 업데이트하기 위해서 updateItemImg() 메소드에 상품 이미지 아이디와 상품 이미지 파일 정보를 파라미터로 전달한다.
itemImgFileList.get(i));
상품을 수정하는 URL을 ItemController 클래스에 추가하자.
ItemController.java
package com.shop.shop.controller;
import com.shop.shop.dto.ItemFormDto;
import com.shop.shop.service.ItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.persistence.EntityNotFoundException;
import javax.validation.Valid;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class ItemController {
private final ItemService itemService;
@GetMapping(value = "/admin/item/new")
public String itemForm(Model model){
model.addAttribute("itemFormDto", new ItemFormDto());
return "item/itemForm";
}
@PostMapping(value = "/admin/item/new")
public String itemNew(@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:/";
}
@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";
}
@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.updateItem(itemFormDto, itemImgFileList);
} catch (Exception e){
model.addAttribute("errorMessage", "상품 수정 중 에러가 발생하였습니다.");
return "item/itemForm";
}
return "redirect:/";
}
}
▹상품 수정 로직을 호출한다.
try {
itemService.updateItem(itemFormDto, itemImgFileList);
상품 데이터를 수정 후 저장해보자.
개구리 사진 대신에 사자 사진을 넣어서 한 번 확인해봤다.
그러면 이렇게 기존에 있던 개구리 사진이 사라지고, 새로 업로드한 사자 사진이 보일 것이다.
'프레임워크 > Springboot' 카테고리의 다른 글
[Springboot] 등록 상품 메인 화면에서 보기 / 상품 상세 페이지 (0) | 2023.03.15 |
---|---|
[Springboot] 상품 관리하기 (2) | 2023.03.14 |
[Springboot] 상품 등록하기 (0) | 2023.03.12 |
[Springboot] 연관 관계 매핑 (0) | 2023.03.06 |
[Springboot] 스프링 시큐리티를 이용한 로그인/로그아웃 (0) | 2023.02.26 |