Sfoglia il codice sorgente

상품 대량 이미지 등록 개발중

eskim 5 anni fa
parent
commit
a97e57a093

+ 1 - 0
src/main/java/com/style24/persistence/domain/GoodsImg.java

@@ -20,6 +20,7 @@ public class GoodsImg extends TscBaseDomain {
 	private String sysImgNm;
 	private String defaultImgYn;
 	private String mouseoverImgYn;
+	private String extmallImgYn;
 	private String colorNm;
 	private String mode;
 	private int defaultImgOrd;

+ 14 - 0
src/main/java/com/style24/persistence/mybatis/shop/TssGoods.xml

@@ -1877,6 +1877,7 @@
 		     , SUBSTRING_INDEX(SYS_IMG_NM , '/', 2) AS SYS_IMG_URL
 		     , DEFAULT_IMG_YN
 		     , MOUSEOVER_IMG_YN
+		     , EXTMALL_IMG_YN
 		FROM   TB_GOODS_IMG
 		WHERE  GOODS_CD = #{goodsCd}
 		AND    COLOR_CD = #{colorCd}
@@ -1911,6 +1912,8 @@
 		     , DISP_ORD
 		     , SYS_IMG_NM
 		     , DEFAULT_IMG_YN
+		     , MOUSEOVER_IMG_YN
+		     , EXTMALL_IMG_YN
 		     , REG_NO
 		     , REG_DT
 		)
@@ -1920,6 +1923,8 @@
 		     , #{dispOrd}
 		     , #{sysImgNm}
 		     , #{defaultImgYn}
+		     , #{mouseoverImgYn}
+		     , #{extmallImgYn}
 		     , #{regNo}
 		     , NOW()
 		)
@@ -2574,6 +2579,15 @@
 		AND OPT_CD2 = #{optCd2}
 	</select>
 	
+	<!-- 상품옵션1 존재 여부 확인 -->
+	<select id="getGoodsOption1Count" parameterType="Option" resultType="int">
+		/* TssGoods.getGoodsOption1Count */
+		SELECT COUNT(*)
+		FROM TB_OPTION
+		WHERE  GOODS_CD = #{goodsCd}
+		AND OPT_CD1 = #{optCd1}
+	</select>
+	
 	<!-- 사은품 목록 -->
 	<select id="getFreeGoodsList" parameterType="GoodsSearch" resultType="FreeGoods">
 		/* TssGoods.getFreeGoodsList */

+ 13 - 3
src/main/java/com/style24/scm/biz/dao/TssGoodsDao.java

@@ -592,7 +592,7 @@ public interface TssGoodsDao {
 	 * @since 2020. 12. 28
 	 */
 	public void updateFreeGoods(FreeGoods freeGoods);
-	
+
 	/**
 	 * 상품 안전인증 조회
 	 *
@@ -602,7 +602,7 @@ public interface TssGoodsDao {
 	 * @since 2021. 05. 10
 	 */
 	GoodsSafeNo getGoodsDetailSafe(Goods goods);
-	
+
 	/**
 	 * 안전인증대상 상품 저장
 	 *
@@ -620,7 +620,7 @@ public interface TssGoodsDao {
 	 * @since 2021. 04. 27
 	 */
 	GoodsImg getGoodsModelInfo(GoodsImg goodsImg);
-	
+
 	/**
 	 * 상품 모델 정보 저장
 	 *
@@ -630,4 +630,14 @@ public interface TssGoodsDao {
 	 * @since 2021. 04. 27
 	 */
 	void saveGoodsModelInfo(GoodsImg goodsImg);
+
+	/**
+	 * 상품옵션1 존재 여부 확인
+	 *
+	 * @param
+	 * @return
+	 * @author eskim
+	 * @since 2021. 05. 16
+	 */
+	int getGoodsOption1Count(Option option);
 }

+ 61 - 19
src/main/java/com/style24/scm/biz/service/TssGoodsService.java

