본문 바로가기
Today I learned

1월7일

by soheemon 2019. 1. 7.

Controller => Action => Service => DAO => Mybatis => DB

=Service를 건너뛰고 바로 DAO를 호출하는 일이 없도록 하자.

Controller부터 Action까지는 Spring이 대신 해주지만, 그 이후에 로직은 지금이나 Spring을 쓸때나 같다.

*Service


client로부터 요청이 들어오면 controller가 요청에 따라 Action을 호출하고 Action내에서 dao를 호출했다.

=> 단순한 처리였기때문에 가능했다. 하지만 복잡한 기능을 처리해야 하는 경우 서비스 로직이 필요하다.


예를들어서 CRUD로 가져온 데이터를 재 가공 하거나, DAO를 여러번 호출해야 하거나 할때. <DAO는 DB를 단순 호출한다.>

사례를 보자> 인터넷쇼핑에서 주문기능이 있을때. 내부적으로는 어떤 처리를 해야할까? 단순히 DB에 쿼리하나만 날려서 될 일이 아니다.

재고를 줄이고.. 결재를 하고.. 여러가지 동작이 필요하다.

=> 이런것을 서비스라고 할 수 있지!


//예제를 살펴보자.

//기존의 listAction는 Board테이블 안의 모든 글을 List.jsp(뷰)에게 줬었고

//List.jsp 는 아무생각없이 받은 글들을 출력했었다.

=> 예제에 페이징 기능을 추가해보자.!


//listAction.jsp Service로직을 BoardService라는 클래스로 전부 옮겼다. 간결해졌다.

package kosta.action;


import java.util.List;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import kosta.bean.Board;

import kosta.bean.BoardDao2;

import kosta.bean.BoardService;

import kosta.bean.ListModel;

import kosta.bean.Search;

public class listAction implements Action {


@Override

public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {

BoardService service = BoardService.getInstance();

//데이터 뿐만 아니라 페이징 정보까지 받기 위해 ListModel객체로 받는다.

ListModel list = service.listBoardService(request);

request.setAttribute("listModel", list);

ActionForward forward = new ActionForward();

forward.setRedirect(false);

forward.setPath("List.jsp");


return forward;

}

}


2)Service 로직


package kosta.bean;


import java.util.List;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;


/*

 * DAO메서드 하나만 호출해서 해결되지 않는 비즈니스 로직을 위해 서비스 클래스를 만들었다.

 * 페이징 처리

 * 1) 페이지당 글 갯수 정하기

 * 2) 총 글 개수 구하기

 * 3) 총 페이지 수 구하기

 * 4) 현재 페이지에 뿌려줄 글 가져오기.

 * 5) 시작페이지번호, 마지막 페이지번호 구하기.

 */


