일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 자바
- Level 1
- ajax
- 일단_해보는거야
- 스프링
- 다중 카테고리 구현
- json
- 코딩
- 프로그래머스
- Sts
- 대분류/중분류/소분류
- MVC
- Spring MVC
- SESSION
- 로그인과 장바구니 구현
- Oracle
- jsp
- 오라클
- jsp 프로젝트
- jquery
- 고객센터 구현
- jakarta.mail
- java
- js
- 인증코드로 비밀번호 변경 구현
- MySQL
- 교보문고 따라하기
- 세션
- Spring
- 이메일로 인증코드 전송 구현
감 잃지말고 개발하기
[JSP][MVC][MySQL] Select 박스 옵션에 따른 페이징 처리 구현하기 #2. 로직 구현 본문
도서 목록 페이지에서 <Select> 박스 옵션에 따른 페이징 처리 로직을 기록하고자 한다.
1탄에서 기본적인 설정을 끝냈으니, 이번 포스팅에서는 본격적인 로직을 정리해 보도록 하겠다.
♠ 해당 구현의 로직 흐름이 궁금하면 아래 포스팅을 참고하세요 ♠
2023.05.27 - [JSP/MVC] - [JSP][MVC][MySQL] Select 박스 옵션에 따른 페이징 처리 구현하기 #1. 기본 설정
[JSP][MVC][MySQL] Select 박스 옵션에 따른 페이징 처리 구현하기 #1. 기본 설정
도서 목록 페이지에서 박스 옵션에 따른 페이징 처리 로직을 총 2개의 포스팅에 걸쳐 기록하고자 한다. 이번 포스팅에서는 구현 흐름과 필요한 테이블 및 클래스를 정리해 보도록 하겠다. 목표
persimmon-ary-stepbystep.tistory.com
목표
♠ 페이징 처리를 구현할 수 있다.
로직 코드 및 실행화면
1. 도서 목록 페이지 요청
페이지 상단 내비게이션 바 HTML 일부분이다.
<li>최신 도서</li>를 클릭하면 도서 목록 페이지를 요청한다.
<ul class="nav navbar-nav menu_nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="${request.getContextPath() }/bookShopMain.ok">홈</a>
</li>
<li class="nav-item">
<a class="nav-link" href="${request.getContextPath() }/bookList.ok">최신 도서</a>
</li>
</ul>
2. 컨트롤러(BookFrontController.java)
*.ok 로 들어오는 URL은 해당 컨트롤러에서 처리한다.
/bookList.ok로 요청되면 BookListAction 클래스를 호출한다.
package controller;
import java.io.IOException;
import java.rmi.ServerException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import action.Action;
import action.BookCartListAction;
import vo.ActionForward;
@WebServlet("*.ok")
public class BookFrontController extends HttpServlet{
protected void doProcess(HttpServletRequest req, HttpServletResponse resp)
throws ServerException, IOException, ServletException {
req.setCharacterEncoding("UTF-8");
/* 1. 요청 주소 파악 */
String requestURI = req.getRequestURI();
String contextPath = req.getContextPath();
String command = requestURI.substring(contextPath.length());
/* 2. 각 요청 주소의 매핑 처리 */
ActionForward forward = null;
Action action = null;
// 도서 목록 페이지 요청
if(command.equals("/bookList.ok")) {
action = new BookListAction();
try {
forward = action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
/* 3. 포워딩 처리 */
if(forward != null) {
if(forward.isRedirect()) {
// redirect 방식
resp.sendRedirect(forward.getPath());
} else {
// forward 방식
RequestDispatcher dispatcher = req.getRequestDispatcher(forward.getPath());
dispatcher.forward(req, resp);
}
}
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServerException, IOException, ServletException {
doProcess(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServerException, IOException, ServletException {
doProcess(req, resp);
}
}
3. Action 클래스(BookListAction.java)
☞ int page = 1;
위의 1번에 따라 도서 목록 페이지의 최초 요청 URL의 모습은 http://localhost:.../bookList.ok이지만,
페이징 처리가 들어간 URL은 http://localhost:.../bookList.ok?page=2와 같은 모습을 가진다.
파라미터 page에는 해당 목록 화면의 페이지 번호가 저장되는데, 이 값을 저장할 변수 page를 초기화해 준다.
☞ service.getListCount();
DB에서 도서 총개수를 가져온다.
☞ service.getBookList(page, limit);
도서 목록 화면에서 page번에 출력될 도서를 limit개만 가져온다.
만약 page가 3이면, 3번째 페이지에서 출력될 도서를 9개만 가져오게 된다.
☞ listCount / limit + (listCount % limit == 0 ? 0 : 1);
필요한 총 페이지 수를 계산한다.
만약 도서 총 개수(listCount)가 82개이고 한 화면에 출력될 도서 개수(limit)가 9개일 때, 필요한 페이지 수는 10개이다.
즉, 나머지가 생겼을 때 이를 올림처리해서 페이지 수를 계산한다.
☞ if(endPage > maxPage) endPage = maxPage;
계산된 endPage 값을 존재하는 페이지의 마지막 페이지 번호(maxPage)로 지정하는 부분이다.
예를 들어, 글이 72개가 있고 한 화면에 출력될 도서 개수가 9개일 때,
필요한 페이지 수(maxPage)는 8개인데 마지막 페이지 번호(endPage)는 10이 되게 된다.
이에 대한 처리를 위해 if문을 넣어 만약 마지막 페이지 번호가 필요 페이지 수보다 많을 때 마지막 페이지 번호를 필요 페이지 번호로 설정해 준다.
☞ req.setAttribute("pageInfo", pageInfo);
페이징 처리에 대한 정보를 저장한 pageInfo 객체를 속성으로 공유한다.
bookList.jsp 페이지에서 해당 정보를 가져다 사용할 것이다.
package action;
import java.util.ArrayList;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import svc.BookListService;
import vo.ActionForward;
import vo.Book;
import vo.PageInfo;
/** 책 상품 목록보기 요청을 처리하는 Action 클래스*/
public class BookListAction implements Action {
@Override
public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {
/* 필요 변수 초기화 */
int page = 1;
int limit = 9;
/* URL 파라미터 설정 */
if(req.getParameter("page") != null) {
page = Integer.parseInt(req.getParameter("page"));
}
/* DB 처리
* 1. DB에 저장된 총 책 개수 GET
* 2. 지정한 페이지에 출력될 책 목록을 GET */
BookListService service = new BookListService();
int listCount = service.getListCount();
ArrayList<Book> bookList = service.getBookList(page, limit);
/* 페이징 처리
* 1. 총 페이지 수(나머지가 있는 경우에만 올림처리) 계산
* 2. 페이징 부분에 출력되는 페이지 번호 중 첫 번째 페이지 번호(1, 11, 21 등) 계산
* 3. 페이징 부분에 출력되는 페이지 번호 중 마지막 페이지 번호(10, 20, 30 등) 계산 */
int maxPage = listCount / limit + (listCount % limit == 0 ? 0 : 1);
int startPage = (((int)((double)page / 10 + 0.9)) - 1) * 10 + 1;
int endPage = startPage + 10 - 1;
if(endPage > maxPage) endPage = maxPage;
/* 페이징에 관한 정보를 저장할 PageInfo 객체 생성 */
PageInfo pageInfo = new PageInfo();
pageInfo.setEndPage(endPage);
pageInfo.setListCount(listCount);
pageInfo.setMaxPage(maxPage);
pageInfo.setPage(page);
pageInfo.setStartPage(startPage);
/* 포워딩할 때 가져갈 정보 저장
* 1. 책 상품 목록 정보를 속성으로 공유
* 2. pageInfo 객체를 request 영역에 속성 값으로 공유
* .ok -> .jsp : Forward
* */
req.setAttribute("bookList", bookList);
req.setAttribute("pageInfo", pageInfo);
ActionForward forward = new ActionForward();
forward.setPath("/book/bookList.jsp");
forward.setRedirect(false);
return forward;
}
}
4. Service 클래스(BookListService.java)
☞ getListCount();
해당 메서드는 DB에 저장된 총 책 개수(count(*))를 구해 리턴한다.
☞ getBookList(int page, int limit);
해당 메서드는 두 개의 인자를 가지고 페이지에서 출력될 책 상품 목록을 ArrayList 객체 타입으로 리턴한다.
package svc;
import java.sql.Connection;
import java.util.ArrayList;
import dao.BookDAO;
import vo.Book;
import static db.JdbcUtil.*;
/** 책 상품 목록보기 요청을 처리하는 비즈니스 로직을 구현하는 Service 클래스*/
public class BookListService {
/** DB에 저장된 총 책 개수(count(*))를 구하는 메서드 */
public int getListCount() {
int listCount = 0;
/* DB 처리 */
Connection conn = getConnection();
BookDAO boardDAO = BookDAO.getInstance();
boardDAO.setConnection(conn);
listCount = boardDAO.selectListCount();
close(conn);
return listCount;
}
/** 파라미터로 넘어온 페이지에서 출력될 책 상품 목록을 ArrayList 객체 타입으로 반환하는 메서드 */
public ArrayList<Book> getBookList(int page, int limit) throws Exception{
/* DB 처리 */
BookDAO bookDAO = BookDAO.getInstance();
Connection conn = getConnection();
bookDAO.setConnection(conn);
ArrayList<Book> bookList = bookDAO.selectBookList(page, limit);
close(conn);
return bookList;
}
}
5. DAO 클래스(BookDAO.java)
☞ SELECT *
FROM jspbookshop.book
ORDER BY b_publish_date DESC
LIMIT ?, ?
해당 쿼리문은 가장 최신에 출판된 도서부터 정렬하여,
읽기 시작할 레코드 인덱스를 첫 번째 ?에, 조회할 레코드 수를 두 번째 ?로 매핑해 해당 데이터를 가져온다.
☞ int startrow = (page-1)*limit;
읽기 시작할 row(해당 페이지에서 출력되어야 하는 시작 레코드의 인덱스) 번호를 설정하는 변수이다.
만약 현재 페이지가 1이고 limit가 9라면, 읽기 시작해야 할 인덱스 번호는 0이다.
만약 현재 페이지가 2라면, 읽기 시작해야 할 인덱스 번호는 9이다.
package dao;
import static db.JdbcUtil.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import vo.Book;
/** MySQL DB로 SQL구문을 전송하는 클래스*/
public class BookDAO {
Connection conn;
private static BookDAO bookDAO;
private BookDAO() {
// TODO Auto-generated constructor stub
}
public static BookDAO getInstance() {
if(bookDAO == null) {
bookDAO = new BookDAO();
}
return bookDAO;
}
/** BookDAO 객체에 Connection 객체를 주입하는 메서드 */
public void setConnection(Connection conn) {
this.conn = conn;
}
/** 전체 책 개수 구하는 메서드 */
public int selectListCount() {
int listCount = 0;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "SELECT COUNT(*) FROM jspbookshop.book";
try {
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
if(rs.next()) {
listCount = rs.getInt(1);
}
} catch (Exception e) {
System.out.println(" selectListCount ERROR : "+e);
} finally {
close(rs);
close(pstmt);
}
return listCount;
}
/** 해당 페이지에 출력될 책 상품 목록을 반환하는 메서드 */
public ArrayList<Book> selectBookList(int page, int limit) {
PreparedStatement pstmt = null;
ResultSet rs = null;
ArrayList<Book> bookList = null;
String book_sql = "SELECT * "
+ "FROM jspbookshop.book "
+ "ORDER BY b_publish_date DESC "
+ "LIMIT ?, ? ";
int startrow = (page-1)*limit; // 읽기 시작할 row 번호(해당 페이지에서 출력되어야 하는 시작 레코드의 인덱스 번호)
try {
pstmt = conn.prepareStatement(book_sql);
pstmt.setInt(1, startrow);
pstmt.setInt(2, limit);
rs = pstmt.executeQuery();
if (rs.next()) {
bookList = new ArrayList<>();
do {
bookList.add(new Book(
rs.getInt("b_id"),
rs.getString("b_name"),
rs.getString("b_writer"),
rs.getString("b_translator"),
rs.getString("b_publisher"),
rs.getString("b_catgy"),
rs.getInt("b_price"),
rs.getString("b_image"),
rs.getInt("b_page"),
rs.getString("b_publish_date"),
rs.getString("b_content"),
rs.getInt("b_readcount")));
} while (rs.next());
}
} catch (Exception e) {
System.out.println(" B.DAO : selectBookList ERROR : "+e);
} finally {
close(rs);
close(pstmt);
}
return bookList;
}
}
6. bookList.jsp
아래 페이징 처리 HTML 코드를 추가한다.
- 필요한 페이지 수가 10개 이상이면 왼쪽 방향 화살표가 나타나도록 설정한다.
- 필요한 페이지 수가 마지막 페이지 번호(10, 20, 30, ...)보다 크면 오른쪽 방향 화살표가 나타나도록 설정한다.
- 해당 페이지로 넘어가는 <a> 태그의 href 속성 값으로 파라미터 page를 추가한다.
<c:if test="${pageInfo.listCount != null }">
<div class="pagination">
<!-- 이전 화살표 -->
<c:if test="${pageInfo.page > 10 }">
<a href="/bookList.ok?page=${pageInfo.page-1 }" class="prev-arrow">
<i class="fa fa-long-arrow-left pt-3" aria-hidden="true"></i>
</a>
</c:if>
<c:forEach var="a" end="${pageInfo.endPage }" step="1" begin="${pageInfo.startPage }">
<c:if test="${a == pageInfo.page}">
<a>${a }</a>
</c:if>
<c:if test="${a != pageInfo.page}">
<a href="/bookList.ok?page=${a }">${a }</a>
</c:if>
</c:forEach>
<!-- 다음 화살표 -->
<c:if test="${pageInfo.endPage < pageInfo.maxPage }">
<a href="/bookList.ok?page=${pageInfo.endPage+1 }" class="next-arrow">
<i class="fa fa-long-arrow-right pt-3" aria-hidden="true"></i>
</a>
</c:if>
</div>
</c:if>
♠ 추가 설명 ♠
1. LIMIT ?, ?
예시를 통해 이해해보자.
먼저 DB의 book 테이블을 아래 쿼리문으로 조회해보자.
SELECT * FROM jspbookshop.book
order by b_publish_date desc;
▼ 조회 확인
이젠 LIMIT를 걸어 다시 조회해보자.
select *
from book
order by b_publish_date desc
limit 3, 9;
▼ 조회 확인
레코드 인덱스 3부터 9개의 데이터가 조회된 것을 확인할 수 있다.
이렇게 기본적인 페이징 처리 로직이 구현되었다.
다음 포스팅에서는 도서 목록 화면에 <select> 박스 옵션을 추가해 추가적인 정보에 따른 페이징 처리 구현을 정리해 봄으로써 이번 구현을 마무리해 보도록 하겠다.
끝.
'JSP > MVC' 카테고리의 다른 글
[JSP][MVC][MySQL] 도서 등록 페이지 카테고리 구현하기 #2. 서버 딴 구현 (0) | 2023.05.31 |
---|---|
[JSP][MVC][MySQL] 도서 등록 페이지 카테고리 구현하기 #1. 기본 세팅 (0) | 2023.05.31 |
[JSP][MVC][MySQL] Select 박스 옵션에 따른 페이징 처리 구현하기 #3. 로직 구현(마지막) (0) | 2023.05.27 |
[JSP][MVC][MySQL] Select 박스 옵션에 따른 페이징 처리 구현하기 #1. 기본 설정 (0) | 2023.05.27 |
[JSP][MVC][Session] 세션 및 로그인 도서 장바구니 구현하기 #7. 장바구니 수량 변경하기 (2탄) (0) | 2023.05.24 |
[JSP][MVC][Session] 세션 및 로그인 도서 장바구니 구현하기 #6. 장바구니 수량 변경하기 (1탄) (0) | 2023.05.24 |