안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.
페이징
페이지에 보여지는 목록이 너무 많다면, 한 눈에 보기가 어렵고 스압이 일어납니다.
만일 회원이 100명이 넘어간다면, 회원관리 탭은 100건이 넘는 건이 한 페이지에 나타나게 됩니다.
보기에도 어렵고, 구분이 어렵기 때문에 페이징 작업은 필수입니다.
content 영역
페이징 쿼리 작성
-- 페이징 쿼리 작성 (top-n분석)
-- 1. rownum
-- rownum을 새로 부여하려면, where 조건절 변경/inline view를 사용해야 함
-- offset이 있는 경우, inline view를 한 레벨 더 사용해야됨
select
*
from (
select
rownum rnum,
m.*
from (
select
*
from
member
order by
enroll_date desc
) m
) m
where
rnum between 11 and 20;
-- 2. row_number 윈도우함수
-- numPerPage = 10
-- cPage = 1, start = 1, end = 10
-- cPage = 2, start = 11, end = 20
-- cPage = 3, start = 21, end = 30
select
*
from (
select
row_number() over (order by enroll_date desc) rnum,
m.*
from
member m
) m
where
rnum between 11 and 20;
페이징 쿼리 함수를 이용하여 페이징 처리를 할 수 있습니다.
간편하게 row_number 함수를 이용하여 처리해주도록 하겠습니다.
Controller
AdminMemberListServlet
@WebServlet("/admin/memberList")
public class AdminMemberListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private MemberService memberService = new MemberService();
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// 1. 사용자입력값
int cPage = 1;
int numPerPage = 10; // 10개씩 보여줌
// 기본 값을 1로 세팅해두고 try~catch로 감쌌기 때문에 오류가 발생하면 값 대입이 이뤄지지 않고 기본값을 그대로 유지!
// cPage가 null이라면 null을 Integer로 변환하기 때문에 NumberFormatException 발생!
try {
cPage = Integer.valueOf(request.getParameter("cPage"));
} catch (NumberFormatException e) {}
// 2. 업무로직
// a. content 영역
int start = ((cPage - 1) * numPerPage) + 1;
int end = cPage * numPerPage;
Map<String, Object> param = new HashMap<>();
param.put("start", start);
param.put("end", end);
List<Member> memberList = memberService.findAll(param);
// 3. view단 응답처리
request.setAttribute("memberList", memberList);
request.getRequestDispatcher("/WEB-INF/views/admin/memberList.jsp").forward(request, response);
} catch(Exception e) {
e.printStackTrace();
throw e;
}
}
}
cPage(current Page) - 현재 페이지와 numPerPage - 보여줄 content의 개수를 지정해주었습니다.
cPage는 기본 값을 1로 세팅하고, 만일 넘어온 cPage가 있다면 대입되도록 하였고 처음 페이지를 로딩할 때 cPage는 null이기 때문에 null값을 Integer 타입으로 변환 시에는 NumberFormatException이 발생하므로 try~catch로 잡아주었습니다.
만일 발생한다면, 기본 값 1이 계속 세팅 되어있어야 하므로 catch절에서 예외 작업을 하지 않았으므로 cPage는 그대로 1이 될 것입니다.
cPage가 1일 때, start는 1, end는 10
cPage가 2일 때, start는 11, end는 20 ... 이 되는 규칙을 통해 공식을 이용하여 계산해주었습니다.
(보여줄 content영역의 순서에 의해 정해짐 - SQL 참고!! between start and end)
Service
MemberService
public List<Member> findAll(Map<String, Object> param) {
Connection conn = getConnection();
List<Member> memberList = memberDao.findAll(conn, param);
close(conn);
return memberList;
}
Dao
MemberDao
// 회원 전체 조회
// findAll = select * from (select row_number() over (order by enroll_date desc) rnum, m.* from member m) m where rnum between ? and ?
public List<Member> findAll(Connection conn, Map<String, Object> param) {
PreparedStatement pstmt = null;
ResultSet rset = null;
List<Member> memberList = new ArrayList<>();
String sql = prop.getProperty("findAll");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, (int)param.get("start"));
pstmt.setInt(2, (int)param.get("end"));
rset = pstmt.executeQuery();
while(rset.next()) {
Member member = handleMemberResultSet(rset);
memberList.add(member);
}
} catch (SQLException e) {
throw new MemberException("회원 전체 조회 오류!", e);
} finally {
close(rset);
close(pstmt);
}
return memberList;
}
이처럼 content영역은 정보가 10개씩 쪼개어져서 나타나는 것을 확인할 수 있으며, cPage의 값에 따라 페이지 이동이 일어나 보여지는 정보가 다른 것을 확인할 수 있습니다.
pagebar 처리
Controller
AdminMemberListServlet
@WebServlet("/admin/memberList")
public class AdminMemberListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private MemberService memberService = new MemberService();
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// 1. 사용자입력값
int cPage = 1;
int numPerPage = 10; // 10개씩 보여줌
// 기본 값을 1로 세팅해두고 try~catch로 감쌌기 때문에 오류가 발생하면 값 대입이 이뤄지지 않고 기본값을 그대로 유지!
// cPage가 null이라면 null을 Integer로 변환하기 때문에 NumberFormatException 발생!
try {
cPage = Integer.valueOf(request.getParameter("cPage"));
} catch (NumberFormatException e) {}
// 2. 업무로직
// a. content 영역
int start = ((cPage - 1) * numPerPage) + 1;
int end = cPage * numPerPage;
Map<String, Object> param = new HashMap<>();
param.put("start", start);
param.put("end", end);
List<Member> memberList = memberService.findAll(param);
// b. pagebar 영역
int totalContent = memberService.getTotalContent();
String url = request.getRequestURI();
String pagebar = HelloMvcUtils.getPagebar(cPage, numPerPage, totalContent, url);
System.out.println("pagebar = " + pagebar);
// 3. view단 응답처리
request.setAttribute("memberList", memberList);
request.setAttribute("pagebar", pagebar);
request.getRequestDispatcher("/WEB-INF/views/admin/memberList.jsp").forward(request, response);
} catch(Exception e) {
e.printStackTrace();
throw e;
}
}
}
회원 수를 알아야 페이지 수를 구할 수 있기 때문에 totalContent로 전체 회원 수를 받아왔습니다.
Service
MemberService
public int getTotalContent() {
Connection conn = getConnection();
int totalContent = memberDao.getTotalContent(conn);
close(conn);
return totalContent;
}
Dao
MemberDao
// getTotalContent = select count(*) from member
public int getTotalContent(Connection conn) {
PreparedStatement pstmt = null;
ResultSet rset = null;
int totalContent = 0;
String sql = prop.getProperty("getTotalContent");
try {
pstmt = conn.prepareStatement(sql);
rset = pstmt.executeQuery();
if(rset.next()) {
totalContent = rset.getInt(1);
}
} catch (SQLException e) {
throw new MemberException("전체 회원 수 조회 오류!", e);
} finally {
close(rset);
close(pstmt);
}
return totalContent;
}
컬럼 별칭을 따로 지정하지 않은 경우에는 인덱스 값으로 가져올 수도 있습니다.
또한, 단일 컬럼인 것이 확실하다면 while문이 아닌 if문으로도 대체 가능합니다.
HelloMvcUtils
/**
* @param cPage
* @param numPerPage
* @param totalContent
* @param url
*
* totalPage 전체 페이지 수
* pagebarSize 한 페이지에 표시할 페이지 개수
* pagebarStart ~ pagebarEnd
* pageNo 증감변수
*
* 1. 이전영역
* 2. pageNo 영역
* 3. 다음영역
*/
public static String getPagebar(int cPage, int numPerPage, int totalContent, String url) {
StringBuilder pagebar = new StringBuilder();
url += "?cPage=";
int totalPage = (int)Math.ceil((double)totalContent / numPerPage);
int pagebarSize = 5;
int pagebarStart = ((cPage - 1) / pagebarSize * pagebarSize) + 1;
int pagebarEnd = pagebarStart + pagebarSize - 1;
int pageNo = pagebarStart;
// 이전영역
if(pageNo == 1) {
} else {
pagebar.append("<a href='" + url + (pageNo -1) + "'>이전</a>\n");
}
// pageNo영역
while(pageNo <= pagebarEnd && pageNo <= totalPage) {
// 현재페이지
if(pageNo == cPage) {
pagebar.append("<span class='cPage'>" + pageNo + "</span>\n");
}
// 현재페이지가 아닌 경우
else {
pagebar.append("<a href='" + url + pageNo + "'>" + pageNo + "</a>\n");
}
pageNo++;
}
// 다음영역
if(pageNo > totalPage) {
} else {
pagebar.append("<a href='" + url + pageNo + "'>다음</a>\n");
}
return pagebar.toString();
}
@콘솔출력값
pagebar = <span class='cPage'>1</span>
<a href='/mvc2/admin/memberList?cPage=2'>2</a>
<a href='/mvc2/admin/memberList?cPage=3'>3</a>
<a href='/mvc2/admin/memberList?cPage=4'>4</a>
<a href='/mvc2/admin/memberList?cPage=5'>5</a>
<a href='/mvc2/admin/memberList?cPage=6'>다음</a>
pagebar = <a href='/mvc2/admin/memberList?cPage=5'>이전</a>
<a href='/mvc2/admin/memberList?cPage=6'>6</a>
<span class='cPage'>7</span>
<a href='/mvc2/admin/memberList?cPage=8'>8</a>
<a href='/mvc2/admin/memberList?cPage=9'>9</a>
<a href='/mvc2/admin/memberList?cPage=10'>10</a>
<a href='/mvc2/admin/memberList?cPage=11'>다음</a>
총 페이지 개수, pagebar의 시작 값, pagebar의 마지막 값을 공식을 이용하여 구했습니다.
이전영역/content영역/다음영역으로 나눠서 분기처리를 통해 a태그로 링크를 걸거나, 다음/이전을 표시할 수 있도록 하였습니다.
totalPage = 12
1~5 내에 있는 페이지에 접속했을 때,
- 이전영역 if문
pageNo = pagebarStart이므로, pageNo == 1 → '이전'영역은 표시 되지 않음
- content영역 while문
while문을 돌면서 현재페이지인 경우에는 span태그, 그렇지 않다면 a태그를 가진 content 영역이 생성
- 다음영역 if문
while문을 돌고 pageNo은 ++이 된 채로 탈출하므로, 다음영역의 if문을 돌 때 pageNo = 6 → 6페이지로 이동하는 '다음'영역 표시
5~10 내에 있는 페이지에 접속했을 때,
- 이전영역 if문
pageNo = pagebarStart이므로, pageNo = 6 → pageNo-1 즉 5페이지로 이동하는 a태그를 가진 '이전'영역 표시
- content영역 while문
while문을 돌면서 현재페이지인 경우에는 span태그, 그렇지 않다면 a태그를 가진 content 영역 생성
- 다음영역 if문
while문을 돌고 pageNo은 ++이 된 채로 탈출하므로, 다음영역의 if문을 돌 때 pageNo = 11 → 11페이지로 이동하는 '다음'영역 표시
10~12 내에 있는 페이지에 접속했을 때,
- 이전영역 if문
pageNo = pagebarStart이므로, pageNo = 10 → pageNo-1 즉 9페이지로 이동하는 a태그를 가진 '이전'영역 표시
- content영역 while문
while문을 돌면서 현재페이지인 경우에는 span태그, 그렇지 않다면 a태그를 가진 content 영역 생성
이 때 pageNo <= totalPage 즉, pageNo이 13이 되어버리면 while문을 탈출!
- 다음영역 if문
다음영역의 if문을 돌 때 pageNo = 13 → pageNo > totalPage (13 > 12) 참이므로 '다음'영역이 표시 되지 않음
memberList
- pagebar 추가
<div id="pagebar">
<%= request.getAttribute("pagebar") %>
</div>
'Java > Servlet & JSP' 카테고리의 다른 글
JSP) 검색 페이징 처리 (0) | 2022.07.01 |
---|---|
JSP) 검색기능 구현하기 (0) | 2022.07.01 |
JSP) 관리자 모드 - 회원 정보 조회하기 (0) | 2022.06.27 |
JSP) error page - exception 발생 예외/status 발생 예외 (0) | 2022.06.27 |
JSP) 암호화 - salt 처리, 비밀번호 변경 페이지 생성 (0) | 2022.06.26 |