[Spring][쇼핑몰 프로젝트] 21. 상품 정보 수정 구현

YB·2023년 2월 24일
0

쇼핑몰

목록 보기
32/40
post-thumbnail

목표

상품 수정 페이지와 수정 기능 구현을 목표로 합니다.

1. 수정 페이지 이동 및 출력

수정 페이지로 이동할 수 있는 인터페이스인 버튼과 페이지 이동에 사용될 URL매핑 메서드를 작성하겠습니다. 더불어 '상품 목록 페이지(goodsManage.jsp)' 이동 버튼 기능도 구현을 합니다.

goodsDetail.jsp
먼저 'goodsDetail.jsp'는 상품 등록 페이지 코드를 긁어 왔기 때문에 '버튼' 태그와 <form>태그가 있습니다. 해당 코드를 아래의 코드로 각각 수정해줍니다.

                   			<div class="btn_section">
                   				<button id="cancelBtn" class="btn">상품 목록</button>
	                    		<button id="modifyBtn" class="btn enroll_btn">수정 </button>
	                    	</div>  
     

                	
                	<form id="moveForm" action="/admin/goodsManage" method="get" >
 						<input type="hidden" name="pageNum" value="${cri.pageNum}">
						<input type="hidden" name="amount" value="${cri.amount}">
						<input type="hidden" name="keyword" value="${cri.keyword}">
                	</form>

버튼을 동작시키기 위해서 <script>내부에 Javascript코드를 추가하였습니다.

/* 목록 이동 버튼 */
$("#cancelBtn").on("click", function(e){
	e.preventDefault();
	$("#moveForm").submit();	
});	

/* 수정 페이지 이동 */
$("#modifyBtn").on("click", function(e){
	e.preventDefault();
	let addInput = '<input type="hidden" name="bookId" value="${goodsInfo.bookId}">';
	$("#moveForm").append(addInput);
	$("#moveForm").attr("action", "/admin/goodsModify");
	$("#moveForm").submit();
});	

AdminController.java
수정 페이지로 이동할 수 있는 URL매핑 메서드를 추가해주어야 합니다. 추가해야 할 수정 페이지 메서드는 '상품 조회 페이지 이동 메서드(goodsDetail)'와 완전 동일합니다. 따라서 기존의 '상품 조회 페이지 이동 메서드'를 '상품 수정 페이지 이동 메서드'로도 활용할 수 있도록 기존의 어노테이션을 아래와 같이 변경해줍니다.

@GetMapping({"/goodsDetail", "/goodsModify"})