public class BoardService {

private static BoardDao2 dao;

private static BoardService service = new BoardService();

private static final int MAX_BOARD_COUNT = 2; //한페이지에 들어갈 최대 글 갯수!

private static final int MAX_PAGE_COUNT = 5; //한페이지에 표시될 페이지목록의 최대 숫자.

public static BoardService getInstance() {

dao = BoardDao2.getInstance(); 

return service;

}



public Search setSearchToSession(HttpServletRequest request) {

Search search = new Search();

HttpSession session = request.getSession();

String sk = "";

String[] area = null;

//검색조건의 체크박스에 체크가 되어있을 경우 새로운 검색어를 가져온다.

if((area = request.getParameterValues("area")) != null) {

sk = request.getParameter("searchKey");

search.setSearchKey('%' + sk + '%');

search.setArea(area);

session.setAttribute("search", search);

}else if(area == null && (search = (Search)session.getAttribute("search")) != null) {

}

return search;

}

//사용자가 요청하는 페이지에 따라서 표시해야할 페이지 예) 2를 클릭하면 1,2,3,4,5를 표시한다.

public ListModel listBoardService(HttpServletRequest request) throws Exception{

//사용자가 클릭한 페이지번호 가져오기.

String pageNum = request.getParameter("pageNum");

//default = 1page.

if(pageNum == null) {

pageNum = "1";

}

int userRequestPage = Integer.parseInt(pageNum);

Search search = setSearchToSession(request);

// 2)총 글개수

int totalCount = dao.countBoard(search); // Search글개수에 따른 totalCount 구하기.

// 3)총 페이지수

int totalPageCount = totalCount/MAX_BOARD_COUNT;

// 잔여 페이지 처리

if(totalCount % MAX_BOARD_COUNT > 0) {

totalPageCount++;

}

//시작페이지, 마지막페이지 구하기

//시작페이지 공식 = 사용자요청페이지 - (사용자요청페이지 - 1) % (몇페이지씩 보여줄지)

int startPage = userRequestPage - (userRequestPage - 1) % MAX_PAGE_COUNT;

int endPage = startPage + (MAX_PAGE_COUNT - 1); //5page씩 약속을 했으니깐!

//글이 적어서 endPage가 MAX_PAGE_COUNT 보다 적으면

if(endPage > totalPageCount) {

endPage = totalPageCount;

}

//startRow = 화면에 출력해야할 row 중에서 시작.

//startRow 구하기: (사용자가 요청한 페이지  - 1) * 페이지당 글갯수

int startRow = (userRequestPage - 1) * MAX_BOARD_COUNT;

//startRow에서 해당하는 Board객체를 받아온다.

List<Board> list = dao.listBoard(search, startRow);

//글과 함께 list객체(글정보가 들어있음!) 그리고 사용자가 요청한 페이지.. 총페이지.. 화면에 표시할 페이지를 객체로 만들어서 return 한다!

ListModel listModel = new ListModel(list, userRequestPage, totalPageCount, startPage, endPage);//객체로 던지기 위해 생성

return listModel;

}

}



길어지긴 했지만 크게 어려운 내용은 없다.

함께 살펴보자.


//싱글톤패턴으로 dao객체를 싱글톤으로 생성 후, service를 return 한다.

//상수들은 주석과 같다.


private static BoardDao2 dao;

private static BoardService service = new BoardService();

private static final int MAX_BOARD_COUNT = 2; //한페이지에 들어갈 최대 글 갯수!

private static final int MAX_PAGE_COUNT = 5; //한페이지에 표시될 페이지목록의 최대 숫자.


public static BoardService getInstance() {

dao = BoardDao2.getInstance(); 

return service;

}


 listBoardService

//사용자가 클릭한 페이지번호에 따라 최대 2개의 글을 list에 담고,

//뷰에서 페이징 처리를 해주기 위해서 총 페이지 갯수(totalPageCount)/ 사용자가 클릭한 페이지의 화면에 표시될 첫페이지 (startPage)/

사용자가 클릭한 페이지의 화면에 표시될 마지막 페이지 숫자(endPage)를 객체로 return 한다.

 

=> 글 갯수에 따라 | 1 | 2 | 3 | 4 | 5 | 이렇게 표시한다. 만약 사용자가 4를 클릭했으면, startPage는 1이고 endPage는 5가 되어야 겠지.






//시작페이지, 마지막페이지 구하기


//시작페이지 공식 = 사용자요청페이지 - (사용자요청페이지 - 1) % (몇페이지씩 보여줄지)


int startPage = userRequestPage - (userRequestPage - 1) % MAX_PAGE_COUNT;


int endPage = startPage + (MAX_PAGE_COUNT - 1); //5page씩 약속을 했으니깐!




//글이 적어서 endPage가 MAX_PAGE_COUNT 보다 적으면




if(endPage > totalPageCount) {


endPage = totalPageCount;


}




//startRow = 화면에 출력해야할 row 중에서 시작.


//startRow 구하기: (사용자가 요청한 페이지  - 1) * 페이지당 글갯수


int startRow = (userRequestPage - 1) * MAX_BOARD_COUNT;



//사용자가 클릭한 페이지번호 가져오기. 글 클릭시 뷰에서 파라미터로 넘겨준다.

//최초 화면이 load됐을경우 1로 설정해준다 (1page 보여주려고)

String pageNum = request.getParameter("pageNum");


//default = 1page.


if(pageNum == null) {

pageNum = "1";

}


