Kim VamPa

[Spring][쇼핑몰 프로젝트][20] 상품조회 기능 구현 - 1 본문

스프링 프레임워크/쇼핑몰 프로젝트

[Spring][쇼핑몰 프로젝트][20] 상품조회 기능 구현 - 1

Kim VamPa 2021. 4. 20. 10:05
728x90
반응형
프로젝트 Github : https://github.com/sjinjin7/Blog_Project
프로젝트 포스팅 색인(index) : https://kimvampa.tistory.com/188

목표

상품 조회 페이지 구현

 이번 포스팅에서는 상품 목록(goodsManage.jsp) 페이지에서 상품의 이름을 클릭하였을 때 이동하는 조회 페이지를 구현하고자 합니다. 조회 페이지에는 선택한 상품에 관한 등록된 정보가 출력되어야 합니다. 앞서 구현했던 작가 조회 페이지 구현과 동일합니다. 단, 조금 신경 써야 할 처리가 출판일과 카테고리 항목입니다. 이는 다음 포스팅에서 진행합니다.

 

 정보를 불러오기 위한 Mapper 부터 작업을 하여 service, controller, jsp 순으로 진행하겠습니다.

 

 

 

순서

1. Mapper 메서드

2. Service 메서드

3. Controller 

4. View 처리

 

 

 

1.  Mapper 메서드

AdminMapper.java

 

  조회 쿼리를 호출하는 메서드를 AdminMapper.java 인터페이스에 추가합니다.

 

	/* 상품 조회 페이지 */
	public BookVO goodsGetDetail(int bookId);

 

그림 1-1

 

AdminMapper.xml

 

 위에서 작성한 메서드가 실행할 태그 및 쿼리문을 작성합니다. 조회 페이지에 사용자가 보기 편하도록 작가ID가 아닌 작가 이름이 나오도록 서브쿼리를 삽입하였습니다.

 

	<!-- 상품 조회 페이지 -->
	<select id="goodsGetDetail" resultType="com.vam.model.BookVO">
	
		select bookId, bookName, (select authorName from vam_author where authorId =vam_book.authorId) authorName, 
			authorId, publeYear, publisher, cateCode, bookPrice, bookStock, bookDiscount, bookIntro, bookContents, regDate, updateDate 
		from vam_book where bookId = #{bookId}
	
	</select>

 

그림 1-2

 

AdminMapperTests.java

 

 작성한 Mapper 메서드가 정상적으로 동작하는지 확인을 하기 위해서 AdminMapperTest.java 클래스에 아래의 코드를 추가 및 Junit 테스트를 합니다.

 

	/* 상품 조회 페이지 */
	@Test
	public void goodsGetDetailTest() {
		
		int bookId = 150;
		
		BookVO result = mapper.goodsGetDetail(bookId);
		
		System.out.println("상품 조회 데이터 : " + result);
		
		
	}

 

그림 1-3

 

그림 1-4

 

2. Service 메서드

 

 Mapper와 Controller을 연결 시켜줄 Service 메서드를 작성하겠습니다. AdminService.java 인터페이스에 아래의 메서드 선언부를 추가합니다.

 

	/* 상품 조회 페이지 */
	public BookVO goodsGetDetail(int bookId);	

 

그림 2-1

 

 AdminServiceImpl.java 클래스에 앞서 추가한 메서드를 오버라이딩 하여 구현합니다.

 

	/* 상품 조회 페이지 */
	@Override
	public BookVO goodsGetDetail(int bookId) {
		
		log.info("(service)bookGetDetail......." + bookId);
		
		return adminMapper.goodsGetDetail(bookId);
	}	

 

그림 2-2

 

3. Controller

 AdminController.java 클래스에 '상품 조회 페이지' 이동을 위한 url 매핑 메서드를 아래와 같이 추가해줍니다.

 

 사용자가 선택한 상품에 대한 정보를 가져오는 mapper 메서드를 실행시키기 위해 int 타입의 bookId 변수를 파라미터로 추가하였고, 상품 조회 페이지 이동 후 다시 목록 페이지로 이동할 때 필요로 한 데이터인 Criteria 클래스, 상품 조회 페이지에 데이터를 전 달해 주기 위해 Model 클래스를 파라미터로 추가하였습니다.

 

구현부에는 Model 클래스를 사용하여 전달받은 Criteria 정보와 상품 조회 정보를 페이지에 전달하는 코드를 추가하였습니다.

 

	/* 상품 조회 페이지 */
	@GetMapping("/goodsDetail")
	public void goodsGetInfoGET(int bookId, Criteria cri, Model model) {
		
		logger.info("goodsGetInfo()........." + bookId);
		
		/* 목록 페이지 조건 정보 */
		model.addAttribute("cri", cri);
		
		/* 조회 페이지 정보 */
		model.addAttribute("goodsInfo", adminService.goodsGetDetail(bookId));
		
	}

 

그림 3-1

 

 

4. View 처리

 사용자가 '상품 목록(goodsManage.jsp) 페이지'에서 상품 이름을 클릭하였을때 '상품 조회(goodsDetail.jsp) 페이지'로 이동할 수 있도록 해주는 작업을 먼저 진행합니다.

 

 goodsManage.jsp에서 상품 이름이 출력되는 코드를 아래의 태그와 같이 <a> 태그로 감싸줍니다. <a> 태그의 href속성은 선택되는 상품의 ID가 출력이 되도록 작성하였습니다.

 