goodsModify.jsp
수정 페이지를 출력시킬 기본적인 틀을 완성하고자 합니다. goodsModify.jsp를 생성 후 아래의 코드를 추가하였습니다.

  • 각 input태그에 value속성을 추가하여 각 항목의 값이 출력되도록 하였습니다.
  • <form>태그 내부에 'bookId'항목의 type이 hidden인 <input>태그를 추가하였습니다.(수정을 수행하는 쿼리에서는 bookId가 필요로 하기 때문에 추가하였습니다.)
  • 수정할 데이터 태그들을 감싸는 <form>태그에 action, id속성을 수정하였습니다.
  • goodsDetail.jsp에서 작성한 id속성이 'moveForm'인 <form>태그를 복사하여 붙여넣었습니다. 붙여 넣은 <form>태그 내부에 bookId를 담는 <input>태그를 추가해주었습니다.(해당 <form>태그는 수정 페이지에서 조회 페이지 이동할 떄, 조회 페이지에서 목록 페이지로 이동을 할 때 필요로 한 데이터들입니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="../resources/css/admin/goodsModify.css">
<link rel="stylesheet" href="//code.jquery.com/ui/1.8.18/themes/base/jquery-ui.css" />
<script
  src="https://code.jquery.com/jquery-3.4.1.js"
  integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
  crossorigin="anonymous"></script>
 <script src="https://cdn.ckeditor.com/ckeditor5/26.0.0/classic/ckeditor.js"></script>
 <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="//code.jquery.com/ui/1.8.18/jquery-ui.min.js"></script>
</head>
</head>
<body>

				<%@include file="../includes/admin/header.jsp" %>
				
                <div class="admin_content_wrap">
                    <div class="admin_content_subject"><span>상품 등록</span></div>
                    <div class="admin_content_main">
                    	<form action="/admin/goodsModify" method="post" id="modifyForm">
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>책 제목</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="bookName" value="${goodsInfo.bookName}">
                    				<span class="ck_warn bookName_warn">책 이름을 입력해주세요.</span>
                    			</div>
                    		</div>
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>작가</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input id="authorName_input" readonly="readonly" value="${goodsInfo.authorName}">
                    				<input id="authorId_input" name="authorId" type="hidden" value="${goodsInfo.authorId}">
                    				<button class="authorId_btn">작가 선택</button>
                    				<span class="ck_warn authorId_warn">작가를 선택해주세요</span>
                    			</div>
                    		</div>            
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>출판일</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="publeYear" autocomplete="off" readonly="readonly">
                    				<span class="ck_warn publeYear_warn">출판일을 선택해주세요.</span>
                    			</div>
                    		</div>            
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>출판사</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="publisher" value="${goodsInfo.publisher}">
                    				<span class="ck_warn publisher_warn">출판사를 입력해주세요.</span>
                    			</div>
                    		</div>             
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>책 카테고리</label>
                    			</div>
                    			<div class="form_section_content">
                    				<div class="cate_wrap">
                    					<span>대분류</span>
                    					<select class="cate1">
                    						<option selected value="none">선택</option>
                    					</select>
                    				</div>
                    				<div class="cate_wrap">
                    					<span>중분류</span>
                    					<select class="cate2">
                    						<option selected value="none">선택</option>
                    					</select>
                    				</div>
                    				<div class="cate_wrap">
                    					<span>소분류</span>
                    					<select class="cate3" name="cateCode">
                    						<option selected value="none">선택</option>
                    					</select>
                    				</div>  
                    				<span class="ck_warn cateCode_warn">카테고리를 선택해주세요.</span>                  				                    				
                    			</div>
                    		</div>          
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>상품 가격</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="bookPrice" value="${goodsInfo.bookPrice}">
                    				<span class="ck_warn bookPrice_warn">상품 가격을 입력해주세요.</span>
                    			</div>
                    		</div>               
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>상품 재고</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="bookStock" value="${goodsInfo.bookStock}">
                    				<span class="ck_warn bookStock_warn">상품 재고를 입력해주세요.</span>
                    			</div>
                    		</div>          
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>상품 할인율</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input id="discount_interface" maxlength="2" value="0">
                    				<input name="bookDiscount" type="hidden" value="${goodsInfo.bookDiscount}">
                    				<span class="step_val">할인 가격 : <span class="span_discount"></span></span>
                    				<span class="ck_warn bookDiscount_warn">1~99 숫자를 입력해주세요.</span>
                    			</div>
                    		</div>          		
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>책 소개</label>
                    			</div>
                    			<div class="form_section_content bit">
                    				<textarea name="bookIntro" id="bookIntro_textarea">${goodsInfo.bookIntro}</textarea>
                    				<span class="ck_warn bookIntro_warn">책 소개를 입력해주세요.</span>
                    			</div>
                    		</div>        		
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>책 목차</label>
                    			</div>
                    			<div class="form_section_content bct">
                    				<textarea name="bookContents" id="bookContents_textarea">${goodsInfo.bookContents}</textarea>
                    				<span class="ck_warn bookContents_warn">책 목차를 입력해주세요.</span>
                    			</div>
                    		</div>
                    		<input type="hidden" name='bookId' value="${goodsInfo.bookId}">
                   		</form>
                   			<div class="btn_section">
                   				<button id="cancelBtn" class="btn">취 소</button>
	                    		<button id="modifyBtn" class="btn modify_btn">수 정</button>
	                    	</div> 
                    </div>  
                	<form id="moveForm" action="/admin/goodsManage" method="get" >
 						<input type="hidden" name="pageNum" value="${cri.pageNum}">
						<input type="hidden" name="amount" value="${cri.amount}">
						<input type="hidden" name="keyword" value="${cri.keyword}">
						<input type="hidden" name='bookId' value="${goodsInfo.bookId}">
                	</form>                     
                </div>
 
 				<%@include file="../includes/admin/footer.jsp" %>
</body>
</html>

goodsModify.css

틀을 꾸며줄 goods.Modify.css를 생성 후에 아래의 코드를 추가하였습니다.

@charset "UTF-8";
*{
	margin: 0;
	padding:0;
}
a{
	text-decoration: none;
}
ul{
    list-style: none;
}
/* 화면 전체 렙 */
.wrapper{
	width: 100%;
}
/* content 랩 */
.wrap{
	width : 1080px;
	margin: auto;
}
/* 홈페이지 기능 네비 */ 
.top_gnb_area{
	width: 100%;
    height: 50px;
    background-color: #f0f0f1;
    position:relative;
}
.top_gnb_area .list{
	position: absolute;
    top: 0px;
    right: 0;
    
}
.top_gnb_area .list li{
	list-style: none;	
    float : left;
    padding: 13px 15px 0 10px;
    font-weight: 900;
    cursor: pointer;
}

/* 관리제 페이지 상단 현페이지 정보 */
.admin_top_wrap{
    height:110px;
    line-height: 110px;
    background-color: #5080bd;
    margin-bottom: 15px;
}
.admin_top_wrap>span{
    margin-left: 30px;
    display:inline-block;
    color: white;
    font-size: 50px;
    font-weight: bolder;
}
/* 관리자 wrap(네비+컨텐츠) */
.admin_wrap{
    
    
}

/* 관리자페이지 네비 영역 */
.admin_navi_wrap{
    width: 20%;
    height: 300px;
    float:left;
    height: 100%;
}
.admin_navi_wrap li{
    display: block;
    height: 80px;
    line-height: 80px;
    text-align: center;
}
.admin_navi_wrap li a{
    display: block;
    height: 100%;
    width: 95%;
    margin: 0 auto;
    cursor: pointer;
    font-size: 30px;
    font-weight: bolder;
}
.admin_navi_wrap li a:link {color: black;}
.admin_navi_wrap li a:visited {color: black;}
.admin_navi_wrap li a:active {color: black;}
.admin_navi_wrap li a:hover {color: black;}

.admin_list_02{
    background-color: #c8c8c8;
} 


/* 관리자페이지 컨텐츠 영역 */
.admin_content_wrap{
    width: 80%;
    float:left;
    min-height: 700px;
}
.admin_content_subject{	/* 관리자 컨텐츠 제목 영역 */
    font-size: 40px;
    font-weight: bolder;
    padding-left: 15px;
    background-color: #6AAFE6;
    height: 80px;
    line-height: 80px;
    color: white;	
}
/* 관리자 컨텐츠 메인 영역 */
.form_section{
	width: 95%;
    margin-left: 2%;
    margin-top: 20px;
    border: 1px solid #dbdde2;
    background-color: #efefef;	
}
.form_section_title{
	padding: 20px 35px;	
}
.form_section_title label{
	display: block;
    font-size: 20px;
    font-weight: 800;
}
.form_section_content{
	padding: 20px 35px;
    border-top: 1px solid #dbdde2;	
}
.form_section_content input{
	width: 98%;
    height: 25px;
    font-size: 20px;
    padding: 5px 1%;
}

							
.ui-datepicker-trigger {						/* 캘린더 css 설정 */
    margin-left: 25px;
    width: 14%;
    height: 38px;
    font-weight: 600;
    background-color: #dfe8f5;
    font-size: 15px;
    cursor:pointer;
}
input[name='publeYear'] {
    width: 80%;
    text-align: center;
}


.authorId_btn {						/* 작가 선택 css 설정 */
    margin-left: 20px;
    width: 14%;
    height: 38px;
    font-weight: 600;
    background-color: #dfe8f5;
    font-size: 15px;
    cursor:pointer;
}
#authorName_input {
    width: 80%;
    text-align: center;
}

