본문 바로가기
web/Bakery Shop Project

쇼핑몰 구현 9 - 상품 기능

by su0a 2024. 2. 23.

1. ItemRepository

@Repository
public interface ItemRepository extends JpaRepository<Item,Long> {
    //상품 생성 시 이름이 중복되는지 체크하기 위해
    Boolean existsByName(String name);

    //상품 검색 시 해당 이름을 포함한 모든 상품을 찾기 위해
    Page<Item> findAllByNameContains(String name, PageRequest pageRequest);

    //카테고리로 상품을 찾기 위해
    Page<Item> findAllByItemCategory(ItemCategory itemCategory,PageRequest pageRequest);

}

 

2. ItemService

@Service
@RequiredArgsConstructor
public class ItemService {
    private final ItemRepository itemRepository;
    private final UploadImageService uploadImageService;
    private final UploadImageRepository uploadImageRepository;
    private final LikeRepository likeRepository;
    private final OrderItemRepository orderItemRepository;
    
    //상품 생성 시 유효성 검사
    public BindingResult saveValid(ItemJoinRequest req, BindingResult bindingResult){
        System.out.println(req.getStock()+" "+req.getUploadImages());
        if(req.getName().isEmpty()){
            bindingResult.addError(new FieldError("req","name","상품명이 비어있습니다."));
        }else if(itemRepository.existsByName(req.getName())){
            bindingResult.addError(new FieldError("req","name","상품명이 중복됩니다."));
        }
        if(req.getPrice()==null){
            bindingResult.addError(new FieldError("req","price","가격은 필수입력사항 입니다."));
        }else if(req.getPrice()<=0){
            bindingResult.addError(new FieldError("req","price","가격은 0원 이상이어야 합니다."));
        }
        if(req.getDelivery_price()==null){
            bindingResult.addError(new FieldError("req","delivery_price","배송비는 필수입력사항 입니다."));
        }else if(req.getDelivery_price()<=0){
            bindingResult.addError(new FieldError("req","delivery_price","배송비는 0원 이상이어야 합니다."));
        }if(req.getStock()==null) {
            bindingResult.addError(new FieldError("req", "stock", "수량은 0개 이상이어야 합니다."));
        }else if(req.getStock()<=0) {
            bindingResult.addError(new FieldError("req", "stock", "수량은 0개 이상이어야 합니다."));
        }
        if(req.getUploadImages()==null) {
            bindingResult.addError(new FieldError("req", "uploadImages", "상품 이미지는 1개 이상이어야 합니다."));
        }else if(req.getUploadImages().isEmpty()) {
            bindingResult.addError(new FieldError("req", "uploadImages", "상품 이미지는 1개 이상이어야 합니다."));
        }

        return bindingResult;
    }


    //이미지 업로드 하기 위한 메소드
    @Transactional
    public Item updateItemImages(List<MultipartFile> multipartFiles,Long itemId) throws IOException{
        Item item = itemRepository.findById(itemId).get();
        for (MultipartFile image: multipartFiles) {
            UploadImage uploadImage = this.uploadImageService.saveImage(image, item);
            item.getUploadImages().add(uploadImage);
        }
        System.out.println("success");
        return item;
    }

    //상품 저장
    @Transactional
    public Item saveItem(ItemJoinRequest req) throws IOException {
        Item saveItem = itemRepository.save(req.toEntity());
        // 업로드된 이미지들을 저장
        for (MultipartFile file : req.getUploadImages()) {
            UploadImage uploadImage = this.uploadImageService.saveImage(file, saveItem);
            saveItem.getUploadImages().add(uploadImage);
        }
        return saveItem;
    }

    //아이디로 상품을 찾기위한 메소드
    public Item findItem(Long itemId){
        return itemRepository.findById(itemId).get();
    }
    
    //아이디로 상품 찾은 후 ItemDto로 변환 후 반환
    public ItemDto findById(Long itemId){
        Optional<Item> findItem = itemRepository.findById(itemId);

        //id에 해당하는 상품 없으면 null return
        if(findItem.isEmpty()){
            return null;
        }
        return ItemDto.of(findItem.get());
    }

    //모든 상품 조회
    public Page<Item> findItems(PageRequest pageRequest){
        Page<Item> allItems = itemRepository.findAll(pageRequest);
        return allItems;
    }

