본문 바로가기
💻 뚝딱뚝딱/팀내도서대여시스템(OBRS)

[개발일지#010] 페이지네이션 적용하기 (회원목록 / 나의책 / 빌린책 / 모든책)

by 뚜루리 2024. 4. 11.
728x90
320x100
목록을 출력하는 모든 화면에 페이지네이션을 적용해보자.

 

[개발목표]

1. 페이지네이션 적용하기
 
 


 

페이지네이션을 적용할 화면은 회원목록 / 모든책 / 나의책 / 빌린책 총 4개의 화면이 될텐데
모두 비슷한 형태로 사용되기 때문에 회원목록의 예만 올려볼 예정.
 

[구현화면]

  • 맨 처음 / 이전 / 페이지 부분 / 다음 / 맨 끝 형태로 페이지 네이션을 구현한다.
  • 현재 페이지에 대한 표시는 육안으로 알아 볼 수 있게끔 한다.

 

 

 

 

 

MemberMapper.xml 수정 / 추가

<select id="allMemberList" resultType="seulgi.bookRentalSystem.domain.member.Member">
    SELECT
          MEMBER_ID AS memberId
        , MEMBER_NAME AS memberName
        , PASSWORD
        , JOIN_DATE AS joinDate
    FROM MEMBER_TB
    ORDER BY joinDate
    LIMIT #{offset}, #{limit}
</select>
    <select id="countMembers" resultType="int">
        SELECT COUNT(*)
        FROM MEMBER_TB
    </select>
  • allMemberList는 기존에 있던 쿼리인데 LIMIT #{offset}, #{limit} 만 추가해주었다.
  • CountMembers의 쿼리의 경우 목록의 전체 카운트 수를 가져오는 쿼리를 하나 만들어주었다. 

 

memberMapper.java

package seulgi.bookRentalSystem.domain.member;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Optional;

@Mapper
public interface MemberMapper {

    List<Member> allMemberList(@Param("offset") int offset, @Param("limit") int limit);

    int countMembers();


}

offset, limit의 파라미터가 쿼리에서 추가되었으니 mapper에서도 파라미터로 넘겨준다.
 

meberService, memberServiceImpl.java

package seulgi.bookRentalSystem.domain.member;

import org.apache.ibatis.annotations.Param;
import seulgi.bookRentalSystem.domain.book.Book;
import seulgi.bookRentalSystem.domain.book.BookRental;

import java.util.List;

public interface MemberService {

    List<Member> allMemberList(int page, int size);

    int countMembers();

}
package seulgi.bookRentalSystem.domain.member;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import seulgi.bookRentalSystem.domain.book.Book;
import seulgi.bookRentalSystem.domain.book.BookRental;

import java.util.List;
import java.util.Optional;

@Service
@RequiredArgsConstructor
public class MemberServiceImpl implements MemberService{

    private final MemberMapper memberMapper;

    @Override
    public List<Member> allMemberList(int page, int size) {
        int offset = (page - 1) * size;
        return memberMapper.allMemberList(offset, size);
    }

    @Override
    public int countMembers() {
        return memberMapper.countMembers();
    }



}

 
 

MemberController.java

package seulgi.bookRentalSystem.web.member;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import seulgi.bookRentalSystem.domain.login.LoginForm;
import seulgi.bookRentalSystem.domain.login.LoginService;
import seulgi.bookRentalSystem.domain.member.Member;
import seulgi.bookRentalSystem.domain.member.MemberServiceImpl;
import seulgi.bookRentalSystem.domain.member.UpdateForm;
import seulgi.bookRentalSystem.web.login.SessionConst;

import java.util.List;

@Controller
@RequiredArgsConstructor
@RequestMapping("/member")
public class MemberController {

    private final MemberServiceImpl memberService;

    /**
     * 회원 목록 조회
     * @param model
     * @return
     */
    @GetMapping
    public String allMemberList(Model model
    , @RequestParam(defaultValue = "1") int page
    , @RequestParam(defaultValue = "10") int size){
        List<Member> members = memberService.allMemberList(page, size);
        int totalMembers = memberService.countMembers();
        int totalPages = (int) Math.ceil((double) totalMembers / size);
        model.addAttribute("members", members);
        model.addAttribute("currentPage", page);
        model.addAttribute("totalPages", totalPages);
        return "member/allMemberList";
    }

}
  • @RequestParam()을 통해 Page, size를 가져오는데 처음 로딩할 때는 1페이지임으로 defaultValue = '1'로 준다. 
  • 여기서 int page는 현재 페이지를 뜻하며 int size는 한페이지에 몇 개를 담는지에 대한 변수다. 
  • 전체 회원목록 수와 페이지수를 계산하여 model에 담아 넘겨준다.

 
 

allMemberList.html

<nav aria-label="Page navigation example"
    th:fragment="pagenation">
    <ul class="pagination" style="display: flex; justify-content: center;">
        <li class="page-item" th:classappend="${currentPage > 1} ? '' : 'disabled'">
            <a class="page-link" th:href="@{/member(page=1)}">First</a>
        </li>
        <li class="page-item" th:classappend="${currentPage > 1} ? '' : 'disabled'">
            <a class="page-link" th:href="@{/member(page=${currentPage - 1})}">Previous</a>
        </li>
        <li class="page-item" th:classappend="${page == currentPage} ? 'active' : ''"
            th:each="page : ${#numbers.sequence(1, totalPages != null ? totalPages : 1)}">
            <a class="page-link" th:href="@{/member(page=${page})}" th:text="${page}"></a>
        </li>
        <li class="page-item" th:classappend="${currentPage < totalPages} ? '' : 'disabled'">
            <a class="page-link" th:href="@{/member(page=${currentPage + 1})}">Next</a>
        </li>
        <li class="page-item" th:classappend="${currentPage < totalPages} ? '' : 'disabled'">
            <a class="page-link" th:href="@{/member(page=${totalPages})}">Last</a>
        </li>
    </ul>
</nav>

classappend 를 활용하여 클래스를 조절해서 부트스트랩의 테마가 적용 될 수 있도록 하였다. 
(사실 여기서 엄청 헤맸다......은근 복잡한데 다해놓고 보면 또 별거 아니넹)

728x90
320x100