관리 메뉴

거니의 velog

(9) 도서 쇼핑몰 만들기 9 본문

Java_Spring mini project 쇼핑몰

(9) 도서 쇼핑몰 만들기 9

Unlimited00 2023. 11. 27. 13:35

10. 상품 관리 기능 구현하기

* 어떤 쇼핑몰이건 관리자 권한이 따로 있기 마련이다. 관리자는 보통 admin으로 로그인하며 모든 기능에 대해 CRUD 권한을 가진다.

* 아래 표에 쇼핑몰 관리자의 주요 기능을 정리했다.

< 관리자 기능 >

기능 세부 기능
상품 관리 상품정보등록
상품정보조회
상품정보수정
상품정보삭제
주문 관리 주문조회
주문수정
주문취소
회원 관리 회원정보조회
회원정보수정
회원정보삭제(회원탈퇴)

* 다음은 관리자로 로그인했을 때 표시되는 메인 화면이다. 왼쪽 메뉴를 보면 관리자의 주요 기능이 표시되어 있다.


(1) 상품 정보 등록하기

* 관리자의 주요 업무는 새 상품을 등록하는 것이다. 다음은 상품 정보가 저장될 테이블로, 상품과 상품 관련 이미지 정보는 상품이미지정보 테이블에 따로 저장한다.

* 여기서 상품 목차를 저장하는 컬럼의 타입은 2000자 이상을 저장할 수 있는 CLOB 타입으로 선언한다.

* CLOB 타입이란?

- 오라클에서는 문자열을 저장하는 컬럼을 varchar2 타입으로 지정해서 사용한다. 그런데 varchar2로 지정한 컬럼의
  최대 문자열 저장 길이는 2000자(4000바이트)이다. 즉, 2000자 이상의 문자열로 이루어진 정보는 저장할 수 없다.
  그래서 오라클에서는 텍스트, 이미지, 비디오, 사운드 같이 구조화되지 않은 대형 데이터를 저장하기 위해 CLOB
  (Large Object) 타입을 새로 도입했다. 그중 문자의 대형 객체를 저장하는 타입이 바로 CLOB이다.

* 아래 표에는 새 상품 등록 시 goods_status 컬럼의 여러 가지 값이다.

< goods_status 컬럼의 여러 가지 값 >

상품분류 값 설명
bestseller 베스트셀러
steadyseller 스테디셀러
newbook 신간
on_sale 판매중
buy_out 품절
out_of_print 절판

* 그럼 상품정보 테이블에 직접 상품을 등록해 보자.

* 먼저 상품 번호와 상품 이미지 번호로 사용될 시퀀스를 각각 생성한다(미리 생성했다면 생략 가능하다).

1. 새 상품 정보를 등록하는 데 필요한 매퍼 파일 admin_goods.xml을 준비한다.