    //특정 name을 포함한 모든 상품 조회
    public Page<Item> findAllByItemName(String name,PageRequest pageRequest){
        if(name!=null) {
            return itemRepository.findAllByNameContains(name, pageRequest);
        } else{
            return itemRepository.findAll(pageRequest);
        }
    }
    
    //해당 카테고리에 속한 모든 상품 조회
    public Page<Item> findAllByItemCategory(ItemCategory itemCategory,PageRequest pageRequest){
        return itemRepository.findAllByItemCategory(itemCategory,pageRequest);
    }
    
    //위시리스트에 들어있는 상품들 조회
    public Page<Item> findAllWishlist(Authentication auth,PageRequest pageRequest){
        Page<Like> likes = likeRepository.findAllByMemberEmail(pageRequest,auth.getName());
        List<Item> likeItems = new ArrayList<>();
        for(Like like:likes){
            likeItems.add(like.getItem());
        }
        return new PageImpl<>(likeItems, pageRequest, likes.getTotalElements());
    }

    //상품 수정
    @Transactional
    public Item itemEdit(Long itemId,ItemDto itemDto) {
        System.out.println(itemId);
        Item item = itemRepository.findById(itemId).get();

        item.edit(itemDto.getPrice(),itemDto.getItemCategory(),itemDto.getStock(),itemDto.getItemTip(),itemDto.getSizeTip());
        return item;
    }

    //상품 삭제
    @Transactional
    public Boolean itemDelete(Long itemId) {
        if(orderItemRepository.existsByItemId(itemId)){
            System.out.println("itemDelete false");
            return false;
        }

        Item item = itemRepository.findById(itemId).orElseThrow(EntityNotFoundException::new);
        List<UploadImage> uploadImages = item.getUploadImages();
        for(UploadImage uploadImage:uploadImages){
            uploadImageRepository.delete(uploadImage);
        }
        itemRepository.delete(item);
        System.out.println("itemDelete true");
        return true;
    }
}

 

3. ItemController

@Controller
@RequiredArgsConstructor
@SessionAttributes("keyword")
@RequestMapping("/items")
public class ItemController {
    private final ItemService itemService;
    private final UploadImageService uploadImageService;
    private final LikeService likeService;
    @GetMapping(value={"","/"})
    public String itemListPage(Model model,
                                @RequestParam(required = false,defaultValue = "1") int page,
                                @RequestParam(name = "keyword", required = false) String keyword){

        PageRequest pageRequest = PageRequest.of(page - 1, 10, Sort.by("id").descending());
        System.out.println(keyword);
        model.addAttribute("items",itemService.findAllByItemName(keyword,pageRequest));
        return "items/list";
    }
    
    //특정 카테고리에 속한 상품 출력 페이지
    @GetMapping("/{category}")
    public String itemListPage(@PathVariable String category, Model model,
                                @RequestParam(required = false,defaultValue = "1") int page
                                ){
        ItemCategory itemCategory = ItemCategory.of(category);
        if(itemCategory==null){
            model.addAttribute("message","카테고리가 존재하지 않습니다.");
            model.addAttribute("nextUrl","/");
            return "printMessage";
        }

        PageRequest pageRequest = PageRequest.of(page - 1, 10, Sort.by("id").descending());
        model.addAttribute("items",itemService.findAllByItemCategory(itemCategory,pageRequest));
        model.addAttribute("category",category);
        return "items/list";
    }

    //상품 상세페이지
    @GetMapping("/{itemId}/detail")
    public String itemDetailPage(@PathVariable Long itemId, Model model,Authentication auth){
        if(auth!=null){
            model.addAttribute("likeCheck",likeService.checkLike(auth.getName(),itemId));
            model.addAttribute("loginUserLoginId",auth.getName());
        }
        ItemDto itemDto = itemService.findById(itemId);
        System.out.println(itemDto.getUploadImages().size());
        //id에 해당하는 게시글이 없거나 카테고리가 일치하지 않는경우
        if(itemDto==null){
            model.addAttribute("message","해당 게시글이 존재하지 않습니다.");
            model.addAttribute("nextUrl","/items");
            return "printMessage";
        }
        model.addAttribute("itemDto",itemDto);
        return "items/detail";
    }

    @GetMapping("/create")
    public String itemCreatePage(Model model){
        model.addAttribute("itemJoinRequest",new ItemJoinRequest());
        return "items/create";
    }