.ck-content {						/* ckeditor 높이 */
    height: 170px;
}

/* 버튼 영역 */
.btn_section{
	text-align: center;
	margin: 80px 0;
}
.btn{
    min-width: 180px;
    padding: 4px 30px;
    font-size: 25px;
    font-weight: 600;
    line-height: 40px;
}
.enroll_btn{
	background-color: #dbdde2;
	margin-left:15px;
}
#enrollBtn:hover {
    background-color: #c9cbd0;
}

.form_section_content select {		/* 카테고리 css 설정 */
    width: 92%;
    height: 35px;
    font-size: 20px;
    text-align-last: center;
    margin-left: 5px;
}
.cate_wrap span {
    font-weight: 600;
}
.cate_wrap:not(:first-child) {
    margin-top: 20px;
}


.ck_warn{			/* 입력란 공란 경고 태그 */
	display: none;
    padding-top: 10px;
    text-align: center;
    color: #e05757;
    font-weight: 300;    
}


/* footer navai 영역 */
.footer_nav{
	width:100%;
	height:50px;
}
.footer_nav_container{
	width: 100%;
	height: 100%;
	background-color:#8EC0E4;
}
.footer_nav_container>ul{
	font-weight : bold;
	float:left;
	list-style:none;
	position:relative;
	padding-top:10px;
	line-height: 27px;
	font-family: dotum;
	margin-left: 10px;
}
.footer_nav_container>ul>li{
	display:inline;
	width: 45px;
	height: 19px;
	padding: 10px 9px 0 10px;
}
.footer_nav_container>ul>span{
	margin: 0 4px;
}
/* footer 영역 */
.footer{
	width:100%;
	height:130px;
	background-color:#D4DFE6;
	padding-bottom : 50px;
}
.footer_container{
	width: 100%;
	height: 100%;
	margin: auto;
}
.footer_left>img {
	width: 150%;
    height: 130px;
    margin-left: -20px;
    margin-top: -12px;
}
.footer_left{
	float :left;
	width: 170px;
	margin-left: 20px;
	margin-top : 30px;
	
}
.footer_right{
	float :left;
	width: 680px;
	margin-left: 70px;
	margin-top : 30px;
}



