gi_dor

스프링부트 + MyBatis +MYSQL 페이징 처리 본문

Back_End/SpringBoot

스프링부트 + MyBatis +MYSQL 페이징 처리

기돌 2024. 5. 9. 15:16

마이페이지 → 1:1 문의 내역에 대해  페이징 처리를 하려고 합니다

가장 기본적인 List 로 출력 했습니다 , 테스트용 더미 데이터를 추가해보겠습니다

 

 <!--  1:1 문의사항 글 갯수 파악하기 -->
<select id="countInquiry" parameterType="string" resultType="int">
    select count(*)
    from INDIVIDUAL_INQUIRIES i , USER u
    where i.INQUIRY_USER_NO = u.USER_NO
      and u.USER_ID = #{id}
</select>

<!--페이징 되어있는 1:1문의 내역 조회하기 -->
<select id="selectInquiryListPaging" resultType="com.example.bookhub.user.dto.InquiryListDTO">
    select
        i.INDIVIDUAL_INQUIRY_NO             as no,
        i.INQUIRY_CATEGORY_NO               as "faqCategory.no",
        f.FAQ_CATEGORY_NAME                 as "faqCategory.name",
        i.INQUIRY_USER_NO                   as "user.no",
        u.USER_ID                           as "user.id",
        i.INDIVIDUAL_INQUIRY_TITLE          as title,
        i.INDIVIDUAL_INQUIRY_CONTENT        as content,
        i.INDIVIDUAL_INQUIRY_ANSWER_YN      as answerYn,
        i.INDIVIDUAL_INQUIRY_DELETE_YN      as deleteYn,
        i.INDIVIDUAL_INQUIRY_CREATE_DATE    as createdDate ,
        i.INDIVIDUAL_INQUIRY_UPDATE_DATE    as updatedDate,
        u.USER_NAME                         as "user.name"
    from INDIVIDUAL_INQUIRIES i , USER u , FAQ_CATEGORIES f
    where i.INQUIRY_USER_NO = u.USER_NO
      and i.INQUIRY_CATEGORY_NO = f.FAQ_CATEGORY_NO
      and u.USER_ID = #{id}
    order by  i.INDIVIDUAL_INQUIRY_CREATE_DATE DESC
        LIMIT #{offset} ,10
</select>

 

LIMIT - 결과중 처음부터 몇개만 가져오기 

SELECT * FROM 테이블명 LIMIT 10; -- 처음 부터 10개만 출력하기 (1 ~ 10)
SELECT * FROM 테이블명 LIMIT 100, 10; -- 100번째부터 그 후 10개 출력하기 (101 ~ 110)

 

OFFSET - 어디서부터 가져올지

-- 10행씩 출력
--1페이지 
select * from member ORDERS LIMIT 10 OFFSET 0;
-- 1 2 3 4 5 6 7 8 9 10 

-- 2페이지
select * from member ORDERS LIMIT 10 OFFSET 10;
-- 11 12 13 14 15 16 17 18 19 20

SELECT * FROM 테이블명 ORDERS LIMIT 20 OFFSET 5; -- 6 행 부터 25행 까지 출력 (6 ~ 25)
--  6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

-- limit 5, 20 과 같다고 보면 된다.
SELECT * FROM 테이블명 ORDERS LIMIT 5, 20;

 

 

Pagination

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserPagination {

    // 화면에 보여줄 글, 행의 갯수
    private int rows = 10;

    // 페이징 네비게이션의 보여줄 페이지 갯수    1, 2 , 3 , 4 ,5 >  >>
    private int pages = 5;

    // 전체 글의 갯수
    private int totalRows;

    // 전체 페이지 갯수  totalPages = 5 --> 글 갯수 26~30개
    private int totalPages;

    // 전체 페이지네이션 바에 표시할 전체 블럭 갯수
    private int totalBlocks;

    // 현재 페이지 번호
    private int currentPage;

    // 현재 블럭 번호
    private int currentBlock;

    private int begin;
    private int end;
    private int beginPage;
    private int endPage;

    // 현재  첫번째 페이지 ,마지막 페이지 구분
    private boolean isFirst;
    private boolean isLast;

    private void init() {

        // 글이 존재하는지
        if (totalRows > 0) {
            // 전체 페이지 갯수 계산하기
            this.totalPages = (int) Math.ceil((double) totalRows / rows);

            // 전체 페이지 블럭 갯수 계산
            this.totalBlocks = (int) Math.ceil((double) totalPages / pages);

            // 현재 블럭 계싼
            this.currentBlock = (int) Math.ceil((double) currentPage / pages);

            // 게시글 조회범위
            this.begin = (currentPage - 1) * rows + 1;
            this.end = currentPage * rows;

            // 페이지 내비게이션 출력범위 계산
            this.beginPage = (currentBlock - 1) * pages + 1;
            this.endPage = currentBlock * pages;

            if (currentBlock == totalBlocks) {
                this.endPage = this.totalPages;
            }

            if (currentPage == 1) {
                this.isFirst = true;
            }

            if (currentPage == totalPages) {
                this.isLast = true;
            }
        }
    }


    public UserPagination(int currentPage, int totalRows) {
        this.totalRows = totalRows;
        this.currentPage = currentPage;
        init();
    }


    public UserPagination(int currentPage, int totalRows, int rows) {
        this.totalRows = totalRows;
        this.currentPage = currentPage;
        this.rows = rows;
        init();
    }


    public UserPagination(int currentPage, int totalRows, int rows, int pages) {
        this.totalRows = totalRows;
        this.currentPage = currentPage;
        this.rows = rows;
        this.pages = pages;
        init();
    }
}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class InquiryListDTO {
	// 문의사항 번호
    Long no;
    
    // 글 카테고리 
    FaqCategory faqCategory;
    
    // 문의사항 제목
    String title;
    
    // 문의사항 내용
    String content;
    
    // 문의사항 답변여부
    boolean answerYn;
    
    // 글 삭제 여부
    boolean deleteYn;
    
    // 작성날짜
    LocalDateTime createdDate;
    // 글 수정 날짜
    LocalDateTime updatedDate;
    
    // 글작성 사용자 정보
    User user;

}

 

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PageListDTO<T> {

    private List<T> items;
    private UserPagination userPagination;

}

 제네릭 타입을 사용하여 페이지 목록을 나타낸다

  • items: 페이지에 포함된 요소의 목록을 나타내는 제네릭 타입의 리스트입니다. 이는 페이지에 표시될 항목을 저장
  • userPagination: 사용자 페이지네이션 정보를 나타내는 클래스.
    사용자 페이지네이션은 페이지 내비게이션을 관리하기 위해 사용되며 페이지네이션에 필요한 정보를 저장

 

