{Java}

21.06.28{코딩일기} 동빈나 유튜버 JSP게시판 만들기 / 숫자페이징 번외편 | 전자정부프레임워크 eclipse 게시판 만들기{day8}

Davey 2021. 6. 29. 04:41
728x90

게시판 코드작성완료 후기 생생하게 공유드립니다. 많이 놀러와주세여:)

https://www.youtube.com/watch?v=P5s5JwvZjBA&t=27s&pp=sAQA 

'다음' '이전' 버튼 이외에 넘버링으로 페이징 처리하는 방법은 어떻게 하는걸까?
아래처럼 하나씩 문제를 정의했다.

pagingCalculationNote.pdf
0.35MB

우선 무엇을 변수로 가져오고 값을 리턴할지 배분하는게 어려웠다. 그래서 Mr.delbert님과 Jiho님의 도움으로
쿼리문을 아래와 같이 짜고, 변수를 아래와 같은 명하고 변수값을 어떻게 구할지 식을 계산했다.

 

# 입력값

pageNumber totalCount pageSize listSize
총 페이지 값(매개변수) 총게시글수(매개변수) 10(고정값|노출되는 페이지수) 10(고정값| 한페이지당 노출되는 게시글수)

# 출력값

변수명 해를 구하는 식
underBar (TotalCount / listSize ) + 1
현재 Page 게시글 start index (pageNumber - 1)*10+1
현재 Page 게시글 last index (pageNumber) * (listSize)

사실 위 표를 보는것보다 더 중요한게 스스로 아래와 같은 질문을 던지는게 코드를 짜는 사고력을 키우는데 유익하다. 그리고 mysql의 LIMIT와 OFFSET구문이 start인덱스와 last인덱스를 자동으로 db에서 추출해줘서
따로 스크립트단에서 값을 계산할 필요가 없다.
전체 페이징 숫자는 어떻게 구할까? -> (총게시글수) / (한페이지당 노출되는 게시글수)로 나누면돼
그럼만약 총게시글수는 31개일때 한페이지당 노출되는 게시글 수가 10개라면..  페이지수가 3이 아니라 4가되어야 하지 않나?

만약 (총게시글수) / (한페이지당 노출되는 게시글수) = a 라고 가정하면, a < pageNumber(총페이지값)이면, last index값은 pageNumber값을 리턴해야 된다. 

 

위 내용이 어렵다면? 아래 그림들을 참고하자:)
Dbeaver를 활용해 한페이지당 출력되는 값을 Descending(큰숫자->작은숫자로 정렬)방법으로 
시작인덱스에 맞춰 10개씩 출력되도록 쿼리를 실행시켜보았다.
Desending 및 mariaDB query limit와 개념내용 아래링크 참고바란다.
Assending은 반대개념인데, 작은숫자-> 큰숫자로 정렬하는 방법임. ex> 1, 2, 3, ...

https://jojoldu.tistory.com/528

 

1. 페이징 성능 개선하기 - No Offset 사용하기

일반적인 웹 서비스에서 페이징은 아주 흔하게 사용되는 기능입니다. 그래서 웹 백엔드 개발자분들은 기본적인 구현 방법을 다들 필수로 익히시는데요. 다만, 그렇게 기초적인 페이징 구현 방

jojoldu.tistory.com


https://postitforhooney.tistory.com/entry/20160814%EA%B2%8C%EC%8B%9C%ED%8C%90-%ED%8E%98%EC%9D%B4%EC%A7%95-%EC%99%84%EC%84%B1

 

[DB/MARIADB] 게시판 페이징 완성 Using Limit

많은 어려움 끝에 페이징 완성!! 학원에서 배운 것은 번호보다 다음 이전으로만 이동하는 것이었다. 생각보다 마음에 들지 않아, 번호와 함게 이동할 수 있는 것을 만들기 위해 노력한 결과, 페

postitforhooney.tistory.com


LIMIT은 앞서 위 표에 있는 listSize값의 개념과 상동하며 OFFSET은 시작인덱스를의미 (인덱스는 아래 엑셀파일 참조)


{ORDER BY listDate desc: 게시일기준으로 큰숫자부터 정렬해},{보여줄리스트 항목은 10개야 : LIMIT 10}, { 인덱스는 0번째부터시작하자 : OFFSET} 


0번째가 무엇을의미하나?
예를들면 총게시글이 108개인 경우
Desending방식으로 offset이 0이고, listSize가 10인 조건의
쿼리문을 실행시키면
아래 노란박스 부분만 출력됨을 알 수 있다.

 제일 마지막 게시글항목번호(가장큰숫자)부터 10번째까지 차례대로 출력예시