/* float 속성 해제 */
.clearfix{
	clear: both;
}

2. 출판일

'상품 등록 페이지'와 마찬가지로 출판일 항목이 datepicker를 적용해주어야 합니다. 이미 <head>태그에 datepicker에 대한 라이브러리 추가 <script>코드는 하였기 때문에 적용에 대한 코드만 추가해주면 됩니다. 코드는 추가에 앞서 <body>태그 제일 하단에 <script>태그를 추가한 뒤 페이지가 렌더링 후 반드시 실행을 하느 document ready메서드를 추가해줍니다.

  • datepicker를 적용하는 코드를 document ready메서드 내에 추가해줍니다.
  • 수정 페이지이기 때문에 DB에 저장된 데이터가 출력이 되어야 합니다. 문제는 <input>태그에 value속성을 추가해도 datepicker가 적용되었기 때문에 출력이 되지 않습니다. datepicker를 적용시키는 코드에 DB에 저장된 데이터가 출력이 되도록 하는 코드를 따로 추가해주어야 합니다. datepicker를 적용하는 기존 코드 중 익명 함수의 코드를 아래의 코드로 적용시킵니다.
<script>

$(document).ready(function(){
	
/* 캘린더 위젯 적용 */

	/* 설정 */
	const config = {
		dateFormat: 'yy-mm-dd',
		showOn : "button",
		buttonText:"날짜 선택",
	    prevText: '이전 달',
	    nextText: '다음 달',
	    monthNames: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'],
	    monthNamesShort: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'],
	    dayNames: ['일','월','화','수','목','금','토'],
	    dayNamesShort: ['일','월','화','수','목','금','토'],
	    dayNamesMin: ['일','월','화','수','목','금','토'],
	    yearSuffix: '년',
        changeMonth: true,
        changeYear: true
	}			
	
	/* 캘린더 */
	$(function() {
		let publeYear = '${goodsInfo.publeYear}';
		$( "input[name='publeYear']" ).datepicker(config);
		$( "input[name='publeYear']" ).datepicker('setDate', publeYear);
	});	

});

</script>

3. 책 카테고리

책 카테고리는 '상품 조회'페이지에서 처럼 DB에 저장된 카테고리가 출력이 되면서, '상품 등록'페이지와 같이 대분류 선택, 혹은 중분류 선택에 따라서 하위분류가 초기화 및 변경되도록 해야합니다. 따라서 '상품 조회', '상품 등록'페이지에서의 사용한 상품 카테고리 관련 코드를 활용하여 작성할 것입니다.