int userRequestPage = Integer.parseInt(pageNum);


//구하기 위해 아래와 같은 메서드를 실행하는데 우선 기본 로직이 아니니까 뒤에서 설명하자.

public Search setSearchToSession(HttpServletRequest request) {

Search search = new Search();

HttpSession session = request.getSession();

String sk = "";

String[] area = null;


//검색조건의 체크박스에 체크가 되어있을 경우 새로운 검색어를 가져온다.


if((area = request.getParameterValues("area")) != null) {


sk = request.getParameter("searchKey");

search.setSearchKey('%' + sk + '%');

search.setArea(area);

session.setAttribute("search", search);

}else if(area == null && (search = (Search)session.getAttribute("search")) != null) {

}

return search;

}


//총 글개수를 구한다. 여기서 첫번째 Mapper메서드를 호출한다.

//Board.xml에 id countBoard를 select태그로 선언하고, BoardMapper/BoardDao에서 메서드로 맵핑해준다.

//총 페이지 개수는, 모든 글을 페이징한다고 했을때의 총 페이지 개수이다. 화면에 표시될 최대 글개수를 의미한다.

// 그 후 총 글개수가 최대페이지수로 나누어서 떨어지지 않을경우(잔여페이지)를 처리해준다.

Search search = setSearchToSession(request); // 뒤에서 설명할 메서드


// 2)총 글개수

int totalCount = dao.countBoard(search); // Search글개수에 따른 totalCount 구하기.


// 3)총 페이지수

int totalPageCount = totalCount/MAX_BOARD_COUNT;


// 잔여 페이지 처리

if(totalCount % MAX_BOARD_COUNT > 0) {

totalPageCount++;


}


//1 | 2 | 3 | 4 | 5 이런 페이지리스트가 있을때,

//사용자가 임의로 클릭한 페이지에서 시작페이지 넘버와, 마지막 페이지 넘버를 구하는 과정.

//일정한 공식이 있다.


//후에 두번째 MapperMethod를 호출한다.(listBoard)

하지만 listBoard메서드는 이전과 다르다. search(이후 설명)와 startRow를 인자로 받는다.


//시작페이지, 마지막페이지 구하기

//시작페이지 공식 = 사용자요청페이지 - (사용자요청페이지 - 1) % (몇페이지씩 보여줄지)

int startPage = userRequestPage - (userRequestPage - 1) % MAX_PAGE_COUNT;

int endPage = startPage + (MAX_PAGE_COUNT - 1); //5page씩 약속을 했으니깐!

//글이 적어서 endPage가 MAX_PAGE_COUNT 보다 적으면

if(endPage > totalPageCount) {

endPage = totalPageCount;

}

//startRow = 화면에 출력해야할 row 중에서 시작.

//startRow 구하기: (사용자가 요청한 페이지  - 1) * 페이지당 글갯수

int startRow = (userRequestPage - 1) * MAX_BOARD_COUNT;

//startRow에서 해당하는 Board객체를 받아온다.

List<Board> list = dao.listBoard(search, startRow);

//글과 함께 list객체(글정보가 들어있음!) 그리고 사용자가 요청한 페이지.. 총페이지.. 화면에 표시할 페이지를 객체로 만들어서 return 한다!

ListModel listModel = new ListModel(list, userRequestPage, totalPageCount, startPage, endPage);//객체로 던지기 위해 생성

return listModel;

}



//변경후 listBoard

특이사항은 Rowbounds()객체를 파라미터로 전달한다는점이다.

RowBounds함수는 DB 조회 결과중에서 startRow번째부터, MAX_BOARD_COUNT개만큼을 list로 반환해준다는것이다.