<a class="move" href='<c:out value="${list.bookId}"/>'>
	<c:out value="${list.bookName}"></c:out>
</a>

 

그림 4-1

 

 

 작성한 <a> 태그가 동작하도록 <script> 태그에 아래의 Javascript코드를 추가해줍니다.

 

/* 상품 조회 페이지 */
$(".move").on("click", function(e){
	
	e.preventDefault();
	
	moveForm.append("<input type='hidden' name='bookId' value='"+$(this).attr("href") + "'>");
	moveForm.attr("action", "/admin/goodsDetail");
	moveForm.submit();
	
	
});

 

그림 4-2

 

 

 "goodsDetail" jsp, css파일을 새로 생성해주고, jsp파일에 css파일을 연결해주는 <link> 태그를 추가해줍니다. 그리고 jquery를 사용하기 위해 <script> 코드와 jstl을 사용하기 위해 라이브러리 코드를 추가해주었습니다. 

 

그림 4-3

 

그림 4-4

 서버를 구동시켜서 '상품 목록'페이지에서 '상품 조회'페이지로 이동하는지 확인합니다.

 

그림 4-5

 

 확인을 위해 작성한 <h1> 태그를 지우고 <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">

                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>책 제목</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="bookName" value="<c:out value="${goodsInfo.bookName}"/>" disabled>
                    			</div>
                    		</div>
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>등록 날짜</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input value="<fmt:formatDate value='${goodsInfo.regDate}' pattern='yyyy-MM-dd'/>" disabled>
                    			</div>
                    		</div>
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>최근 수정 날짜</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input value="<fmt:formatDate value='${goodsInfo.updateDate}' pattern='yyyy-MM-dd'/>" disabled>
                    			</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 }" disabled>
                    				                    				
                    			</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" value="<c:out value="${goodsInfo.publeYear}"/>" disabled>                    				
                    			</div>
                    		</div>            
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>출판사</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="publisher" value="<c:out value="${goodsInfo.publisher}"/>" disabled>
                    			</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" disabled>
                    						<option  value="none">선택</option>
                    					</select>
                    				</div>
                    				<div class="cate_wrap">
                    					<span>중분류</span>
                    					<select class="cate2" disabled>
                    						<option  value="none">선택</option>
                    					</select>
                    				</div>
                    				<div class="cate_wrap">
                    					<span>소분류</span>
                    					<select class="cate3" name="cateCode" disabled>
                    						<option value="none">선택</option>
                    					</select>
                    				</div>                  				                    				
                    			</div>
                    		</div>          
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>상품 가격</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="bookPrice" value="<c:out value="${goodsInfo.bookPrice}"/>" disabled>
                    			</div>
                    		</div>               
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>상품 재고</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="bookStock" value="<c:out value="${goodsInfo.bookStock}"/>" disabled>
                    			</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" disabled>
                    			</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" disabled>${goodsInfo.bookIntro}</textarea>
                    			</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" disabled>${goodsInfo.bookContents}</textarea>
                    			</div>
                    		</div>
                   		
                   			<div class="btn_section">
                   				<button id="cancelBtn" class="btn">상품 목록</button>
	                    		<button id="enrollBtn" class="btn enroll_btn">수정 </button>
	                    	</div> 
                    </div>      

                	
                	<form id="moveForm" action="/admin/goodsManage" method="get" >
 						<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
						<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
						<input type="hidden" name="keyword" value="${pageMaker.cri.keyword}">
                	</form>
                	
                </div>
 				<%@include file="../includes/admin/footer.jsp" %>

 

그림 4-6

 

 등록 페이지의 태그 코드들을 그대로 가져와서 일부를 수정 및 추가하였습니다. 

 

- <form> 태그를 지웠습니다.

- 각 항목의 경고 문구 태그를 지웠습니다.

- 각 input 태그의 name 속성을 지웠습니다. (안 지워도 상관없습니다.)

- 작가 검색 버튼을 지웠습니다.

 

- '상품 ID', '상품 등록 날짜', '상품 수정 날짜'가 출력되도록 코드를 추가하였습니다.

- 각 <input>, <select> 태그에 사용자가 입력을 할 수 없도록 disabled 속성을 추가하였습니다.

- 각 <input> 태그 <textarea> 태그에 서버로부터 전달받은 상품 정보가 출력되도록 코드를 추가하였습니다.

 

 

 페이지를 꾸며주기 위해서 'goodsDetail.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;
}

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

.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;
}






/* 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;
}

 

 추가 해준 후 정상적으로 출력이 되는지 '상품 조회 페이지'에 접속해봅니다.

 

그림 4-7

 

결과물을 보시면 아직 출력이 안된 부분이 있거나 데이터는 출력이 되어있지만 가공을 해주어야 하는 부분이 있습니다. 이는 다음 포스팅에서 진행합니다.

 

 

REFERENCE

 

DATE

  • 2020.04.20
728x90
반응형
Comments