/ SPRING

게시판 페이징 기능 만들기

스프링 목록

스프링 부트 목록




게시판에 피이징 기능을 추가하는 이유?

프로젝트 초기에는 모든 글을 다 읽어와도 성능상 별차이가 없지만, 글의 수가 많아 지면 많아질수록 DB에 부하가 걸릴 가능성이 높아지기 때문에 쪼개서 특정 갯 수 만큼 불러옵니다.





해야 할것들

  • DB에 START_ROW, END_ROW 함수 만들어주기 (페이징떄 사용함)
  • SQL 구문에 rownum 처리 해주기
  • Controller의 list() 부분 매개변수로 페이지 번호 수 설정해주기
  • DAO , Service , RepBoardMapper 수정해주기 (페이징 처리)
  • 페이지 정보가 담긴 DTO 만들어주기
  • Front JS 수정해주기





ORACLE (SQL DEVELOPER )


1. DB에 페이징 함수 추가하기

crr_page : 현재 페이지 cnt_per_page : 한 페이지 당 게시글 수.

create or replace FUNCTION START_ROW(crr_page number, cnt_per_page number)
return number
IS
    start_row number;
BEGIN
    start_row := (crr_page -1)*cnt_per_page +1;
    return start_row;
END;


create or replace FUNCTION END_ROW(crr_page number, cnt_per_page number)
return number
IS
    start_row number;
BEGIN
    start_row := crr_page *cnt_per_page;
    return start_row;
END;



5개씩 읽어오는 페이지의 1페이지 시작과 끝
START_ROW(1, 5) = 1 END_ROW(1, 5) =5

5개씩 읽어오는 페이지의 2페이지 시작과 끝
START_ROW(2, 5) = 6 END_ROW(2, 5) =10





2. SQL 로 함수 테스트 하기

SELECT *
FROM (
        SELECT rownum r , a.*
        FROM (
                SELECT level,
                       R.board_no,
                       R.parent_no,
                       R.board_id "boardC.id",
                       R.board_title,
                       R.board_content,
                       R.board_viewcount,
                       R.board_dt
                FROM repboard R
                START WITH R.parent_no = 0
                CONNECT BY PRIOR R.board_no = R.parent_no
                ORDER SIBLINGS BY R.board_no DESC
                ) a
     )
WHERE r BETWEEN START_ROW(1,5) AND END_ROW(1,5);

제대로 쿼리문 5개씩 읽어오는 지 확인





Spring (이클립스)