그럼 만약 offset이 10부터라면? 무슨의미인가?
위에 엑셀그림처럼 98번째 게시글부터 89번째 게시글인덱스, 즉 11번째 인덱스부터 +10(=listSize)를 더한 20번째 인덱스까지 포함해서 리턴한다고 보면된다.
offset 10 인 쿼리문의 결과는?
현재 nvrg db에는 총27개의 게시글이 저장되어 있으므로 (27-10=17)번째 인덱스부터 쿼리실행결과값이 도출됨
결국, 유저가 게시물을 지속적으로 등록하기 때문에 총 게시글이 고정변수가 아니다.
시작인덱스값과 마지막인덱스값은 계속 변할 수 있다는 점 때문에 offset값으로 쿼리를 짜게됨을 깨달아야한다.

# list.jsp code 수정

<div class="pager">태그아래 아래와 같이 코드를 추가해주었다.
해당 코드는 위 내용을 포괄하여 paging처리를 해주는 조건문 및 변수들이다.
태그내에서 새롭게 선언한 변수들인 initSize와 underBar 변수는 앞서 본게시글 상단 입력출력값 해설표 참고바란다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="java.io.PrintWriter"%>
<%@ page import="list.ListDAO"%>
<%@ page import="list.Board"%>
<%@ page import="java.util.ArrayList"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width" , initial-scale="1">
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

