web developer

[java] custom 페이징 처리와 페이지 네비게이션 구현 본문

Language/Java

[java] custom 페이징 처리와 페이지 네비게이션 구현

trueman 2024. 8. 9. 11:58
728x90
728x90

Controller

  • 컨트롤러에서 Service를 호출하여 데이터를 JSP로 전달
@Controller
public class BoardController {

    @Resource(name = "BoardService")
    private BoardService boardService;
    
    @RequestMapping(value = "/board.do")
    public String selectBoard(
        ModelMap model,
        @RequestParam(defaultValue = "1") int page, 
        @RequestParam(defaultValue = "10") int pageSize
    ) throws Exception {
        // PagingVO 객체 생성
        PagingVO pagingVO = new PagingVO(page, pageSize);
        
        // 비지니스 로직 
        List<BoardVO> pagedDataList = boardService.selectBoardList(pagingVO);
        int totalDataCount = boardService.selectSampleListTotCnt(pagingVO);
        int totalPages = (int) Math.ceil((double) totalDataCount / pageSize);

        model.addAttribute("pagedData", pagedDataList);
        model.addAttribute("totalPages", totalPages);
        model.addAttribute("currentPage", page);
        model.addAttribute("pageSize", pageSize);

        return "board/list";
    }

    /* list 데이터 가져오기 
     * RequestParam을 이용한 경우 
     */
    @ResponseBody
    @RequestMapping(value = "/boardList.do")
    public Map<String, Object> selectBoardList(
        ModelMap model,
        @RequestParam(defaultValue = "1") int page, 
        @RequestParam(defaultValue = "10") int pageSize
    ) throws Exception {
        // PagingVO 객체 생성
        PagingVO pagingVO = new PagingVO(page, pageSize);

        // 비지니스 로직 
        List<BoardVO> pagedDataList = boardService.selectBoardList(pagingVO);
        int totalDataCount = boardService.selectSampleListTotCnt(pagingVO);
        int totalPages = (int) Math.ceil((double) totalDataCount / pageSize);

        Map<String, Object> response = new HashMap<>();
        response.put("pagedData", pagedDataList);
        response.put("totalPages", totalPages);
        response.put("currentPage", page);

        return response;
    }
}

PagingVO

public class PagingVO extends SampleDefaultVO {

    private static final long serialVersionUID = 1L;

    private int page;
    private int pageSize;

    // 추가로 필요한 필드가 있다면 여기 추가
    // 예: 검색 조건, 필터링 옵션 등

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    // 필요하다면 생성자도 추가 가능
    public PagingVO() {
        // 기본 값 설정
        this.page = 1;
        this.pageSize = 10;
    }

    public PagingVO(int page, int pageSize) {
        this.page = page;
        this.pageSize = pageSize;
    }

    // startRow와 endRow를 계산하는 메서드
    public int getStartRow() {
        return (page - 1) * pageSize + 1;
    }

    public int getEndRow() {
        return page * pageSize;
    }
	
}

Service 인터페이스와 구현체

  • Service 인터페이스
package board.sample.service;

import java.util.List;
import java.util.Map;
import board.sample.service.BoardVO;
import board.sample.service.PagingVO;
import egovframework.rte.psl.dataaccess.util.EgovMap;

public interface BoardService {
	// 240902 custom 페이지네이션
	List<BoardVO> selectBoardList(PagingVO pagingVO) throws Exception;
	int selectSampleListTotCnt(PagingVO pagingVO) throws Exception;
}
  • ServiceImpl 구현체
package board.sample.service.impl;

import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import board.sample.service.BoardService;
import board.sample.service.BoardVO;
import board.sample.service.PagingVO;

@Service("BoardService")
public class BoardServiceImpl implements BoardService {

	// myBatis 사용
	@Resource(name="BoardMapper")
	private BoardMapper boardMapper;
	
	// 240902 custom 페이지네이션
	@Override
	public List<BoardVO> selectBoardList(PagingVO pagingVO) throws Exception {
		return boardMapper.selectBoardList(pagingVO);
	}
	@Override
	public int selectSampleListTotCnt(PagingVO pagingVO) throws Exception {
		return boardMapper.selectSampleListTotCnt(pagingVO);
	}
    
}

DAO 인터페이스

  • MyBatis Mapper XML에 매핑되는 DAO 인터페이스
package board.sample.service.impl;

import java.util.List;
import java.util.Map;
import board.sample.service.BoardVO
import board.sample.service.PagingVO;
import egovframework.rte.psl.dataaccess.mapper.Mapper;
import egovframework.rte.psl.dataaccess.util.EgovMap;

@Mapper("BoardMapper")
public interface BoardMapper {
	// 240902 custom 페이지네이션
	List<BoardVO> selectBoardList(PagingVO pagingVO) throws Exception;
	int selectSampleListTotCnt(PagingVO pagingVO) throws Exception;
}

Query

  • MyBatis에서는 LIMIT 대신 ROWNUM을 이용한 Oracle 페이징 쿼리를 작성
<select id="selectBoardList" parameterType="pagingVO" resultType="BoardVO">
    SELECT *
    FROM (
        SELECT 
            A.*, 
            ROWNUM AS rnum
        FROM (
            SELECT 
                id, 
                subject, 
                content, 
                writer, 
                register_datetime, 
                update_datetime 
            FROM BOARD
            WHERE 1=1 
            ORDER BY id DESC
        ) A
        WHERE ROWNUM <![CDATA[<=]]> #{endRow}
    )
    WHERE rnum BETWEEN #{startRow} AND #{endRow}
