WEB JAVA SPRING/PROJECT

3.상품 등록하기

sshhhh 2023. 9. 12. 16:59

화면단

 

상품, 상품이미지

    @ManyToOne : itemimg의 입장에서 하나의 item에 여러개의 사진 가능
    @JoinColumn(name = "item_id") //fk
 

 

 

1.ItemImg 엔티티

package com.shop.entity;


import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

/**
 * 상품 이미지 엔티티
 */
@Entity
@Getter @Setter
@Table(name = "item_img")
public class ItemImg {


    @Id
    @Column(name="item_img_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String imgName; //이미지 파일명

    private String oriImgName; //원본 이미지 파일명

    private String imgUrl; //이미지 조회 경로

    private String repimgYn; //대표 이미지 여부

    @ManyToOne(fetch = FetchType.LAZY) //itemimg의 입장에서 하나의 item에 여러개의 사진 가능
    @JoinColumn(name = "item_id") //fk
    private Item item;


    //이미지 정보 업데이트
    public void updateItemImg(String oriImgName, String imgName, String imgUrl){
        this.oriImgName = oriImgName;
        this.imgName = imgName;
        this.imgUrl = imgUrl;
    }

}

 

 

 

 

2.ItemImgDto

/**
 *상품 저장 후 상품 이미지에 대한 데이터 전달
 */

package com.shop.dto;

import com.shop.entity.ItemImg;
import lombok.Getter;
import lombok.Setter;
import org.modelmapper.ModelMapper;


@Getter @Setter
public class ItemImgDto {


    private Long id;

    private String imgName;

    private String oriImgName;

    private String imgUrl;

    private String repImgYn; //대표상품

    private static ModelMapper modelMapper = new ModelMapper(); //멤버 변수로 modelMapper를 추가

    public static ItemImgDto of(ItemImg itemImg) {
        return modelMapper.map(itemImg,ItemImgDto.class);
    }
}

 

 

 

 

3.ItemImgFormDto

/**
 * 상품 데이터 정보 전달
 */

package com.shop.dto;

import com.shop.constant.ItemSellStatus;
import com.shop.entity.Item;
import lombok.Getter;
import lombok.Setter;
import org.modelmapper.ModelMapper;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;

@Getter @Setter
public class ItemFormDto {

    private Long id;

    @NotBlank(message = "상품명은 필수 입력 값입니다.")
    private String itemNm;

    @NotNull(message = "가격은 필수 입력 값입니다.")
    private Integer price;

    @NotBlank(message = "상품 상세는 필수 입력 값입니다.")
    private String itemDetail;

    @NotNull(message = "재고는 필수 입력 값입니다.")
    private Integer stockNumber;

    private ItemSellStatus itemSellStatus; // SELL, SOLD_OUT


    private List<ItemImgDto> itemImgDtoList = new ArrayList<>(); //상품 저장 후 수정할때 상품 이미지 정보 저장


    private List<Long> itemImgIds = new ArrayList<>(); //상품의 이미지 아이디 저장 (상품 등록 시 이미지x ,수정시 이미지o)


    private static ModelMapper modelMapper = new ModelMapper();

    //modelMapper를 이용하여 엔티티 객체와 DTO객체 간의 데이터를 복사하여 복사한 객체를 반환
    public Item createItem(){
        return modelMapper.map(this, Item.class);
    }

    public static ItemFormDto of(Item item){
        return modelMapper.map(item,ItemFormDto.class);
    }

}

 

 

 

 

4.ItemController

/**
 * 상품 등록 페이지로 이동
 */

@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";
    }

 

 

 

 

5.itemForm.html

 

script 부분

실패메세지

 

이미지 파일만 등록 가능하게


html

상품 이미지 등록
상품 이미지 수정
상품 아이디 유무 (저장 or 수정)

 

 

 

 

 

6.WebMvcConfigurer

/**
 * 업로드한 이미지 파일을 읽어올 경로 설정
 */

package com.shop.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Value("${uploadPath}") //properties에 설정한 uploadPath 프로퍼티 값 읽어옴
    String uploadPath;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/images/**") //uploadPath에 설정한 폴더를 기준으로 파일 읽어옴
                .addResourceLocations(uploadPath); //로컬 컴퓨터에 저장된 파일을 읽어올 root 경로 설정
    }

}

 

 

 

 

 

7.FileService

/**
 * 파일처리 (등록,삭제)
 */

package com.shop.service;