먼저 DB에 저장된 카테고리가 선택된 상태로 출력시킬 코드를 추가해줍니다. 아래의 코드는 document ready메서드 내부에 반드시 작성해주어야 합니다.

/* 카테고리 */
	let cateList = JSON.parse('${cateList}');

	let cate1Array = new Array();
	let cate2Array = new Array();
	let cate3Array = new Array();
	let cate1Obj = new Object();
	let cate2Obj = new Object();
	let cate3Obj = new Object();
	
	let cateSelect1 = $(".cate1");		
	let cateSelect2 = $(".cate2");
	let cateSelect3 = $(".cate3");
	
	/* 카테고리 배열 초기화 메서드 */
	function makeCateArray(obj,array,cateList, tier){
		for(let i = 0; i < cateList.length; i++){
			if(cateList[i].tier === tier){
				obj = new Object();
				
				obj.cateName = cateList[i].cateName;
				obj.cateCode = cateList[i].cateCode;
				obj.cateParent = cateList[i].cateParent;
				
				array.push(obj);				
				
			}
		}
	}	
	
	/* 배열 초기화 */
	makeCateArray(cate1Obj,cate1Array,cateList,1);
	makeCateArray(cate2Obj,cate2Array,cateList,2);
	makeCateArray(cate3Obj,cate3Array,cateList,3);
	
	
	let targetCate2 = '';
	let targetCate3 = '${goodsInfo.cateCode}';
	
	/* 소분류 */
	for(let i = 0; i < cate3Array.length; i++){
		if(targetCate3 === cate3Array[i].cateCode){
			targetCate3 = cate3Array[i];
		}
	}// for			
	
	for(let i = 0; i < cate3Array.length; i++){
		if(targetCate3.cateParent === cate3Array[i].cateParent){
			cateSelect3.append("<option value='"+cate3Array[i].cateCode+"'>" + cate3Array[i].cateName + "</option>");
		}
	}				
	
	$(".cate3 option").each(function(i,obj){
		if(targetCate3.cateCode === obj.value){
			$(obj).attr("selected", "selected");
		}
	});			
	
	/* 중분류 */
	for(let i = 0; i < cate2Array.length; i++){
		if(targetCate3.cateParent === cate2Array[i].cateCode){
			targetCate2 = cate2Array[i];	
		}
	}// for		
	
	for(let i = 0; i < cate2Array.length; i++){
		if(targetCate2.cateParent === cate2Array[i].cateParent){
			cateSelect2.append("<option value='"+cate2Array[i].cateCode+"'>" + cate2Array[i].cateName + "</option>");
		}
	}		
	
	$(".cate2 option").each(function(i,obj){
		if(targetCate2.cateCode === obj.value){
			$(obj).attr("selected", "selected");
		}
	});				
	
	
	/* 대분류 */
	for(let i = 0; i < cate1Array.length; i++){
		cateSelect1.append("<option value='"+cate1Array[i].cateCode+"'>" + cate1Array[i].cateName + "</option>");
	}	
	
	$(".cate1 option").each(function(i,obj){
		if(targetCate2.cateParent === obj.value){
			$(obj).attr("selected", "selected");
		}
	});	

이번엔 사용자 선택에 따라 분류들이 변경되도록 할 차례입니다. 새로 작성할 코드는 렌더링될 때 실행될 코드와 구분하기 위해서 기존의 <script>태그 아래에 새로운 <script>를 추가하여 작업할 것입니다. 새로 추가한 두번째 <script>태그에 사용자 선택에 따라 카테고리 분류가 변경되도록 해주는 기능을 하는 Javavscript코드를 추가합니다. (해당 코드는 '상품 등록'페이지의 코드를 그대로 가져왔습니다. 단 위에서 이미 대분류를 출력시키는 코드는 존재하기 때문에 대분류<option>태그를 출력시키는 코드는 추가하지 않았습니다.)

<script>
/* 카테고리 */
let cateList = JSON.parse('${cateList}');

let cate1Array = new Array();
let cate2Array = new Array();
let cate3Array = new Array();
let cate1Obj = new Object();
let cate2Obj = new Object();
let cate3Obj = new Object();

