Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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 31
Tags
more
Archives
Today
Total
관리 메뉴

게으른 완벽주의자의 개발자 도전기

[shop]이미지와 함께 상품 등록하기 (enctype="multipart/form-data") 본문

Spring Boot

[shop]이미지와 함께 상품 등록하기 (enctype="multipart/form-data")

머리방울 2022. 10. 9. 16:55

1. html

<div class="col-5 ms-4">
<div class="row g-3">
<h4>상품등록</h4>

<form th:action="@{/admin/regItem}" method="post" enctype="multipart/form-data">

<div class="col-12 mb-3">
    <div class="row g-3">

      <div class="col mb-3">
          상품 이름
        <input type="text" class="form-control" placeholder="item_name" name="itemName">
      </div>
    </div>
    <div class="row g-3">
      <div class="col-6 mb-3">
      	상품 재고
        <input type="number" class="form-control" placeholder="item_stock" min="1" name="itemStock">
      </div>
      <div class="col-6">
     	 상품가격
        <input type="text" class="form-control" placeholder="item_price" name="itemPrice">
      </div>
    </div>
    <div class="row g-3">
    <div class="col-12 mb-3">
   	 카테코드
    <select class="form-select" name="cateCode" id="cateCode">
        <option selected>전체</option>
        <th:block th:each="statusList : ${statusList}"> 
              <option th:text ="${statusList.cateName}" th:value="${statusList.cateCode}"></option>
        </th:block>
    </select>
    </div>
    </div>
    <div class="row g-3">
        <div class="col-12 mb-3">
       	 Main IMG				<!-- 파일 여러개 선택 가능 multiple -->
        <input type="file" class="form-control" name="mainImg">
        </div>
    </div>
    <div class="row g-3">
        <div class="col-12 mb-3">
       		 Sub IMG
    		<input type="file" class="form-control" name="subImgs" multiple>
	    </div>
    </div> 
    <div class="row g-3">
        <div class="col-12">
        	상품 코맨트
        	 <textarea class="form-control" rows="3" name="itemComment"></textarea>
        </div>
    </div>

    <div class="row g-3" style="margin: 0 auto; text-align: center;">
        <div class="col-12">
            <button class="btn btn-outline-success" type="submit">
            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
                fill="currentColor" class="bi bi-cart-plus"viewBox="0 0 16 16">
            <path d="M9 5.5a.5.5 0 0 0-1 0V7H6.5a.5.5 0 0 0 0 1H8v1.5a.5.5 0 0 0 1 0V8h1.5a.5.5 0 0 0 0-1H9V5.5z" />
            <path d="M.5 1a.5.5 0 0 0 0 1h1.11l.401 1.607 1.498 7.985A.5.5 0 0 0 4 12h1a2 2 0 1 0 0 4 2 2 0 0 0 0-4h7a2 2 0 1 0 0 4 2 2 0 0 0 0-4h1a.5.5 0 0 0 .491-.408l1.5-8A.5.5 0 0 0 14.5 3H2.89l-.405-1.621A.5.5 0 0 0 2 1H.5zm3.915 10L3.102 4h10.796l-1.313 7h-8.17zM6 14a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm7 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
            </svg>	등록 </button>
        </div>
    </div>
  </div>
</form>
</div>
</div>
</div>

 

2. mapper

ITEM_CODE 가져오기
<select id="getItemCode" resultType="String">
SELECT 'ITEM_'||LPAD(NVL(MAX(TO_NUMBER(SUBSTR(ITEM_CODE, 6))),0)+1, 3, 0) 
FROM SHOP_ITEM
</select>


 상품등록
<insert id="regItem">

INSERT INTO SHOP_ITEM (
	  ITEM_CODE
	  , ITEM_NAME
	  , ITEM_STOCK
	  , ITEM_PRICE
	  , CATE_CODE
	  , ITEM_COMMENT
	)VALUES(
	    #{itemCode}	<!--select key 지웟으니 자료 넣어줘야 한다  -->
	  , #{itemName}
	  , #{itemStock}
	  , #{itemPrice}
	  , #{cateCode}
	  , #{itemComment}
	)

</insert>


