기능구현

  • 회원가입(주소API연동, 이메일 인증, ajax를 사용하여 아이디 중복검사)
  • 관리자 페이지(인터셉터 적용, 상품관리, 회원관리)
  • 업로드(이미지 등록, 수정, 삭제)
  • 검색
  • 페이징
  • 구매(장바구니, 포인트사용)
  • 댓글(등록,수정,삭제)
  • 중간에 막혔거나 에러 해결 못하겠으면 ybnr92@gmail.com 으로 문의


목표

  • 작가 목록 출력 쿼리 구현


순서

  • 수정사항
  • Criteria 작성
  • AuthorMapper.java
  • AuthorMapper.xml
  • AuthorMapper 메서드 테스트


  • 정해진 갯수와 페이지의 작가 정보를 출력을 구현한 뒤 사용자가 마우스를 통해 페이지 이동을 할 수 있도록 페이지네이션을 구현할 예정이다.
  • 이번편은 지정한 수만큼 작가 데이터를 출력시키는데 필요로 한 쿼리 작성과 해당 쿼리를 호출하는 Mapper 작성을 목표로 한다.


수정사항

  • /resource/admin 폴더에 있는 css 모든 파일에 .admin_content_wrap 식별자가 가지고 있는 height 속성을 지우고 min-height 속성을 작성한다. height 속성의 경우 고정된 높이지만, min-height 속성의 경우는 속성 값으로 최소 높이를 설정하여 속성 값보다 높이가 작아지는 것을 방지하면서 그 이상의 높이는 유동적으로 변경될 수 있도록 해준다.
  • 적용 대상 파일
    • authorEnroll.css
    • authorManage.css
    • goodsEnroll.css
    • goodsManage.css
    • main.css


/* 기존 코드 */
.admin_content_wrap{
    width: 80%;
    float:left;
    height: 100%;  
    height:700px;
}
 
/* 수정 코드 */
.admin_content_wrap{
    width: 80%;
    float:left;
    min-height:700px;
}


admin 폴더 jsp 파일 include 태그 적용

  • admin 폴더에서 중복이자 공통적으로 적용되는 코드를 include태그를 적용을 한다. 각 jsp파일마다 변경될 코드에 집중할 수 있도록 하기 위함이다. 더불어 공통되는 코드들을 하나의 파일로 관리하는 것이기 때문에 유지보수에도 용이하다.
  • ../WEB-INF/views경로에 includes/admin 폴더를 생성 후 header.jsp, footer.jsp 파일을 생성한다. 각 파일에 아래의 코드만 남기고 모든 태그 코드를 삭제한다.


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>


  • admin 폴더에 있는 jsp 파일 중 한 파일을 선택해서 body태그 다음의 코드부터 class 속성값이 admin_content_wrap인 div 태그 이전 코드까지 복사하여 head.jsp 파일에 붙여 넣는다.
 
    <div class="wrapper">
        <div class="wrap">
            <!-- gnv_area -->    
            <div class="top_gnb_area">
                <ul class="list">    
                    <li><a href="/main">메인 페이지</a></li>
                    <li><a href="/member/logout.do">로그아웃</a></li>
                    <li>고객센터</li>            
                </ul>
            </div>
            <!-- top_subject_area -->
            <div class="admin_top_wrap">
                <span>관리자 페이지</span>
                
            </div>
            <!-- contents-area -->
            <div class="admin_wrap">
                <!-- 네비영역 -->
                <div class="admin_navi_wrap">
                  <ul>
                      <li >
                          <a class="admin_list_01" href="/admin/goodsEnroll">상품 등록</a>
                      </li>
                      <li>
                          <a class="admin_list_02" href="/admin/goodsManage">상품 관리</a>
                      </li>
                      <lI>
                          <a class="admin_list_03" href="/admin/authorEnroll">작가 등록</a>                            
                      </lI>
                      <lI>
                          <a class="admin_list_04" href="/admin/authorManage">작가 관리</a>                            
                      </lI>
                      <lI>
                          <a class="admin_list_05">회원 관리</a>                            
                      </lI>                                                                                             
                  </ul>
                </div>


  • class 속성 값이 admin_content_wrap인 div 태그 다음 코드부터 /body 혹은 script 태그 이전 코드들을 복사 하여 footer.jsp파일에 붙여 넣는다.


