본문 바로가기
Spring Boot

스프링 부트(Spring Boot) 게시판 - Ajax(비동기) 페이징 새로고침 시 페이지 번호 유지하기 [Thymeleaf, MariaDB, IntelliJ, Gradle, MyBatis]

by 도뎡 2023. 5. 1.
반응형
  • 본 게시판 프로젝트는 단계별(step by step)로 진행되니, 이전 단계를 진행하시는 것을 권장드립니다.
  • DBMS 툴은 DBeaver를 이용하며, DB는 MariaDB를 이용합니다. (MariaDB 설치하기)
  • 화면 처리는 HTML5 기반의 자바 템플릿 엔진인 타임리프(Thymeleaf)를 사용합니다.

이전 글에서는 jQuery의 Ajax를 이용해서 REST API 방식으로 댓글에 페이징을 적용해 보았습니다. 하지만 개선해야 할 점이 한 가지 남아있습니다.

게시글과 같은 동기 처리는 페이지를 이동하는 시점에 주소(URL)가 변경되기 때문에 브라우저를 새로고침 해도 페이지 번호와 검색 조건이 유지되지만, Ajax는 페이지 번호에 해당되는 데이터를 조회하되 주소는 변경되지 않기 때문에 브라우저를 새로고침 해도 페이지 번호가 유지되지 않는다는 문제가 있습니다.

이번에는 브라우저의 History API를 이용해서 URI를 강제로 변경해 비동기 페이징 처리의 새로고침 문제를 해결해 보도록 하겠습니다.

 

1. History API란?

사용자가 어떠한 페이지에 접근하면 브라우저에 세션 기록이 쌓이게 되는데요. 이 세션 기록에 접근할 수 있게 해주는 녀석이 브라우저의 history 객체입니다. 자바스크립트에서 history 객체를 이용하면 페이지를 이동할 수 있는데요. 주로 사용되는 메서드는 다음과 같습니다.

// 현재 페이지를 기준으로 뒤로 이동
history.back( )

// 현재 페이지를 기준으로 앞으로 이동
history.forward( )

// history.back( )과 동일
history.go(-1)

// history.forward( )와 동일
history.go(1)

// 페이지 새로고침
history.go( )
history.go(0)


우리는 history 객체의 replaceState( )라는 메서드를 이용해서 강제로 URI를 변경해 Ajax 페이징의 새로고침 문제를 해결합니다. 자세한 방법은 다음 단계에서 알아보겠습니다.

 

2. drawPage( ) 함수 수정하기

우선 view.html의 drawPage( )를 다음과 같이 변경해 주시면 되는데요. 기존 로직은 모두 동일하니 8번 로직만 추가로 작성해 주시면 됩니다.

    // 페이지네이션 HTML draw
    function drawPage(pagination, page) {

        // 1. 필수 파라미터가 없는 경우, 페이지네이션 HTML을 제거한 후 로직 종료
        if ( !pagination || !page ) {
            document.querySelector('.paging').innerHTML = '';
            throw new Error('Missing required parameters...');
        }

        // 2. 페이지네이션 HTML을 그릴 변수
        let html = '';

        // 3. 첫/이전 페이지 버튼 추가
        if (pagination.existPrevPage) {
            html += `
                <a href="javascript:void(0);" onclick="findAllComment(1)" class="page_bt first">첫 페이지</a>
                <a href="javascript:void(0);" onclick="findAllComment(${pagination.startPage - 1})" class="page_bt prev">이전 페이지</a>
            `;
        }

        // 4. 페이지 번호 추가
        html += '<p>';
        for (let i = pagination.startPage; i <= pagination.endPage; i++) {
            html += `<a href="javascript:void(0);" onclick="findAllComment(${i});">${i}</a>`
        }
        html += '</p>';

        // 5. 다음/끝 페이지 버튼 추가
        if (pagination.existNextPage) {
            html += `
                <a href="javascript:void(0);" onclick="findAllComment(${pagination.endPage + 1});" class="page_bt next">다음 페이지</a>
                <a href="javascript:void(0);" onclick="findAllComment(${pagination.totalPageCount});" class="page_bt last">마지막 페이지</a>
            `;
        }

        // 6. <div class="paging"></div> 태그에 변수 html에 담긴 내용을 렌더링
        const paging = document.querySelector('.paging');
        paging.innerHTML = html;

        // 7. 사용자가 클릭한 페이지 번호(page) 또는 끝 페이지 번호(totalPageCount)에 해당되는 a 태그를 찾아 활성화(active) 처리한 후 클릭 이벤트 제거
        const currentPage = Array.from(paging.querySelectorAll('a')).find(a => (Number(a.text) === page || Number(a.text) === pagination.totalPageCount));
        currentPage.classList.add('on');
        currentPage.removeAttribute('onclick');

        // 8. 페이지 URI 강제 변경
        const postId = new URLSearchParams(location.search).get('id');
        history.replaceState({}, '', location.pathname + `?id=${postId}&page=${currentPage.text}`);
    }

 