2. admin_goods.xml을 다음과 같이 작성한다.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
	PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.admin.goods">

	<resultMap id="goodsResult" type="goodsVO">
		<result property="goods_id" column="goods_id" />
		<result property="goods_title" column="goods_title" />
		<result property="goods_writer" column="goods_writer" />
		<result property="goods_price" column="goods_price" />
		<result property="goods_publisher" column="goods_publisher" />
		
		<result property="goods_status" column="goods_status" />
		<result property="goods_sales_price" column="goods_sales_price" />
		<result property="goods_published_date" column="goods_published_date" />
		<result property="goods_total_page" column="goods_total_page" />
		<result property="goods_isbn" column="goods_isbn" />
		<result property="goods_delivery_price" column="goods_delivery_price" />
		<result property="goods_delivery_date" column="goods_delivery_date" />
		
		<result property="goods_fileName" column="fileName" />
		<result property="goods_sort" column="goods_sort" />
		<result property="goods_writer_intro" column="goods_writer_intro" />
		<result property="goods_intro" column="goods_intro" />
		<!-- goods_contents_order 컬럼의 타입은 CLOB이다. -->
		<result property="goods_contents_order" column="goods_contents_order" javaType="java.lang.String" jdbcType="CLOB"  />
	</resultMap>	

	<resultMap id="imageResult" type="ImageFileVO">
	   <result property="goods_id" column="goods_id" />
	   <result property="fileName" column="fileName" />
	   <result property="reg_id" column="reg_id" />
	   <result property="image_id" column="image_id" />
	   <result property="fileType" column="fileType" />
	</resultMap>
	
	<resultMap id="orderGoodsResult" type="OrderVO">
		<result property="order_id" column="order_id" />
		<result property="member_id" column="member_id" />
		<result property="goods_id" column="goods_id" />
		<result property="goods_title" column="goods_title" />
		<result property="goods_sales_price" column="goods_sales_price" />
		<result property="order_total_price" column="order_total_price" />
		<result property="order_goods_qty" column="order_goods_qty" />
		
		<result property="orderer_name" column="orderer_name" />
		<result property="receiver_name" column="receiver_name" />
		<result property="receiver_hp1" column="receiver_hp1" />
		<result property="receiver_hp2" column="receiver_hp2" />
		<result property="receiver_hp3" column="receiver_hp3" />
		
		<result property="receiver_tel1" column="receiver_tel1" />
		<result property="receiver_tel2" column="receiver_tel2" />
		<result property="receiver_tel3" column="receiver_tel3" />
		<result property="delivery_address" column="delivery_address" />
		<result property="delivery_message" column="delivery_message" />
		
		<result property="delivery_method" column="delivery_method" />
		<result property="gift_wrapping" column="gift_wrapping" />
		<result property="pay_method" column="pay_method" />
		<result property="card_com_name" column="card_com_name" />
		<result property="card_pay_month" column="card_pay_month" />
		
		<result property="pay_orderer_hp_num" column="pay_orderer_hp_num" />
		<result property="pay_order_time" column="pay_order_time" />
		<result property="delivery_state" column="delivery_state" />
		<result property="final_total_price" column="final_total_price" />
		<result property="goods_qty" column="goods_qty" />
		
		<result property="goods_fileName" column="goods_fileName" />
	</resultMap>
	
	<insert id="insertNewGoods" parameterType="java.util.Map">
	
		<!-- 새 상품을 추가하기 전에 시퀀스에서 상품 번호를 먼저 가져온다. -->
		<selectKey resultType="String" keyProperty="goods_id" order="BEFORE">
	    	select seq_goods_id.nextval from dual
	    </selectKey>
	    
	    <![CDATA[
		   insert into t_shopping_goods(
						                goods_id, 
						                goods_sort,
					                    goods_title,
					                    goods_writer,
					                    goods_publisher,
										goods_price,
										goods_sales_price,
										goods_point,
										goods_published_date,
										goods_total_page,
										goods_isbn,
										goods_delivery_price,
										goods_delivery_date,
										goods_status,
										goods_writer_intro,
										goods_intro,
										goods_publisher_comment,
										goods_recommendation,
			              goods_contents_order)
					  			values(
					  			      #{goods_id},
					  			      #{goods_sort},
					  			      #{goods_title},
					  			      #{goods_writer},
					  			     
					  			      #{goods_publisher },
					  			      #{goods_price},
					  			      #{goods_sales_price},
					  			      #{goods_point},
					  			      #{goods_published_date},
					  			      
					  			      #{goods_total_page},
					  			      #{goods_isbn },
					  			      #{goods_delivery_price },
					  			      #{goods_delivery_date },
					  			      #{goods_status },
					  			      #{goods_writer_intro},
											
									      #{goods_intro},
					  			      #{goods_publisher_comment },
					  			      #{goods_recommendation },	
					  			      #{goods_contents_order:VARCHAR}
					 			 )
		]]>
		<!-- #{goods_id} : 시퀀스에서 가져온 상품 번호를 추가한다. -->
		<!-- #{goods_contents_order:VARCHAR} : CLOB 타입으로 데이터 입력 시 VARCHAR로 지정ㅎ나다. -->
		
	</insert> 
		<insert id="insertGoodsImageFile" parameterType="imageFileVO">
		
		<!-- 시퀀스에서 상품 이미지 번호를 미리 가져온다. -->
		<selectKey resultType="int" keyProperty="image_id" order="BEFORE">
	    	select seq_image_id.nextval from dual
	    </selectKey>
	    
	    <![CDATA[
		   insert into t_goods_detail_image (image_id,
		                                     goods_id,
											 fileName,
											 fileType,
											 reg_id)
				   					values(#{image_id},
			   					 			 #{goods_id},
			   							 	 #{fileName},
			   								 #{fileType},
			   								 #{reg_id} )
		]]>
	</insert> <!-- 새 상품일 경우 첨부한 상품 이미지 정보를 저장한다. -->
	
	<select id="selectNewGoodsList" resultMap="goodsResult"   parameterType="java.util.Map"  >
	    <![CDATA[
		  select * from (
			   select rowNum as recNum,
			   		  goods_id,
			          goods_title,
			          goods_writer,
			          goods_publisher,
			          goods_sales_price,
			          to_char(goods_creDate,'YYYY-MM-DD')  as goods_creDate,
			          to_char(goods_published_date,'YYYY-MM-DD') as goods_published_date
			       from (
			             select  goods_id,
			             		 goods_title,
			             		 goods_writer,
			             		 goods_publisher,
			             		 goods_sales_price,
			             		 goods_creDate,
			             		 goods_published_date
			              from t_shopping_goods 
			                where  to_char(goods_creDate,'YYYY-MM-DD')  between #{beginDate} and #{endDate}
			               order by goods_creDate desc
					    )
				)							
			where				
		recNum between (#{section}-1)*100+ (#{pageNum}-1)*10+1 and (#{section}-1)*100+(#{pageNum})*10				        
    	]]>
	</select>
	
	<select id="selectOrderGoodsList" resultMap="orderGoodsResult"   parameterType="java.util.Map"  >
		  select * from (
			    select rowNum as recNum,t.*
			       from (
			              select  *  from t_shopping_order 
			              where to_char(pay_order_time,'yyyy-mm-dd')  between #{beginDate} and #{endDate}
			                <if test="search_type=='orderer_id'">
			                  AND orderer_id=#{search_word}
			                </if>
			                <if test="search_type=='orderer_name'">
			                  AND orderer_name=#{search_word}
			                </if>
			                <if test="search_type=='orderer_hp_num'">
			                   AND pay_orderer_hp_num=#{search_word} 
			                </if>
			              order by PAY_ORDER_TIME desc
					    ) t
				)							
			where				
		recNum between (#{section}-1)*100+ (#{pageNum}-1)*10+1 and (#{section}-1)*100+(#{pageNum})*10				        
	</select>
	
	<select id="selectGoodsDetail" resultMap="goodsResult"   parameterType="String"  >
	    <![CDATA[
		     select g.*,to_char(g.goods_published_date,'YYYY-MM-DD') as goods_published_date, d.fileName from t_shopping_goods g, t_goods_detail_image d
	        where g.goods_id=d.goods_id
	        and d.filetype='main_image'
	        and g.goods_id=#{goods_id}
	        order by g.goods_id
    	]]>
	</select>
	
	<select id="selectGoodsImageFileList" resultMap="imageResult"   parameterType="String"  >
	    <![CDATA[
		    	select * from  t_goods_detail_image 
		    	where  
			    goods_id=#{goods_id}
			    order by image_id asc
    	]]>
	</select>	
	
	<update id="updateGoodsInfo" parameterType="java.util.HashMap" >
	   update t_shopping_goods
	    <set> 
	      <if test=" goods_sort!='' and goods_sort!=null">
	        goods_sort=#{goods_sort},
	      </if>
	      <if test=" goods_title!='' and goods_title!=null">
	        goods_title=#{goods_title},
	      </if>
	      <if test=" goods_writer!='' and goods_writer!=null">
	        goods_writer=#{goods_writer},
	      </if>
	      <if test=" goods_publisher!='' and goods_publisher!=null">
	        goods_publisher=#{goods_publisher},
	      </if>
	      <if test=" goods_price!='' and goods_price!=null">
	        goods_price=#{goods_price},
	      </if>
	      <if test=" goods_published_date!='' and goods_published_date!=null">
	        goods_published_date=#{goods_published_date},
	      </if>
	      <if test=" goods_sales_price!='' and goods_sales_price!=null">
	        goods_sales_price=#{goods_sales_price},
	      </if>
	      <if test=" goods_point!='' and goods_point!=null">
	        goods_point=#{goods_point},
	      </if>
	      <if test=" goods_page_total!='' and goods_page_total!=null">
	        goods_page_total=#{goods_page_total},
	      </if>
	      <if test=" goods_isbn!='' and goods_isbn!=null">
	        goods_isbn=#{goods_isbn},
	      </if>
	      <if test=" goods_delivery_price!='' and goods_delivery_price!=null">
	        goods_delivery_price=#{goods_delivery_price},
	      </if>
	      <if test=" goods_delivery_date!='' and goods_delivery_date!=null">
	        goods_delivery_date=#{goods_delivery_date},
	      </if>
	      <if test=" goods_status!='' and goods_status!=null">
	        goods_status=#{goods_status},
	      </if>
	      <if test=" goods_writer_intro!='' and goods_writer_intro!=null">
	        goods_writer_intro=#{goods_writer_intro},
	      </if>
	      <if test=" goods_intro!='' and goods_intro!=null">
	        goods_intro=#{goods_intro},
	      </if>
	      <if test=" publisher_comment!='' and publisher_comment!=null">
	        publisher_comment=#{publisher_comment},
	      </if>
	      <if test=" recommendation!='' and recommendation!=null">
	        recommendation=#{recommendation},
	      </if>
	      <if test=" goods_contents_order!='' and goods_contents_order!=null">
	        goods_contents_order=#{goods_contents_order:VARCHAR}
	      </if>
	     </set>
	    where 
	    goods_id=#{goods_id}
	
	</update>	
	
	<update id="updateGoodsImage" parameterType="imageFileVO">
		update t_goods_detail_image
		set fileName=#{fileName}
		where	 
		goods_id=#{goods_id} and image_id=#{image_id}
	</update>
	
	<delete id="deleteGoodsImage" parameterType="String">
	  delete from t_goods_detail_image
	  where image_id=#{image_id}
	</delete>
	
	<update id="updateOrderGoods" parameterType="java.util.HashMap" >
	   update t_shopping_order
	    <set> 
	      <if test=" delivery_state!='' and delivery_state!=null">
	        delivery_state=#{delivery_state},
	      </if>
	      <if test=" delivery_address!='' and delivery_address!=null">
	        delivery_address=#{delivery_address},
	      </if>
	    </set>
	    where 
	    order_id=#{order_id}
	</update>	
		
</mapper>

3. 상품 정보 등록을 실제로 구현할 자바 클래스는 다음과 같다.

4. 새 상품은 상품 등록창에서 상품 정보와 상품 메인 이미지, 상품 상세 이미지를 첨부하여 전송한다. 따라서 이미지 파일을 전송할 때는 해당 이미지가 메인 이미지인지 상세 이미지인지 구분해서 전송해야 한다. 자바 클래스를 각각 다음과 같이 작성한다.

[BaseController.java]

package com.bookshop01.common.base;

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;

import com.bookshop01.goods.vo.ImageFileVO;

public abstract class BaseController {
	private static final String CURR_IMAGE_REPO_PATH = "C:\\shopping\\file_repo";

	protected List<ImageFileVO> upload(MultipartHttpServletRequest multipartRequest) throws Exception {
		
		List<ImageFileVO> fileList = new ArrayList<ImageFileVO>(); // 파일 정보를 저장할 fileList를 선언한다.
		Iterator<String> fileNames = multipartRequest.getFileNames();
		
		while (fileNames.hasNext()) {
			ImageFileVO imageFileVO = new ImageFileVO();
			String fileName = fileNames.next();
			imageFileVO.setFileType(fileName);
			MultipartFile mFile = multipartRequest.getFile(fileName);
			String originalFileName = mFile.getOriginalFilename();
			imageFileVO.setFileName(originalFileName);
			fileList.add(imageFileVO);

			File file = new File(CURR_IMAGE_REPO_PATH + "\\" + fileName);
			if (mFile.getSize() != 0) { // File Null Check
				if (!file.exists()) { // 경로상에 파일이 존재하지 않을 경우
					if (file.getParentFile().mkdirs()) { // 경로에 해당하는 디렉토리들을 생성
						file.createNewFile(); // 이후 파일 생성
					}
				}
				mFile.transferTo(new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + originalFileName)); // 임시로 저장된
			}
		} // 상품 등록 창에서 전송된 파일들의 정보를 fileList에 저장한다.
		
		return fileList;
		
	}

	private void deleteFile(String fileName) {
		
		File file = new File(CURR_IMAGE_REPO_PATH + "\\" + fileName);
		
		try {
			file.delete();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	@RequestMapping(value = "/*.do", method = { RequestMethod.POST, RequestMethod.GET })
	protected ModelAndView viewForm(HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		
		String viewName = (String) request.getAttribute("viewName");
		ModelAndView mav = new ModelAndView(viewName);
		return mav;
		
	}

	protected String calcSearchPeriod(String fixedSearchPeriod) {
		
		String beginDate = null;
		String endDate = null;
		String endYear = null;
		String endMonth = null;
		String endDay = null;
		String beginYear = null;
		String beginMonth = null;
		String beginDay = null;
		DecimalFormat df = new DecimalFormat("00");
		Calendar cal = Calendar.getInstance();

		endYear = Integer.toString(cal.get(Calendar.YEAR));
		endMonth = df.format(cal.get(Calendar.MONTH) + 1);
		endDay = df.format(cal.get(Calendar.DATE));
		endDate = endYear + "-" + endMonth + "-" + endDay;

		if (fixedSearchPeriod == null) {
			cal.add(cal.MONTH, -4);
		} else if (fixedSearchPeriod.equals("one_week")) {
			cal.add(Calendar.DAY_OF_YEAR, -7);
		} else if (fixedSearchPeriod.equals("two_week")) {
			cal.add(Calendar.DAY_OF_YEAR, -14);
		} else if (fixedSearchPeriod.equals("one_month")) {
			cal.add(cal.MONTH, -1);
		} else if (fixedSearchPeriod.equals("two_month")) {
			cal.add(cal.MONTH, -2);
		} else if (fixedSearchPeriod.equals("three_month")) {
			cal.add(cal.MONTH, -3);
		} else if (fixedSearchPeriod.equals("four_month")) {
			cal.add(cal.MONTH, -4);
		}

		beginYear = Integer.toString(cal.get(Calendar.YEAR));
		beginMonth = df.format(cal.get(Calendar.MONTH) + 1);
		beginDay = df.format(cal.get(Calendar.DATE));
		beginDate = beginYear + "-" + beginMonth + "-" + beginDay;

		return beginDate + "," + endDate;
		
	}

}

[AdminGoodsControllerImpl.java]

package com.bookshop01.admin.goods.controller;

import java.io.File;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import com.bookshop01.admin.goods.service.AdminGoodsService;
import com.bookshop01.common.base.BaseController;
import com.bookshop01.goods.vo.GoodsVO;
import com.bookshop01.goods.vo.ImageFileVO;
import com.bookshop01.member.vo.MemberVO;

@Controller("adminGoodsController")
@RequestMapping(value = "/admin/goods")
public class AdminGoodsControllerImpl extends BaseController implements AdminGoodsController {
	
	private static final String CURR_IMAGE_REPO_PATH = "C:\\shopping\\file_repo";
	
	@Autowired
	private AdminGoodsService adminGoodsService;

	@RequestMapping(value = "/adminGoodsMain.do", method = { RequestMethod.POST, RequestMethod.GET })
	public ModelAndView adminGoodsMain(@RequestParam Map<String, String> dateMap, 
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		String viewName = (String) request.getAttribute("viewName");
		ModelAndView mav = new ModelAndView(viewName);
		HttpSession session = request.getSession();
		session = request.getSession();
		session.setAttribute("side_menu", "admin_mode"); // 마이페이지 사이드 메뉴로 설정한다.

		String fixedSearchPeriod = dateMap.get("fixedSearchPeriod");
		String section = dateMap.get("section");
		String pageNum = dateMap.get("pageNum");
		String beginDate = null, endDate = null;

		String[] tempDate = calcSearchPeriod(fixedSearchPeriod).split(",");
		beginDate = tempDate[0];
		endDate = tempDate[1];
		dateMap.put("beginDate", beginDate);
		dateMap.put("endDate", endDate);

		Map<String, Object> condMap = new HashMap<String, Object>();
		if (section == null) {
			section = "1";
		}
		condMap.put("section", section);
		if (pageNum == null) {
			pageNum = "1";
		}
		condMap.put("pageNum", pageNum);
		condMap.put("beginDate", beginDate);
		condMap.put("endDate", endDate);
		List<GoodsVO> newGoodsList = adminGoodsService.listNewGoods(condMap);
		mav.addObject("newGoodsList", newGoodsList);

		String beginDate1[] = beginDate.split("-");
		String endDate2[] = endDate.split("-");
		mav.addObject("beginYear", beginDate1[0]);
		mav.addObject("beginMonth", beginDate1[1]);
		mav.addObject("beginDay", beginDate1[2]);
		mav.addObject("endYear", endDate2[0]);
		mav.addObject("endMonth", endDate2[1]);
		mav.addObject("endDay", endDate2[2]);

		mav.addObject("section", section);
		mav.addObject("pageNum", pageNum);
		return mav;

	}

	@RequestMapping(value = "/addNewGoods.do", method = { RequestMethod.POST })
	public ResponseEntity addNewGoods(MultipartHttpServletRequest multipartRequest, 
			HttpServletResponse response)
			throws Exception {
		
		multipartRequest.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=UTF-8");
		String imageFileName = null;

		Map newGoodsMap = new HashMap();
		Enumeration enu = multipartRequest.getParameterNames();
		while (enu.hasMoreElements()) {
			String name = (String) enu.nextElement();
			String value = multipartRequest.getParameter(name);
			newGoodsMap.put(name, value);
		} // 상품 정보를 가져와 Map에 저장한다.

		HttpSession session = multipartRequest.getSession();
		MemberVO memberVO = (MemberVO) session.getAttribute("memberInfo");
		String reg_id = memberVO.getMember_id(); // 로그인 ID를 가져온다.
		List<ImageFileVO> imageFileList = upload(multipartRequest); // 첨부한 이미지 정보를 가져온다.
		if (imageFileList != null && imageFileList.size() != 0) {
			for (ImageFileVO imageFileVO : imageFileList) {
				imageFileVO.setReg_id(reg_id);
			}
			newGoodsMap.put("imageFileList", imageFileList);
		} // 이미지 정보에 상품 관리자 ID를 속성으로 추가한다.

		String message = null;
		ResponseEntity resEntity = null;
		HttpHeaders responseHeaders = new HttpHeaders();
		responseHeaders.add("Content-Type", "text/html; charset=utf-8");
		try {
			
			int goods_id = adminGoodsService.addNewGoods(newGoodsMap); // 상품 정보와 이미지 정보를 각 테이블에 추가한다.
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					File destDir = new File(CURR_IMAGE_REPO_PATH + "\\" + goods_id);
					FileUtils.moveFileToDirectory(srcFile, destDir, true);
				}
			} // 업로드한 이미지를 상품번호 폴더에 저장한다.
			message = "<script>";
			message += " alert('새상품을 추가했습니다.');";
			message += " location.href='" + multipartRequest.getContextPath() + "/admin/goods/addNewGoodsForm.do';";
			message += ("</script>");
			
		} catch (Exception e) {
			
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					srcFile.delete();
				}
			}

			message = "<script>";
			message += " alert('오류가 발생했습니다. 다시 시도해 주세요');";
			message += " location.href='" + multipartRequest.getContextPath() + "/admin/goods/addNewGoodsForm.do';";
			message += ("</script>");
			e.printStackTrace();
			
		}
		
		resEntity = new ResponseEntity(message, responseHeaders, HttpStatus.OK);
		return resEntity;
		
	}

	@RequestMapping(value = "/modifyGoodsForm.do", method = { RequestMethod.GET, RequestMethod.POST })
	public ModelAndView modifyGoodsForm(@RequestParam("goods_id") int goods_id, 
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		String viewName = (String) request.getAttribute("viewName");
		ModelAndView mav = new ModelAndView(viewName);

		Map goodsMap = adminGoodsService.goodsDetail(goods_id);
		mav.addObject("goodsMap", goodsMap);

		return mav;
		
	}

	@RequestMapping(value = "/modifyGoodsInfo.do", method = { RequestMethod.POST })
	public ResponseEntity modifyGoodsInfo(@RequestParam("goods_id") String goods_id,
			@RequestParam("attribute") String attribute, @RequestParam("value") String value,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		// System.out.println("modifyGoodsInfo");

		Map<String, String> goodsMap = new HashMap<String, String>();
		goodsMap.put("goods_id", goods_id);
		goodsMap.put(attribute, value);
		adminGoodsService.modifyGoodsInfo(goodsMap);

		String message = null;
		ResponseEntity resEntity = null;
		HttpHeaders responseHeaders = new HttpHeaders();
		message = "mod_success";
		resEntity = new ResponseEntity(message, responseHeaders, HttpStatus.OK);
		return resEntity;
		
	}

	@RequestMapping(value = "/modifyGoodsImageInfo.do", method = { RequestMethod.POST })
	public void modifyGoodsImageInfo(MultipartHttpServletRequest multipartRequest, 
			HttpServletResponse response)
			throws Exception {
		
		System.out.println("modifyGoodsImageInfo");
		multipartRequest.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		String imageFileName = null;

		Map goodsMap = new HashMap();
		Enumeration enu = multipartRequest.getParameterNames();
		while (enu.hasMoreElements()) {
			String name = (String) enu.nextElement();
			String value = multipartRequest.getParameter(name);
			goodsMap.put(name, value);
		}

		HttpSession session = multipartRequest.getSession();
		MemberVO memberVO = (MemberVO) session.getAttribute("memberInfo");
		String reg_id = memberVO.getMember_id();

		List<ImageFileVO> imageFileList = null;
		int goods_id = 0;
		int image_id = 0;
		try {
			imageFileList = upload(multipartRequest);
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					goods_id = Integer.parseInt((String) goodsMap.get("goods_id"));
					image_id = Integer.parseInt((String) goodsMap.get("image_id"));
					imageFileVO.setGoods_id(goods_id);
					imageFileVO.setImage_id(image_id);
					imageFileVO.setReg_id(reg_id);
				}

				adminGoodsService.modifyGoodsImage(imageFileList);
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					File destDir = new File(CURR_IMAGE_REPO_PATH + "\\" + goods_id);
					FileUtils.moveFileToDirectory(srcFile, destDir, true);
				}
			}
		} catch (Exception e) {
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					srcFile.delete();
				}
			}
			e.printStackTrace();
		}

	}

	@Override
	@RequestMapping(value = "/addNewGoodsImage.do", method = { RequestMethod.POST })
	public void addNewGoodsImage(MultipartHttpServletRequest multipartRequest, 
			HttpServletResponse response)
			throws Exception {
		
		System.out.println("addNewGoodsImage");
		multipartRequest.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		String imageFileName = null;

		Map goodsMap = new HashMap();
		Enumeration enu = multipartRequest.getParameterNames();
		while (enu.hasMoreElements()) {
			String name = (String) enu.nextElement();
			String value = multipartRequest.getParameter(name);
			goodsMap.put(name, value);
		}

		HttpSession session = multipartRequest.getSession();
		MemberVO memberVO = (MemberVO) session.getAttribute("memberInfo");
		String reg_id = memberVO.getMember_id();

		List<ImageFileVO> imageFileList = null;
		int goods_id = 0;
		try {
			imageFileList = upload(multipartRequest);
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					goods_id = Integer.parseInt((String) goodsMap.get("goods_id"));
					imageFileVO.setGoods_id(goods_id);
					imageFileVO.setReg_id(reg_id);
				}

				adminGoodsService.addNewGoodsImage(imageFileList);
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					File destDir = new File(CURR_IMAGE_REPO_PATH + "\\" + goods_id);
					FileUtils.moveFileToDirectory(srcFile, destDir, true);
				}
			}
		} catch (Exception e) {
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					srcFile.delete();
				}
			}
			e.printStackTrace();
		}
	}

	@Override
	@RequestMapping(value = "/removeGoodsImage.do", method = { RequestMethod.POST })
	public void removeGoodsImage(@RequestParam("goods_id") int goods_id, 
			@RequestParam("image_id") int image_id,
			@RequestParam("imageFileName") String imageFileName, 
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		adminGoodsService.removeGoodsImage(image_id);
		try {
			File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + goods_id + "\\" + imageFileName);
			srcFile.delete();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

}