    @PostMapping("/create")
    public String itemCreate(@Valid @ModelAttribute ItemJoinRequest req, BindingResult bindingResult,Model model) throws IOException {
        if(itemService.saveValid(req,bindingResult).hasErrors()){
            return "items/create";
        }
        itemService.saveItem(req);
        model.addAttribute("message","상품이 등록되었습니다!");
        model.addAttribute("nextUrl","/items");
        return "printMessage";
    }
    
    @GetMapping("/{itemId}/edit")
    public String itemEditPage(@PathVariable Long itemId, Model model){
        ItemDto itemDto = itemService.findById(itemId);
        model.addAttribute("itemDto",itemDto);
        return "items/edit";
    }

    @PostMapping("/{itemId}/edit")
    public String itemEdit(@PathVariable Long itemId,@Valid @ModelAttribute ItemDto itemDto,Model model){

        itemService.itemEdit(itemId,itemDto);
        model.addAttribute("message","상품이 수정되었습니다!");
        model.addAttribute("nextUrl","/items/"+itemId+"/detail");
        return "printMessage";
    }

    @PostMapping("/{itemId}/delete")
    public String itemDelete(@PathVariable Long itemId,Model model){
        if(itemService.itemDelete(itemId)){
            model.addAttribute("message","상품이 삭제되었습니다!");
            model.addAttribute("nextUrl","/items");
        }
        else{
            model.addAttribute("message","주문된 상품은 삭제할 수 없습니다.");
            model.addAttribute("nextUrl","/items/"+itemId+"/detail");
        }
        return "printMessage";
    }
    
    //이미지 삭제시 호출되는 메서드
    @PostMapping("/deleteImage/{itemId}/{delImageId}")
    public String deleteImage(@PathVariable Long itemId,@PathVariable Long delImageId, Model model) throws IOException{
        UploadImage delImage = uploadImageService.findById(delImageId);
        uploadImageService.deleteImage(delImage);
        model.addAttribute("message","해당 이미지가 삭제되었습니다.");
        model.addAttribute("nextUrl","/items/"+itemId+"/edit");
        return "printMessage";
    }
    
    //이미지 등록시 호출되는 메서드
    @PostMapping("/uploadImages/{itemId}")
    public String updateImages(@PathVariable Long itemId, @RequestParam("uploadImages") MultipartFile[] files,Model model) throws IOException{
        List<MultipartFile> fileList = Arrays.asList(files);
        itemService.updateItemImages(fileList,itemId);
        ItemDto itemDto = itemService.findById(itemId);
        model.addAttribute("itemDto",itemDto);
        return "items/edit";
    }
    
    @ResponseBody
    @GetMapping("/images/{filename}")
    public Resource showImage(@PathVariable String filename) throws MalformedURLException {
        return new UrlResource("file:"+uploadImageService.getFullPath(filename));
    }

}

 

4. ItemJoinRequest

  • 상품 생성 시 사용되는 DTO
@Data
@NoArgsConstructor
public class ItemJoinRequest {
    private String name; //상품 이름
    private Integer price; //상품 가격
    private Integer delivery_price; //배송비
    private ItemCategory itemCategory; //상품 종류
    private Integer stock; //재고
    private String itemTip; //상품 설명
    private String sizeTip; //사이즈 설명
    private List<MultipartFile> uploadImages;
    public Item toEntity(){
        return Item.builder()
                .name(name)
                .price(price)
                .itemCategory(itemCategory)
                .itemTip(itemTip)
                .sizeTip(sizeTip)
                .stockQuantity(stock)
                .uploadImages(new ArrayList<>())
                .delivery_price(delivery_price)
                .build();
    }

}

 

5. ItemDto

  • 상품 조회 시 사용되는 DTO
@Data
@Builder
public class ItemDto {
    private Long id;
    private String name; //상품 이름
    private Integer price; //상품 가격
    private Integer delivery_price; //배송비
    private ItemCategory itemCategory; //상품 종류
    private String itemTip; //상품 설명
    private String sizeTip; //크기 설명
    private Integer stock; //재고
    private List<UploadImage> uploadImages;

    public static ItemDto of(Item item){
        ItemDto itemDto = ItemDto.builder()
                .id(item.getId())
                .name(item.getName())
                .price(item.getPrice())
                .delivery_price(item.getDelivery_price())
                .itemTip(item.getItemTip())
                .itemCategory(item.getItemCategory())
                .stock(item.getStockQuantity())
                .sizeTip(item.getSizeTip())
                .uploadImages(new ArrayList<>(item.getUploadImages()))
                .build();
        return itemDto;
    }
}