<div class="clearfix"></div>
            </div>
        
        <!-- Footer 영역 -->
        <div class="footer_nav">
            <div class="footer_nav_container">
                <ul>
                    <li>회사소개</li>
                    <span class="line">|</span>
                    <li>이용약관</li>
                    <span class="line">|</span>
                    <li>고객센터</li>
                    <span class="line">|</span>
                    <li>광고문의</li>
                    <span class="line">|</span>
                    <li>채용정보</li>
                    <span class="line">|</span>
                </ul>
            </div>
        </div> <!-- class="footer_nav" -->
        
        <div class="footer">
            <div class="footer_container">
                
                <div class="footer_left">
                    <img src="../resources/img/civically-1.jpg">
                </div>
                <div class="footer_right">
                    (주) 이름없는 회사    대표이사 : OOO
                    <br>
                    사업자등록번호 : ooo-oo-ooooo
                    <br>
                    대표전화 : oooo-oooo(발신자 부담전화)
                    <br>
                    <br>
                    COPYRIGHT(C) <strong>yoonbitnara.github.io</strong>    ALL RIGHTS RESERVED.
                </div>
                <div class="clearfix"></div>
            </div>
        </div> <!-- class="footer" -->        
        
    </div>    <!-- class="wrap" -->
</div>    <!-- class="wrapper" -->


  • 아래의 코드를 view/admin 폴더에 있는 모든 파일에 위에서 복사한 코드들과 동일한 코드들을 아래의 태그로 변경해준다.


    <%@include file="../includes/admin/header.jsp" %>
 
    <%@include file="../includes/admin/footer.jsp" %>


  • 대략 아래와 같이 header, footer 부분을 include한다.


<%@ 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/authorEnroll.css">
 
<script
  src="https://code.jquery.com/jquery-3.4.1.js"
  integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
  crossorigin="anonymous"></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/authorEnroll.do" method="post" id="enrollForm">
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>작가 이름</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="authorName">
                    				<span id="warn_authorName">작가 이름을 입력 해주세요.</span>
                    			</div>
                    		</div>
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>소속 국가</label>
                    			</div>
                    			<div class="form_section_content">
                    				<select name="nationId">
                    					<option value="none" selected>=== 선택 ===</option>
                    					<option value="01">국내</option>
                    					<option value="02">국외</option>
                    				</select>
                    				<span id="warn_nationId">소속 국가를 선택해주세요.</span>
                    			</div>
                    		</div>
                    		<div class="form_section">
                    			<div class="form_section_title">
                    				<label>작가소개</label>
                    			</div>
                    			<div class="form_section_content">
                    				<input name="authorIntro" type="text">
                    				<span id="warn_authorIntro">작가 소개를 입력 해주세요.</span>
                    			</div>
                    		</div>
                   		</form>
                   			<div class="btn_section">
                   				<button id="cancelBtn" class="btn">취 소</button>
	                    		<button id="enrollBtn" class="btn enroll_btn">등 록</button>
	                    	</div> 
                    </div>
                    <!-- 작가 정보 작성 및 전송 코드 추가 -->
                </div>
                <div class="clearfix"></div>
            </div>
        
<%@include file="../includes/admin/footer.jsp" %>


  • jsp 파일이 함축되어 가독성이 좋아졌다.


Criteria 클래스 작성

  • com.store.model 패키지에 Criteria.java 클래스를 생성 후 아래의 코드를 작성한다.
  • 해당 클래스는 지정한 개수와 검색 조건에 따라서 작가 데이터를 출력하는 쿼리를 실행하는데 필요로 한 데이터들의 모임이다.
  • 참고로 Criteria는 기준이라는 의미다.
  • 아래의 코드를 추가한다.


public class Criteria {
	
	/* 현재 페이지 번호 */
	private int pageNum;
	
	/* 페이지 표시 개수 */
	private int amount;
	
	/* 페이지 skip */
	private int skip;
	
	/* 검색 타입 */
	private String type;
	
	/* 검색 키워드 */
	private String keyword;
	
	/* Criteria 생성자 */
	public Criteria(int pageNum, int amount) {
		
		this.pageNum 	= pageNum;
		this.amount 	= amount;
		this.skip 		= (pageNum -1) * amount;
		
	}
	
	/* Criteria 기본 생성자 */
	public Criteria() {
		
		this(1,10);
	}
	
	/* 검색 타입 데이터 배열 변환 */
	public String[] getTypeArr() {
		
		return type == null ? new String[] {}:type.split("");
	}
  • getter,setter,toString 메서드를 추가한다.


package com.store.model;

public class Criteria {
	
	/* 현재 페이지 번호 */
	private int pageNum;
	
	/* 페이지 표시 개수 */
	private int amount;
	
	/* 페이지 skip */
	private int skip;
	
	/* 검색 타입 */
	private String type;
	
	/* 검색 키워드 */
	private String keyword;
	
	/* Criteria 생성자 */
	public Criteria(int pageNum, int amount) {
		
		this.pageNum 	= pageNum;
		this.amount 	= amount;
		this.skip 		= (pageNum -1) * amount;
		
	}
	
	/* Criteria 기본 생성자 */
	public Criteria() {
		
		this(1,10);
	}
	
	/* 검색 타입 데이터 배열 변환 */
	public String[] getTypeArr() {
		
		return type == null ? new String[] {}:type.split("");
	}

	public int getPageNum() {
		return pageNum;
	}

	public void setPageNum(int pageNum) {
		this.pageNum = pageNum;
	}

