ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] 페이징처리를 위해 써먹는 Paging 객체 만들기 및 활용
    웹 개발/Spring Framework 2019. 5. 18. 18:12

    회사 내에서 페이징 객체를 만들어야겠다고 생각한 계기는 특정 고객사에서 특정 메뉴를 주로 사용하는데 이 메뉴가 페이징 처리가 안되어있어 너무 느리다는 불만사항을 자주 들었다. 그 이외 UI 라이브러리 문제도 있었어서(고객사는 이 문제에 대한 불만이 더 많았다.) 새로 회사에서 사용하는 라이브러리로 바꿀 겸 이 메뉴에 대한 페이징 처리를 하기로 마음 먹었다.

     

    기존에는 페이징 처리를 메서드마다 페이지 인덱스와 페이지 사이즈를 계산하고 Map에 담아 return 방식으로 페이징 처리를 하고 있었는데, 이 부분 때문에..

    페이징 객체를 만들자!!!

     

    먼저 내가 구성한 건, 페이징 처리를 위한 변수 정하기. 내가 생각한 리스트는 아래와 같다.

    1. pageIndex : 현재 이 페이지가 몇번째 페이지냐
    2. pageSize : 페이지 사이즈가 얼마나 되냐? 10개를 보여줄거냐 50개를 보여줄거냐
    3. startRow : 그럼 DB는 몇번째 데이터부터 찾으면 되냐
    4. endRow : 그럼 DB는 몇번째 데이터까지 찾으면 되냐
    5. resultList : DB에서 가져온 리스트 결과를 담아줄 변수
    6. totalCount : 페이징 인덱스를 매기기 위해 실제 데이터는 몇개가 되냐

    코드로 표현해보면?

    
    public class Paging {
    
        private int pageIndex; 
    
        private int startRow; 
    
        private int endRow;
    
        private int pageSize; 
    
        private List<?> resultList;
    
        private int totalCount;
    
        public int getPageIndex() {
            return pageIndex;
        }
    
        public int getStartRow() {
            return startRow;
        }
    
        public int getEndRow() {
            return endRow;
        }
    
        public int getPageSize() {
            return pageSize;
        }
    
        public List<?> getResultList() {
            return resultList;
        }
    
        public int getTotalCount() {
            return totalCount;
        }
    }
    
    1. ResultList는 어떤 형의 데이터든지 받을 수 있도록 와일드카드(List<?>) 방식을 사용했다.
    2. 의미없는 setter는 안 만들고 값을 꺼내쓰기 위한 getter만 구현
    3. 내 생각에 MySQL, Maria 사용자는 변수 endRow는 필요없을 것 같다. 쿼리에서 limit를 사용해 데이터를 가져올 때 페이지 사이즈로 마지막 row를 찾으니까 말이다. 난 oracle도 사용하기 때문에 그에 대비하여 만들었다.

     


    이렇게 기본적인 골격을 짰고, 이제 페이지 인덱스와 페이지 사이즈를 활용하여 startRow와 endRow를 계산할 메서드를 만들어야 한다.

    
    public void handlePaging(int pageIndex, int pageSize) {
            this.pageIndex = pageIndex < 1 ? 1 : pageIndex;
            this.pageSize = pageSize;
            this.startRow = ((pageIndex-1) * pageSize);
            this.endRow = startRow + pageSize;
    }
    
    1. 페이지 인덱스에 0 이하로 들어올 일은 없겠지만, 혹시나 하는 마음에 1 미만의 숫자는 강제로 1부터 시작하도록 만들었다.
    2. startRow는 페이지 인덱스 1이 들어오면(1페이지), -1을 통해 0, 2 페이지면서 페이지 사이즈가 10이라면 index가 10부터 시작할 수 있도록 했다.
    3. endRow는 단순하게 startRow에서 페이지 사이즈만큼만 더해주었다.

     


    처리된 데이터들을 Paging객체에 담아줄 수 있는 메서드는.

    
    public void handlePagingList(List<?> resultList, int totalCount) {
            this.resultList = resultList;
            this.totalCount = totalCount;
    }
    
    1. DB의 리스트 결과값은 resultList에 담기고, 총 데이터 갯수는 totalCount에 담긴다.

     


    완성된 페이징 객체를 보면 아래처럼 구성된다.

    
    public class Paging {
    
        private int pageIndex; 
    
        private int startRow; 
    
        private int endRow;
    
        private int pageSize; 
    
        private List<?> resultList;
    
        private int totalCount;
    
        // startRow, endRow를 계산한다. 
        public void handlePaging(int pageIndex, int pageSize) {
            this.pageIndex = pageIndex < 1 ? 1 : pageIndex;
            this.pageSize = pageSize;
            this.startRow = ((pageIndex-1) * pageSize);
            this.endRow = startRow + pageSize;
        }
    
        // 페이징 처리된 결과값을 담는 메서드 
        public void handlePagingList(List<?> resultList, int totalCount) {
            this.resultList = resultList;
            this.totalCount = totalCount;
        }
    
    
        public int getPageIndex() {
            return pageIndex;
        }
    
        public int getStartRow() {
            return startRow;
        }
    
        public int getEndRow() {
            return endRow;
        }
    
        public int getPageSize() {
            return pageSize;
        }
    
        public List<?> getResultList() {
            return resultList;
        }
    
        public int getTotalCount() {
            return totalCount;
        }
    }
    

     


    활용편

    Service layer

    
    @Service
    public class ZorbaServiceImpl {
    
        private final ZorbaDao zorbaDao;
    
        public ZorbaServiceImpl(ZorbaDao zorbaDao) {
            this.zorbaDao = zorbaDao;
        }
    
        public Paging findZorbaUsers(UserDto userDto) {
                Paging paging = new Paging();
                paging.handlePaging(userDto.getPageIndex(), userDto.getPageSize());
    
                // startRow, endRow, pageSize가 계산된 페이징 객체값을 파라미터 변수에 set.
                userDto.setPaging(paging);
    
                return zorbaDao.findZorbaUsers(userDto);
        }
    
    }
    1. handlePaging 메서드를 통해 startRow, endRow, pageSize를 계산해서 페이징 객체에 set해둔다.
    2. 처리가 된 페이징 객체(Paging)을 DAO 메서드에 보내기 위한 파라미터인 UserDto에 담아준다.
      1. 내부적으로 startRow, endRow, pageSize를 set한다.

     


    Repository layer

    
    @Repository
    public class ZorbaDao {
    
        public Paging getSearchAttReqMainMgrList(UserDto userDto) {
                Paging paging = new Paging();
    
                // findList라는 list 쿼리를 조회하는 메서드, findOne이라는 하나의 데이터만 가져오는 메서드가 있다고 가정 
                return paging.handlePagingList(findList("findZorbaUsers",userDto)
                            ,findOne("findZorbaUsers_totalcount", userDto));
    }
    
    1. 쿼리의 리스트 결과 값을 곧바로 페이징 객체의 resultList에 담고, totalCount 결과 값을 페이징 객체의 totalCount에 담는다.

     


    정리

    전체 데이터를 가져와서 리스트에 뿌려주는 것보다 페이징 처리된 메뉴가 빠르다는 걸 몸소 느꼈고, 앞으로 리스트를 보여줘야할 메뉴는 사용자를 위해 페이징 처리가 필수일 것 같다.

Designed by Tistory.