<title>BluevulpeBoard</title>
</head>
<body style="background-color: lightblue;">
	<%
		String userID = null;
	if (session.getAttribute("userID") != null) {
		userID = (String) session.getAttribute("userID");
	}
	int pageNumber = 1;
	if (request.getParameter("pageNumber") != null && request.getParameter("pageNumber") != "") {
		pageNumber = Integer.parseInt(request.getParameter("pageNumber"));
	} else {
		pageNumber = 1;
	}
	%>

	<nav class="navbar navbar-default">
		<!-- navbar-색상(inverse = 검은색, default = 색x) -->
		<div class="navbar-header">
			<button type="button" class="navbar-toggle collapsed"
				data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
				aria-expanded="false">
				<!-- class="navbar-toggle collapsed"=>네비게이션의 화면 출력유무 
				data-toggle="collapse" : 모바일 상태에서 클릭하면서 메뉴가 나오게 설정 -->

				<span class="icon-bar"></span> <span class="icon-bar"></span> <span
					class="icon-bar"></span>
				<!-- 아이콘 이미지 -->

			</button>

			<a class="navbar-brand" href="main.jsp">BluevulpeBoard</a>
			<!-- Bootstrap navbar 기본 메뉴바 -->
		</div>

		<div class="collapse navbar-collapse"
			id="bs-example-navbar-collapse-1">
			<ul class="nav navbar-nav">
				<!-- navbar-nav => 네비게이션 바의 메뉴 -->
				<li><a href="main.jsp">메인</a></li>
				<li class="active"><a href="list.jsp">게시판</a></li>
				<!-- 메뉴, 게시판의 main.jsp와 bbs.jsp의 파일로 각각 이동 -->
			</ul>
			<%
				if (userID == null) {
			%>
			<ul class="nav navbar-nav navbar-right">
				<li class="dropdown"><a href="#" class="dropdown-toggle"
					data-toggle="dropdown" role="button" aria-haspopup="true"
					aria-expanded="false">회원관리<span class="caret"></span></a> <!-- 임시의 주소링크 "#"을 기재한다. -->
					<!-- caret = creates a caret arrow icon (▼) -->
					<ul class="dropdown-menu">
						<!-- dropdown-menu : 버튼을 눌렀을때, 생성되는 메뉴(접속하기를 눌렀을때 로그인, 회원가입 메뉴 -->
						<li><a href="login.jsp">로그인</a></li>
						<!-- active = 활성화 되었을때 로그인, 회원가입-->
						<li><a href="join.jsp">회원가입</a></li>
					</ul></li>
			</ul>
			<%
				} else {
			%>
			<ul class="nav navbar-nav navbar-right">
				<li class="dropdown"><a href="#" class="dropdown-toggle"
					data-toggle="dropdown" role="button" aria-haspopup="true"
					aria-expanded="false">회원관리<span class="caret"></span></a> <!-- 임시의 주소링크 "#"을 기재한다. -->
					<!-- caret = creates a caret arrow icon (▼) -->
					<ul class="dropdown-menu">
						<!-- dropdown-menu : 버튼을 눌렀을때, 생성되는 메뉴(접속하기를 눌렀을때 로그인, 회원가입 메뉴 -->
						<li><a href="logout.jsp">로그아웃</a></li>
					</ul></li>
			</ul>
			<%
				}
			%>
		</div>
	</nav>
	<div class="container">
		<div class="row">
			<table class="table table-striped"
				style="text-align: center; border: 1px solid #dddddd">
				<thead>
					<tr>
						<th style="background-color: #eeeeee; text-align: center;">번호</th>
						<th style="background-color: #eeeeee; text-align: center;">제목</th>
						<th style="background-color: #eeeeee; text-align: center;">작성자</th>
						<th style="background-color: #eeeeee; text-align: center;">작성일</th>
					</tr>
				</thead>
				<tbody>
					<%
						ListDAO listDAO = new ListDAO();
					ArrayList<Board> list = listDAO.getList(pageNumber);
					
					int totalCount = listDAO.getCount();
					for (int i = 0; i < list.size(); i++) {
					%>
					<tr>
						<td><%=list.get(i).getListID()%></td>
						<td><a href="view.jsp?listID=<%=list.get(i).getListID()%>"><%=list.get(i).getListTitle()%></a></td>
						<td><%=list.get(i).getUserID()%></td>
						<td><%=list.get(i).getListDate().substring(0, 11) + list.get(i).getListDate().substring(11, 13) + "시"
		+ list.get(i).getListDate().substring(14, 16) + "분"%></td>
					</tr>
					<%
						}
					%>
				</tbody>
			</table>
			
			<a href="list.jsp?pageNumber=<%=pageNumber - 1%>"
				class="btn btn-success btn-arrow-Left">이전</a>
			<div class="pager">
			<% 
				int listSize = 10;
				int underBar = (totalCount / listSize) + 1;
				for(int i = 1; i <= underBar; i++){
					if(pageNumber == i){
						out.println("<strong style='color: red;'>"+i+"</strong>");
					}else {
						out.println("<a href='/test/list.jsp?pageNumber="+i+"'>"+i+"</a>");	
					}
				}
			%>
				</div>
			<%
				
			if (listDAO.nextPage(pageNumber + 1)) {
			%>
			<a href="list.jsp?pageNumber=<%=pageNumber + 1%>"
				class="btn btn-success btn-arrow-Left">다음</a>
			<%
				}
			%>
			<a href="write.jsp" class="btn btn-primary pull-right">글쓰기</a>
		</div>
	</div>
</body>
</html>

 

참고로 pageNumber나 totalCount는 이전에 짜놓은 ListDAO.java 클래스의 getCount()메소드나
ArrayList<Board> getList(int pageNumber) 메소드의 인자값에서 가져오는 변수값들이다.

# ListDAO.java 클래스의 getList() 메소드 code 수정

getNext()함수가 적용되지 않아, 특정 게시글을 삭제하면 해당 id의 listAvailable값은 0이되지만
list.jsp에선 그대로 게시글이 노출되는 예외가 발생했다.
예외처리를 위해 아래와 같이 쿼리를 수정해주었다.
where절은 반드시 ORDER BY 또는 AND절 앞에 위치해야 한다. 안그러면 쿼리Syntax 에러가 뜬다.


	public ArrayList<Board> getList(int pageNumber) {
		String SQL = "SELECT * FROM LIST WHERE listAvailable = 1 ORDER BY listDate desc limit 10 offset ?";
		ArrayList<Board> list = new ArrayList<Board>();
		int offset = 0;
		if (pageNumber > 1 )
		{
			offset = 10 * pageNumber - 10;
		}
		
		try {
			PreparedStatement pstmt = conn.prepareStatement(SQL);
			pstmt.setInt(1,  offset);
			rs =pstmt.executeQuery();
			while ( rs.next()) {
				Board text = new Board();
				text.setListID(rs.getInt(1));
				text.setListTitle(rs.getString(2));
				text.setUserID(rs.getString(3));
				text.setListDate(rs.getString(4));
				text.setListContent(rs.getString(5));
				text.setListAvailable(rs.getInt(6));
				list.add(text);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list; //데이터베이스 오류		
	}

위코드를 ListDAO.jsp 파일에 추가수정해주면 아래와 같이 페이징 처리도 잘되고, 
'Hi bluevulpe!'라는 지겨운ㅠㅠ ㅋㅋㅋㅋ 크로스 스크립트 알림창도 안뜨는 게시판 기능구현 성공~

list 첫번째 페이지 화면 예시


list 두번째 페이지 화면출력 예시


list 3번째 페이지 화면출력 예시


위 사진들 속 해당페이지 숫자들에 하이라이트마냥 빨간색표시가 되어있는것을 인지했는가?

# 페이징 숫자 하이라이트


<div class="pager">
	<% 
		int listSize = 10;
		int underBar = (totalCount / listSize) + 1;
		for(int i = 1; i <= underBar; i++){
			if(pageNumber == i){
				out.println("<strong style='color: red;'>"+i+"</strong>");
			}else {
				out.println("<a href='/test/list.jsp?pageNumber="+i+"'>"+i+"</a>");	
			}
		}
	%>
</div>

현재 페이지 넘버가 i와 일치할때란? 결국 사용자가 선택한 페이지라고 이해하면 된다.
선택된 페이지는 하이퍼링크 처리는 안되며, 대신 red 로 하이라이트 색상처리를 해준다는 의미의 코드다.

빠른시일내로 '다음'과 '이전'버튼이 pageSize를 초과할때만 노출되고 구현되게끔 코드를 짜서 업데이트 하겠다.
여기까지 따라와주신 분들게 진심으로 감사드립니다:)

Copyright ⓒ 2021 by bluevulpe All Contents cannot be copied without permission.

728x90