728x90
프로젝트 구조
오늘은 이전 포스팅에서 생성했던 유저 목록 페이지에 페이지 나누기 기능을 추가해 보겠습니다.
페이지를 나누려면 별도로 페이지네이션 기능 공식 파일을 생성해서 변수로 추출해서 사용해야 하는데,
이전에 JSP 포스팅했을 때 사용했던 Pager.java 파일을 사용해서 기능 구현을 해보겠습니다.
Pager.java
Pager 파일은 페이지 나누는 공식과 변수를 담은 파일입니다. 각 변수의 역할은 주석으로 작성했습니다.
package com.example.spring.service.board;
public class Pager {
public static final int PAGE_SCALE=10;//페이지당 게시물수(10개)
public static final int BLOCK_SCALE=10;//페이지 블록 갯수
private int curPage; //현재 페이지
private int prevPage; //이전 페이지
private int nextPage; //다음 페이지
private int totPage; //전체 페이지 갯수
private int totBlock; //전체 페이지블록 갯수
private int curBlock; //현재 페이지블록
private int prevBlock; //이전 페이지블록
private int nextBlock; //다음 페이지블록
private int pageBegin; // #{start}에 전달될 값
private int pageEnd; // #{end}에 전달될 값
private int blockStart; //페이지블록의 시작페이지 번호
private int blockEnd; //페이지블록의 끝페이지 번호
//getter,setter만 생성, 단 상수2개는(PAGE_SCALE,BLOCK_SCALE)빼고 만듦
// Pager(레코드갯수, 보여줄페이지번호)
public Pager(int count, int curPage){
curBlock=1; //페이지블록을 1로 초기화
this.curPage=curPage;
setTotPage(count); //전체 페이지 갯수 계산
setPageRange(); // #{start}, #{end} 값 계산
setTotBlock(); // 페이지블록의 갯수 계산
setBlockRange(); //페이지블록의 범위 설정
}
//페이지블록의 범위 설정
public void setBlockRange(){
//현재페이지가 몇번째 페이지블록에 속하는지 계산
//(현재페이지-1)/페이지블록단위 + 1
curBlock=(int)Math.ceil((curPage-1) / BLOCK_SCALE)+1;
//(현재블록-1)*블록단위+1
blockStart=(curBlock-1) * BLOCK_SCALE + 1;
//블록시작번호+(페이지블록단위-1)
blockEnd=blockStart + (BLOCK_SCALE-1);
//블록의 마지막 페이지번호가 범위를 초과하지 않도록 처리
if(blockEnd > totPage){
blockEnd = totPage;
}
//[이전] 11 12 13 14 15 16 17 18 19 20 [다음]
//[이전]을 눌렀을 때 이동할 페이지, 현재블럭이 1이면 1로감,[이전]이란표시는 빼야함
prevPage=curBlock==1 ? 1 : (curBlock-1) * BLOCK_SCALE;
//[다음]을 눌렀을 때 이동할 페이지
nextPage=curBlock>totBlock
? (curBlock*BLOCK_SCALE) : (curBlock*BLOCK_SCALE)+1;
if(nextPage >= totPage){//다음페이지가 토탈페이지보다 크면 [다음]표시뺌
nextPage = totPage;
}
}
public void setPageRange(){
//시작번호=(현재페이지 - 1 ) * 페이지당게시물수 + 1
pageBegin = (curPage - 1) * PAGE_SCALE + 1;
//끝번호=시작번호 + ( 페이지당게시물수 – 1 )
pageEnd = pageBegin + (PAGE_SCALE - 1);
}
public int getCurPage() {
return curPage;
}
public void setCurPage(int curPage) {
this.curPage = curPage;
}
public int getPrevPage() {
return prevPage;
}
public void setPrevPage(int prevPage) {
this.prevPage = prevPage;
}
public int getNextPage() {
return nextPage;
}
public void setNextPage(int nextPage) {
this.nextPage = nextPage;
}
public int getTotPage() {
return totPage;
}
//전체 페이지 갯수 계산
public void setTotPage(int count) {
// 991 / 10 => 99.1 올림 => 100
// 991/10 => 99
// 991.0/10 => 99.1
//ceil() 올림, round() 반올림, floor() 버림
totPage = (int)Math.ceil(count * 1.0 / PAGE_SCALE);
}
public int getTotBlock() {
return totBlock;
}
//페이지블록의 갯수 계산
public void setTotBlock() {
// 991페이지 : 991/10 => 99, 한페이지 누락이기때문에 올림(ceil)처리함
totBlock = (int)Math.ceil(totPage * 1.0 / BLOCK_SCALE);
}
public int getCurBlock() {
return curBlock;
}
public void setCurBlock(int curBlock) {
this.curBlock = curBlock;
}
public int getPrevBlock() {
return prevBlock;
}
public void setPrevBlock(int prevBlock) {
this.prevBlock = prevBlock;
}
public int getNextBlock() {
return nextBlock;
}
public void setNextBlock(int nextBlock) {
this.nextBlock = nextBlock;
}
public int getPageBegin() {
return pageBegin;
}
public void setPageBegin(int pageBegin) {
this.pageBegin = pageBegin;
}
public int getPageEnd() {
return pageEnd;
}
public void setPageEnd(int pageEnd) {
this.pageEnd = pageEnd;
}
public int getBlockStart() {
return blockStart;
}
public void setBlockStart(int blockStart) {
this.blockStart = blockStart;
}
public int getBlockEnd() {
return blockEnd;
}
public void setBlockEnd(int blockEnd) {
this.blockEnd = blockEnd;
}
}
BoardController
Controller 에서는 이전 포스팅에서 생성했던 list.do url 메서드에 Pager 파일을 대입해서 stard,end 설정 후 Service에 같이 보내줍니다.
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.example.spring.model.board.dto.BoardDTO;
import com.example.spring.service.board.BoardService;
import com.example.spring.service.board.Pager;
@Controller
@RequestMapping("board/*")
public class BoardController {
@Inject
BoardService boardService;
//로깅을 위한 변수
private static final Logger logger=
LoggerFactory.getLogger(BoardController.class);
@RequestMapping("list.do") // 세부 url
//defaultValue = "1" : 파라미터가 없을 때 1로 셋팅해줌
public ModelAndView list(@RequestParam(defaultValue = "1") int curPage) throws Exception{
//레코드 개수 계산
int count = boardService.countArticle();
// 페이지 관련 설정
Pager pager = new Pager(count, curPage);
int start=pager.getPageBegin();
int end =pager.getPageEnd();
List<BoardDTO> list=boardService.listAll(start,end); // 게시물 목록
logger.info(list.toString());
ModelAndView mav = new ModelAndView();
Map<String, Object> map = new HashMap<>();
map.put("list", list); // map에 자료 저장
map.put("count",count); //레코드 갯수 파악
map.put("pager", pager); // 페이지 네비게이션을 위한 변수
mav.setViewName("board/list"); // 포워딩 뷰
mav.addObject("map",map); //전달 데이터
return mav;
}
페이지 나누기 기능은 mapper 에서 쿼리문으로 요청을 보내서 데이터만 가져오면 되기 때문에 Service단과 DAO 에서는 각각 Service => DAO 요청 , DAO => mapper 요청을 보내는 코드만 작성해 줍니다.
BoardService
package com.example.spring.service.board;
import java.util.List;
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.spring.model.board.dao.BoardDAO;
import com.example.spring.model.board.dto.BoardDTO;
@Service
public class BoardServiceImpl implements BoardService {
@Inject
BoardDAO boardDao;
@Override //레코드 개수
public int countArticle() throws Exception {
return boardDao.countArticle();
}
@Override //유저 목록
public List<BoardDTO> listAll(int start, int end) throws Exception {
return boardDao.listAll(start,end); // 페이지네이션 변수 보내줌
}
BoardDAO
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
import javax.sound.midi.Sequence;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
import com.example.spring.model.board.dto.BoardDTO;
@Repository
public class BoardDAOImpl implements BoardDAO {
@Override
public List<BoardDTO> listAll(int start, int end) throws Exception {
// mapper에 요청할 땐 매개 변수 1개만 보낼 수 있기 때문에
// map에 담아서 보내줌
Map<String, Object> map = new HashMap<>();
map.put("start", start);
map.put("end", end);
return sqlsession.selectList("board.listAll" , map) ;
}
@Override
public int countArticle() throws Exception {
return sqlsession.selectOne("board.countArticle");
}
그럼 다음으로 쿼리문을 작성해서 데이터를 디비에서 가져옵니다.
mapper
목록에 페이지 나누기 기능을 구현할 땐 rownum을 활용하면 됩니다.
또한, 유저 ID 값과 NAME이 출력되어야 하기 때문에 member 테이블과 조인 시켜서 쿼리문을 작성해 줍니다.
<?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와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="board">
<select id="listAll" resultType="com.example.spring.model.board.dto.BoardDTO">
select *
from (
select rownum as rn, A.*
from(
select bno,title,writer,name,regdate,viewcnt
from board b, member m
where b.writer = m.userid
order by bno desc
)A
)where rn between #{start} and #{end}
</select>
<!-- 레코드 갯수 계산 -->
<select id="countArticle" resultType="int" >
select count(*)
from board b , member m
where b.writer=m.userid
</select>
list.jsp
이전 포스팅에서 생성했던 목록 페이지에서 맨 아래줄에 페이지네이션 코드를 변수값을 대입해서 작성합니다.
<%@ 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>
<%@ include file="../include/header.jsp" %>
<script type="text/javascript">
$(function() {
$("#btnWrite").click(function(){
location.href="${path}/board/write.do";
});
});
function list(page) {
location.href="${path}/board/list.do?curPage="+page;
}
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>게시판</h2>
<button type="button" id="btnWrite">글쓰기</button>
${map.count}개의 게시물이 있습니다.
<table border="1">
<tr>
<th>번호</th>
<th>제목</th>
<th>이름</th>
<th>내용</th>
<th>날짜</th>
<th>조회수</th>
</tr>
<c:forEach var="row" items="${map.list}">
<tr>
<td>${row.bno}</td>
<td><a href="${path }/board/view.do?bno=${row.bno}">${row.title}</a></td>
<td>${row.name}</td>
<td>${row.content}</td>
<td><fmt:formatDate value="${row.regdate}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td>${row.viewcnt}</td>
</tr>
</c:forEach>
<!-- 페이지 네비게이션 출력 -->
<tr>
<td colspan="6" align="center">
<c:if test="${map.pager.curBlock > 1}">
<a href="#" onclick="list('1')">[처음]</a>
</c:if>
<c:if test="${map.pager.curBlock > 1}">
<a href="#" onclick="list('${map.pager.prevPage}')">
[이전]</a>
</c:if>
<c:forEach var="num"
begin="${map.pager.blockStart}"
end="${map.pager.blockEnd}">
<c:choose>
<c:when test="${num == map.pager.curPage}">
<!-- 현재 페이지인 경우 하이퍼링크 제거 -->
<span style="color:red;">${num}</span>
</c:when>
<c:otherwise>
<a href="#" onclick="list('${num}')">${num}</a>
</c:otherwise>
</c:choose>
</c:forEach>
<c:if test="${map.pager.curBlock < map.pager.totBlock}">
<a href="#"
onclick="list('${map.pager.nextPage}')">[다음]</a>
</c:if>
<c:if test="${map.pager.curPage < map.pager.totPage}">
<a href="#"
onclick="list('${map.pager.totPage}')">[끝]</a>
</c:if>
</td>
</tr>
</table>
</body>
</html>
출력
마치며
오늘은 유저 목록 페이지 나누기 기능을 구현해 보았습니다.
다음 포스팅에서 뵙겠습니다.
728x90
'[ JAVA ] > JAVA Spring' 카테고리의 다른 글
[ Spring Boot ] Spring boot 개요 및 설정 (0) | 2023.05.08 |
---|---|
[ Spring ] 도로명주소 API 연동 (0) | 2023.04.27 |
[ Spring ] 게시판 01 - 목록/글쓰기 구현 (0) | 2023.04.24 |
[ Spring ] Ajax 파일업로드 (0) | 2023.04.20 |
[ Spring ] 코드 난독화 (1) | 2023.04.19 |