3. RepboardMapper.xml

  • findAll 수정

  • parameterType = "map" 추가
    <map>currentPage , cntPerPage 넣어 줄거
	<select id="findAll" resultType="Repboard" parameterType="map">
    SELECT *
    FROM (
            SELECT rownum r ,a.*
            FROM (
                SELECT level,
                       R.board_no,
                       R.parent_no,
                       R.board_id "boardC.id",
                       R.board_title,
                       R.board_content,
                       R.board_viewcount,
                       R.board_dt
                FROM repboard R
                START WITH R.parent_no = 0
                CONNECT BY PRIOR R.board_no = R.parent_no
                ORDER SIBLINGS BY R.board_no DESC
                ) a
     )
    WHERE r BETWEEN START_ROW(#{currentPage},#{cntPerPage}) AND END_ROW(#{currentPage},#{cntPerPage})
	</select>





4. PageDTO.java

(com.my.dto/PageDTO.java)

DTO 내부에서 startPage, endPage, totalPage 내부로 적으로 초기화 해주기

public class PageDTO<T> {
	private String url; //ex. board/list
	private int currentPage = 1; //현재페이지
	static public int CNT_PER_PAGE = 5; //한 페이지당 출력되는 게시물 갯수

    // 그룹 당 페이지 수 ex)3이면  (1~3페이지) (4~6페이지)(7~9페이지) 이런식
	static public int CNT_PER_PAGE_GROUP = 3; 

	private int totalCnt; //DB 내의  총 게시물 갯수 

	private int totalPage; //총페이지수

	private int startPage; //시작페이지
	private int endPage;  //끝페이지
	private List<T> list; //ex. 게시글목록

	public PageDTO() {
		super();
	}
	public PageDTO(String url,  int totalCnt, List<T> list) {
		this(url, 1, totalCnt, list);
	}
	public PageDTO(String url,  int currentPage, int totalCnt, List<T> list) {
		super();
		this.url = url;
		this.currentPage = currentPage;
		this.totalCnt = totalCnt; 
		this.totalPage = (int) Math.ceil((double)totalCnt/CNT_PER_PAGE);
		this.startPage = (currentPage-1)/CNT_PER_PAGE_GROUP * CNT_PER_PAGE_GROUP + 1;
		this.endPage = startPage + CNT_PER_PAGE_GROUP - 1; 
		if(endPage > totalPage) {
			this.endPage = totalPage;
		}
		this.list = list;
		
		System.out.println(totalPage + ":" + startPage + ":" + endPage);
	}
	public PageDTO(String url, 
			int currentPage,  
			int totalCnt, 
			int totalPage,
			int startPage, 
			int endPage, List<T> list) {
		super();
		this.url = url;
		this.currentPage = currentPage;
		this.totalCnt = totalCnt;
		this.totalPage = totalPage;
		this.startPage = startPage;
		this.endPage = endPage;
		this.list = list;
	}
	
    // getter setter 는 알아서 추가





5. RepBoardController.java

  • list() 수정
  • pageDTO 사용하기
	@GetMapping(value= {"/list", "/list/{currentPage}"})
	public Object  list(@PathVariable Optional<Integer> currentPage) {
		try {
			PageDTO<RepBoard> pageDTO;
			if(currentPage.isPresent()) { //currentPage값이 있는 경우
				int cp = currentPage.get();
				pageDTO = service.findAll(cp);
			}else { //값이 없는 경우(null인 경우)
				pageDTO = service.findAll();
			}
			return pageDTO;
		}catch(FindException e) {
			Map<String, Object> returnMap = new HashMap<>();
			returnMap.put("msg", e.getMessage());
			returnMap.put("status", 0);
			return returnMap;
		}
	}





6. DAO, Service, Mapper 수정해 주기

  • Mapper에 pageDTO에 필요한 findCount 추가됨
  • DAO에 Page 정보들 Map으로 추가로 넣어주기
  • Service에 findAll할때 findCount도 같이 읽어오기




A) RepBoardMapper.xml

findCount 추가

	<select id="findCount" resultType="int">
		SELECT COUNT(*) FROM repboard
	</select>
	




B) RepboardDAOOracle.java

  • findAll() 수정 , findCount() 추가
  • 인터페이스에도 추가 해주기

	@Override
	public List<RepBoard> findAll() throws FindException {
		return findAll(1,10);
	}



//인터페이스에 findAll 오버로딩 추가 해주기 
	@Override
	public List<RepBoard> findAll(int crrPage, int cntPage) throws FindException {
		SqlSession s = sqlSessionFactory.openSession();
		try {
			Map<String, Integer> page = new HashMap<String, Integer>();
			page.put("currentPage", crrPage);
			page.put("cntPerPage", cntPage);

			List<RepBoard> list=
					s.selectList("com.my.board.RepBoardMapper.findAll", page);
			if(list == null || list.isEmpty()) {
				throw new FindException();
			}
			return list;
		} catch (Exception e) {
			e.printStackTrace();
			throw new FindException();
		}finally {
			if(s != null) {s.close();}
		}
	}



    @Override
	public int findCount() throws FindException {
		SqlSession session = null;
		try {
			session = sqlSessionFactory.openSession();
			return session.selectOne("com.my.board.RepBoardMapper.findCount");
		}catch(Exception e) {
			e.printStackTrace();
			throw new FindException(e.getMessage());
		}finally {
			if(session != null) {
				session.close();
			}
		}
	}




C) RepboardService.java

  • findAll() 수정
	public PageDTO<RepBoard> findAll() throws FindException{
		return findAll(1);
	}

	public PageDTO<RepBoard> findAll(int currentPage) throws FindException{
		String url = "/board/list";
		int totalCnt = dao.findCount();
		List<RepBoard> list = dao.findAll(currentPage, PageDTO.CNT_PER_PAGE);
		PageDTO<RepBoard> pageDTO = new PageDTO<>(url, currentPage, totalCnt, list);
		return pageDTO;
	}




스프링 목록

스프링 부트 목록