[AdminGoodsServiceImpl.java]

package com.bookshop01.admin.goods.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.bookshop01.admin.goods.dao.AdminGoodsDAO;
import com.bookshop01.goods.vo.GoodsVO;
import com.bookshop01.goods.vo.ImageFileVO;
import com.bookshop01.order.vo.OrderVO;

@Service("adminGoodsService")
@Transactional(propagation = Propagation.REQUIRED)
public class AdminGoodsServiceImpl implements AdminGoodsService {
	
	@Autowired
	private AdminGoodsDAO adminGoodsDAO;

	@Override
	public int addNewGoods(Map newGoodsMap) throws Exception {
		int goods_id = adminGoodsDAO.insertNewGoods(newGoodsMap); // 상품 정보를 테이블에 추가한다.
		ArrayList<ImageFileVO> imageFileList = (ArrayList) newGoodsMap.get("imageFileList");
		for (ImageFileVO imageFileVO : imageFileList) {
			imageFileVO.setGoods_id(goods_id);
		} // 각 이미지 정보에 상품 번호를 설정한다.
		adminGoodsDAO.insertGoodsImageFile(imageFileList); // 이미지 정보를 이미지 테이블에 추가한다.
		return goods_id;
	}

	@Override
	public List<GoodsVO> listNewGoods(Map condMap) throws Exception {
		return adminGoodsDAO.selectNewGoodsList(condMap);
	}

	@Override
	public Map goodsDetail(int goods_id) throws Exception {
		Map goodsMap = new HashMap();
		GoodsVO goodsVO = adminGoodsDAO.selectGoodsDetail(goods_id);
		List imageFileList = adminGoodsDAO.selectGoodsImageFileList(goods_id);
		goodsMap.put("goods", goodsVO);
		goodsMap.put("imageFileList", imageFileList);
		return goodsMap;
	}

	@Override
	public List goodsImageFile(int goods_id) throws Exception {
		List imageList = adminGoodsDAO.selectGoodsImageFileList(goods_id);
		return imageList;
	}