let cateSelect1 = $(".cate1");		
let cateSelect2 = $(".cate2");
let cateSelect3 = $(".cate3");

/* 카테고리 배열 초기화 메서드 */
function makeCateArray(obj,array,cateList, tier){
	for(let i = 0; i < cateList.length; i++){
		if(cateList[i].tier === tier){
			obj = new Object();
			
			obj.cateName = cateList[i].cateName;
			obj.cateCode = cateList[i].cateCode;
			obj.cateParent = cateList[i].cateParent;
			
			array.push(obj);				
			
		}
	}
}	

	/* 배열 초기화 */
makeCateArray(cate1Obj,cate1Array,cateList,1);
makeCateArray(cate2Obj,cate2Array,cateList,2);
makeCateArray(cate3Obj,cate3Array,cateList,3);


	/* 중분류 <option> 태그 */
$(cateSelect1).on("change",function(){
	
	let selectVal1 = $(this).find("option:selected").val();	
	
	cateSelect2.children().remove();
	cateSelect3.children().remove();
	
	cateSelect2.append("<option value='none'>선택</option>");
	cateSelect3.append("<option value='none'>선택</option>");
	
	for(let i = 0; i < cate2Array.length; i++){
		if(selectVal1 === cate2Array[i].cateParent){
			cateSelect2.append("<option value='"+cate2Array[i].cateCode+"'>" + cate2Array[i].cateName + "</option>");	
		}
	}// for
	
});

	/* 소분류 <option>태그 */
$(cateSelect2).on("change",function(){
	
	let selectVal2 = $(this).find("option:selected").val();
	
	cateSelect3.children().remove();
	
	cateSelect3.append("<option value='none'>선택</option>");		
	
	for(let i = 0; i < cate3Array.length; i++){
		if(selectVal2 === cate3Array[i].cateParent){
			cateSelect3.append("<option value='"+cate3Array[i].cateCode+"'>" + cate3Array[i].cateName + "</option>");	
		}
	}// for		
	
});
</script>

5. 책 소개, 책 목차

책 소개, 책 목차는 단순히 ckeditor를 적용시켜주기만 하면 됩니다. ckeditor를 적용시키는 코드를 document ready메서드 구현부에 추가해줍니다.

/* 위지윅 적용 */
 
	/* 책 소개 */
	ClassicEditor
		.create(document.querySelector('#bookIntro_textarea'))
		.catch(error=>{
			console.error(error);
		});
		
	/* 책 목차 */	
	ClassicEditor
	.create(document.querySelector('#bookContents_textarea'))
	.catch(error=>{
		console.error(error);
	});

6. 할인율

페이지에 들어가 보면 0으로 되어 있지만 실질적으로 서버에 전송되어야 할 할인율 데이터는 type이 hidden인 <input>태그에 저장되어 있습니다. 해당 <input>태그에는 할인율이 소수로 저장되어 있는데 이를 자연수로 변경하여 사용자에게 노출되는 <input>태그 값으로 삽입할 것입니다. 더불어 원가와 할인율을 통해 할인 가격이 얼마인지도 사용자가 볼 수 있도록 해줄 것입니다.

document readdy메서드 구현부에 작성합니다. 그리고 사용자가 할인율을 변경했을 때 입력된 할인율을 소수로 변경하여 서버로 전송될 할인율을 저장하는 <input>태그의 값으로 삽입되도록 하여야 합니다. 그리고 할인 가격이 얼마인지 출력되는 <span>태그의 값도 입력된 값에 따라 변경되도록 해주어야 합니다. 더불어서 상품 가격에 새로운 값을 입력하여도 할인가격 <span>태그의 값이 변경되도록 합니다.

이러한 기능을 하는 코드를 이미 '상품 등록 페이지'에 작성하였기 때문에 해당 코드를 그대로 복사하여 두번째 <script>태그에 붙여 넣습니다.