import lombok.extern.java.Log;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.FileOutputStream;
import java.util.UUID;

/**
 * 파일 처리
 */
@Service
@Log
public class FileService {

    //파일 업로드
    public String uploadFile(String uploadPath, String originalFileName, byte[] fileData) throws Exception{
        UUID uuid = UUID.randomUUID(); //Universally Unique Identifier 서로 다른 개체 구별하기위해 이름을 부여할 때 사용(파일명 중복 해결)
        String extension = originalFileName.substring(originalFileName.lastIndexOf("."));
        String savedFileName = uuid.toString() + extension; // + 확장자 =저장될 파일 이름
        String fileUploadFullUrl = uploadPath + "/" + savedFileName;
        FileOutputStream fos = new FileOutputStream(fileUploadFullUrl); //FileOutputStream클래스는 바이트 단위의 출력을 내보내는 클래스, 생성자로 파일이 저장될 위치와 파일의 이름을 넘겨 파일 출력 스트림 만든다.
        fos.write(fileData); //fileData를 파일 출력 스트림에 입력
        fos.close();
        return savedFileName; //업로드된 파일 이름 반환
    }

    //삭제
    public void deleteFile(String filePath) throws Exception{
        File deleteFile = new File(filePath); //파일이 저장된 경로를 이용해 파일 객체 생성
        if(deleteFile.exists()) {
            deleteFile.delete();
            log.info("파일을 삭제하였습니다.");
        } else {
            log.info("파일이 존재하지 않습니다.");
        }
    }

}

 

 

 

 

8.ItemImgRepository

/**
 * 상품 이미지 정보를 저장
 */

package com.shop.repository;

import com.shop.entity.ItemImg;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface ItemImgRepository extends JpaRepository<ItemImg,Long> {
    /*
    이미지가 잘 저장됐는지 테스트 코드 작성 위해...
    매개변수로 넘겨준 상품id를 가지며, 상품 이미지 아이디를 오름차순으로 가져옴
     */
    List<ItemImg> findByItemIdOrderByIdAsc(Long itemId);

}

 

 

 

 

 

9.ItemImgService

/**
 * 상품 이미지 업로드, 상품 이미지 정보 저장
 */

@Service
@RequiredArgsConstructor
@Transactional
public class ItemImgService {

    @Value("${itemImgLocation}") //properties파일에 등록한 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:실제로컬에 저장된 상품 이미지 파일 이름, oriImgName: 업로드했던 상품 이미지파일 원래 이름
            imgName = fileService.uploadFile(itemImgLocation, oriImgName,
                    itemImgFile.getBytes());
            imgUrl = "/images/item/" + imgName; //업로드 결과 로컬에 저장된 상품 이미지 파일 불러오는 경로
        }

        //상품 이미지 정보 저장
        itemImg.updateItemImg(oriImgName, imgName, imgUrl);
        itemImgRepository.save(itemImg);
     }
    
    }

 

 

 

 

 

10.ItemService


/**
 * 상품 등록
 */

@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();//상품 등록 폼으로부터 입력받은 데이터를 이용해 item객체 생성
        itemRepository.save(item); //상품 데이터 저장

        //이미지 등록
        for(int i=0;i<itemImgFileList.size();i++){
            ItemImg itemImg = new ItemImg();
            itemImg.setItem(item);

            if(i == 0) //첫번째 이미지일 경우
                itemImg.setRepimgYn("Y"); //대표 상품 이미지 여부를 Y로 세팅
            else
                itemImg.setRepimgYn("N");

            itemImgService.saveItemImg(itemImg, itemImgFileList.get(i)); //상품 이미지 정보 저장

        }

        return item.getId();
    }

 

 

 

 

 

11.ItemController

//상품 등록하는 url

@PostMapping(value = "/admin/item/new")
public String itemNew(@Valid ItemFormDto itemFormDto, BindingResult bindingResult,
                      Model model, @RequestParam("itemImgFile") List<MultipartFile> itemImgFileList) {
   /*- 검증하려는 객체 앞에 @Vaild 선언하고, bindingResult 객체 추가 후 검사후 결과 담는다.
         bindingResult.hasErrors()를 호출하여 에러가 있는지 검사
      - @RequestParam("가져올 데이터의 이름") [데이터타입] [가져온데이터를 담을 변수]
    */

    //상품 등록시 필수 값이 없다면 다시 상품 등록 페이지로 전환
    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:/";  //정상 등록 시 메인
}

 

 

 

이미지 등록하기 힘들다.