	@Override
	public void modifyGoodsInfo(Map goodsMap) throws Exception {
		adminGoodsDAO.updateGoodsInfo(goodsMap);
	}

	@Override
	public void modifyGoodsImage(List<ImageFileVO> imageFileList) throws Exception {
		adminGoodsDAO.updateGoodsImage(imageFileList);
	}

	@Override
	public List<OrderVO> listOrderGoods(Map condMap) throws Exception {
		return adminGoodsDAO.selectOrderGoodsList(condMap);
	}

	@Override
	public void modifyOrderGoods(Map orderMap) throws Exception {
		adminGoodsDAO.updateOrderGoods(orderMap);
	}

	@Override
	public void removeGoodsImage(int image_id) throws Exception {
		adminGoodsDAO.deleteGoodsImage(image_id);
	}

	@Override
	public void addNewGoodsImage(List imageFileList) throws Exception {
		adminGoodsDAO.insertGoodsImageFile(imageFileList);
	}

}

[AdminGoodsDAOImpl.java]

package com.bookshop01.admin.goods.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;

import com.bookshop01.goods.vo.GoodsVO;
import com.bookshop01.goods.vo.ImageFileVO;
import com.bookshop01.order.vo.OrderVO;

@Repository("adminGoodsDAO")
public class AdminGoodsDAOImpl implements AdminGoodsDAO {
	
	@Autowired
	private SqlSession sqlSession;

	@Override
	public int insertNewGoods(Map newGoodsMap) throws DataAccessException {
		sqlSession.insert("mapper.admin.goods.insertNewGoods", newGoodsMap); // 상품 정보를 추가한다.
		return Integer.parseInt((String) newGoodsMap.get("goods_id"));
	}

	@Override
	public void insertGoodsImageFile(List fileList) throws DataAccessException {
		for (int i = 0; i < fileList.size(); i++) {
			ImageFileVO imageFileVO = (ImageFileVO) fileList.get(i);
			sqlSession.insert("mapper.admin.goods.insertGoodsImageFile", imageFileVO); // 상품 이미지 정보를 추가한다.
		}
	}

	@Override
	public List<GoodsVO> selectNewGoodsList(Map condMap) throws DataAccessException {
		ArrayList<GoodsVO> goodsList = (ArrayList) sqlSession.selectList("mapper.admin.goods.selectNewGoodsList", condMap);
		return goodsList;
	}

	@Override
	public GoodsVO selectGoodsDetail(int goods_id) throws DataAccessException {
		GoodsVO goodsBean = new GoodsVO();
		goodsBean = (GoodsVO) sqlSession.selectOne("mapper.admin.goods.selectGoodsDetail", goods_id);
		return goodsBean;
	}

	@Override
	public List selectGoodsImageFileList(int goods_id) throws DataAccessException {
		List imageList = new ArrayList();
		imageList = (List) sqlSession.selectList("mapper.admin.goods.selectGoodsImageFileList", goods_id);
		return imageList;
	}

	@Override
	public void updateGoodsInfo(Map goodsMap) throws DataAccessException {
		sqlSession.update("mapper.admin.goods.updateGoodsInfo", goodsMap);
	}

	@Override
	public void deleteGoodsImage(int image_id) throws DataAccessException {
		sqlSession.delete("mapper.admin.goods.deleteGoodsImage", image_id);
	}

	@Override
	public void deleteGoodsImage(List fileList) throws DataAccessException {
		int image_id;
		for (int i = 0; i < fileList.size(); i++) {
			ImageFileVO bean = (ImageFileVO) fileList.get(i);
			image_id = bean.getImage_id();
			sqlSession.delete("mapper.admin.goods.deleteGoodsImage", image_id);
		}
	}

	@Override
	public List<OrderVO> selectOrderGoodsList(Map condMap) throws DataAccessException {
		List<OrderVO> orderGoodsList = (ArrayList) sqlSession.selectList("mapper.admin.selectOrderGoodsList", condMap);
		return orderGoodsList;
	}

	@Override
	public void updateOrderGoods(Map orderMap) throws DataAccessException {
		sqlSession.update("mapper.admin.goods.updateOrderGoods", orderMap);

	}

	@Override
	public void updateGoodsImage(List<ImageFileVO> imageFileList) throws DataAccessException {
		for (int i = 0; i < imageFileList.size(); i++) {
			ImageFileVO imageFileVO = imageFileList.get(i);
			sqlSession.update("mapper.admin.goods.updateGoodsImage", imageFileVO);
		}
	}

}

5. 이제 JSP로 구현할 차례이다. 다음과 같이 addNewGoodsForm.jsp를 준비한다.

6. 상품 이미지를 여러 개 첨부할 경우 첫 번째 파일 업로드의 name 속성 값을 main_image로 설정한다. 그러면 테이블에 저장되는 file_type 속성이 main_image 로 저장된다. 그 외의 파일들은 detail_image로 저장된다.

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8"
	isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>

<meta charset="utf-8">

<head>
    <script type="text/javascript">
        var cnt = 0; // 상세 이미지의 첨부 순서를 나타낸다.

        function fn_addFile() {
            if (cnt == 0) {
            	// 첫 번째 파일 업로드는 메인 이미지를 첨부하므로 name 속성을 main_image로 설정한다.
                $("#d_file").append("<br>" + "<input  type='file' name='main_image' id='f_main_image' />");
            } else {
            	// 그 외의 이미지들은 name 속성의 값을 detail_image+cnt로 설정한다.
                $("#d_file").append("<br>" + "<input  type='file' name='detail_image" + cnt + "' />");
            }

            cnt++;
        }

        function fn_add_new_goods(obj) {
            fileName = $('#f_main_image').val();
            if (fileName != null && fileName != undefined) {
                obj.submit();
            } else {
                alert("메인 이미지는 반드시 첨부해야 합니다.");
                return;
            }

        }
    </script>
</head>

<BODY>
    <form action="${contextPath}/admin/goods/addNewGoods.do" method="post" enctype="multipart/form-data">
        <h1>새상품 등록창</h1>
        <div class="tab_container">
            <!-- 내용 들어 가는 곳 -->
            <div class="tab_container" id="container">
                <ul class="tabs">
                    <li><a href="#tab1">상품정보</a></li>
                    <li><a href="#tab2">상품목차</a></li>
                    <li><a href="#tab3">상품저자소개</a></li>
                    <li><a href="#tab4">상품소개</a></li>
                    <li><a href="#tab5">출판사 상품 평가</a></li>
                    <li><a href="#tab6">추천사</a></li>
                    <li><a href="#tab7">상품이미지</a></li>
                </ul>
                <div class="tab_container">
                    <div class="tab_content" id="tab1">
                        <table>
                            <tr>
                                <td width=200>제품분류</td>
                                <td width=500><select name="goods_sort">
                                        <option value="컴퓨터와 인터넷" selected>컴퓨터와 인터넷
                                        <option value="디지털 기기">디지털 기기
                                    </select>
                                </td>
                            </tr>
                            <tr>
                                <td>제품이름</td>
                                <td><input name="goods_title" type="text" size="40" /></td>
                            </tr>
                            <tr>
                                <td>저자</td>
                                <td><input name="goods_writer" type="text" size="40" /></td>
                            </tr>
                            <tr>
                                <td>출판사</td>
                                <td><input name="goods_publisher" type="text" size="40" /></td>
                            </tr>
                            <tr>
                                <td>제품정가</td>
                                <td><input name="goods_price" type="text" size="40" /></td>
                            </tr>
                            <tr>
                                <td>제품판매가격</td>
                                <td><input name="goods_sales_price" type="text" size="40" /></td>
                            </tr>
                            <tr>
                                <td>제품 구매 포인트</td>
                                <td><input name="goods_point" type="text" size="40" /></td>
                            </tr>
                            <tr>
                                <td>제품출판일</td>
                                <td><input name="goods_published_date" type="date" size="40" /></td>
                            </tr>
                            <tr>
                                <td>제품 총 페이지수</td>
                                <td><input name="goods_total_page" type="text" size="40" /></td>
                            </tr>
                            <tr>
                                <td>ISBN</td>
                                <td><input name="goods_isbn" type="text" size="40" /></td>
                            </tr>
                            <tr>
                                <td>제품 배송비</td>
                                <td><input name="goods_delivery_price" type="text" size="40" /></td>
                            </tr>
                            <tr>
                                <td>제품 도착 예정일</td>
                                <td><input name="goods_delivery_date" type="date" size="40" /></td>
                            </tr>
                            <tr>
                                <td>제품종류</td>
                                <td>
                                    <select name="goods_status">
                                        <option value="bestseller">베스트셀러</option>
                                        <option value="steadyseller">스테디셀러</option>
                                        <option value="newbook" selected>신간</option>
                                        <option value="on_sale">판매중</option>
                                        <option value="buy_out">품절</option>
                                        <option value="out_of_print">절판</option>
                                    </select>
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <br>
                                </td>
                            </tr>
                        </table>
                    </div>
                    <div class="tab_content" id="tab2">
                        <H4>책목차</H4>
                        <table>
                            <tr>
                                <td>책목차</td>
                                <td><textarea rows="100" cols="80" name="goods_contents_order"></textarea></td>
                            </tr>
                        </table>
                    </div>
                    <div class="tab_content" id="tab3">
                        <H4>제품 저자 소개</H4>
                        <table>
                            <tr>
                                <td>제품 저자 소개</td>
                                <td><textarea rows="100" cols="80" name="goods_writer_intro"></textarea></td>
                            </tr>
                        </table>
                    </div>
                    <div class="tab_content" id="tab4">
                        <H4>제품소개</H4>
                        <table>
                            <tr>
                                <td>제품소개</td>
                                <td><textarea rows="100" cols="80" name="goods_intro"></textarea></td>
                            </tr>
                        </table>
                    </div>
                    <div class="tab_content" id="tab5">
                        <H4>출판사 제품 평가</H4>
                        <table>
                            <tr>
                                <td>출판사 제품 평가</td>
                                <td><textarea rows="100" cols="80" name="goods_publisher_comment"></textarea></td>
                            </tr>
                        </table>
                    </div>
                    <div class="tab_content" id="tab6">
                        <H4>추천사</H4>
                        <table>
                            <tr>
                                <td>추천사</td>
                                <td><textarea rows="100" cols="80" name="goods_recommendation"></textarea></td>
                            </tr>
                        </table>
                    </div>
                    <div class="tab_content" id="tab7">
                        <h4>상품이미지</h4>
                        <table>
                            <tr>
                                <td align="right">이미지파일 첨부</td>
								<%-- 파일 추가 클릭 시 파일 업로드가 동적으로 추가된다. --%>
                                <td align="left"> <input type="button" value="파일 추가" onClick="fn_addFile()" /></td>
                                <td>
                                    <div id="d_file">
                                    </div>
                                </td>
                            </tr>
                        </table>
                    </div>
                </div>
            </div>
            <div class="clear"></div>
            <center>
                <table>
                    <tr>
                        <td align=center>
                            <!--   <input  type="submit" value="상품 등록하기"> -->
                            <input type="button" value="상품 등록하기" onClick="fn_add_new_goods(this.form)">
                        </td>
                    </tr>
                </table>
            </center>
        </div>
    </form>