/* 할인율 */
 	
	/* 할인율 인터페이스 출력 */
	let bookPriceInput = $("input[name='bookPrice']");
	let discountInput = $("input[name='bookDiscount']");
	
	let bookPrice = bookPriceInput.val();
	let rawDiscountRate = discountInput.val();
	let discountRate = rawDiscountRate * 100;
	
	
	let discountPrice = bookPrice * (1-rawDiscountRate);
	$(".span_discount").html(discountPrice);
	$("#discount_interface").val(discountRate);
	
	/* 할인율 Input 설정 */
	$("#discount_interface").on("propertychange change keyup paste input", function(){
		
		let userInput = $("#discount_interface");
		let discountInput = $("input[name='bookDiscount']");
		
		let discountRate = userInput.val();					// 사용자가 입력한 할인값
		let sendDiscountRate = discountRate / 100;			// 서버에 전송할 할인값
		let goodsPrice = $("input[name='bookPrice']").val();			// 원가
		let discountPrice = goodsPrice * (1 - sendDiscountRate);		// 할인가격
		
		if(!isNaN(discountRate)){
			$(".span_discount").html(discountPrice);		
			discountInput.val(sendDiscountRate);				
		}

		
	});	
	
	$("input[name='bookPrice']").on("change", function(){
		
		let userInput = $("#discount_interface");
		let discountInput = $("input[name='bookDiscount']");
		
		let discountRate = userInput.val();					// 사용자가 입력한 할인값
		let sendDiscountRate = discountRate / 100;			// 서버에 전송할 할인값
		let goodsPrice = $("input[name='bookPrice']").val();			// 원가
		let discountPrice = goodsPrice * (1 - sendDiscountRate);		// 할인가격
		
		if(!isNaN(discountRate)){
			$(".span_discount").html(discountPrice);	
		}
		
		
	});	

7. Mapper

수정 쿼리를 실행하는 Mapper, Service, Controller메서드를 만들 것입니다. 먼저 Mapper단계의 메서드부터 작업합니다.

AdminMapper.java

	/* 상품 수정 */
	public int goodsModify(BookVO vo);

AdminMapper.xml
앞서 작성한 메서드가 실행할 태그와 쿼리문을 작성합니다.

	<!-- 상품 정보 수정 -->
	<update id="goodsModify">
		update test_book set bookName = #{bookName}, authorId = #{authorId}, publeYear = #{publeYear}, publisher = #{publisher}, cateCode = ${cateCode}, 
		bookPrice = #{bookPrice}, bookStock = #{bookStock}, bookDiscount = #{bookDiscount}, bookIntro = #{bookIntro}, bookContents = #{bookContents}, updateDate = now()
		where bookId = ${bookId}
	</update>

8. Service

AdminService.java
상품 정보 수정 Mapper메서드를 수행할 Service단계의 메서드 선언부를 작성합니다.

	/* 상품 정보 수정 */
	public int goodsModify(BookVO vo);

AdminServiceImpl.java
AdminService.java에서 선언한 메서드를 오버라이딩하여 구현부를 작성합니다.

	/* 상품 정보 수정 */
	@Override
	public int goodsModify(BookVO vo) {
		
		log.info("goodsModfiy()............");
		
		return adminMapper.goodsModify(vo);
	}

9. Controller

'상품 수정 페이지'에서 수정 버튼을 눌렀을 때 수행할 URL매핑 메서드를 작성합니다.

	/* 상품 정보 수정 */
	@PostMapping("/goodsModify")
	public String goodsModifyPOST(BookVO vo, RedirectAttributes rttr) {
		
		logger.info("goodsModifyPOST........." + vo);
		
		int result = adminService.goodsModify(vo);
		
		rttr.addFlashAttribute("modify_result", result);
		
		return "redirect:/admin/goodsManage";
		
	}

10. View 처리

1) 버튼 동작

goodsModify.jsp페이지의 두번째 <script>태그에 취소 버튼과 수정 버튼을 동작시키는 아래의 코드를 추가합니다.

	/* 취소 버튼 */
	$("#cancelBtn").on("click", function(e){
		e.preventDefault();
		$("#moveForm").submit();
	});
	
	/* 수정 버튼 */
	$("#modifyBtn").on("click", function(e){
		e.preventDefault();
		$("#modifyForm").submit();
	});

2) 유효성 검사 적용

수정 버튼의 경우 서버로 수정 요청을 하기 전 사용자가 작성하지 않은 빈 항목이 없는 확인을 해야 하는데, 이미 '상품 등록'구현 때 작성한 코드가 있기 때문에 이를 활용하여 앞서 작성한 '수정'버튼 코드를 아래의 코드로 수정합니다.