(즉, 결과가 몇개라도 내가 원하는 번호의 행에서 2개만 가져 올 수 있다.)

        public List<Board> listBoard(Search search, int startRow){

               SqlSession sqlSession = getSqlSessionFactory().openSession();

               List<Board> list = null;

              

               try {

                       //DB조회 결과중에서 startRow번부터 2개만 떼서 준다.

                       list = sqlSession.getMapper(BoardMapper.class).listBoard(new RowBounds(startRow, BoardService.MAX_BOARD_COUNT), search);

                                                                                                                                 //RowBounds = Mybatis에던지는게 아니라, 시작과 마지막값을 지정할 있음!

                                                                                                                                 //결과가 10개라도 RowBounds 해당하는 갯수의 list객체를 만들어준다!

                                                                                                                                 //XML 실행할 필요가 없다!

               } catch (Exception e) {

                       e.printStackTrace();

               }

               return list;

        }


//여기까지 마치면 페이징에 대한 서버측 구현은 마무리된다.


//리스트를 표시해줄 List.jsp

<%@page import="kosta.bean.BoardDao2"%>

<%@page import="kosta.bean.Board"%>

<%@page import="java.util.List"%>

 

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

   

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

        <h3>글목록 보기</h3>

        <a href="insertForm.do"> 글쓰기 </a>

        <table width="500" border="1" cellpadding="0" cellspacing="0">

               <tr>

                       <td>글번호</td>

                       <td>제목</td>

                       <td>작성자</td>

                       <td>작성일</td>

                       <td>조회수</td>

               </tr>

               <c:forEach var="board" items='${listModel.list}'>

               <tr>

                       <td>${board.seq}</td>

                      

                       <td><a href="detail.do?seq=${board.seq}">${board.title}</a></td>

                       <td>${board.writer}</td>

                       <td>

                              <fmt:parseDate var="dateString" value='${board.regdate}'

                               pattern="yyyy-MM-dd"/>

                              <fmt:formatDate value="${dateString}" pattern="yyyy-MM-dd"/>

                                     

                       </td>

                       <td>${board.hitcount}</td>

                       <td>

                                      <c:if test="${board.fname != null }">

                                              <c:set var="head" value="${fn:substring(board.fname,

                                                                                           0, fn:length(board.fname)-4) }"></c:set>

                                              <c:set var="pattern" value="${fn:substring(board.fname,

                                              fn:length(head) +1, fn:length(board.fname)) }"></c:set>

                                     

                                              <c:choose>

                                                     <c:when test="${pattern == 'jpg' || pattern == 'gif' }">

                                                             <img src="upload/${head }_small.${pattern}">

                                                     </c:when>

                                                     <c:otherwise>

                                                             <c:out value="NO IMAGE"></c:out>

                                                     </c:otherwise>

                                              </c:choose>

                                      </c:if>

                              </td>

               </tr>

               </c:forEach>

        </table>

       

        <!-- 페이지처리 영역 -->

       

        <!-- 이전  startPage-->

        <c:if test='${listModel.startPage > 5}'>

               <a href="List.do?pageNum=${listModel.startPage - 5}"> [이전] </a>

        </c:if>

       

        <!-- 페이지 목록 -->

        <c:forEach var = "pageNo" begin='${listModel.startPage}'

               end='${listModel.endPage }'>

               <!-- 현재페이지에 b태그 적용 -->

               <c:if test = '${listModel.requestPage == pageNo }'><b></c:if>

               <a href="List.do?pageNum=${pageNo}">[${pageNo}]</a>

               <c:if test = '${listModel.requestPage == pageNo }'></b></c:if>

        </c:forEach>

       

        <!-- 이후  startPage-->

        <c:if test='${listModel.endPage < listModel.totalPageCount}'>

               <a href="List.do?pageNum=${listModel.startPage + 5}"> [이후] </a>

        </c:if>

 

        <!-- 동적쿼리문 작성 예제 -->

        <form action="List.do" method="post" accept-charset="euc-kr" onsubmit="document.charset='euc=kr';">

               <input type="checkbox" name="area" value="title"> 제목

               <input type="checkbox" name="area" value="writer"> 작성자

               <input type="text" name="searchKey" size="10">

               <input type="submit" value="검색">

        </form>

 

</body>

</html>



'Today I learned' 카테고리의 다른 글

12월4일  (0) 2019.01.10
1월10일  (0) 2019.01.10
1월3일  (0) 2019.01.03
2019년 1월2일  (0) 2019.01.02
12월28일  (0) 2019.01.02

댓글