<T>  제네릭의 타입 매개변수다. 여러 종류의 타입에 대한 클래스를 작성할 수 있다

타입 매개변수로 인해 계속해서 ListDTO + Pageination을 담은 클래스를 만들지 않고도 사용할 수 있다

 코드의 재사용성도 높아지고 중복된 코드를 줄일 수 있다

@Mapper
public interface MyPageMapper {
	List<InquiryListDTO>selectInquiryListPaging(@Param("id")String id , @Param("offset")int offset);
}

 

@Slf4j
@Service
@RequiredArgsConstructor
public class MyPageService {
public PageListDTO<InquiryListDTO> getInquiryListByIdPage(String id , int page) {
    // 사용자 정보조회
    User user = userMapper.selectUserById(id);

    // 사용자의 아이디로 전체 작성된 1:1문의 갯수 조회
    int totalRows = myPageMapper.countInquiry(user.getId());

    // 페이징 정보
    UserPagination userPagination =  new UserPagination(page , totalRows);

    int offset = userPagination.getBegin() -1;

    // 페이징된 결과 조회
    List<InquiryListDTO> inquiryListDTO = myPageMapper.selectInquiryListPaging(user.getId(), offset);

   // <T> 제네릭 타입매개변수 사용
    PageListDTO<InquiryListDTO> pageListDTO = new PageListDTO<>();
    pageListDTO.setItems(inquiryListDTO);
    pageListDTO.setUserPagination(userPagination);

    // PageListDTO<InquiryListDTO> pageListDTO = new PageListDTO<>(inquiryListDTO,userPagination);

    return pageListDTO;

	}
}

 

<div>
    <nav aria-label="Page navigation example">
        <ul class="pagination justify-content-center pagination-sm">
            <!-- 첫 페이지로 이동하는 링크 -->
            <li class="page-item">
                <a class="page-link" th:if="${page.currentPage > 1}"
                   th:href="@{/mypage/list/inquiryList(page=1)}" >&laquo;</a>
                <span class="page-link disabled" th:unless="${page.currentPage > 1}">&laquo;</span>
            </li>
            <!-- 이전 페이지 링크 -->
            <li class="page-item">
                <a class="page-link" th:attr="data-page=${page.currentPage - 1}"  onclick="page(event)"
                   th:href="@{/mypage/list/inquiryList(page=${page.currentPage - 1})}"
                   th:if="${page.currentPage > 1}">&lt;</a>
                <span class="page-link disabled" th:unless="${page.currentPage > 1}">&lt;</span>
            </li>
            <!-- 페이지 번호를 표시하기 위한 리스트 아이템 -->
            <li class="page-item" th:each="pageNo : ${#numbers.sequence(page.beginPage, page.endPage)}"
                th:class="${pageNo == page.currentPage} ? 'active' : ''">        <!-- 현재 페이지와 페이지 번호를 비교하여 활성화 클래스를 동적으로 설정 -->
                <a class="page-link" th:attr="data-page=${pageNo}" onclick="page(event)"
                   th:href="@{/mypage/list/inquiryList(page=${pageNo})}" th:text="${pageNo}"></a>
            </li>
            <!-- 다음 페이지 링크 -->
            <li class="page-item">
                <a class="page-link" th:attr="data-page=${page.currentPage + 1}" onclick="page(event)"
                   th:href="@{/mypage/list/inquiryList(page=${page.currentPage + 1})}"
                   th:if="${page.currentPage < page.totalPages}">&gt;</a>
                <span class="page-link disabled" th:unless="${page.currentPage < page.totalPages}">&gt;</span>
            </li>
            <!-- 마지막 페이지로 이동하는 링크 -->
            <li class="page-item">
                <a class="page-link" th:if="${page.currentPage < page.totalPages}"
                   th:href="@{/mypage/list/inquiryList(page=${page.totalPages})}">&raquo;</a>
                <span class="page-link disabled" th:unless="${page.currentPage < page.totalPages}">&raquo;</span>
            </li>
        </ul>
    </nav>
</div>

 

<li class="page-item">
    <a class="page-link" th:if="${page.currentPage > 1}"
       th:href="@{/mypage/list/inquiryList(page=1)}" >&laquo;</a>
    <span class="page-link disabled" th:unless="${page.currentPage > 1}">&laquo;</span>
</li>

현재 페이지가 1보다 큰 경우에만 이전 페이지로 이동하는 링크를 활성화하고, 그렇지 않은 경우 비활성화

728x90