7. 실행 결과를 보자. admin으로 로그인하여 상단의 관리자를 클릭한 후 상품 등록하기를 클릭한다.

- http://localhost/bookshop01/admin/goods/adminGoodsMain.do

8. 새상품 등록창에서 상품정보 탭을 클릭한 후 상품 정보를 입력한다. 입력 시 '제품종류'를 신간으로 설정하고 진행한다. 또한 상품목차, 상품저자소개, 상품소개, 출판사 상품 평가, 추천사 탭을 각각 클릭해 해당하는 정보를 입력한다.

9. 이번에는 상품이미지 탭을 클릭한 후 파일 추가를 클릭하여 원하는 만큼 이미지 파일을 첨부하고 상품 등록하기를 클릭한다. 단, 첫 번째 이미지 파일에는 반드시 메인 이미지를 첨부해 업로드 해야 한다.

10. 이제 메인 화면의 새로 출판된 책 항목에 새 상품이 진열되어 있는 것을 확인할 수 있다.


(2) 상품 정보 수정하기

1. 상품 수정은 상품 정보를 수정하는 update문과 상품 이미지 정보를 수정하는 update문으로 이루어진다. 그리고 상품을 수정할 때 새로 첨부한 이미지 파일 정보를 insert 문으로 추가한다.

[admin_goods.xml]

	<!-- 상품 정보를 수정한다. -->
	<update id="updateGoodsInfo" parameterType="java.util.HashMap" >
	   update t_shopping_goods
	    <set> 
	      <if test=" goods_sort!='' and goods_sort!=null">
	        goods_sort=#{goods_sort},
	      </if>
	      <if test=" goods_title!='' and goods_title!=null">
	        goods_title=#{goods_title},
	      </if>
	      <if test=" goods_writer!='' and goods_writer!=null">
	        goods_writer=#{goods_writer},
	      </if>
	      <if test=" goods_publisher!='' and goods_publisher!=null">
	        goods_publisher=#{goods_publisher},
	      </if>
	      <if test=" goods_price!='' and goods_price!=null">
	        goods_price=#{goods_price},
	      </if>
	      <if test=" goods_published_date!='' and goods_published_date!=null">
	        goods_published_date=#{goods_published_date},
	      </if>
	      <if test=" goods_sales_price!='' and goods_sales_price!=null">
	        goods_sales_price=#{goods_sales_price},
	      </if>
	      <if test=" goods_point!='' and goods_point!=null">
	        goods_point=#{goods_point},
	      </if>
	      <if test=" goods_page_total!='' and goods_page_total!=null">
	        goods_page_total=#{goods_page_total},
	      </if>
	      <if test=" goods_isbn!='' and goods_isbn!=null">
	        goods_isbn=#{goods_isbn},
	      </if>
	      <if test=" goods_delivery_price!='' and goods_delivery_price!=null">
	        goods_delivery_price=#{goods_delivery_price},
	      </if>
	      <if test=" goods_delivery_date!='' and goods_delivery_date!=null">
	        goods_delivery_date=#{goods_delivery_date},
	      </if>
	      <if test=" goods_status!='' and goods_status!=null">
	        goods_status=#{goods_status},
	      </if>
	      <if test=" goods_writer_intro!='' and goods_writer_intro!=null">
	        goods_writer_intro=#{goods_writer_intro},
	      </if>
	      <if test=" goods_intro!='' and goods_intro!=null">
	        goods_intro=#{goods_intro},
	      </if>
	      <if test=" publisher_comment!='' and publisher_comment!=null">
	        publisher_comment=#{publisher_comment},
	      </if>
	      <if test=" recommendation!='' and recommendation!=null">
	        recommendation=#{recommendation},
	      </if>
	      <if test=" goods_contents_order!='' and goods_contents_order!=null">
	        goods_contents_order=#{goods_contents_order:VARCHAR}
	      </if>
	     </set>
	    where 
	    goods_id=#{goods_id}
	
	</update>	
	
	<!-- 상품 이미지 정보를 수정한다. -->
	<update id="updateGoodsImage" parameterType="imageFileVO">
		update t_goods_detail_image
		set fileName=#{fileName}
		where	 
		goods_id=#{goods_id} and image_id=#{image_id}
	</update>

2. 자바 클래스에서는 다음 요소들을 통해 도서 쇼핑몰의 상품 수정 기능을 구현한다.

- 상품 정보 수정

- 첨부한 상품 이미지 수정

- 첨부한 상품 이미지 삭제

- 새 상품 이미지 추가 첨부

[AdminGoodsControllerImpl.java]

package com.bookshop01.admin.goods.controller;

import java.io.File;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import com.bookshop01.admin.goods.service.AdminGoodsService;
import com.bookshop01.common.base.BaseController;
import com.bookshop01.goods.vo.GoodsVO;
import com.bookshop01.goods.vo.ImageFileVO;
import com.bookshop01.member.vo.MemberVO;

@Controller("adminGoodsController")
@RequestMapping(value = "/admin/goods")
public class AdminGoodsControllerImpl extends BaseController implements AdminGoodsController {
	
	private static final String CURR_IMAGE_REPO_PATH = "C:\\shopping\\file_repo";
	
	@Autowired
	private AdminGoodsService adminGoodsService;

	@RequestMapping(value = "/adminGoodsMain.do", method = { RequestMethod.POST, RequestMethod.GET })
	public ModelAndView adminGoodsMain(@RequestParam Map<String, String> dateMap, 
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		String viewName = (String) request.getAttribute("viewName");
		ModelAndView mav = new ModelAndView(viewName);
		HttpSession session = request.getSession();
		session = request.getSession();
		session.setAttribute("side_menu", "admin_mode"); // 마이페이지 사이드 메뉴로 설정한다.

		String fixedSearchPeriod = dateMap.get("fixedSearchPeriod");
		String section = dateMap.get("section");
		String pageNum = dateMap.get("pageNum");
		String beginDate = null, endDate = null;

		String[] tempDate = calcSearchPeriod(fixedSearchPeriod).split(",");
		beginDate = tempDate[0];
		endDate = tempDate[1];
		dateMap.put("beginDate", beginDate);
		dateMap.put("endDate", endDate);

		Map<String, Object> condMap = new HashMap<String, Object>();
		if (section == null) {
			section = "1";
		}
		condMap.put("section", section);
		if (pageNum == null) {
			pageNum = "1";
		}
		condMap.put("pageNum", pageNum);
		condMap.put("beginDate", beginDate);
		condMap.put("endDate", endDate);
		List<GoodsVO> newGoodsList = adminGoodsService.listNewGoods(condMap);
		mav.addObject("newGoodsList", newGoodsList);

		String beginDate1[] = beginDate.split("-");
		String endDate2[] = endDate.split("-");
		mav.addObject("beginYear", beginDate1[0]);
		mav.addObject("beginMonth", beginDate1[1]);
		mav.addObject("beginDay", beginDate1[2]);
		mav.addObject("endYear", endDate2[0]);
		mav.addObject("endMonth", endDate2[1]);
		mav.addObject("endDay", endDate2[2]);

		mav.addObject("section", section);
		mav.addObject("pageNum", pageNum);
		return mav;

	}