/* 수정 버튼 */
$("#modifyBtn").on("click",function(e){
	
	e.preventDefault();
	
	/* 체크 변수 */
	let bookNameCk = false;
	let authorIdCk = false;
	let publeYearCk = false;
	let publisherCk = false;
	let cateCodeCk = false;
	let priceCk = false;
	let stockCk = false;
	let discountCk = false;
	let introCk = false;
	let contentsCk = false;	
	
	/* 체크 대상 변수 */
	let bookName = $("input[name='bookName']").val();
	let authorId = $("input[name='authorId']").val();
	let publeYear = $("input[name='publeYear']").val();
	let publisher = $("input[name='publisher']").val();
	let cateCode = $("select[name='cateCode']").val();
	let bookPrice = $("input[name='bookPrice']").val();
	let bookStock = $("input[name='bookStock']").val();
	let bookDiscount = $("#discount_interface").val();
	let bookIntro = $(".bit p").html();
	let bookContents = $(".bct p").html();	
	
	/* 공란 체크 */
	if(bookName){
		$(".bookName_warn").css('display','none');
		bookNameCk = true;
	} else {
		$(".bookName_warn").css('display','block');
		bookNameCk = false;
	}
	
	if(authorId){
		$(".authorId_warn").css('display','none');
		authorIdCk = true;
	} else {
		$(".authorId_warn").css('display','block');
		authorIdCk = false;
	}
	
	if(publeYear){
		$(".publeYear_warn").css('display','none');
		publeYearCk = true;
	} else {
		$(".publeYear_warn").css('display','block');
		publeYearCk = false;
	}	
	
	if(publisher){
		$(".publisher_warn").css('display','none');
		publisherCk = true;
	} else {
		$(".publisher_warn").css('display','block');
		publisherCk = false;
	}
	
	if(cateCode != 'none'){
		$(".cateCode_warn").css('display','none');
		cateCodeCk = true;
	} else {
		$(".cateCode_warn").css('display','block');
		cateCodeCk = false;
	}	
	
	if(bookPrice != 0){
		$(".bookPrice_warn").css('display','none');
		priceCk = true;
	} else {
		$(".bookPrice_warn").css('display','block');
		priceCk = false;
	}	
	
	if(bookStock != 0){
		$(".bookStock_warn").css('display','none');
		stockCk = true;
	} else {
		$(".bookStock_warn").css('display','block');
		stockCk = false;
	}		
	
	if(!isNaN(bookDiscount)){
		$(".bookDiscount_warn").css('display','none');
		discountCk = true;
	} else {
		$(".bookDiscount_warn").css('display','block');
		discountCk = false;
	}	
	
	if(bookIntro != '<br data-cke-filler="true">'){
		$(".bookIntro_warn").css('display','none');
		introCk = true;
	} else {
		$(".bookIntro_warn").css('display','block');
		introCk = false;
	}	
	
	if(bookContents != '<br data-cke-filler="true">'){
		$(".bookContents_warn").css('display','none');
		contentsCk = true;
	} else {
		$(".bookContents_warn").css('display','block');
		contentsCk = false;
	}		
	
	/* 최종 확인 */
	if(bookNameCk && authorIdCk && publeYearCk && publisherCk && cateCodeCk && priceCk && stockCk && discountCk && introCk && contentsCk ){
		//alert('통과');
		$("#modifyForm").submit();
	} else {
		return false;
	}

3) '상품 관리(목록) 페이지'

수정을 수행하는 url매핑 메서드에서 수정이 정상적으로 완료되었을 경우 '상품 관리(목록)' 페이지에 데이터를 전송하였습니다. 이를 활용하여 사용자가 자신이 요청한 수정 기능이 정상적으로 완료되었음을 알리는 메시지를 구현할 것입니다. goodsManage.jsp의 <script>태그 내에 있는 document ready메서드 내에 아래의 코드를 추가합니다.

	/* 수정 성공 이벤트 */
	let modify_result = '${modify_result}';
	
	if(modify_result == 1){
		alert("수정 완료");
	}	

11. 테스트




profile
개인이 공부한걸 작성하는 블로그입니다..

0개의 댓글