	public int getAmount() {
		return amount;
	}

	public void setAmount(int amount) {
		this.amount = amount;
	}

	public int getSkip() {
		return skip;
	}

	public void setSkip(int skip) {
		this.skip = skip;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getKeyword() {
		return keyword;
	}

	public void setKeyword(String keyword) {
		this.keyword = keyword;
	}

	@Override
	public String toString() {
		return "Criteria [pageNum=" + pageNum + ", amount=" + amount + ", skip=" + skip + ", type=" + type
				+ ", keyword=" + keyword + "]";
	}
	
	
	
	
}


  • amount와 pageNum 변수의 값이 변경될때 skip변수의 값도 변경되도록 setAmount(), setPageNum() 메서드를 일부 수정해준다.
  • Criteria 클래스의 데이터를 사용할 때 매번 새로운 생성자를 호출하여 사용하기 때문에 해당 과정이 필요 없지만 혹시 모를 경우를 위해 작업했다.


	public void setPageNum(int pageNum) {
		this.pageNum = pageNum;
		this.skip = (pageNum - 1) * this.amount;
	}

    	public void setAmount(int amount) {
		this.amount = amount;
		this.skip = (this.pageNum - 1) * this.amount;
	}


AuthorMapper.java 인터페이스

  • 작가 데이터 목록 쿼리를 실행하는 메서드를 선언한다.
  • 여러 작가의 데이터를 반환받아야 하기 때문에 리턴 타입으로 List 자료구조를 지정하였다.
    • List는 배열과 비슷한 자료구조이다. 배열과는 다르게 삽입되는 데이터에 따라 크기가 동적으로 변한다.
  • List에 저장될 데이터가 AuthorVO(작가정보)임을 명시하기 위해 AuthorVO 제네릭을 선언하였다.
  • List는 java.util.List를 import 해야 한다.


package com.store.mapper;

import java.util.List;

import com.store.model.AuthorVO;
import com.store.model.Criteria;

public interface AuthorMapper {
	
	/* 작가 등록 */
	public void authorEnroll(AuthorVO author);
	
	/* 작가 목록 */
	public List<AuthorVO> authorGetList(Criteria cri);

}


AuthorMapper.xml

  • AuthorMapper.java 인터페이스에서 선언한 메서드가 실행할 쿼리 코드를 작성한다.
  • select 태그의 resultType속성 값은 com.store.model.AuthorVO를 부여한다.
  • resultType을 클래스로 지정하였지만 메서드의 리턴 타입을 List로 선언하였기 때문에 MyBatis가 지정된 클래스 인스턴스 요소를 가지는 List로 자동 변환해준다.


<?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="com.store.mapper.AuthorMapper">
  	
  	<!-- 작가 등록 -->
  	<insert id="authorEnroll">
  		insert into author(authorName, nationId, authorIntro) values(#{authorName}, #{nationId}, #{authorIntro});
  	</insert>
  	
  	<!-- 작가 목록 -->
  	<select id="authorGetList" resultType="com.store.model.AuthorVO">
  		select authorid, authorname, nationid, regdate, updatedate
  		from author
  		<if test="keyword != null">
  			where authorname like concat('%',#{keyword}, '%')
  		</if>
  		order by authorid desc
  		limit #{skip}, #{amount}
  	</select>
      
  </mapper>


AuthorMapper 메서드 테스트

  • 새로 작성한 authorGetList() 메서드가 정상적으로 동작하는지 확인하기 위해 테스트를 진행한다.
  • 테스트하기 앞서 페이징 적용이 되는지 확인하기 위해 재귀 복사를 통해 여러 행을 추가해주었다.


insert into author(authorname, nationid)(select authorname, nationid from author);



  • AuthorMapperTests.java 클래스에 기존 테스트 코드는 주석 처리를 한 후 아래의 코드를 추가한다.
  • Junit테스트를 하여 정상적으로 동작하는지를 확인한다.


	/* 작가 목록 테스트 */
	@Test
	public void authorGetListTest() throws Exception {
		
		Criteria cri = new Criteria(3,10); // 3page & 10개 행 표시
		
		List<AuthorVO> list = mapper.authorGetList(cri);
		
		for(int i = 0; i < list.size(); i++) {
			System.out.println("list" + i + ".............." + list.get(i));
		}
		
	}



  • 검색어를 입력한 경우에도 쿼리가 정상적으로 동작하는지 확인하기 위해 keyword 변수에 데이터를 넣은 후 테스트를 해본다.


	/* 작가 목록 테스트 */
	@Test
	public void authorGetListTest() throws Exception {
		
		Criteria cri = new Criteria(3,10); // 3page & 10개 행 표시
		cri.setKeyword("핏불");
		
		List<AuthorVO> list = mapper.authorGetList(cri);
		
		for(int i = 0; i < list.size(); i++) {
			System.out.println("list" + i + ".............." + list.get(i));
		}
		
	}



  • 잘된다.

Leave a comment