	@RequestMapping(value = "/addNewGoods.do", method = { RequestMethod.POST })
	public ResponseEntity addNewGoods(MultipartHttpServletRequest multipartRequest, 
			HttpServletResponse response)
			throws Exception {
		
		multipartRequest.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=UTF-8");
		String imageFileName = null;

		Map newGoodsMap = new HashMap();
		Enumeration enu = multipartRequest.getParameterNames();
		while (enu.hasMoreElements()) {
			String name = (String) enu.nextElement();
			String value = multipartRequest.getParameter(name);
			newGoodsMap.put(name, value);
		} // 상품 정보를 가져와 Map에 저장한다.

		HttpSession session = multipartRequest.getSession();
		MemberVO memberVO = (MemberVO) session.getAttribute("memberInfo");
		String reg_id = memberVO.getMember_id(); // 로그인 ID를 가져온다.
		List<ImageFileVO> imageFileList = upload(multipartRequest); // 첨부한 이미지 정보를 가져온다.
		if (imageFileList != null && imageFileList.size() != 0) {
			for (ImageFileVO imageFileVO : imageFileList) {
				imageFileVO.setReg_id(reg_id);
			}
			newGoodsMap.put("imageFileList", imageFileList);
		} // 이미지 정보에 상품 관리자 ID를 속성으로 추가한다.

		String message = null;
		ResponseEntity resEntity = null;
		HttpHeaders responseHeaders = new HttpHeaders();
		responseHeaders.add("Content-Type", "text/html; charset=utf-8");
		try {
			
			int goods_id = adminGoodsService.addNewGoods(newGoodsMap); // 상품 정보와 이미지 정보를 각 테이블에 추가한다.
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					File destDir = new File(CURR_IMAGE_REPO_PATH + "\\" + goods_id);
					FileUtils.moveFileToDirectory(srcFile, destDir, true);
				}
			} // 업로드한 이미지를 상품번호 폴더에 저장한다.
			message = "<script>";
			message += " alert('새상품을 추가했습니다.');";
			message += " location.href='" + multipartRequest.getContextPath() + "/admin/goods/addNewGoodsForm.do';";
			message += ("</script>");
			
		} catch (Exception e) {
			
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					srcFile.delete();
				}
			}

			message = "<script>";
			message += " alert('오류가 발생했습니다. 다시 시도해 주세요');";
			message += " location.href='" + multipartRequest.getContextPath() + "/admin/goods/addNewGoodsForm.do';";
			message += ("</script>");
			e.printStackTrace();
			
		}
		
		resEntity = new ResponseEntity(message, responseHeaders, HttpStatus.OK);
		return resEntity;
		
	}

	// 상품 정보 수정창을 나타낸다.
	@RequestMapping(value = "/modifyGoodsForm.do", method = { RequestMethod.GET, RequestMethod.POST })
	public ModelAndView modifyGoodsForm(@RequestParam("goods_id") int goods_id, 
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		String viewName = (String) request.getAttribute("viewName");
		ModelAndView mav = new ModelAndView(viewName);

		Map goodsMap = adminGoodsService.goodsDetail(goods_id);
		mav.addObject("goodsMap", goodsMap);

		return mav;
		
	}

	@RequestMapping(value = "/modifyGoodsInfo.do", method = { RequestMethod.POST })
	public ResponseEntity modifyGoodsInfo(@RequestParam("goods_id") String goods_id,
			@RequestParam("attribute") String attribute, 
			@RequestParam("value") String value, // 상품 정보 수정창에서 Ajax로 수정할 상품 번호, 상품 속성, 수정 값을 전달받는다.
			HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		
		// System.out.println("modifyGoodsInfo");

		Map<String, String> goodsMap = new HashMap<String, String>();
		goodsMap.put("goods_id", goods_id);
		goodsMap.put(attribute, value); // Map에 상품 번호와 key/value로 전송된 attribute/value를 저장한다.
		adminGoodsService.modifyGoodsInfo(goodsMap); // 상품 정보를 수정한다.

		String message = null;
		ResponseEntity resEntity = null;
		HttpHeaders responseHeaders = new HttpHeaders();
		message = "mod_success";
		resEntity = new ResponseEntity(message, responseHeaders, HttpStatus.OK);
		return resEntity;
		
	}

	@RequestMapping(value = "/modifyGoodsImageInfo.do", method = { RequestMethod.POST })
	public void modifyGoodsImageInfo(MultipartHttpServletRequest multipartRequest, 
			HttpServletResponse response)
			throws Exception {
		
		System.out.println("modifyGoodsImageInfo");
		multipartRequest.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		String imageFileName = null;

		Map goodsMap = new HashMap();
		Enumeration enu = multipartRequest.getParameterNames();
		while (enu.hasMoreElements()) {
			String name = (String) enu.nextElement();
			String value = multipartRequest.getParameter(name);
			goodsMap.put(name, value);
		} // 수정 이미지 파일 전송 시 함께 전송된 상품 번호와 이미지 번호를 가져온다.

		HttpSession session = multipartRequest.getSession();
		MemberVO memberVO = (MemberVO) session.getAttribute("memberInfo");
		String reg_id = memberVO.getMember_id();

		List<ImageFileVO> imageFileList = null;
		int goods_id = 0;
		int image_id = 0;
		try {
			imageFileList = upload(multipartRequest); // 첨부한 이미지 파일 정보를 가져온다.
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					goods_id = Integer.parseInt((String) goodsMap.get("goods_id"));
					image_id = Integer.parseInt((String) goodsMap.get("image_id")); // 이미지 파일 정보에 상품 번호와 이미지 번호를 설정한다.
					imageFileVO.setGoods_id(goods_id);
					imageFileVO.setImage_id(image_id);
					imageFileVO.setReg_id(reg_id);
				}

				adminGoodsService.modifyGoodsImage(imageFileList); // 이미지 파일 정보를 수정한다.
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					File destDir = new File(CURR_IMAGE_REPO_PATH + "\\" + goods_id);
					FileUtils.moveFileToDirectory(srcFile, destDir, true);
				} // 새로 첨부한 이미지 파일을 업로드한다.
			}
		} catch (Exception e) {
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					srcFile.delete();
				}
			}
			e.printStackTrace();
		}

	}

	@Override
	@RequestMapping(value = "/addNewGoodsImage.do", method = { RequestMethod.POST })
	public void addNewGoodsImage(MultipartHttpServletRequest multipartRequest, 
			HttpServletResponse response)
			throws Exception {
		
		System.out.println("addNewGoodsImage");
		multipartRequest.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		String imageFileName = null;

		Map goodsMap = new HashMap();
		Enumeration enu = multipartRequest.getParameterNames();
		while (enu.hasMoreElements()) {
			String name = (String) enu.nextElement();
			String value = multipartRequest.getParameter(name);
			goodsMap.put(name, value);
		}

		HttpSession session = multipartRequest.getSession();
		MemberVO memberVO = (MemberVO) session.getAttribute("memberInfo");
		String reg_id = memberVO.getMember_id();

		List<ImageFileVO> imageFileList = null;
		int goods_id = 0;
		try {
			imageFileList = upload(multipartRequest);
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					goods_id = Integer.parseInt((String) goodsMap.get("goods_id"));
					imageFileVO.setGoods_id(goods_id);
					imageFileVO.setReg_id(reg_id);
				}

				adminGoodsService.addNewGoodsImage(imageFileList);
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					File destDir = new File(CURR_IMAGE_REPO_PATH + "\\" + goods_id);
					FileUtils.moveFileToDirectory(srcFile, destDir, true);
				}
			}
		} catch (Exception e) {
			if (imageFileList != null && imageFileList.size() != 0) {
				for (ImageFileVO imageFileVO : imageFileList) {
					imageFileName = imageFileVO.getFileName();
					File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + "temp" + "\\" + imageFileName);
					srcFile.delete();
				}
			}
			e.printStackTrace();
		}
	}

	@Override
	@RequestMapping(value = "/removeGoodsImage.do", method = { RequestMethod.POST })
	public void removeGoodsImage(@RequestParam("goods_id") int goods_id, 
			@RequestParam("image_id") int image_id,
			@RequestParam("imageFileName") String imageFileName, 
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		adminGoodsService.removeGoodsImage(image_id);
		try {
			File srcFile = new File(CURR_IMAGE_REPO_PATH + "\\" + goods_id + "\\" + imageFileName);
			srcFile.delete();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

}

3. Service 클래스와 DAO 클래스는 다음과 같다.

package com.bookshop01.admin.goods.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.bookshop01.admin.goods.dao.AdminGoodsDAO;
import com.bookshop01.goods.vo.GoodsVO;
import com.bookshop01.goods.vo.ImageFileVO;
import com.bookshop01.order.vo.OrderVO;

@Service("adminGoodsService")
@Transactional(propagation = Propagation.REQUIRED)
public class AdminGoodsServiceImpl implements AdminGoodsService {
	
	@Autowired
	private AdminGoodsDAO adminGoodsDAO;

	@Override
	public int addNewGoods(Map newGoodsMap) throws Exception {
		int goods_id = adminGoodsDAO.insertNewGoods(newGoodsMap); // 상품 정보를 테이블에 추가한다.
		ArrayList<ImageFileVO> imageFileList = (ArrayList) newGoodsMap.get("imageFileList");
		for (ImageFileVO imageFileVO : imageFileList) {
			imageFileVO.setGoods_id(goods_id);
		} // 각 이미지 정보에 상품 번호를 설정한다.
		adminGoodsDAO.insertGoodsImageFile(imageFileList); // 이미지 정보를 이미지 테이블에 추가한다.
		return goods_id;
	}

	@Override
	public List<GoodsVO> listNewGoods(Map condMap) throws Exception {
		return adminGoodsDAO.selectNewGoodsList(condMap);
	}

	@Override
	public Map goodsDetail(int goods_id) throws Exception {
		Map goodsMap = new HashMap();
		GoodsVO goodsVO = adminGoodsDAO.selectGoodsDetail(goods_id);
		List imageFileList = adminGoodsDAO.selectGoodsImageFileList(goods_id);
		goodsMap.put("goods", goodsVO);
		goodsMap.put("imageFileList", imageFileList);
		return goodsMap;
	}

	@Override
	public List goodsImageFile(int goods_id) throws Exception {
		List imageList = adminGoodsDAO.selectGoodsImageFileList(goods_id);
		return imageList;
	}

	@Override
	public void modifyGoodsInfo(Map goodsMap) throws Exception {
		adminGoodsDAO.updateGoodsInfo(goodsMap);
	}

	@Override
	public void modifyGoodsImage(List<ImageFileVO> imageFileList) throws Exception {
		adminGoodsDAO.updateGoodsImage(imageFileList);
	}

	@Override
	public List<OrderVO> listOrderGoods(Map condMap) throws Exception {
		return adminGoodsDAO.selectOrderGoodsList(condMap);
	}

	@Override
	public void modifyOrderGoods(Map orderMap) throws Exception {
		adminGoodsDAO.updateOrderGoods(orderMap);
	}

	@Override
	public void removeGoodsImage(int image_id) throws Exception {
		adminGoodsDAO.deleteGoodsImage(image_id);
	}

	@Override
	public void addNewGoodsImage(List imageFileList) throws Exception {
		adminGoodsDAO.insertGoodsImageFile(imageFileList);
	}

}
package com.bookshop01.admin.goods.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;

import com.bookshop01.goods.vo.GoodsVO;
import com.bookshop01.goods.vo.ImageFileVO;
import com.bookshop01.order.vo.OrderVO;

@Repository("adminGoodsDAO")
public class AdminGoodsDAOImpl implements AdminGoodsDAO {
	
	@Autowired
	private SqlSession sqlSession;

	@Override
	public int insertNewGoods(Map newGoodsMap) throws DataAccessException {
		sqlSession.insert("mapper.admin.goods.insertNewGoods", newGoodsMap); // 상품 정보를 추가한다.
		return Integer.parseInt((String) newGoodsMap.get("goods_id"));
	}

	@Override
	public void insertGoodsImageFile(List fileList) throws DataAccessException {
		for (int i = 0; i < fileList.size(); i++) {
			ImageFileVO imageFileVO = (ImageFileVO) fileList.get(i);
			sqlSession.insert("mapper.admin.goods.insertGoodsImageFile", imageFileVO); // 상품 이미지 정보를 추가한다.
		}
	}

	@Override
	public List<GoodsVO> selectNewGoodsList(Map condMap) throws DataAccessException {
		ArrayList<GoodsVO> goodsList = (ArrayList) sqlSession.selectList("mapper.admin.goods.selectNewGoodsList", condMap);
		return goodsList;
	}

	@Override
	public GoodsVO selectGoodsDetail(int goods_id) throws DataAccessException {
		GoodsVO goodsBean = new GoodsVO();
		goodsBean = (GoodsVO) sqlSession.selectOne("mapper.admin.goods.selectGoodsDetail", goods_id);
		return goodsBean;
	}

	@Override
	public List selectGoodsImageFileList(int goods_id) throws DataAccessException {
		List imageList = new ArrayList();
		imageList = (List) sqlSession.selectList("mapper.admin.goods.selectGoodsImageFileList", goods_id);
		return imageList;
	}

	@Override
	public void updateGoodsInfo(Map goodsMap) throws DataAccessException {
		sqlSession.update("mapper.admin.goods.updateGoodsInfo", goodsMap);
	}

	@Override
	public void deleteGoodsImage(int image_id) throws DataAccessException {
		sqlSession.delete("mapper.admin.goods.deleteGoodsImage", image_id);
	}

	@Override
	public void deleteGoodsImage(List fileList) throws DataAccessException {
		int image_id;
		for (int i = 0; i < fileList.size(); i++) {
			ImageFileVO bean = (ImageFileVO) fileList.get(i);
			image_id = bean.getImage_id();
			sqlSession.delete("mapper.admin.goods.deleteGoodsImage", image_id);
		}
	}

	@Override
	public List<OrderVO> selectOrderGoodsList(Map condMap) throws DataAccessException {
		List<OrderVO> orderGoodsList = (ArrayList) sqlSession.selectList("mapper.admin.selectOrderGoodsList", condMap);
		return orderGoodsList;
	}

	@Override
	public void updateOrderGoods(Map orderMap) throws DataAccessException {
		sqlSession.update("mapper.admin.goods.updateOrderGoods", orderMap);

	}

	@Override
	public void updateGoodsImage(List<ImageFileVO> imageFileList) throws DataAccessException {
		for (int i = 0; i < imageFileList.size(); i++) {
			ImageFileVO imageFileVO = imageFileList.get(i);
			sqlSession.update("mapper.admin.goods.updateGoodsImage", imageFileVO);
		}
	}

}

4. 이제 JSP를 구현해 보자. 상품 정보 수정과 이미지 파일 정보 수정도 Ajax를 이용해 수행한다. 먼저 Ajax로 상품 정보에 대한 수정 데이터를 전달해 테이블 값을 수정한다. 그리고 이미지 파일을 수정하거나 새로운 이미지를 추가할 때는 제이쿼리의 FormData 객체를 이용해 이미지 파일을 Ajax로 업로드하면서 수정한다.

[modifyGoodsForm.jsp]

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="euc-kr"
	isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<c:set var="goods" value="${goodsMap.goods}" />
<c:set var="imageFileList" value="${goodsMap.imageFileList}" />

<c:choose>
    <c:when test='${not empty goods.goods_status}'>
        <script>
            window.onload = function() {
                init();
            }

            function init() {
                var frm_mod_goods = document.frm_mod_goods;
                var h_goods_status = frm_mod_goods.h_goods_status;
                var goods_status = h_goods_status.value;
                var select_goods_status = frm_mod_goods.goods_status;
                select_goods_status.value = goods_status;
            }
        </script>
    </c:when>
</c:choose>
<script type="text/javascript">
    function fn_modify_goods(goods_id, attribute) { // 수정된 상품 정보의 속성과 수정 값을 컨트롤러로 전송한다.
        var frm_mod_goods = document.frm_mod_goods;
        var value = "";
        if (attribute == 'goods_sort') {
            value = frm_mod_goods.goods_sort.value;
        } else if (attribute == 'goods_title') {
            value = frm_mod_goods.goods_title.value;
        } else if (attribute == 'goods_writer') {
            value = frm_mod_goods.goods_writer.value;
        } else if (attribute == 'goods_publisher') {
            value = frm_mod_goods.goods_publisher.value;
        } else if (attribute == 'goods_price') {
            value = frm_mod_goods.goods_price.value;
        } else if (attribute == 'goods_sales_price') {
            value = frm_mod_goods.goods_sales_price.value;
        } else if (attribute == 'goods_point') {
            value = frm_mod_goods.goods_point.value;
        } else if (attribute == 'goods_published_date') {
            value = frm_mod_goods.goods_published_date.value;
        } else if (attribute == 'goods_page_total') {
            value = frm_mod_goods.goods_page_total.value;
        } else if (attribute == 'goods_isbn') {
            value = frm_mod_goods.goods_isbn.value;
        } else if (attribute == 'goods_delivery_price') {
            value = frm_mod_goods.goods_delivery_price.value;
        } else if (attribute == 'goods_delivery_date') {
            value = frm_mod_goods.goods_delivery_date.value;
        } else if (attribute == 'goods_status') {
            value = frm_mod_goods.goods_status.value;
        } else if (attribute == 'goods_contents_order') {
            value = frm_mod_goods.goods_contents_order.value;
        } else if (attribute == 'goods_writer_intro') {
            value = frm_mod_goods.goods_writer_intro.value;
        } else if (attribute == 'goods_intro') {
            value = frm_mod_goods.goods_intro.value;
        } else if (attribute == 'publisher_comment') {
            value = frm_mod_goods.publisher_comment.value;
        } else if (attribute == 'recommendation') {
            value = frm_mod_goods.recommendation.value;
        }

        $.ajax({
            type: "post",
            async: false, //false인 경우 동기식으로 처리한다.
            url: "${contextPath}/admin/goods/modifyGoodsInfo.do",
            data: {
                goods_id: goods_id,
                attribute: attribute,
                value: value // 상품 속성과 수정 값을 Ajax로 전송한다.
            },
            success: function(data, textStatus) {
                if (data.trim() == 'mod_success') {
                    alert("상품 정보를 수정했습니다.");
                } else if (data.trim() == 'failed') {
                    alert("다시 시도해 주세요.");
                }

            },
            error: function(data, textStatus) {
                alert("에러가 발생했습니다." + data);
            },
            complete: function(data, textStatus) {
                //alert("작업을완료 했습니다");

            }
        }); //end ajax	
    }

    function readURL(input, preview) {
        //  alert(preview);
        if (input.files && input.files[0]) {
            var reader = new FileReader();
            reader.onload = function(e) {
                $('#' + preview).attr('src', e.target.result);
            }
            reader.readAsDataURL(input.files[0]);
        }
    }

    var cnt = 1;

    function fn_addFile() {
        $("#d_file").append("<br>" + "<input  type='file' name='detail_image" + cnt + "' id='detail_image" + cnt + "'  onchange=readURL(this,'previewImage" + cnt + "') />");
        $("#d_file").append("<img  id='previewImage" + cnt + "'   width=200 height=200  />");
        $("#d_file").append("<input  type='button' value='추가'  onClick=addNewImageFile('detail_image" + cnt + "','${imageFileList[0].goods_id}','detail_image')  />");
        cnt++;
    } //  이미지 추가 클릭 시 상세 이미지 파일 업로드를 추가한다.

    function modifyImageFile(fileId, goods_id, image_id, fileType) {
        // alert(fileId);
        var form = $('#FILE_FORM')[0];
        var formData = new FormData(form);
        formData.append("fileName", $('#' + fileId)[0].files[0]);
        formData.append("goods_id", goods_id);
        formData.append("image_id", image_id);
        formData.append("fileType", fileType); // formData에 수정할 이미지와 이미지 정보를 name/value로 저장한다.

        $.ajax({
            url: '${contextPath}/admin/goods/modifyGoodsImageInfo.do',
            processData: false,
            contentType: false,
            data: formData, // formData를 Ajax로 전송한다.
            type: 'POST',
            success: function(result) {
                alert("이미지를 수정했습니다!");
            }
        });
    } // 기존 이미지를 다른 이미지로 변경한 후 FormData를 이용해 Ajax로 수정한다.

    function addNewImageFile(fileId, goods_id, fileType) {
        //  alert(fileId);
        var form = $('#FILE_FORM')[0];
        var formData = new FormData(form);
        formData.append("uploadFile", $('#' + fileId)[0].files[0]);
        formData.append("goods_id", goods_id);
        formData.append("fileType", fileType);

        $.ajax({
            url: '${contextPath}/admin/goods/addNewGoodsImage.do',
            processData: false,
            contentType: false,
            data: formData,
            type: 'post',
            success: function(result) {
                alert("이미지를 수정했습니다!");
            }
        });
    } // 새 이미지 추가 후 FormData를 이용해 Ajax로 수정한다.

    function deleteImageFile(goods_id, image_id, imageFileName, trId) {
        var tr = document.getElementById(trId);

        $.ajax({
            type: "post",
            async: true, //false인 경우 동기식으로 처리한다.
            url: "${contextPath}/admin/goods/removeGoodsImage.do",
            data: {
                goods_id: goods_id,
                image_id: image_id,
                imageFileName: imageFileName
            },
            success: function(data, textStatus) {
                alert("이미지를 삭제했습니다!!");
                tr.style.display = 'none';
            },
            error: function(data, textStatus) {
                alert("에러가 발생했습니다." + textStatus);
            },
            complete: function(data, textStatus) {
                //alert("작업을완료 했습니다");

            }
        }); //end ajax	
    } // 이미지를 삭제한다.
</script>

</HEAD>

<BODY>
    <form name="frm_mod_goods" method=post>
        <DIV class="clear"></DIV>
        <!-- 내용 들어 가는 곳 -->
        <DIV id="container">
            <UL class="tabs">
                <li><A href="#tab1">상품정보</A></li>
                <li><A href="#tab2">상품목차</A></li>
                <li><A href="#tab3">상품저자소개</A></li>
                <li><A href="#tab4">상품소개</A></li>
                <li><A href="#tab5">출판사 상품 평가</A></li>
                <li><A href="#tab6">추천사</A></li>
                <li><A href="#tab7">상품이미지</A></li>
            </UL>
            <DIV class="tab_container">
                <DIV class="tab_content" id="tab1">
                    <table>
                        <tr>
                            <td width=200>상품분류</td>
                            <td width=500>
                                <select name="goods_sort">
                                    <c:choose>
                                        <c:when test="${goods.goods_sort=='컴퓨터와 인터넷' }">
                                            <option value="컴퓨터와 인터넷" selected>컴퓨터와 인터넷 </option>
                                            <option value="디지털 기기">디지털 기기 </option>
                                        </c:when>
                                        <c:when test="${goods.goods_sort=='디지털 기기' }">
                                            <option value="컴퓨터와 인터넷">컴퓨터와 인터넷 </option>
                                            <option value="디지털 기기" selected>디지털 기기 </option>
                                        </c:when>
                                    </c:choose>
                                </select>
                            </td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_sort')" />
                            </td>
                        </tr>
                        <tr>
                            <td>상품이름</td>
                            <td><input name="goods_title" type="text" size="40" value="${goods.goods_title }" /></td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_title')" />
                            </td>
                        </tr>

                        <tr>
                            <td>저자</td>
                            <td><input name="goods_writer" type="text" size="40" value="${goods.goods_writer }" /></td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_writer')" />
                            </td>

                        </tr>
                        <tr>
                            <td>출판사</td>
                            <td><input name="goods_publisher" type="text" size="40" value="${goods.goods_publisher }" /></td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_publisher')" />
                            </td>

                        </tr>
                        <tr>
                            <td>상품정가</td>
                            <td><input name="goods_price" type="text" size="40" value="${goods.goods_price }" /></td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_price')" />
                            </td>

                        </tr>

                        <tr>
                            <td>상품판매가격</td>
                            <td><input name="goods_sales_price" type="text" size="40" value="${goods.goods_sales_price }" /></td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_sales_price')" />
                            </td>

                        </tr>


                        <tr>
                            <td>상품 구매 포인트</td>
                            <td><input name="goods_point" type="text" size="40" value="${goods.goods_point }" /></td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_point')" />
                            </td>

                        </tr>

                        <tr>
                            <td>상품출판일</td>
                            <td>
                                <input name="goods_published_date" type="date" value="${goods.goods_published_date }" />
                            </td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_published_date')" />
                            </td>

                        </tr>

                        <tr>
                            <td>상품 총 페이지수</td>
                            <td><input name="goods_total_page" type="text" size="40" value="${goods.goods_total_page }" /></td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_total_page" />
                            </td>

                        </tr>

                        <tr>
                            <td>ISBN</td>
                            <td><input name="goods_isbn" type="text" size="40" value="${goods.goods_isbn }" /></td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_isbn')" />
                            </td>

                        </tr>
                        <tr>
                            <td>상품 배송비</td>
                            <td><input name="goods_delivery_price" type="text" size="40" value="${goods.goods_delivery_price }" /></td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_delivery_price')" />
                            </td>

                        </tr>
                        <tr>
                            <td>상품 도착 예정일</td>
                            <td>
                                <input name="goods_delivery_date" type="date" value="${goods.goods_delivery_date }" />
                            </td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_delivery_date')" />
                            </td>

                        </tr>

                        <tr>
                            <td>상품종류</td>
                            <td>
                                <select name="goods_status">
                                    <option value="bestseller">베스트셀러</option>
                                    <option value="steadyseller">스테디셀러</option>
                                    <option value="newbook">신간</option>
                                    <option value="on_sale">판매중</option>
                                    <option value="buy_out" selected>품절</option>
                                    <option value="out_of_print">절판</option>
                                </select>
                                <input type="hidden" name="h_goods_status" value="${goods.goods_status }" />
                            </td>
                            <td>
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_status')" />
                            </td>
                        </tr>
                        <tr>
                            <td colspan=3>
                                <br>
                            </td>
                        </tr>
                    </table>
                </DIV>
                <DIV class="tab_content" id="tab2">
                    <h4>책목차</h4>
                    <table>
                        <tr>
                            <td>상품목차</td>
                            <td><textarea rows="100" cols="80" name="goods_contents_order">
					  ${goods.goods_contents_order }
					</textarea>
                            </td>
                            <td>
                                &nbsp;&nbsp;&nbsp;&nbsp;
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_contents_order')" />
                            </td>
                        </tr>
                    </table>
                </DIV>
                <DIV class="tab_content" id="tab3">
                    <H4>상품 저자 소개</H4>
                    <P>
                    <table>
                        <tr>
                            <td>상품 저자 소개</td>
                            <td><textarea rows="100" cols="80" name="goods_writer_intro">
						  ${goods.goods_writer_intro }
						</textarea>
                            </td>
                            <td>
                                &nbsp;&nbsp;&nbsp;&nbsp;
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_writer_intro')" />
                            </td>
                        </tr>
                    </table>
                    </P>
                </DIV>
                <DIV class="tab_content" id="tab4">
                    <H4>상품소개</H4>
                    <P>
                    <table>
                        <tr>
                            <td>상품소개</td>
                            <td><textarea rows="100" cols="80" name="goods_intro">
						${goods.goods_intro }
						</textarea>
                            </td>
                            <td>
                                &nbsp;&nbsp;&nbsp;&nbsp;
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_intro')" />
                            </td>
                        </tr>
                    </table>
                    </P>
                </DIV>
                <DIV class="tab_content" id="tab5">
                    <H4>출판사 상품 평가</H4>
                    <P>
                    <table>
                        <tr>
                            <td><textarea rows="100" cols="80" name="goods_publisher_comment">
						  ${goods.goods_publisher_comment }
						</textarea>
                            </td>
                            <td>
                                &nbsp;&nbsp;&nbsp;&nbsp;
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_publisher_comment')" />
                            </td>
                        </tr>
                    </table>
                    </P>
                </DIV>
                <DIV class="tab_content" id="tab6">
                    <H4>추천사</H4>
                    <table>
                        <tr>
                            <td>추천사</td>
                            <td><textarea rows="100" cols="80" name="goods_recommendation">
						  ${goods.goods_recommendation }
						</textarea>
                            </td>
                            <td>
                                &nbsp;&nbsp;&nbsp;&nbsp;
                                <input type="button" value="수정반영" onClick="fn_modify_goods('${goods.goods_id }','goods_recommendation')" />
                            </td>
                        </tr>
                    </table>
                </DIV>
                <DIV class="tab_content" id="tab7">
                    <form id="FILE_FORM" method="post" enctype="multipart/form-data">
                        <h4>상품이미지</h4>
                        <table>
                            <tr>
                                <c:forEach var="item" items="${imageFileList }" varStatus="itemNum">
                                    <c:choose>
                                        <c:when test="${item.fileType=='main_image' }">
                            <tr>
                                <td>메인 이미지</td>
                                <td>
                                    <input type="file" id="main_image" name="main_image" onchange="readURL(this,'preview${itemNum.count}');" />
                                    <%-- <input type="text" id="image_id${itemNum.count }"  value="${item.fileName }" disabled  /> --%>
                                    <input type="hidden" name="image_id" value="${item.image_id}" />
                                    <br>
                                </td>
                                <td>
                                    <img id="preview${itemNum.count }" width=200 height=200 src="${contextPath}/download.do?goods_id=${item.goods_id}&fileName=${item.fileName}" />
                                </td>
                                <td>
                                    &nbsp;&nbsp;&nbsp;&nbsp;
                                </td>
                                <td>
                                    <input type="button" value="수정" onClick="modifyImageFile('main_image','${item.goods_id}','${item.image_id}','${item.fileType}')" />
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <br>
                                </td>
                            </tr>
                            </c:when>
                            <c:otherwise>
                                <tr id="${itemNum.count-1}">
                                    <td>상세 이미지${itemNum.count-1 }</td>
                                    <td>
                                        <input type="file" name="detail_image" id="detail_image" onchange="readURL(this,'preview${itemNum.count}');" />
                                        <%-- <input type="text" id="image_id${itemNum.count }"  value="${item.fileName }" disabled  /> --%>
                                        <input type="hidden" name="image_id" value="${item.image_id }" />
                                        <br>
                                    </td>
                                    <td>
                                        <img id="preview${itemNum.count }" width=200 height=200 src="${contextPath}/download.do?goods_id=${item.goods_id}&fileName=${item.fileName}">
                                    </td>
                                    <td>
                                        &nbsp;&nbsp;&nbsp;&nbsp;
                                    </td>
                                    <td>
                                        <input type="button" value="수정" onClick="modifyImageFile('detail_image','${item.goods_id}','${item.image_id}','${item.fileType}')" />
                                        <input type="button" value="삭제" onClick="deleteImageFile('${item.goods_id}','${item.image_id}','${item.fileName}','${itemNum.count-1}')" />
                                    </td>
                                </tr>
                                <tr>
                                    <td>
                                        <br>
                                    </td>
                                </tr>
                            </c:otherwise>
                            </c:choose>
                            </c:forEach>
                            <tr align="center">
                                <td colspan="3">
                                    <div id="d_file">
                                        <%-- <img  id="preview${itemNum.count }"   width=200 height=200 src="${contextPath}/download.do?goods_id=${item.goods_id}&fileName=${item.fileName}" /> --%>
                                    </div>
                                </td>
                            </tr>
                            <tr>
                                <td align=center colspan=2>

                                    <input type="button" value="이미지파일추가하기" onClick="fn_addFile()" />
                                </td>
                            </tr>
                        </table>
                    </form>
                </DIV>
                <DIV class="clear"></DIV>

    </form>

5. 다음은 실행 결과이다. 왼쪽의 상품관리를 클릭하고 '상품이름' 목록에서 원하는 상품이름을 클릭한다. 여기서는 리액트를 다루는 기술을 클릭한다.

6. 상품정가를 35000원으로, 상품판매가격을 32000원으로 수정한 후 각각 수정반영을 클릭한다.

7. 상품이미지 탭을 클릭한다. 파일 선택을 클릭해 수정하고자 하는 이미지 파일을 첨부한 후 수정을 클릭한다. 여기서는 상세 이미지 1을 수정해 보자.

8. 상세 이미지1에 html로고.png를 첨부하면 수정된 이미지가 표시된다(이미지 크기가 클 경우 흐리게 표시되기도 한다.)

    만약에 이미지를 삭제하고 싶을 때는 해당 이미지 옆에 있는 삭제를 클릭하면 된다.

9. 해당 상품의 상세 페이지를 보면 수정된 이미지가 나타난다.

* 그 외 상품 이미지를 추가하는 기능은 여러분이 직접 구현해 보기 바란다.