페이징 처리를 정리해본다
게시판 만드는데에서 난이도가 있는 기능이라고 생각한다.
페이징 처리를 어떤원리로 처리하고 데이터를 어떻게 화면에 보여주는지 중요하다고 생각한다
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<h2>hello spring framework</h2>
<a href="/board/save">글작성</a>
<a href="/board/">글목록</a>
<a href="/board/paging">페이징 목록</a>
</body>
</html>
페이징 처리를 위한 요청 주소를 추가 한다.
// /board/paging?page=2
// 처음 페이지 요청은 1페이지를 보여줌
@GetMapping("/paging")
public String paging(Model model,
@RequestParam(value = "page", required = false, defaultValue = "1") int page) {
System.out.println("page = " + page);
// 해당 페이지에서 보여줄 글 목록
List<BoardDTO> pagingList = boardService.pagingList(page);
System.out.println("pagingList = " + pagingList);
PageDTO pageDTO = boardService.pagingParam(page);
model.addAttribute("boardList", pagingList);
model.addAttribute("paging", pageDTO);
return "paging";
}
페이징 처리는 데이터를 가지고 화면에 출력하는 내용이니까 Model 객체가 필요하다
사용자가 어떤 페이지를 클릭하냐에 따라 화면에 보여줄 데이터는 바뀌게 된다.
/board/paging?page=2 페이지 값을 보내도록 할것이다. 페이징 처리를 해서 어떤 페이지를 보여줄것인지
@RequestParam(value = "page", required = false, defaultValue = "1") int page)
value 파라미터 이름 표시
required 는 page 파라미터가 없어도 필수가 아니기 때문에 에러가 발생하지 않는다
defaultValue 는 없으면 기본값으로 1 설정
목록이 필요하므로 DTO 가 담긴 List 필요 .
페이징 처리를 하기 위해 게시글들을 추가해 준다
mySQL은 간단한 쿼리를 사용하는데
1page : 12 , 11 , 10
2page : 9 , 8 , 7
3page : 6 , 5 , 4
사용자가 요청하는 페이지에 따라 앞자리 숫자가 바뀌게 된다.
오라클에서는 서브쿼리를 사용해서 구현하고 , mySQL 은 리밋을 사용했다
BoardService
public List<BoardDTO> pagingList(int page) {
/*
1페이지당 보여지는 글 갯수 3
1page => 0
2page => 3
3page => 6
*/
int pagingStart = (page - 1) * pageLimit;
Map<String, Integer> pagingParams = new HashMap<>();
pagingParams.put("start", pagingStart);
pagingParams.put("limit", pageLimit);
List<BoardDTO> pagingList = boardRepository.pagingList(pagingParams);
return pagingList;
}
BoardService
int pageLimit = 3; // 한 페이지당 보여줄 글 갯수
int blockLimit = 3; // 하단에 보여줄 페이지 번호 갯수
public List<BoardDTO> pagingList(int page) {
/*
1페이지당 보여지는 글 갯수 3
1page => 0
2page => 3
3page => 6
*/
int pagingStart = (page - 1) * pageLimit;
Map<String, Integer> pagingParams = new HashMap<>();
pagingParams.put("start", pagingStart);
pagingParams.put("limit", pageLimit);
List<BoardDTO> pagingList = boardRepository.pagingList(pagingParams);
return pagingList;
}
page - 몇페이지가 요청했냐에 따라 간단하게 식을 사용
limit - 한 페이지당 몇개씩 보여줄것인지 변수
숫자 2개를 전달하기 위해 Map를 선언해서 pagingStart 와 limit 를 전달 한다
BoardRepository
public List<BoardDTO> pagingList(Map<String, Integer> pagingParams) {
return sql.selectList("Board.pagingList", pagingParams);
}
BoardMapper
<select id="pagingList" parameterType="java.util.HashMap" resultType="board">
select * from board_table order by id desc limit #{start}, #{limit}
</select>
Map으로 넘어온 키값 start 와 limit 매칭 시켜 준다
PageDTO
package com.codingrecipe.board.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class PageDTO {
private int page; // 현재 페이지
private int maxPage; // 전체 필요한 페이지 갯수
private int startPage; // 현재 페이지 기준 시작 페이지 값
private int endPage; // 현재 페이지 기준 마지막 페이지 값
}
BoardController
// /board/paging?page=2
// 처음 페이지 요청은 1페이지를 보여줌
@GetMapping("/paging")
public String paging(Model model,
@RequestParam(value = "page", required = false, defaultValue = "1") int page) {
System.out.println("page = " + page);
// 해당 페이지에서 보여줄 글 목록
List<BoardDTO> pagingList = boardService.pagingList(page);
System.out.println("pagingList = " + pagingList);
PageDTO pageDTO = boardService.pagingParam(page);
model.addAttribute("boardList", pagingList);
model.addAttribute("paging", pageDTO);
return "paging";
}
목록과 계산된값을 모델에 담아서 paging 으로 리턴
BoardService
int pageLimit = 3; // 한 페이지당 보여줄 글 갯수
int blockLimit = 3; // 하단에 보여줄 페이지 번호 갯수
public PageDTO pagingParam(int page) {
// 전체 글 갯수 조회
int boardCount = boardRepository.boardCount();
// 전체 페이지 갯수 계산(10/3=3.33333 => 4)
int maxPage = (int) (Math.ceil((double) boardCount / pageLimit));
// 시작 페이지 값 계산(1, 4, 7, 10, ~~~~)
int startPage = (((int)(Math.ceil((double) page / blockLimit))) - 1) * blockLimit + 1;
// 끝 페이지 값 계산(3, 6, 9, 12, ~~~~)
int endPage = startPage + blockLimit - 1;
if (endPage > maxPage) {
endPage = maxPage;
}
PageDTO pageDTO = new PageDTO();
pageDTO.setPage(page);
pageDTO.setMaxPage(maxPage);
pageDTO.setStartPage(startPage);
pageDTO.setEndPage(endPage);
return pageDTO;
}
pageLimit - 한 페이지에 보여줄 갯수
blockLimit - 하단에 숫자가 몇개씩 보여줄 것인가
pageDTO 에 담아서 화면에 표현하기 위해 담아준다
BoardRepository
public int boardCount() {
return sql.selectOne("Board.boardCount");
}
BoardMapper.xml
<select id="boardCount" resultType="Integer">
select count(id) from board_table
</select>
paging.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>paging</title>
</head>
<body>
<div>
<table>
<tr>
<th>id</th>
<th>title</th>
<th>writer</th>
<th>date</th>
<th>hits</th>
</tr>
<c:forEach items="${boardList}" var="board">
<tr>
<td>${board.id}</td>
<td>
<a href="/board?id=${board.id}&page=${paging.page}">${board.boardTitle}</a>
</td>
<td>${board.boardWriter}</td>
<td>${board.boardCreatedTime}</td>
<td>${board.boardHits}</td>
</tr>
</c:forEach>
</table>
</div>
<div>
<c:choose>
<%-- 현재 페이지가 1페이지면 이전 글자만 보여줌 --%>
<c:when test="${paging.page<=1}">
<span>[이전]</span>
</c:when>
<%-- 1페이지가 아닌 경우에는 [이전]을 클릭하면 현재 페이지보다 1 작은 페이지 요청 --%>
<c:otherwise>
<a href="/board/paging?page=${paging.page-1}">[이전]</a>
</c:otherwise>
</c:choose>
<%-- for(int i=startPage; i<=endPage; i++) --%>
<c:forEach begin="${paging.startPage}" end="${paging.endPage}" var="i" step="1">
<c:choose>
<%-- 요청한 페이지에 있는 경우 현재 페이지 번호는 텍스트만 보이게 --%>
<c:when test="${i eq paging.page}">
<span>${i}</span>
</c:when>
<c:otherwise>
<a href="/board/paging?page=${i}">${i}</a>
</c:otherwise>
</c:choose>
</c:forEach>
<c:choose>
<c:when test="${paging.page>=paging.maxPage}">
<span>[다음]</span>
</c:when>
<c:otherwise>
<a href="/board/paging?page=${paging.page+1}">[다음]</a>
</c:otherwise>
</c:choose>
</div>
</body>
</html>
게시글 상세 조회 시 id 값만 넘겼는데 이제는 상세조회 시 페이지 값도 같이 넘긴다
div 로 묶어둔 부분이 이전 숫자 다음을 표현하는 부분
3페이지를 클릭시 이전이라는 부분이 보여진다
jstl 태그를 이용하여 if - else 로 표현
현재 페이지가 1보다 작거나 같으면 링크 없는 이전 표시
만약 1페이지가 아닌 경우 otherwise 부분이 보여지며 이전은 링크가 달리게 되고
현재 페이지보다 하나 작은 페이지로 controller 로 요청하는 링크가 생긴다
다음은 반대되는 역할 비교 대상은 현재 페이지가 maxpage 끝페이지 인 경우 다음은 텍스트만 나오게 한다
그게 아닌 경우 링크가 붙으며 현재페이지 보다 1 큰 페이지를 요청한다
@GetMapping
public String findById(@RequestParam("id") Long id,
@RequestParam(value = "page", required = false, defaultValue = "1") int page,
Model model) {
boardService.updateHits(id);
BoardDTO boardDTO = boardService.findById(id);
model.addAttribute("board", boardDTO);
model.addAttribute("page", page);
}
page 파라미터가 없으면 오류가 발생하기때문에 필수가 아닌정보로 오류가 안나도록 한다.
모델에다가 페이지 값을 같이 가져간다.
@PostMapping("/save")
public String save(@ModelAttribute BoardDTO boardDTO) {
int saveResult = boardService.save(boardDTO);
if (saveResult > 0) {
return "redirect:/board/paging";
} else {
return "save";
}
}
글작성 했을때도 기존 목록으로 갔는데 페이징 목록으로 가게 한다
detail.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>detail.jsp</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
</head>
<body>
<table>
<tr>
<th>id</th>
<td>${board.id}</td>
</tr>
<tr>
<th>writer</th>
<td>${board.boardWriter}</td>
</tr>
<tr>
<th>date</th>
<td>${board.boardCreatedTime}</td>
</tr>
<tr>
<th>hits</th>
<td>${board.boardHits}</td>
</tr>
<tr>
<th>title</th>
<td>${board.boardTitle}</td>
</tr>
<tr>
<th>contents</th>
<td>${board.boardContents}</td>
</tr>
</table>
<button onclick="listFn()">목록</button>
<button onclick="updateFn()">수정</button>
<button onclick="deleteFn()">삭제</button>
<div>
<input type="text" id="commentWriter" placeholder="작성자">
<input type="text" id="commentContents" placeholder="내용">
<button id="comment-write-btn" onclick="commentWrite()">댓글작성</button>
</div>
<div id="comment-list">
<table>
<tr>
<th>댓글번호</th>
<th>작성자</th>
<th>내용</th>
<th>작성시간</th>
</tr>
<c:forEach items="${commentList}" var="comment">
<tr>
<td>${comment.id}</td>
<td>${comment.commentWriter}</td>
<td>${comment.commentContents}</td>
<td>${comment.commentCreatedTime}</td>
</tr>
</c:forEach>
</table>
</div>
</body>
<script>
const listFn = () => {
const page = '${page}';
location.href = "/board/paging?page=" + page;
}
const updateFn = () => {
const id = '${board.id}';
location.href = "/board/update?id=" + id;
}
const deleteFn = () => {
const id = '${board.id}';
location.href = "/board/delete?id=" + id;
}
}
</script>
</html>
detail.jsp 에서 목록 버튼을 누르면 그 이전에 사용자가 있었던 페이지로 다시 요청을 해줘야 한다
페이지 요청을 해서 몇페인지인지 줘야한다.
const listFn = () => {
const page = '${page}';
location.href = "/board/paging?page=" + page;
}
'BACKEND > 스프링 Spring' 카테고리의 다른 글
인텔리제이 Port 8080 was already in use 해결 (0) | 2024.01.09 |
---|---|
spring 게시판 인텔리제이로 Ajax 댓글 기능 구현 (1) | 2024.01.04 |
spring 게시판 인텔리제이로 게시판 글조회, 조회수 , 글삭제 , 글수정 (2) | 2024.01.04 |
인텔리제이 smart Tomcat 설치 (0) | 2024.01.03 |
Spring Framework 회원 프로젝트 (1) | 2024.01.03 |