@@ -166,7 +166,7 @@ public class TssGoodsService {
 				for (GagaMap gagaMap : dataList) {
 					if (!StringUtils.isBlank(gagaMap.get("SYS_IMG_NM").toString())) {
 						gagaMap.set("SYS_IMG_NM", targetPath + '/' + gagaMap.get("SYS_IMG_NM").toString() + "?RS=60");
-					}else {
+					} else {
 						gagaMap.set("SYS_IMG_NM", env.getProperty("domain.uximage") + "/image/no.png");
 					}
 				}
@@ -178,7 +178,7 @@ public class TssGoodsService {
 			} catch (Exception e) {
 				throw new IllegalStateException(e);
 			}
-			
+
 		} else {
 			// 헤더 title 설정
 			String[] listTitles = {"상품코드", "업체명", "브랜드명", "상품명", "품목", "전시재고", "상품상태", "스타일년도",
@@ -332,6 +332,20 @@ public class TssGoodsService {
 		return resultGoods;
 	}
 
+	/**
+	 * 상품 상세 정보만
+	 *
+	 * @param goods
+	 * @return
+	 * @author eskim
+	 * @since 2021. 5. 16
+	 */
+	public Goods getGoodsInfo(Goods goods) {
+		// 상품기본정보
+		Goods resultGoods = goodsDao.getGoods(goods);
+		return resultGoods;
+	}
+
 	/**
 	 * 상품 상세 조회
 	 *
@@ -1124,6 +1138,22 @@ public class TssGoodsService {
 		}
 	}
 
+	/**
+	 * 상품이미지 저장 처리
+	 * 
+	 * @param goodsImgList - 상품이미지 목록
+	 * @throws
+	 * @author eskim
+	 * @since 2020. 12. 23
+	 */
+	@Transactional("shopTxnManager")
+	public void saveGoodsImageMassList(Collection<GoodsImg> goodsImgList) {
+		for (GoodsImg goodsImg : goodsImgList) {
+			goodsDao.deleteGoodsImage(goodsImg);
+			goodsDao.createGoodsImage(goodsImg);
+		}
+	}
+
 	/**
 	 * 상품등록로그 목록
 	 *
@@ -2351,44 +2381,43 @@ public class TssGoodsService {
 
 		//인증대상구분
 		if (StringUtils.isNotBlank(goodsMass.getCertTargetGb())) {
-			commonCode.setCdGb("G083"); 	
+			commonCode.setCdGb("G083");
 			commonCode.setCd(goodsMass.getCertTargetGb());
 			Collection<CommonCode> certTargetGbList = rendererService.getCommonCodeList(commonCode);
 			if (certTargetGbList == null || certTargetGbList.isEmpty()) {
 				goods.setGoodsRegMsg("인증대상 오류");
 				goods.setGoodsStat("10");
 				return goods;
-			}	
+			}
 			goods.setCertTargetGb(goodsMass.getCertTargetGb().trim());
 		}
-		
+
 		//인증형태구분
 		if (StringUtils.isNotBlank(goodsMass.getCertFormGb())) {
-			commonCode.setCdGb("G084"); 	
+			commonCode.setCdGb("G084");
 			commonCode.setCd(goodsMass.getCertFormGb());
 			Collection<CommonCode> certFormGbList = rendererService.getCommonCodeList(commonCode);
 			if (certFormGbList == null || certFormGbList.isEmpty()) {
 				goods.setGoodsRegMsg("인증형태 오류");
 				goods.setGoodsStat("10");
 				return goods;
-			}	
+			}
 			goods.setCertFormGb(goodsMass.getCertFormGb().trim());
 		}
-		
-		
+
 		//인증타입
 		if (StringUtils.isNotBlank(goodsMass.getCertType())) {
-			commonCode.setCdGb("G081"); 	
+			commonCode.setCdGb("G081");
 			commonCode.setCd(goodsMass.getCertType());
 			Collection<CommonCode> certTypeList = rendererService.getCommonCodeList(commonCode);
 			if (certTypeList == null || certTypeList.isEmpty()) {
 				goods.setGoodsRegMsg("인증타입 오류");
 				goods.setGoodsStat("10");
 				return goods;
-			}	
+			}
 			goods.setCertType(goodsMass.getCertType().trim());
 		}
-		
+
 		if (StringUtils.isNotBlank(goodsMass.getCertNum())) {
 			if (StringUtils.isBlank(goodsMass.getCertTargetGb()) ||
 				StringUtils.isBlank(goodsMass.getCertFormGb()) ||
@@ -2407,7 +2436,7 @@ public class TssGoodsService {
 		goods.setErpStockLinkYn("N"); // ERP재고연동여부
 		goods.setMainColorCd("XX"); // 무의미 데이터
 		goods.setTobeFormYn("N"); // 입점 신규 기본값
-		
+
 		return goods;
 	}
 
@@ -3525,7 +3554,7 @@ public class TssGoodsService {
 	public GoodsSafeNo getGoodsDetailSafe(Goods goods) {
 		return goodsDao.getGoodsDetailSafe(goods);
 	}
-	
+
 	/**
 	 * 안전인증번호 저장
 	 *
@@ -3541,7 +3570,7 @@ public class TssGoodsService {
 			goodsSafeNo.setUpdNo(TssSession.getInfo().getUserNo());
 			//인증대상
 			if ("G083_1".equals(goodsSafeNo.getCertTargetGb())) {
-				
+
 				//인증형태 (방송통신, 위해) or 인증타입 - 공급자적합성
 				if ("G084_4".equals(goodsSafeNo.getCertFormGb()) || "G084_5".equals(goodsSafeNo.getCertFormGb()) || "G081_3".equals(goodsSafeNo.getCertType())) {
 					goodsSafeNo.setCertDt("");
@@ -3550,7 +3579,7 @@ public class TssGoodsService {
 					goodsSafeNo.setCertDiv("");
 					goodsSafeNo.setCertOrganName("");
 					goodsDao.saveGoodsSafeNo(goodsSafeNo);
-				}else {
+				} else {
 					GagaMap result = safetyKoreaApi.getKoreaCertifyDetail(goodsSafeNo.getCertNum());
 					if (result != null || !StringUtil.isNullOrEmpty(result.get("certNum").toString())) {
 						goodsSafeNo.setCertDt(result.get("certDt").toString());
@@ -3558,11 +3587,11 @@ public class TssGoodsService {
 						goodsSafeNo.setCertDiv(result.get("certDiv").toString());
 						goodsSafeNo.setCertOrganName(result.get("certOrganName").toString());
 						goodsDao.saveGoodsSafeNo(goodsSafeNo);
-					}else {
+					} else {
 						throw new IllegalStateException(message.getMessage("FAIL_1001"));
 					}
 				}
-			}else {	//인증대상 그외 - 인증처리 안해도 됨
+			} else {	//인증대상 그외 - 인증처리 안해도 됨
 				goodsSafeNo.setCertDt("");
 //				goodsSafeNo.setCertNum("");
 				goodsSafeNo.setCertState("");
@@ -3702,7 +3731,7 @@ public class TssGoodsService {
 		goodsSafeNo.setCertFormGb(goods.getCertFormGb());
 		goodsSafeNo.setCertType(goods.getCertType());
 		goodsSafeNo.setCertNum(goods.getCertNum());
-		saveGoodsDetailCertNum(goodsSafeNo); 
+		saveGoodsDetailCertNum(goodsSafeNo);
 	}
 
 	/**
@@ -3729,4 +3758,17 @@ public class TssGoodsService {
 	public void saveGoodsModelInfo(GoodsImg goodsImg) {
 		goodsDao.saveGoodsModelInfo(goodsImg);
 	}
+
+	/**
+	 * 상품옵션1 존재 여부 확인
+	 *
+	 * @param
+	 * @return
+	 * @author eskim
+	 * @since 2021. 05. 16
+	 */
+	public int getGoodsOption1Count(Option option) {
+
+		return goodsDao.getGoodsOption1Count(option);
+	}
 }

+ 306 - 16
src/main/java/com/style24/scm/biz/web/TssGoodsController.java

@@ -1,11 +1,15 @@
 package com.style24.scm.biz.web;
 
+import java.awt.Image;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 
+import javax.imageio.ImageIO;
 import javax.servlet.http.HttpServletRequest;
+import javax.swing.ImageIcon;
 
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -24,6 +28,7 @@ import org.springframework.web.servlet.ModelAndView;
 
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.style24.core.support.env.TscConstants.GoodsType;
 import com.style24.core.support.message.TscMessageByLocale;
 import com.style24.persistence.TscPageRequest;
 import com.style24.persistence.domain.CommonCode;
@@ -213,7 +218,7 @@ public class TssGoodsController extends TssBaseController {
 				goodsSearch.setSearchGb("MASTER");
 			}
 		}
