Languages/java

[JAVA] 페이징 처리

뱅타 2021. 4. 6. 20:01

페이징 시 알아두면 좋을 용어

페이징처리

연산식 구하기

총 페이지 수 연산(totalPage):

  • totalRecord % screenSize== 0? totalRecord/ screenSize: totalRecord/ screenSize + 1

시작게시물번호 연산(startRow):

  • startRow = (currentPage -1) * screenSize + 1;
  • endRow = currentPage * screenSize;

시작페이지 연산(startPage):

  • endPage = (currentPage + (blockSize - 1)) / blockSize * blockSize;
  • startPage = endPage - (blockSize -1);

필요 요소

  • totalPage는 totalRecord의 값을 알아야 구할 수 있다.
  • startRow, startPage 두개 모두 currentPage를 알아야 구할 수 있다.

VO에서 값을 가져간다 → db에 해당 쿼리문 실행 → 값을 다시 vo로

  • 코드(PagingVO)
    package kr.or.ddit.vo;
    
    import static org.junit.Assume.assumeNoException;
    
    import java.io.Serializable;
    import java.util.List;
    import java.util.Set;
    
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    @Setter
    @Getter
    @NoArgsConstructor // 기본생성자
    public class PagingVO<T> implements Serializable{
    	
    	public PagingVO(int screenSize, int blockSize) {
    		super();
    		this.screenSize = screenSize;
    		this.blockSize = blockSize;
    	}
    
    	private int totalRecord;
    	private int screenSize = 10;
    	private int blockSize = 5;
    	private int currentPage;
    	
    	private int totalPage;
    	private int startRow;
    	private int endRow;
    	private int startPage;
    	private int endPage;
    	private List<T> dataList;
    	
    	private SearchVO simpleSearch;
    
    	public void setTotalRecord(int totalRecord) {
    		this.totalRecord = totalRecord;
    		totalPage = totalRecord % screenSize == 0?
    				totalRecord/screenSize :
    				totalRecord/screenSize +1;
    	}
    	
    	public void setCurrentPage(int currentPage) {
    		this.currentPage = currentPage;
    		startRow = (currentPage - 1)*screenSize + 1;
    		endRow = currentPage * screenSize;
    		endPage = (currentPage + (blockSize-1))/blockSize * blockSize;
    		startPage = endPage - (blockSize  - 1);
    	}
    	
    	private static String aPattern = "<a href='#' data-page = '%d'>[%s]</a>";
    	private static String currentPagePtrn = "<a href='#'>[%s]</a>";
    	
    	public String getPagingHTML() {
    		StringBuffer html = new StringBuffer();
    		if(startPage > 1) {
    			html.append(
    				String.format(aPattern, (startPage-1), "이전")
    			);
    		}
    		endPage = endPage < totalPage ? endPage : totalPage;
    		for(int page=startPage; page<=endPage; page++) {
    			if(page == currentPage) {
    				html.append(
    					String.format(currentPagePtrn, page+"")
    				);
    			}else {
    				html.append(
    					String.format(aPattern, page, page+"")
    				);
    			}
    		}
    		if(endPage < totalPage) {
    			html.append(
    				String.format(aPattern, (endPage +1), "다음")
    			);
    		}
    		return html.toString();
    	}
    	
    }
  • 코드(member.xml)
    <sql id="searchFrag">
    		<where>
    			<if test="simpleSearch!=null and @org.apache.commons.lang3.StringUtils@isNotBlank(simpleSearch.searchWord)">
    				<choose>
    					<when test="simpleSearch.searchType eq 'name'">
    						INSTR(MEM_NAME, #{simpleSearch.searchWord}) > 0
    					</when>
    					<when test="simpleSearch.searchType eq 'address'">
    						INSTR(MEM_ADD1, #{simpleSearch.searchWord}) > 0
    					</when>
    					<otherwise>
    						INSTR(MEM_NAME, #{simpleSearch.searchWord}) > 0
    						OR
    						INSTR(MEM_ADD1, #{simpleSearch.searchWord}) > 0
    					</otherwise>
    				</choose>
    			</if>
    		</where>
    	</sql>
    	<select id="selectMemberList" resultType="memberVO" parameterType="PagingVO" >
    		SELECT B.*
    		FROM(
    			SELECT A.*, ROWNUM RNUM
    			FROM(
    				SELECT ROWID RID, mem_id, mem_pass, mem_name, mem_mail 
    				, MEM_ADD1
    				FROM member
    				<include refid="searchFrag" />
    				ORDER BY RID DESC
    			) A
    		) B
    		<![CDATA[
    			WHERE RNUM >= #{startRow} AND RNUM <= #{endRow}
    		]]>
    	</select>
    	
    	<select id="selectTotalRecord" resultType = "int" parameterType ="PagingVO">
    		SELECT COUNT(*)
    		FROM MEMBER
    		<include refid="searchFrag" />
    	</select>
  • MemberDAOImpl.java
    package kr.or.ddit.member.dao;
    
    import java.util.List;
    
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    
    import kr.or.ddit.db.mybatis.CustomSqlSessionFactoryBuilder;
    import kr.or.ddit.vo.MemberVO;
    import kr.or.ddit.vo.PagingVO;
    
    public class MemberDAOImpl implements IMemberDAO {
    	// 싱글톤 만들기
    	private static MemberDAOImpl self;
    	private MemberDAOImpl() {}
    	public static MemberDAOImpl getInstance() {
    		if(self==null) self = new MemberDAOImpl();
    		return self;
    	}
    	
    	private SqlSessionFactory sessionFactory = 
    			CustomSqlSessionFactoryBuilder.getSessionFactory();
    	
    
    	@Override
    	public MemberVO selectMemberForAuth(String mem_id) {
    		try( SqlSession session = sessionFactory.openSession();
    		){
    //			return (MemberVO) session.selectOne("kr.or.ddit.member.dao.IMemberDAO.selectMemberForAuth", mem_id);
    			// mapper proxy - 가짜 매퍼
    			IMemberDAO mapper = session.getMapper(IMemberDAO.class);
    			return mapper.selectMemberForAuth(mem_id);
    		}
    	}
    
    	@Override
    	public MemberVO selectMemberDetail(String mem_id) {
    		try(
    			SqlSession session = sessionFactory.openSession();
    		){
    			IMemberDAO mapper = session.getMapper(IMemberDAO.class);
    			return mapper.selectMemberDetail(mem_id);
    		}
    	}
    
    	@Override
    	public int insertMember(MemberVO member) {
    		try(
    			SqlSession session = sessionFactory.openSession();
    		){
    			IMemberDAO mapper = session.getMapper(IMemberDAO.class);
    			int cnt = mapper.insertMember(member);
    			session.commit();
    			return cnt;
    		}
    	}
    
    	@Override
    	public int updateMember(MemberVO member) {
    		try(
    			SqlSession session = sessionFactory.openSession();
    			// 문제가 있다. 문제가 있어도 commit을 해버림
    		){
    //			MemberDAOImpl.class.equals(this.getClass());
    			IMemberDAO mapper = session.getMapper(IMemberDAO.class);
    			int cnt = mapper.updateMember(member);
    			session.commit();
    			return cnt;
    		}
    	}
    
    	@Override
    	public int deleteMember(String mem_id) {
    		try(
    				SqlSession session = sessionFactory.openSession();	
    			){
    				IMemberDAO mapper =
    						session.getMapper(IMemberDAO.class);
    				int cnt = mapper.deleteMember(mem_id);
    				session.commit();
    				return cnt;
    			}
    	}
    
    	@Override
    	public List<MemberVO> selectMemberList(PagingVO pagingVO) {
    		try(
    				SqlSession session = sessionFactory.openSession();
    				// 문제가 있다. 문제가 있어도 commit을 해버림
    			){
    //				MemberDAOImpl.class.equals(this.getClass());
    				IMemberDAO mapper = session.getMapper(IMemberDAO.class);
    				return mapper.selectMemberList(pagingVO);
    			}
    	}
    	@Override
    	public int selectTotalRecord(PagingVO pagingVO) {
    		try(
    				SqlSession session = sessionFactory.openSession();
    				// 문제가 있다. 문제가 있어도 commit을 해버림
    			){
    //				MemberDAOImpl.class.equals(this.getClass());
    				IMemberDAO mapper = session.getMapper(IMemberDAO.class);
    				return mapper.selectTotalRecord(pagingVO);
    			}
    	}
    
    }
  • MemberServiceImpl.java
    package kr.or.ddit.member.service;
    
    import java.lang.reflect.InvocationTargetException;
    import java.util.List;
    
    import org.apache.commons.beanutils.BeanUtils;
    
    import kr.or.ddit.enumpkg.ServiceResult;
    import kr.or.ddit.member.UserNotFoundException;
    import kr.or.ddit.member.dao.IMemberDAO;
    import kr.or.ddit.member.dao.MemberDAOImpl;
    import kr.or.ddit.vo.MemberVO;
    import kr.or.ddit.vo.PagingVO;
    
    public class MemberServiceImpl implements IMemberService {
    	private IMemberDAO dao = MemberDAOImpl.getInstance();
    	private IAuthenticateService authService = new AuthenticateServiceImpl();
    
    	@Override
    	public MemberVO retrieveMember(String mem_id) {
    		MemberVO savedMember = dao.selectMemberDetail(mem_id);
    		if (savedMember == null) {
    			// custom exception 발생
    			// compile error가 발생하면 checked exception이다. ex)Exceiption()
    			throw new UserNotFoundException("아이디에 해당하는 회원이 존재하지 않음.");
    		}
    		return savedMember;
    		// 특정 상황에 쓸 수 있는 커스텀 익셉션
    	}
    
    	@Override
    	public ServiceResult createMember(MemberVO member) {
    		ServiceResult result = null;
    		if (dao.selectMemberDetail(member.getMem_id()) == null) { // 중복되지 않는다면
    			int rowcnt = dao.insertMember(member);
    			if (rowcnt > 0) { // 성공
    				result = ServiceResult.OK;
    			} else { // 실패
    				result = ServiceResult.FAIL;
    			}
    		} else { // 중복
    			result = ServiceResult.PKDUPLICATED;
    		}
    		return result;
    	}
    
    	@Override
    	public ServiceResult modifyMember(MemberVO member) {
    		retrieveMember(member.getMem_id());
    
    		ServiceResult result = authService.authenticate(new MemberVO(member.getMem_id(), member.getMem_pass()));
    
    		if (ServiceResult.OK.equals(result)) {
    			int rowcnt = dao.updateMember(member);
    			if (rowcnt > 0) {
    				result = ServiceResult.OK;
    			} else {
    				result = ServiceResult.FAIL;
    			}
    		}
    		return result;
    	}
    
    	@Override
    	public ServiceResult removeMember(MemberVO member) {
    		retrieveMember(member.getMem_id());
    
    		ServiceResult result = authService.authenticate(new MemberVO(member.getMem_id(), member.getMem_pass()));
    		if (ServiceResult.OK.equals(result)) {
    			int rowcnt = dao.deleteMember(member.getMem_id());
    			if (rowcnt > 0) {
    				result = ServiceResult.OK;
    			} else {
    				result = ServiceResult.FAIL;
    			}
    		}
    		return result;
    	}
    
    	@Override
    	public List<MemberVO> retrieveMemberList(PagingVO pagingVO) {
    		return dao.selectMemberList(pagingVO);
    	}
    
    	@Override
    	public int retrieveMemberCount(PagingVO<MemberVO> pagingVO) {
    		return dao.selectTotalRecord(pagingVO);
    	}
    }
  • MemberListServlet.java
    package kr.or.ddit.member.controller;
    
    import java.io.IOException;
    import java.util.List;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    import kr.or.ddit.member.service.IMemberService;
    import kr.or.ddit.member.service.MemberServiceImpl;
    import kr.or.ddit.vo.MemberVO;
    import kr.or.ddit.vo.PagingVO;
    import kr.or.ddit.vo.SearchVO;
    
    @WebServlet("/member/memberList.do")
    public class MemberListServlet extends HttpServlet {
    	IMemberService service = new MemberServiceImpl();
    	@Override
    	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    		req.setCharacterEncoding("utf-8");
    		String searchType = req.getParameter("searchType");
    		String searchWord = req.getParameter("searchWord");
    		
    		SearchVO searchVO = new SearchVO(searchType, searchWord);
    		
    		
    		String pageParam = req.getParameter("page");
    		int currentPage = 1;
    		if(pageParam!=null && pageParam.matches("\\d+")) {
    			currentPage = Integer.parseInt(pageParam);
    		}
    		PagingVO<MemberVO> pagingVO = new PagingVO(7, 2);
    		pagingVO.setCurrentPage(currentPage);
    		// 검색 조건 먼저 담아주어야함.
    		pagingVO.setSimpleSearch(searchVO);
    		
    		int totalRecord = service.retrieveMemberCount(pagingVO);
    		pagingVO.setTotalRecord(totalRecord);
    		
    		List<MemberVO> memberList =  service.retrieveMemberList(pagingVO);
    		pagingVO.setDataList(memberList);
    		
    		req.setAttribute("pagingVO", pagingVO);
    		
    		String view = "/WEB-INF/views/member/memberList.jsp";
    		req.getRequestDispatcher(view).forward(req, resp);
    	}
    }
  • memberList.jsp
    <%@page import="kr.or.ddit.vo.SearchVO"%>
    <%@page import="kr.or.ddit.vo.PagingVO"%>
    <%@page import="kr.or.ddit.vo.MemberVO"%>
    <%@page import="java.util.List"%>
    <%@ 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>
    <jsp:include page = "/includee/preScript.jsp" />
    </head>
    <body>
    <h4>회원 목록 조회</h4>
    
    <table border= '1'>
    	<thead>
    		<tr>
    			<th>No.</th>
    			<th>회원아이디</th>
    			<th>회원명</th>
    			<th>이메일</th>
    			<th>휴대폰</th>
    			<th>마일리지</th>
    			<th>탈퇴여부</th>
    			<th>지역</th>
    		</tr>
    	</thead>
    	<tbody>
    	<%
    		PagingVO<MemberVO> pagingVO = (PagingVO) request.getAttribute("pagingVO");
    		List<MemberVO> memberList = pagingVO.getDataList();
    		if(memberList.size()>0){
    			for(MemberVO member : memberList){
    				%>
    				<tr>
    					<td><%=member.getRnum() %></td>
    					<td><%=member.getMem_id() %></td>
    					<td><%=member.getMem_name() %></td>
    					<td><%=member.getMem_mail() %></td>
    					<td><%=member.getMem_hp() %></td>
    					<td><%=member.getMem_mileage()%></td>
    					<td>
    						<%="Y".equals(member.getMem_delete())?"탈퇴" : "" %>
    					</td>
    					<td><%=member.getMem_add1()%></td>
    				</tr>
    				<%
    			}
    		}else{
    			%>
    			<tr>
    				<td colspan="5">
    					등록된 데이터 없음.
    			<%
    		}
    			%>
    	</tbody>
    	<tfoot>
    		<tr>
    			<td colspan="6">
    					<form id = "searchForm">
    					
    						<input type = "text" name = "searchType" value="${pagingVO.simpleSearch.searchType }"/>
    						<input type = "text" name = "searchWord" value="${pagingVO.simpleSearch.searchWord }"/>
    						<input type = "text" name = "page" />
    					</form>
    					<div id = "searchUI">
    						<select name = "searchType">
    							<option value>전체</option>
    							<option value="name">이름</option>
    							<option value="address">지역</option>
    						</select>
    						<input type = "text" name = "searchWord" value="${pagingVO.simpleSearch.searchWord }" />
    						<input id = "searchBtn" type = "button" value = "검색" />
    					</div>
    				<div id = "pagingArea">
    					<%=pagingVO.getPagingHTML() %>
    				</div>
    			</td>
    		</tr>
    	</tfoot>
    </table>
    <script type = "text/javascript">
    	let searchForm = $("#searchForm");
    	let searchUI = $("#searchUI");
    	searchUI.find("[name='searchType']").val("${pagingVO.simpleSearch.searchType }");
    	$("#searchBtn").on("click", function(){
    		let inputs = searchUI.find(":input[name]");
    		$(inputs).each(function(idx, input){
    			let name = $(this).attr("name");
    			let sameInput = searchForm.find("[name='"+name+"']")
    			$(sameInput).val($(this).val());
    		});
    		searchForm.submit();
    	});
    	
    	$("#pagingArea").on("click", "a", function(event){
    		event.preventDefault();
    		let page = $(this).data("page");
    		if(page){
    			searchForm.find("[name='page']").val(page);
    			searchForm.submit();
    		}
    		return false;
    	});
    </script>
    
    </body>
    </html>

*알면 좋은 단축키들 - alt +shift+c

  • 해당 인스턴스 파라미터 변경하기. preview로 무엇이 영향을 받는지 알 수 있다.

HAS A 관계에서는 꼭 result Map을 꼭 쓰지 않아도 된다.

  • has a → association
  • has many → collections

strict alias를 잘 쓰면 된다.

**추가

.find(":input[name]") 분석

: 모든 input 태그

[name] name을 가지고 있는 모든 input 태그.

data-page로 값 찾기.

ogln과 el의 문법은 거의 비슷하다.

728x90
반응형