</select>

<select id="selectSampleListTotCnt" parameterType="pagingVO" resultType="int">
    SELECT COUNT(*) totcnt
    FROM BOARD
    WHERE 1=1
    <if test="searchKeyword != null and searchKeyword != ''">
        <choose>
            <when test="searchCondition == 0">
                AND CONTENT LIKE '%' || #{searchKeyword} || '%'
            </when>
            <when test="searchCondition == 1">
                AND	WRITER LIKE '%' || #{searchKeyword} || '%'
            </when>
        </choose>
    </if>
</select>


위의 XML에서는 #{startRow}와 #{endRow}가 쿼리에 바인딩


JSP

  • 전달받은 데이터를 출력
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
    <title>User List</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
    <h1>User List</h1>
    <div id="userTable">
        <table border="1">
            <caption style="visibility:hidden"></caption>
            <colgroup>
                <col width="auto"/>
            </colgroup>
            <thead>
                <tr>
                    <th align="center">id</th>
                    <th align="center">subject</th>
                    <th align="center">content</th>
                    <th align="center">writer</th>
                    <th align="center">register_datetime</th>
                </tr>
            </thead>
            <tbody>
                <c:choose>
                    <c:when test="${not empty pagedData}">
                        <c:forEach var="result" items="${pagedData}">
                            <tr>
                                <td align="center" class="listtd">
                                    <c:out value="${result.id}"/>
                                </td>
                                <td align="center" class="listtd">
                                    <a href="#" onclick="boardView('<c:out value="${result.id}"/>');"><c:out value="${result.subject}"/></a>
                                </td>
                                <td align="center" class="listtd">
                                    <c:out value="${result.content}"/>
                                </td>
                                <td align="center" class="listtd">
                                    <c:out value="${result.writer}"/>
                                </td>
                                <td align="center" class="listtd">
                                    <c:out value="${result.register_datetime}"/>
                                </td>
                            </tr>
                        </c:forEach>
                    </c:when>
                    <c:otherwise>
                        <tr>
                            <td colspan="5">No data available</td>
                        </tr>
                    </c:otherwise>
                </c:choose>
            </tbody>
        </table>
    </div>
    
    <div id="pagination">
        <button onclick="loadPage(${currentPage - 1})" ${currentPage == 1 ? 'disabled' : ''}>Previous</button>
        
        <c:forEach var="i" begin="${currentPage - (currentPage - 1) % 10}" end="${currentPage - (currentPage - 1) % 10 + 9}">
            <c:if test="${i <= totalPages}">
                <button onclick="loadPage(${i})" ${currentPage == i ? 'disabled' : ''}>${i}</button>
            </c:if>
        </c:forEach>
        
        <button onclick="loadPage(${currentPage + 1})" ${currentPage == totalPages ? 'disabled' : ''}>Next</button>
    </div>
</body>
</html>

JavaScript

 <script type="text/javaScript">
     /* 페이지를 로드하는 함수 */
     function loadPage(page) {
        $.ajax({
            url: '/boardList.do',
            type: 'post',
            data: {
                page: page,
                pageSize: '${pageSize}'
            },
            success: function(response) {
                var tableBody = $('#userTable tbody');
                tableBody.empty(); // 기존 데이터를 지우고

                // 새로운 데이터를 추가
                $.each(response.pagedData, function(index, user) {
                    tableBody.append(
                        '<tr>' +
                        '<td align="center" class="listtd">' + user.id + '</td>' +
                        '<td align="center" class="listtd">' + '<a href="#" onclick="boardView(' + user.id + ');">' + user.subject + '</a>' + '</td>' +
                        '<td align="center" class="listtd">' + user.subject + '</td>' +
                        '<td align="center" class="listtd">' + user.content + '</td>' +
                        '<td align="center" class="listtd">' + user.writer + '</td>' +
                        '<td align="center" class="listtd">' + user.register_datetime + '</td>' +
                        '</tr>'
                    );
                });

                // 페이지 버튼 업데이트
                updatePagination(response.currentPage, response.totalPages);
            },
            error: function() {
                alert('Error loading data');
            }
        });
    }

    /* 페이지네이션을 업데이트하는 함수 */
    function updatePagination(currentPage, totalPages) {
        var paginationDiv = $('#pagination');
        paginationDiv.empty();

        // 이전 버튼
        paginationDiv.append('<button onclick="loadPage(' + (currentPage - 1) + '); return false;"' + (currentPage === 1 ? 'disabled' : '') + '>Previous</button> ');

        // 10개씩 페이지 번호
        var startPage = currentPage - (currentPage - 1) % 10;
        var endPage = Math.min(startPage + 9, totalPages);

        for (var i = startPage; i <= endPage; i++) {
            paginationDiv.append('<button onclick="loadPage(' + i + '); return false;"' + (currentPage === i ? 'disabled' : '') + '>' + i + '</button> ');
        }

        // 다음 버튼
        paginationDiv.append('<button onclick="loadPage(' + (currentPage + 1) + '); return false;"' + (currentPage === totalPages ? 'disabled' : '') + '>Next</button>');
    }
</script>

참고 : https://hackmd.io/@wisdom88/Sk1G7QGH2 
참고 : https://www.elancer.co.kr/blog/view?seq=231 [JPA vs Mybatis, 현직 개발자는 이럴 때 사용합니다.]

728x90
728x90