개빡셨다 뭔가 다 헷갈렸다 ㅋㅋ
pagination(페이지 구분)
세미로 만드는 부분에서 크게 별다른 부분은 차이가 나지않았지만
pagination 부분은 진짜 헷갈렸다.
하나의 section안에 div 3개와 form태그 하나로 구성햇다.
게시판 테이블을 감싸는 'list-wrapper' div객체
게시글 작성을 위한 작성 버튼을 감싼 'btn-area' div객체
pagination을 나누기 위한 ul을 감싸는 'pagination-area' div
( 보통 pagination을 나눌때는 주로 list을 사용한다고 함)
+ 검색를 하기 위한 form 태그
- table중에서 사용되는 td에는 고유한 border가 있는데. 이 테두리가 테이블을 개 못생기게 한다.이러한 고유 border를 지워버리는 옵션을 사용하면 예뻐진다.
@WebServlet("/board/list") --게시판에서 요청되는 웹상 주소
public class BoardListServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
--type : 게시판의 종류를 읽어온다. 1:공지 2:자유
--queryString Parameter는 무조건 String 자료형이라 int형 parse필요
int type = Integer.parseInt(req.getParameter("type"));
--nav 메뉴선택시 queryString에 cp가 없으면 1으로 고정
--cp( Current Page )현재 페이지 별다른 요청이 없으면 1으로 고정
int cp = 1;
--페이지네이션의 번호 선택 시
--쿼리스트링에 cp가 있음 --> cp = 쿼리스트링의 cp 값
if(req.getParameter("cp") !=null){
cp =Integer.parseInt(req.getParameter("cp"));}
BoardService service = new BoardService();
--매개값으로'현재게시판 번호','현재 페이지 수'를 전달한다.
--게시판 이름, 페이지네이션 객체, 게시글 리스트 3개를 한번에 반환하는 service 호출
Map<String, Object> map = service.selectBoardList(type,cp);
--request범위로 map을 세팅
req.setAttribute("map", map);
--요청위임할 주소저장하고 dispatcher로 요청전달
String path = "/WEB-INF/views/board/boardList.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(path);
dispatcher.forward(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
순차적으로 진행한다
String boardName = dao.selectBoardName(conn,type);
int listCount = dao.selectListCount(conn,type);
1번에서 board_type 테이블에서 게시판의 이름을 조회해 해당 게시판에 있는 모든 게시글의 수를 측정한다.
DAO 수행문도 게시판의 이름을 알아내는거랑 거의 동일하다
2-1에서 요청받은 게시판에 잇는 모든 게시글의 수를 확인했고
cp 매개변수에는 요청부터 전달된 현재 페이지의 값이 들어있다
이 두개의 정보를 가지고 페이징(한쪽한쪽분할 하는거)Pagination pagination = new Pagination(cp, listCount);
public class Pagination {
//페이징 처리 : 1쪽 2쪽 한 페이지를 나눈다는 의미
//페이지네이션 : 페이징 처리에 필요한 모든 값을 저장하고 있는 객체
private int currentPage; //현재 페이지 번호
private int listCount; //모든 게시글 수
private int limit = 10; //한 페이지에 보여질 게시글의 수
private int pageSize =10; // 목록 하단에 페이즈번호의 노출 개수.
private int maxPage; //제일 큰 페이지 번호 == 50페이지.
private int startPage; //목록 하단에 노출된 페이지의 시작번호
private int endPage; //목록 하단에 노출된 페이지의 끝번호
private int prevPage; //목록 하단된 노출된 번호의 이전 목록 끝 번호
private int nextPage; //목록 하단된 노출된 번호의 시작 목록 시작 번호
public Pagination(int currentPage,int listCount) {
this.currentPage = currentPage;
this.listCount = listCount;
calculatePagination(); //자동으로 계산하게 메서드 호출
}
객체가 생성될 때(new) 기본생성자가 생성되지 않고 매개변수생성자만 수행될 수 있다.
입력받은 현재 페이지와 모든게시글의 수를 전달받아
나머지 계산하는 함수를 호출해 필요한 데이터들을 계산해 대입한다.
// 페이징 처리에 필요한 값을 계산하는 메서드
private void calculatePagination() {
// * maxPage 계산 : 최대 페이지 수 == 마지막 페이지 번호
// 전체 게시글 수 : 500개 // 보여지는 게시글 수: 10개
// -> 마지막 페이지 번호는? 500 / 10 = 50
// 전체 게시글 수 : 501개 // 보여지는 게시글 수: 10개
// -> 마지막 페이지 번호는? 501 / 10 = 51 (50.1의 올림 처리)
maxPage = (int) Math.ceil((double) listCount / limit);
// * startPage : 목록 하단에 노출된 페이지의 시작 번호
// 목록 하단 페이지 번호의 노출 개수가 10개일 때
// 현재 페이지가 1~10 인 경우 : 1
// 현재 페이지가 11~20 인 경우 : 11
// 현재 페이지가 21~30 인 경우 : 21
startPage = (currentPage - 1) / pageSize * pageSize + 1;
// * endPage : 목록 하단에 노출된 페이지의 끝 번호
// 목록 하단 페이지 번호의 노출 개수가 10개일 때
// 현재 페이지가 1~10 인 경우 : 10
// 현재 페이지가 11~20 인 경우 : 20
// 현재 페이지가 21~30 인 경우 : 30
endPage = startPage + pageSize - 1;
// 만약에 endPage가 maxPage를 초과하는 경우
if (endPage > maxPage) {
endPage = maxPage;
}
// * prevPage(<) : 목록 하단에 노출된 번호의 이전 목록 끝 번호
// * nextPage(>) : 목록 하단에 노출된 번호의 다음 목록 시작 번호
// 현재 페이지가 1~10 일 경우
// < : 1 페이지
// > : 11 페이지
// 현재 페이지가 11~20 일 경우
// < : 10 페이지
// > : 21 페이지
// 현재 페이지가 41~50 일 경우 (maxPage가 50)
// < : 40 페이지
// > : 50 페이지
if (currentPage <= pageSize) {
prevPage = 1;
} else {
prevPage = startPage - 1;
}
if (endPage == maxPage) {
nextPage = maxPage;
} else {
nextPage = endPage + 1;
}
}
넘 헷갈렸다 ㅋㅋㅋ 실질적인 코드는 적은데 엄청 헷갈린다.
lombok를 사용하지 하지 않고 그냥 추가했는데 이유는
현재페이지,
모든게시글의수,
한페이지에 보여질 게시글의 수,
목록하단에 위치한 페이지번호의 노출 갯수
에 변화가 있을때 다시 계산할 필요성이 있어 위 4개의 값에 setter가 수행하면
calculatePagination()함수를 호출한다.
현재페이지를 기준으로해 해당 페이지의 게시글 목록을 가져온다
게시글은 여러개이다 보니 list형태로 가져와야한다.
이때 매개변수로 Connection + 생성한Pagination + typeList<Board> boardList = dao.selectBoardList(conn,pagination,type);
DAO 수행구문은 그냥 평범하지만 게시글 목록에 첫글과 마지막 글을 지정하는 구문이 필요하다 이게 좀 헷갈린다.
int start = (pagination.getCurrentPage()-1)*pagination.getLimit()+1; int end = start+pagination.getLimit()-1;
시작
- (현재페이지-1)*한페이지 보일 최대 게시글 수+1
ex) 1페이지 : 1-10 번 게시글들이 보여야함
(1-1)*10+1
0*10+1
[1페이지부터 시작하게 됨]0+1
끝
- 시작페이지+한페이지에 보일 최대 게시글-1;
1+10-1;
[10페이지까지 끝나게 됨]11 - 1;
이런 로직이 수행된다.
이렇게 수행되는 SQL문이 복잡하다
3개의 SELECT문으로 구성되어 있다.
1. 게시글번호+게시글제목+닉네임+작성일+조회수를 조회하는 SELECT
- 보통 게시글은 최신순부터 게시글을 정렬해서 100,99,98,97 이런형태로 정렬된다
- 이렇게 반대로 정렬된 SELECT에서 ROWNUM을 이용해 순서를 대입한다
- 게시글번호를 반대로 정렬되있어 범위 산정하기 힘들다.
- ROWNUM은 무조건 1부터 시작되어야해 BETWEEN을 사용하면 문제가 생겨 또 하나의 SELECT를 생성해 감싼 후 ROWNUM이 아닌 하나의 컬럼으로 인식시켜 문제를 해결한다.
1 SELECT * FROM( 2 SELECT ROWNUM AS RNUM, A.* FROM( 3 SELECT BOARD_NO,BOARD_TITLE,MEMBER_NICK, TO_CHAR(CREATE_DT,'YYYY-DD-MM') AS CREATE_DT, READ_COUNT FROM BOARD JOIN MEMBER USING(MEMBER_NO) WHERE BOARD_CD=? AND BOARD_ST='N' ORDER BY BOARD_NO DESC ) A ) WHERE RNUM BETWEEN ? AND ?
Map를 사용해 한번에 전달할 수 있다.
Map<String, Object> map = new HashMap<String, Object>();
map.put("boardName", boardName);
map.put("pagination", pagination);
map.put("boardList", boardList);
map 객체를 생성해 K:String(문자열) , V:Object(모든자료형)으로 타입 지정한다.
map에는 put으로 값을 추가한다( tmi:ArrayList는 .add)
그 다음 Servlet에서 jsp로 forward한다.
//게시판 이름, 페이지네이션 객체, 게시글 리스트 3개를 한번에 반환하는 service 호출
Map<String, Object> map = service.selectBoardList(type,cp);
//request범위로 map을 세팅
req.setAttribute("map", map);
String path = "/WEB-INF/views/board/boardList.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(path);
dispatcher.forward(req, resp);