로직 해석

history 객체의 replaceState( ) 메서드를 이용하면 현재 페이지의 세션 기록을 수정할 수 있는데요. 주로 URL을 업데이트하는 경우에 사용됩니다. 추가된 로직에 대해 가볍게 설명을 드리자면 postId는 URI상의 게시글 번호를 의미하며, history.replaceState( ) 함수에는 state, title, url 총 세 개의 파라미터를 전달해야 합니다.

파라미터 설명
state history 항목과 연관된 자바스크립트 객체입니다. history.state 문법으로 state 객체에 접근할 수 있으며, 우리는 state를 사용할 일이 없기 때문에 빈 리터럴 객체를 전달합니다.
title 페이지의 타이틀을 의미합니다. 대부분의 브라우저에서 지원하지 않기 때문에 빈 문자열(' ')을 전달하면 됩니다.
url replaceState( )의 핵심 파라미터입니다. 변경할 URL을 의미하며, 새 URL은 현재 URL과 도메인이 동일해야 합니다. 만약 도메인이 동일하지 않으면 예외가 발생합니다.

이전에 몇번 설명드렸듯이 location.pathname은 페이지의 주소("/post/view.do")를 리턴하는데요. 우리는 해당 파라미터로 페이지 주소 + (게시글 번호(id) & 페이지 번호(page))를 전달합니다.

 

이제 상세 페이지에 접속해 보면 page가 쿼리 스트링으로 연결되는 것을 확인하실 수 있습니다.

댓글 1페이지

 

페이지를 이동해도 주소가 정상적으로 변경되고 있습니다.

댓글 15페이지

 

3. findAllComment( ) 함수 수정하기

findAllComment( ) 함수 구조

위 코드는 상세 페이지(view.html)에서 전체 댓글을 조회하는 findAllComment( ) 함수의 구조입니다. 우선은 해당 함수를 아래와 같이 변경해 주세요.

    // 전체 댓글 조회
    function findAllComment(page) {
    
        const uriPage = new URLSearchParams(location.search).get('page');
        page = (page) ? page : (uriPage ? Number(uriPage) : 1);
    
        const postId = [[ ${post.id}]];
        const uri = `/posts/${postId}/comments`;
        const params = {
            page : page,
            recordSize : 5,
            pageSize : 10,
            postId : postId,
        }
    
        const response = getJson(uri, params);
        const pagination = response.pagination;
        drawComments(response.list);
        drawPage(pagination, page);
    }

 

로직 해석

함수에서 최상단 두 줄의 코드만 변경되었는데요. 기존에는 113~114번 라인의 코드를 통해 페이지네이션에서 활성화(on) 된 페이지 번호(currentPage)를 기준으로 page를 세팅했으나, 이제는 주소(URL)에서 페이지 번호를 찾을 수 있으니 쿼리 스트링 상의 페이지 번호(uriPage)를 기준으로 page를 세팅해야 합니다.

 

4. 페이지 번호 유지 테스트 해보기

이제 페이지를 이동한 후 새로고침을 해보면 페이지 번호가 유지되는 것을 확인하실 수 있습니다.

댓글 19페이지

 

다음으로 19 페이지의 모든 댓글을 삭제해 보니 18페이지로 이동했고, 쿼리 스트링상의 page도 18로 정상적으로 변경됩니다. 마찬가지로 새로고침 시 페이지 번호도 정상적으로 유지됩니다.

댓글 18페이지

 

마치며

여기까지 Ajax(비동기) 페이징의 새로고침 문제를 해결해 보았습니다. History API는 페이지 번호 유지 이외에도 활용할 곳이 많을 듯합니다. 앞으로 강제로 주소를 변경해야 할 일이 있을 때 오늘 구현한 기능을 응용해 주시면 되겠습니다.

다음 글부터는 게시판에 회원 기능을 적용해 볼 건데요. 우선적으로 회원 테이블을 생성한 후 회원가입 기능을 구현하고, 인터셉터를 이용해 로그인과 로그아웃 처리를 해보도록 하겠습니다.

오늘도 방문해 주신 여러분께 감사의 말씀을 전합니다. 좋은 하루 보내세요 :)

Board.zip
0.88MB

 

반응형

댓글