이미지 등록 
<insert id="insertImgs">
INSERT INTO ITEM_IMG(
            IMG_CODE
            , ORIGIN_NAME
            , ATTACHED_NAME
            , IS_MAIN
            , ITEM_CODE 
            )
        <!-- itemVO에 list<ImgVO> imgList에 이미지 파일 데이터 다 넣었음 
        itemVO.getImgList(); getter가 호출된다. -->
        <foreach collection="imgList" item="img" separator="UNION ALL" index="i">
        SELECT 
            (SELECT 'IMG_'||LPAD(NVL(MAX(TO_NUMBER(SUBSTR(IMG_CODE, 5))) ,0) +1 + #{i}, 3, 0) FROM ITEM_IMG)
            , #{img.originName}
            , #{img.attachedName}
            , #{img.isMain}
            , #{img.itemCode}
        FROM DUAL
        </foreach>
</insert>
@Getter
@Setter
@ToString
public class ItemVO {

	private String itemCode;
	private String itemName;
	private int itemPrice;
	private String itemComment;
	private String regDate;
	private int itemStock;
	private String cateCode;
	private String itemStatus;
	
	//association
	private CateVO cateInfo;
	
	private List<ImgVO> imgList;
}

 

아이템 코드조회
@Override
public String getItemCode() {
    return sqlSession.selectOne("adminMapper.getItemCode");
}


상품등록(트렌젝션처리)
@Transactional(rollbackFor = Exception.class)
@Override
public void regItem(ItemVO itemVO) {

    sqlSession.insert("adminMapper.regItem", itemVO);
    sqlSession.insert("adminMapper.insertImgs", itemVO);

}

 

3. 사진 업로드 관련 메소드 만들기

public class UploadFileUtil {
//파일이 첨부될 경로 + "\\" 추가하기
private static final String UPLOAD_PATH = "D:\\자바관련자료\\dev\\workspaceSTS\\Shop\\src\\main\\resources\\static\\image\\";

//파일 첨부
public static ImgVO uploadFile(MultipartFile mainImg) {
    //여기서 선언하여 return 시 사용가능하도록 만듦
    String fileName = null;		//첨부 파일명
    String originFileName = null;	//원본 파일명

    //실제 첨부파일이 있을 때만 첨부파일 기능 실행. 첨부파일 없다면 빈문자로 들어옴
    if(!mainImg.isEmpty()) {
        //첨부파일 기능 (첨부하려는 원본 파일명)
        originFileName =	mainImg.getOriginalFilename();

        //랜덤 문자 만들기(파일명 중복방지)
        String uuid = UUID.randomUUID().toString();

        //원본파일명에서 확장자(.jpg)만 가져오기
        String extension = originFileName.substring(originFileName.lastIndexOf(".")); //"apple.jpg".substring(3) -> "le.jpg"
        //indexOf("매개변수") 매개변수에 들어온 문자가 몇번째에 위치하는지 숫자로 알려줌
        //lastIndexOf("매개변수") 중복된 문자 중 가장 마지막꺼 위치 알려줌

        //첨부될 파일명 생성
        fileName = uuid + extension;

        try {
            //파일 객체 생성 (파일경로 + 파일명)
            File file = new File(UPLOAD_PATH + fileName);

            //파일 업로드
            mainImg.transferTo(file);
        } catch (Exception e) {
            e.printStackTrace();
        }			
    }

    //원본파일명 첨부파일명 둘다 가져가야 함 ImgVO
    //리턴해야 하는 데이터 저장 위한 객체
    ImgVO imgVO = new ImgVO();

    imgVO.setAttachedName(fileName);	//첨부파일명
    imgVO.setOriginName(originFileName);	//원본파일명
    imgVO.setIsMain("Y");

    return imgVO;
}

//다중 파일 첨부
public static List<ImgVO> multiUploadFile(List<MultipartFile> subImgs) {

    List<ImgVO> list = new ArrayList<>();

    //첨부된 파일의 개수만큼 첨부 할 것
    for(MultipartFile subImg :subImgs) {
        ImgVO vo =	uploadFile(subImg);		//uploadFile() 자체가 위에서 만든 메소드 불러온것
        //메소드의 리턴값이 imgVO값으로 되기 때문에 list에 담는다.
        vo.setIsMain("N");
        list.add(vo);
    }


    return list;
  }
}

4. controller

@PostMapping("/regItem")
public String regItem(ItemVO itemVO, MultipartFile mainImg
  	  		, List<MultipartFile> subImgs) {

    //이미지 파일 첨부(메인이미지 첨부파일 하나)
    //원본파일명, 첨부파일명, IS_MAIN
    ImgVO uploadInfo = UploadFileUtil.uploadFile(mainImg);	

    //다중이미지파일 첨부 (서브이미지)
    //원본파일명, 첨부파일명, IS_MAIN
    List<ImgVO> uploadList = UploadFileUtil.multiUploadFile(subImgs);

    //메인과 서브 이미지의 원본파일명, 첨부파일명, ismain 값 집어 넣음
    uploadList.add(uploadInfo);

    //item_code 상품과 이미지 둘다 아이템코드가 동일해야 한다.
    //다음에 들어갈 item_code 조회하고(별도로 분리) 조회한 아이템코드로 insert 진행
    String getItemCode = adminService.getItemCode();
    itemVO.setItemCode(getItemCode); 


    //이미지 정보를 INSERT하기 위한 데이터를 가진 UPLOADLIST에 
    //조회한 ITEM_CODE값도 추가해 준다.
    for(ImgVO vo :uploadList) {
        vo.setItemCode(getItemCode);
    }
    //itemVO의 List<ImgVO> imgList에 전체 이미지 데이터 다 넣겠다
    itemVO.setImgList(uploadList);


    //상품 정보 insert + 이미지 정보 insert
    itemVO.setItemStatus(ItemStatus.ON_SALE.toString());
    adminService.regItem(itemVO);


    return "redirect:/admin/main";
}

Enum을 활용하기 (ItemStatus)

우리는 ItemStatus의 default 값을 ON_SALE로 주기로 하였고, 필요에 따라 SOLD_OUT을 쓰고자 한다.

그래서 ItemStatus의 값을 세팅할 때 Enum에서 정의한 ON_SALE, SOLD_OUT 중에서

ON_SALE을 toString() 하고자 한다. 

itemVO.setItemStatus(ItemStatus.ON_SALE.toString());