-		
+
 		goodsSearch.setRegNo(TssSession.getInfo().getUserNo()); // 엑셀조회시 로그인 사용자의 엑셀 상품조회시 사용
 		goodsSearch.setPageable(new TscPageRequest(goodsSearch.getPageNo() - 1, goodsSearch.getPageSize()));
 		goodsSearch.getPageable().setTotalCount(goodsService.getGoodsListCount(goodsSearch));
@@ -261,7 +266,7 @@ public class TssGoodsController extends TssBaseController {
 				} else {
 
 					// 택가/판매가 입력 여부 확인
-					Goods dataGoods = goodsService.getGoods(tmpGoods);
+					Goods dataGoods = goodsService.getGoodsInfo(tmpGoods);
 					if (dataGoods == null) {
 						returnGoods += tmpGoods.getGoodsCd() + ",";
 						continue;
@@ -388,7 +393,7 @@ public class TssGoodsController extends TssBaseController {
 	/**
 	 * 상품 상세 화면
 	 *
-	 * @param goodsCode - 상품코드
+	 * @param GoodsCd - 상품코드
 	 * @return
 	 * @author eskim
 	 * @since 2020. 10. 23
@@ -494,7 +499,7 @@ public class TssGoodsController extends TssBaseController {
 	public ModelAndView getGoodsDetailSizeStockForm(Goods goods) {
 
 		ModelAndView mav = new ModelAndView();
-		mav.addObject("goods", goodsService.getGoods(goods));
+		mav.addObject("goods", goodsService.getGoodsInfo(goods));
 		mav.addObject("goodsSizeList", goodsService.getGoodsSizeList(goods));
 		mav.addObject("goodsColorList", goodsService.getGoodsColorList(goods));
 		// 사용여부
@@ -606,14 +611,14 @@ public class TssGoodsController extends TssBaseController {
 	/**
 	 * 상품 이미지 보기 화면
 	 *
-	 * @param goodsCode - 상품코드
+	 * @param GoodsCd - 상품코드
 	 * @return
 	 * @author eskim
 	 * @since 2020. 12. 23
 	 */
 	@GetMapping("/image/form")
 	@ResponseBody
-	public ModelAndView imageMassForm(GoodsImg goodsImg) {
+	public ModelAndView imageForm(GoodsImg goodsImg) {
 		ModelAndView mav = new ModelAndView();
 
 		Collection<GoodsImg> goodsImgList = goodsService.getGoodsImgList(goodsImg);
@@ -629,11 +634,15 @@ public class TssGoodsController extends TssBaseController {
 				if (goodsImgInfo.getMouseoverImgYn().equals("Y")) {
 					mav.addObject("mouseoverImgOrd", goodsImgInfo.getDispOrd());
 				}
+				if (goodsImgInfo.getExtmallImgYn().equals("Y")) {
+					mav.addObject("extmallImgOrd", goodsImgInfo.getDispOrd());
+				}
 			}
 		} else { // 대표이미지와 마우스오버이미지가 없으면
 			mav.addObject("goodsImgList", new ArrayList<GoodsImg>());
 			mav.addObject("defaultImgOrd", "1");
 			mav.addObject("mouseoverImgOrd", "1");
+			mav.addObject("extmallImgOrd", "0");
 		}
 
 		GoodsImg goodsModelInfo = goodsService.getGoodsModelInfo(goodsImg);
@@ -688,7 +697,7 @@ public class TssGoodsController extends TssBaseController {
 			if (strBrandNo.isEmpty()) {
 				Goods goods = new Goods();
 				goods.setGoodsCd(goodsImg.getGoodsCd());
-				Goods goodsInfo = goodsService.getGoods(goods);
+				Goods goodsInfo = goodsService.getGoodsInfo(goods);
 				if (goodsInfo == null || goodsInfo.getGoodsCd().isEmpty()) {
 					throw new IllegalStateException(message.getMessage("FAIL_1001"));
 				}
@@ -698,11 +707,6 @@ public class TssGoodsController extends TssBaseController {
 			String brandDir = GagaStringUtil.getLPadding(strBrandNo, 10, "0");
 
 			if (goodsImg.getMode().equals("C")) { // 업로드 된 파일 rename 처리
-//				String newFilename = goodsImg.getGoodsCd()
-//						+ "_" + goodsImg.getColorCd()
-//						+ "_" + String.valueOf(index)
-//						+ "(" + GagaDateUtil.getTodayTime() + ")"
-//						+ "." + StringUtils.getFilenameExtension(goodsImg.getSysImgNm());
 				String newFilename = goodsImg.getSysImgNm();
 
 				//브랜드 폴더 확인
@@ -740,6 +744,15 @@ public class TssGoodsController extends TssBaseController {
 				goodsImg.setDispOrd(index++);
 				goodsImg.setOrgImgNm(GagaFileUtil.getConcatenationPath(brandYmdDir, newFile.getName()));
 				goodsImg.setSysImgNm(GagaFileUtil.getConcatenationPath(brandYmdDir, newFile.getName()));
+
+				Image srcImg = getImageObject(newFile);
+				int width = srcImg.getWidth(null);
+				int height = srcImg.getHeight(null);
+
+				if (width == height) {
+					// 외부몰연동용 이미지로 설정
+					goodsImg.setExtmallImgYn("Y");
+				}
 			} else {
 				goodsImg.setOrgImgNm(GagaFileUtil.getConcatenationPath(goodsImg.getSysImgUrl(), goodsImg.getSysImgNm()));
 				goodsImg.setSysImgNm(GagaFileUtil.getConcatenationPath(goodsImg.getSysImgUrl(), goodsImg.getSysImgNm()));
@@ -772,21 +785,298 @@ public class TssGoodsController extends TssBaseController {
 	/**
 	 * 상품 이미지 대량관리 화면
 	 *
-	 * @param goodsCode - 상품코드
+	 * @param GoodsCd - 상품코드
 	 * @return
 	 * @author eskim
 	 * @since 2020. 11. 09
 	 */
 	@GetMapping("/image/mass/form")
 	@ResponseBody
-	public ModelAndView imageMassForm(Goods goods) {
+	public ModelAndView imageMassForm() {
 		ModelAndView mav = new ModelAndView();
 
-		mav.addObject("params", goods);
 		mav.setViewName("goods/GoodsImageMassForm");
 		return mav;
 	}
 
+	/**
+	 * 상품 대량 썸네일 이미지 저장 처리
+	 * @param goodsImgList - 상품이미지 목록
+	 * @return
+	 * @throws Exception
+	 * @author eskim
+	 * @since 2021. 5. 16
+	 */
+	@RequestMapping(value = "/thumbnail/image/mass/save", method = RequestMethod.POST)
+	@ResponseBody
+	public GagaResponse saveGoodsThumbnailImageMassList(@RequestBody Collection<GoodsImg> goodsImgList) throws Exception {
+		if (goodsImgList == null || goodsImgList.isEmpty()) {
+			throw new IllegalStateException(message.getMessage("FAIL_1001"));
+		}
+
+		String dextUploadPath = env.getProperty("upload.dext.target.path");
+		String goodsTargetPath = env.getProperty("upload.goods.target.path");
+
+		//순서 재정렬된 파일 목록
+		Collection<GoodsImg> resultGoodsImgList = new ArrayList<GoodsImg>();
+		boolean procFlag = true;
+		int index = 0;
+
+		// 오류 파일 목록
+		Collection<File> errorFileList = new ArrayList<File>();
+		Collection<File> errorFileDextList = new ArrayList<File>();
+
+//		log.debug("SORT 전 : goodsImgList {}", goodsImgList);
+
+		String[] arrGoodsImg = new String[goodsImgList.size()];
+		String[] arrGoodsCd = new String[goodsImgList.size()];
+		;
+		index = 0;
+		for (GoodsImg goodsImg : goodsImgList) {
+
+			File massFile = new File(GagaFileUtil.getConcatenationPath(dextUploadPath, goodsImg.getSysImgNm()));
+			errorFileDextList.add(massFile);
+
+			int lastIdx = goodsImg.getSysImgNm().lastIndexOf('.');
+			String orgFile = goodsImg.getSysImgNm().substring(0, lastIdx);
+			String[] sysFileNmArr = orgFile.split("_");
+
+			// 촬영업체 - 자사상품
+			if ("G001_E000".equals(TssSession.getInfo().getRoleCd())) {
+				if (sysFileNmArr.length != 3) {
+					procFlag = false;
+					break;
+				}
+				// 입점억체 - 입점상품	
+			} else if ("G001_B000".equals(TssSession.getInfo().getRoleCd())) {
+				if (sysFileNmArr.length != 2) {
+					procFlag = false;
+					break;
+				}
+			} else {
+				deleteErrorFileList(errorFileDextList);
+				throw new IllegalStateException("권한이 없습니다.");
+			}
+
+			//for (int i = 0; i < sysFileNmArr.length; i++) log.debug("SORT 후 : sysFileNmArr[i] {}", sysFileNmArr[i]);
+			arrGoodsImg[index] = goodsImg.getSysImgNm();
+			arrGoodsCd[index] = sysFileNmArr[0];
+			index++;
+		}
+
+		if (!procFlag) {
+			String msg = "이미지파일 형식을 확인해주세요.(상품코드_컬러코드_순번.jpg)";
+			if ("G001_B000".equals(TssSession.getInfo().getRoleCd())) {
+				msg = "이미지파일 형식을 확인해주세요.(상품코드_순번.jpg)";
+			}
+			deleteErrorFileList(errorFileDextList);
+			throw new IllegalStateException(msg);
+		}
+
+		Arrays.sort(arrGoodsImg);
+
+		//for (int i = 0; i < arrGoodsImg.length; i++) log.debug("SORT 후 : arrGoodsImg[i] {}", arrGoodsImg[i]);
+
+		index = 0;
+		for (int i = 0; i < arrGoodsImg.length; i++) {
+			for (GoodsImg goodsImg : goodsImgList) {
+				if (arrGoodsImg[i].equals(goodsImg.getSysImgNm())) {
+					resultGoodsImgList.add(goodsImg);
+					index++;
+				}
+			}
+		}
+
+//		log.debug("SORT 후 : resultGoodsImgList {}", resultGoodsImgList);
+
+		index = 1;
+		errorFileList.clear();
+
+		String comGoodsCd = "";
+		String comGoodsColor = "";
+		String strBrandNo = "";
+		String brandDir = "";
+
+		// 1.업로드된 파일
+		for (GoodsImg goodsImg : resultGoodsImgList) {
+
+			int lastIdx = goodsImg.getSysImgNm().lastIndexOf('.');
+			String orgFile = goodsImg.getSysImgNm().substring(0, lastIdx);
+			String[] sysFileNmArr = orgFile.split("_");
+			String selfGoodsYn = "Y";
+			// 촬영업체
+			if ("G001_E000".equals(TssSession.getInfo().getRoleCd())) {
+				goodsImg.setGoodsCd(sysFileNmArr[0]);
+				goodsImg.setColorCd(sysFileNmArr[1]);
+				goodsImg.setDispOrd(index);
+			} else {
+				goodsImg.setGoodsCd(sysFileNmArr[0]);
+				goodsImg.setColorCd("XX");
+				goodsImg.setDispOrd(index);
+			}
+
+			if (!comGoodsCd.equals(goodsImg.getGoodsCd())) {
+				comGoodsCd = goodsImg.getGoodsCd();
+				comGoodsColor = goodsImg.getColorCd();
+				index = 1;
+
+				// 상품코드 확인
+				Goods goods = new Goods();
+				goods.setGoodsCd(comGoodsCd);
+				Goods goodsInfo = goodsService.getGoodsInfo(goods);
+				if (goodsInfo == null || goodsInfo.getGoodsCd().isEmpty()) {
+					deleteErrorFileList(errorFileList);
+					deleteErrorFileList(errorFileDextList);
+					throw new IllegalStateException(goodsImg.getSysImgNm() + "의" + comGoodsCd + " 상품코드가  존재하지 않습니다.");
+				}
+
+				strBrandNo = String.valueOf(goodsInfo.getBrandNo());
+				brandDir = GagaStringUtil.getLPadding(strBrandNo, 10, "0");
+				selfGoodsYn = goodsInfo.getSelfGoodsYn();
+				// 일반상품이고 자사상품인 경우 색상 확인
+				if (GoodsType.NORMAL.equals(goodsInfo.getGoodsType()) && "Y".equals(selfGoodsYn)) {
+					Option option = new Option();
+					option.setGoodsCd(comGoodsCd);
+					option.setOptCd1(comGoodsColor);
+					int opt1CdCnt = goodsService.getGoodsOption1Count(option);
+					if (opt1CdCnt <= 0) {
+						deleteErrorFileList(errorFileList);
+						deleteErrorFileList(errorFileDextList);
+						throw new IllegalStateException(goodsImg.getSysImgNm() + "의" + comGoodsCd + " 상품코드의  " + comGoodsColor + " 색상이  존재하지 않습니다.");
+					}
+				}
+			}
+
+			if (comGoodsCd.equals(goodsImg.getGoodsCd()) && !comGoodsColor.equals(goodsImg.getColorCd()) && "Y".equals(selfGoodsYn)) {
+
+				comGoodsColor = goodsImg.getColorCd();
+				index = 1;
+				Option option = new Option();
+				option.setGoodsCd(comGoodsCd);
+				option.setOptCd1(comGoodsColor);
+				int opt1CdCnt = goodsService.getGoodsOption1Count(option);
+				if (opt1CdCnt <= 0) {
+					deleteErrorFileList(errorFileList);
+					deleteErrorFileList(errorFileDextList);
+					throw new IllegalStateException(goodsImg.getSysImgNm() + "의" + comGoodsCd + " 상품코드의  " + comGoodsColor + " 색상이  존재하지 않습니다.");
+				}
+			}
+
+			String newFilename = goodsImg.getSysImgNm();
+
+			//브랜드 폴더 확인
+			String goodsUploadPath = GagaFileUtil.getConcatenationPath(goodsTargetPath, brandDir); // 브랜드 폴더
+			File brandPath = new File(goodsUploadPath);
+			if (!brandPath.exists()) {
+				brandPath.mkdir();
+			}
+
+			goodsUploadPath = GagaFileUtil.getConcatenationPath(goodsUploadPath, GagaDateUtil.getToday());		//브랜드+/+YYYYMMDD(UPLOAD 일 )
+			String brandYmdDir = GagaFileUtil.getConcatenationPath(brandDir, GagaDateUtil.getToday());	//디비 저장용
+
+			File uniqueFile = GagaFileUtil.getUniqueFile(new File(GagaFileUtil.getConcatenationPath(goodsUploadPath, newFilename)));
+			File newFile = new File(GagaFileUtil.getConcatenationPath(goodsUploadPath, uniqueFile.getName()));
+			//log.debug("newFile.getPath(): {}", newFile.getPath());
+
+			// resizing 처리 시 오류가 발생할 경우 삭제하기 위해 설정
+			errorFileList.add(newFile);
+
+			File oldFile = new File(GagaFileUtil.getConcatenationPath(dextUploadPath, goodsImg.getSysImgNm()));
+			//log.debug("oldFile.getPath(): {}", oldFile.getPath());
+
+			File path = new File(goodsUploadPath);
+			if (!path.exists()) {
+				//log.info("mkdir ={}", goodsUploadPath);
+				path.mkdir();
+			}
+
+			boolean copyFlag = GagaFileUtil.copyFile(oldFile, newFile);
+			if (copyFlag) {
+				//기존이미지 삭제
+				GagaFileUtil.deleteFile(oldFile.getPath());
+			}
+
+			goodsImg.setDispOrd(index);
+			goodsImg.setOrgImgNm(GagaFileUtil.getConcatenationPath(brandYmdDir, newFile.getName()));
+			goodsImg.setSysImgNm(GagaFileUtil.getConcatenationPath(brandYmdDir, newFile.getName()));
+			goodsImg.setDefaultImgYn("N");
+			goodsImg.setMouseoverImgYn("N");
+			goodsImg.setExtmallImgYn("N");
+			goodsImg.setRegNo(TssSession.getInfo().getUserNo());
+
+			// 첫번째 이미지이면 디폴트 이미지 설정
+			if (index == 1) {
+				goodsImg.setDefaultImgYn("Y");
+			}
+
+			// 두번째 이미지이면 마우스오버 이미지 설정
+			if (index == 2) {
+				goodsImg.setMouseoverImgYn("Y");
+			}
+
+			Image srcImg = getImageObject(newFile);
+			int width = srcImg.getWidth(null);
+			int height = srcImg.getHeight(null);
+
+			if (width == height) {
+				// 외부몰연동용 이미지로 설정
+				goodsImg.setExtmallImgYn("Y");
+			}
+			// 오류가 발생했으므로 
+//			deleteErrorFileList(errorFileList);
+//			deleteErrorFileList(errorFileDextList);
+//			throw new IllegalStateException(goodsImg.getSysImgNm() + " 상품이미지 파일의 크기(" + width + "*" + height + ")가 맞지 않습니다. (올바른 크기: 1079*1499, 750*1041, 1000*1000)");
+
+			index++;
+		}
+
+		//log.debug("resultGoodsImgList: {}", resultGoodsImgList);
+
+		// 상품이미지 저장 처리
+		goodsService.saveGoodsImageMassList(resultGoodsImgList);
+
+		return super.ok(message.getMessage("SUCC_0007"));
+	}
+
+	/*
+	 * 이미지 파일 확인
+	 */
+	public static Image getImageObject(File f) throws IOException {
+		Image objImg = null;
+		String suffix = f.getName().substring(f.getName().lastIndexOf('.') + 1).toLowerCase();
+//		if (suffix.equals("bmp") || suffix.equals("png") || suffix.equals("gif") || suffix.equals("jpg")) {
+		if (suffix.equals("png") || suffix.equals("gif") || suffix.equals("jpg")) {
+			objImg = ImageIO.read(f);
+		} else {
+			// ImageIcon을 활용해서 Image 생성
+			// 이렇게 하는 이유는 getScaledInstance를 통해 구한 이미지를
+			// PixelGrabber.grabPixels로 리사이즈 할 때 빠르게 처리하기 위함이다.
+			objImg = new ImageIcon(f.toURI().toURL()).getImage();
+		}
+
+		return objImg;
+	}
+
+	/**
+	 * 파일 삭제
+	 *
+	 * @param errorFileList
+	 * @author eskim
+	 * @since 2021. 5. 16
+	 */
+	private void deleteErrorFileList(Collection<File> errorFileList) {
+		// 파일 삭제
+		if (errorFileList != null && !errorFileList.isEmpty()) {
+			for (File errorFile : errorFileList) {
+				try {
+					GagaFileUtil.deleteFile(errorFile.getPath());
+				} catch (IOException e) {
+					// Nothing Do
+				}
+			}
+		}
+	}
+
 	/**
 	 * 상품 대량 등록 화면
 	 *
@@ -1300,7 +1590,7 @@ public class TssGoodsController extends TssBaseController {
 		goodsService.updateFreeGoods(freeGoods);
 		return super.ok(message.getMessage("SUCC_0001"));
 	}
-	
+
 	/**
 	 * 상품 안전인증 조회
 	 *

+ 3 - 4
src/main/webapp/WEB-INF/views/goods/GoodsImageForm.html

@@ -28,9 +28,7 @@
 				<form id="goodsImgForm" name="goodsImgForm" action="#" th:method="post">
 				<input type="hidden" name="goodsCd" th:value="${goodsImg.goodsCd}"/>
 				<input type="hidden" name="colorCd" th:value="${goodsImg.colorCd}"/>
-<!-- 				<input type="hidden" name="goodsCd" th:value="14373767"/>
-				<input type="hidden" name="colorCd" th:value="IV"/>
- -->				
+				<input type="hidden" name="extmallImgOrd" th:value="${extmallImgOrd}"/>
 					<ul class="notice">
 						<li>[업로드/수정] 버튼 클릭 하면 프론트에 바로 적용되므로 최종 확인 후 전송을 권장합니다.</li>
 						<li>이미지 미리보기 리스트는 <em>업로드 후</em> 확인 할 수 있습니다.</li>
@@ -155,7 +153,7 @@
 // 			}
 // 		}
 
-		console.log(result);
+		//console.log(result);
 
 		var dx = dx5.get(id);
 
@@ -194,6 +192,7 @@
 				params.sysImgUrl = item.url;
 				params.defaultImgYn = ($('#goodsImgForm input[name=defaultImgOrd]').val() == (i + 1)) ? 'Y' : 'N';
 				params.mouseoverImgYn = ($('#goodsImgForm input[name=mouseoverImgOrd]').val() == (i + 1)) ? 'Y' : 'N';
+				params.extmallImgYn = ($('#goodsImgForm input[name=extmallImgOrd]').val() == (i + 1)) ? 'Y' : 'N';
 				params.modelInfo = $('#goodsImgForm input[name=modelInfo]').val();
 				updatedData.push(params);
 			}

+ 206 - 0
src/main/webapp/WEB-INF/views/goods/GoodsImageMassForm.html

@@ -0,0 +1,206 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : GoodsImageMassForm.html
+ * @desc    : 상품 이미지 보기 화면(대량등록)
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2019 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2020.11.27   eskim       최초 작성
+ *******************************************************************************
+ -->
+	<div class="modalPopup" data-width="900" data-height="700">
+	<!-- PANELSTYLE -->
+		<div class="panelStyle">
+			<!-- TITLE -->
+			<div class="panelTitle">
+				<h2>상품 이미지 등록&nbsp;<button type="button" class="btn icn" onclick="fnOpenCommentPopup('comment')" ><i class="fa fa-cog" aria-hidden="true"></i></button></h2>
+				<button type="button" class="close" onclick="fnGoodsImgFormClose()"><i class="fa fa-times"></i></button>
+			</div>
+			<!-- //TITLE -->
+			<!-- CONTENT -->
+			<div class="panelContent">
+			<form id="goodsImgForm" name="goodsImgForm" action="#" th:method="post">
+				<ul class="notice">
+					<li><em>신규 상품이미지</em> 적용만 권장합니다. 개별 이미지 변경건은 상품상세에서 진행해 주세요.</li>
+					<li><em>상품 파일명 기준</em>의 첫번째 이미지파일이 <em>디폴트 이미지</em> , 두번째 이미지파일이 <em>마우스오버 이미지</em> 입니다. 확인해주세요!</li>
+					<li>상품이미지 업로드시 오류가 발생하면 <em>전체 삭제 처리</em> 후 파일 추가작업을 다시 해주세요.</li>
+					<li>자사 상품의 <em>셋트/딜 상품</em> 이미지 등록시 파일면의 색상코드는 <em>'XX'</em>로 생성하여 진행해 주세요.</li>
+				</ul>
+				<table class="frmStyle">
+					<colgroup>
+						<col/>
+					</colgroup>
+					<tr>
+						<th>이미지등록</th>
+						<td class="dexterArea">
+
+							<!-- 덱스터 테이블 영역 -->
+							<ul class="dexterTable">
+								<li class="dexterNo" id="dx5Index">
+									<!-- 덱스터 테이블 번호 -->
+									<!-- //덱스터 테이블 번호 -->
+								</li>
+								<li>
+								<!-- 덱스터 테이블 삽입 -->
+									<!-- 덱스터 테이블 삽입<br/>공간은 테이블 넓이에 따라 자동으로 넓어집니다.<br/>
+									(최소 넓이 : 350px로 설정됨)<br/> -->
+									<div id="dext5-container" style="width: 100%; height: 480px;"></div>
+								<!-- //덱스터 테이블 -->
+								<li>
+							</ul>
+							<!-- //덱스터 테이블 영역 -->
+						</td>
+					</tr>
+				</table>
+			</form>	
+			</div>
+			<!-- 버튼 배치 영역 -->
+			<ul class="panelBar marT10">
+				<li class="center">
+					<button type="button" class="btn btn-base btn-sm" id="btnAddFiles">파일 추가</button>
+					<button type="button" class="btn btn-default btn-sm" onclick="gagaDx5.deleteChooseFile();">선택 삭제</button>
+					<button type="button" class="btn btn-default btn-sm" onclick="gagaDx5.deleteAllFiles();">전체 삭제</button>
+					<button type="button" class="btn btn-info btn-sm" onclick="gagaDx5.moveFile(true);">위로 이동</button>
+					<button type="button" class="btn btn-info btn-sm" onclick="gagaDx5.moveFile(false);">아래로 이동</button>
+					<!-- <button type="button" class="btn btn-base btn-sm" onclick="gagaDx5.previewImage();">이미지 보기</button> -->
+					<button type="button" class="btn btn-base btn-sm" onclick="gagaDx5.uploadFiles();">업로드/수정</button>
+				</li>
+			</ul>
+			<!-- //버튼 배치 영역 -->
+		</div>
+</div>
+<script type="text/javascript" src="/dx5/dextuploadx5-configuration.js?v=2020122101"></script>
+<script type="text/javascript" src="/dx5/dextuploadx5.js?v=2020122101"></script>
+<script type="text/javascript" src="/ux/plugins/gaga/gaga.dx5.js?2020122101"></script>
+<script th:inline="javascript">
+/*<![CDATA[*/
+	
+	var goodsImgList = null;
+	
+	//--------------------------------------------------------------------------
+	// Dextupload X5 이벤트 Start
+	//--------------------------------------------------------------------------
+	// Dextupload X5 생성
+	gagaDx5.createDX5("dext5", "btnAddFiles", _goodsUrl, "goods");
+
+	// Dextupload X5 생성 후 호출되는 이벤트
+	var onDX5Created = function(id) {
+		var actionUrl = '/dext/files/upload/goods';
+		gagaDx5.onDX5Created(actionUrl, goodsImgList);
+	}
+
+	// Dextupload X5 에러 시 호출되는 이벤트
+	var onDX5Error = function(id, code, msg) {
+		mcxDialog.alert(id + " => " +  code + "\n" + msg);
+	}
+
+	// Dextupload X5 업로드 성공 시 호출되는 이벤트
+	var onDX5UploadCompleted = function(id) {
+		gagaDx5.uploadAfterProcess();
+	}
+
+	// Dextupload X5 이미지 등록이 완료된 후 호출되는 이벤트
+	var onDX5ItemsAdded = function(id, count) {
+		gagaDx5.resortDX5FileList();
+	}
+	//--------------------------------------------------------------------------
+	// Dextupload X5 이벤트 End
+	//--------------------------------------------------------------------------
+	
+	// 업로드 후처리. 반드시 구현해야 함. (gaga.dx5.js 파일에서 호출됨)
+	var fnUploadAfterProcess = function(id, result) {
+// 		if (typeof(result) != 'undefined') {
+// 			if (!gagajf.isNull(result.error.message)) {
+// 				gagaAlert.alert(result.error.message);
+// 				return;
+// 			}
+// 		}
+
+		//console.log(result);
+
+		var dx = dx5.get(id);
+
+		var updatedData = [];
+
+		// 삭제한 파일 설정
+		var deleteFiles = dx.getRemovedFiles();
+		if (deleteFiles.length > 0) {
+			$.each(deleteFiles, function(idx, item) {
+				var params = new Object();
+				params.mode = 'D';
+				params.orgImgNm = item.name;
+				params.sysImgNm = item.name;
+				updatedData.push(params);
+			});
+		}
+
+		// 업로드한 파일 및 순서 변경한 파일 설정
+		var totCnt = dx.getTotalItemCount();
+		if (totCnt > 0) {
+			for (var i = 0; i < totCnt; i++) {
+				var item = dx.getItemByIndex(i);
+
+				var params = new Object();
+				params.mode = (item.type == 'FILE') ? 'C' : '';
+				params.orgImgNm = item.name;
+				params.sysImgNm = item.name;
+				updatedData.push(params);
+			}
+		}
+
+		var jsonData = JSON.stringify(updatedData);
+		//console.log(jsonData);
+
+		gagajf.ajaxJsonSubmit('/goods/thumbnail/image/mass/save', jsonData, fnGoodsImgFormClose);
+	}
+	
+	//창종료
+	var fnGoodsImgFormClose = function(){
+		$('.dx5-pop-up').remove();
+		$('.dx5-pop-dn').remove();
+		$('.dx5-pop-pv').remove();
+		$('.dx5-pop-cp').remove();
+		$('.dx5-pop-ud').remove();
+		uifnPopupClose('popupGoodsMassImage');
+	}
+	
+	//안내팝업
+	var fnOpenCommentPopup = function(id) {
+		var str = '<div class="popupWrap"  id="'+id+'" style="z-index:30">';
+		str = str + '<div class="modalPopup" data-width="500">';
+		str = str + '<div class="panelStyle">';
+		str = str + '<div class="panelTitle"><button type="button" class="close" onclick="uifnPopupClose(\''+id+'\')"><i class="fa fa-times"></i></button></div>';
+		str = str + '<div class="panelContent">';
+		str = str + '<ul class="notice ">';
+		str = str + '<em><b>* 자사 상품 이미지 파일명</b></em>';
+		str = str + '<li><b>상품메인컷</b> : 상품코드_색상코드_<b>01</b>.jpg<em>(앞)</em>,상품코드_색상코드_<b>02</b>.jpg<em>(뒤)</em></li>';
+		str = str + '<li><b>상품모델컷</b> : 상품코드_색상코드_<b>M1</b>.jpg ~ 상품코드_색상코드_<b>M5</b>.jpg</li>';
+		str = str + '<li><b>상품상세컷</b> : 상품코드_색상코드_<b>D1</b>.jpg ~ 상품코드_색상코드_<b>D5</b>.jpg</li>';
+		str = str + '<li><b>상품소재컷</b> : 상품코드_색상코드_<b>S1</b>.jpg</li>';
+		str = str + '<li><b>상품라벨컷</b> : 상품코드_색상코드_<b>L1</b>.jpg, (상품코드_색상코드_<b>L2</b>.jpg)</li>';
+		str = str + '<br/>';
+		str = str + '<em><b>* 입점 상품 이미지 파일명</b></em>';
+		str = str + '<li><b>상품메인컷</b> : 상품코드_<b>01</b>.jpg<em>(앞)</em>,상품코드_<b>02</b>.jpg<em>(뒤)</em></li>';
+		str = str + '<li><b>상품모델컷</b> : 상품코드_<b>M1</b>.jpg ~ 상품코드_<b>M5</b>.jpg</li>';
+		str = str + '<li><b>상품상세컷</b> : 상품코드_<b>D1</b>.jpg ~ 상품코드_<b>D5</b>.jpg</li>';
+		str = str + '<li><b>상품소재컷</b> : 상품코드_<b>S1</b>.jpg</li>';
+		str = str + '<li><b>상품라벨컷</b> : 상품코드_<b>L1</b>.jpg, (상품코드_<b>L2</b>.jpg)</li>';
+		str = str + '</ul>';
+		str = str + '</div></div></div></div>';
+
+		if ($('#'+ id).length == 0) {
+			$('body').append(str);
+		}
+		uifnPopupOpen(id);
+		//$("#"+id).css({display:"block"});
+	}
+	
+/*]]>*/
+</script>
+</html>

+ 15 - 4
src/main/webapp/WEB-INF/views/goods/GoodsMassRegisterForm.html

@@ -28,10 +28,10 @@
 			<ul class="notice">
 				<li>상품을 대량으로 등록/수정하는 페이지입니다.</li>
 				<li>상품을 등록 할 경우 [승인대기] 상태이며, STYLE 관리자의 [승인완료] 상태 변경 후 FRONT애 노출이 가능합니다.</li>
-				<li><th:block th:if="${sessionInfo.roleCd == 'G001_B000'}"><em>입점업체 신규 상품등록시 배송비 정책을 선택하셔야 합니다. </em></th:block></li>
-				<li><th:block th:if="${sessionInfo.roleCd == 'G001_B000'}"><em>대량수정시의 옵션정보는 신규 옵션정보만 가능합니다</em></th:block></li>
-				<li><th:block th:if="${sessionInfo.roleCd == 'G001_E000'}"><em>촬영업체의 대량수정은 고시정보만 적용됩니다.</em></th:block></li>
-				<li><th:block th:if="${wmsSyncYn == 'N'}"><em><b>WMS연동여부가 [N]입니다.</b></em></th:block></li>
+				<li th:if="${sessionInfo.roleCd == 'G001_B000'}"><em>입점업체 신규 상품등록시 배송비 정책을 선택하셔야 합니다. </em></li>
+				<li th:if="${sessionInfo.roleCd == 'G001_B000'}"><em>대량수정시의 옵션정보는 신규 옵션정보만 가능합니다</em></li>
+				<li th:if="${sessionInfo.roleCd == 'G001_E000'}"><em>촬영업체의 대량수정은 고시정보만 적용됩니다.</em></li>
+				<li th:if="${wmsSyncYn == 'N'}"><em><b>WMS연동여부가 [N]입니다.</b></em></li>
 			</ul>
 			<ul class="panelBar">
 				<li class="center">
@@ -54,6 +54,12 @@
 					</span>
 				</li>
 			</ul>
+			<ul class="panelBar">	
+				<li class="center">
+					<input type="button" value="입점상품 이미지 대량 등록" class="btn btn-primary btn-lg" id="btnGoodsImageCreate"/>
+				</li>
+				
+			</ul>
 		</div>
 		<div class="panelStyle" >
 			<!-- 검색조건 영역 -->
@@ -354,6 +360,11 @@
 		$("#"+id).css({display:"block"});
 	}
 	
+	//상품이미지대량등록 클릭시
+	$('#btnGoodsImageCreate').on('click', function() {
+		cfnOpenModalPopup("/goods/image/mass/form", 'popupGoodsMassImage');
+	});
+	
 /*]]>*/
 </script>
 </html>