Spring
[Spring] Day11 (Code): 페이징 처리
jnk1m
2022. 3. 31. 00:58
1. Criteria.java
package com.board.domain;
import org.springframework.web.util.UriComponentsBuilder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Criteria { //페이징 처리시 부수적으로 필요한 정보들 담아줄 객체
private int pageNum; //페이지 번호
private int listQty; //한 페이지에 보여줄 개시물 개수
public Criteria() {
this(1,10); //1 페이지 보여주게끔
}
public Criteria (int pageNum, int listQty) {
this.pageNum = pageNum;
this.listQty = listQty;
}
// 파라미터 완성해서 돌려주는 메서드
public String getParameterLink() {
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("")
.queryParam("pageNum",this.pageNum)
.queryParam("listQty", this.listQty);
System.out.println("uri String: " + builder.toUriString());
return builder.toUriString();
}
}
2. PageDTO
package com.board.domain;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
public class PageDTO { //전체 페이지 관리
private int startPage;
private int endPage;
private boolean prev, next;
private int total; //전체 글 개수
private Criteria cri; //페이지 번호, 페이지 당 보여줄 글의 개수
public PageDTO(Criteria cri, int total) { //좀 더 포괄적인 페이징 처리?..
this.cri = cri;
this.total = total;
this.endPage = (int)(Math.ceil(cri.getPageNum()/10.0)) * 10; //10
this.startPage = this.endPage - 9; //-9
int lastPage= (int)(Math.ceil((total*1.0)/cri.getListQty())); //한페이지에 10개씩 보여줄거야
if(lastPage < this.endPage) {
this.endPage = lastPage;
}
this.prev=this.startPage > 1;
this.next=this.endPage < lastPage;
}
}
3. 글 목록 페이징 추가 버전
//글 목록 (페이징 처리 추가)
@GetMapping("list") //list 요청 시 pageNum, listQty가 들어와야 함.
public void list(Criteria cri, Model model) {
//페이징처리 버전
//현재 페이지 번호에 따른, 보여줄 글 목록을 가져와 view에 전달
model.addAttribute("list", boardService.getList(cri));
//전체 글의 개수 가져오고
int total = boardService.getTotal();
//화면에 띄워줄 페이지 번호 등 계산 완료된 pageDTO 객체도 view 전달
model.addAttribute("pageMaker", new PageDTO(cri, total));
//http://localhost:8080/board/list?pageNum=1&listQty=3# 이런식으로 브라우저 입력
}
controller
현재 페이지 번호에 따른, 보여줄 글 목록을 가져와 view에 전달 getList
//전체글 페이징 처리해서 가져오기
public List<BoardVO> getList(Criteria cri);
--------------------------------------------
//이 밑은 serviceImpl
@Override
public List<BoardVO> getList(Criteria cri) {
System.out.println(cri);
return boardMapper.getListWithPaging(cri);
}
service
//페이징 처리해서 전체 글 가져오기 mapper.java
public List<BoardVO> getListWithPaging(Criteria cri);
-----------------------------------------------------
<select id="getListWithPaging" resultType="boardVO">
<![CDATA[
select bno, title, content, writer, regdate, updatedate from
(select rownum r, bno, title, content, writer, regdate, updatedate from
(select /*+ INDEX_DESC(board pk_board)*/
bno, title, content, writer, regdate, updatedate
from board)
where rownum <= #{pageNum} * #{listQty} )
where r > (#{pageNum} - 1) * #{listQty}
]]>
</select>
mapper
전체 글의 개수 가져오는 getTotal
//전체 글의 개수 가져오기
public int getTotal();
-------------------------
//serviceImpl
@Override
public int getTotal() {
return boardMapper.getTotalCount();
}
controller
//전체 글의 개수 가져오기
public int getTotalCount();
----------------------------------
//mapper.xml
<!-- 전체 글의 개수 가져오기 -->
<select id="getTotalCount" resultType="int">
select count(*) from board
</select>
mapper
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>list</title>
<link href="/resources/css/style.css" rel="stylesheet" type="text/css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<br/>
<h1 align="center">게시판</h1>
<table>
<tr>
<td colspan="5" align="left">
<button onclick="window.location='/board/write'">글 작성</button>
</td>
<tr> <!-- 위에 카테고리 안내 -->
<td>No.</td>
<td>제목</td>
<td>작성자</td>
<td>작성일</td>
<td>수정일</td>
</tr>
<!-- board: BoardVO 객체 담기는 변수
items: 컨트롤러로부터 전달 받은 List<BoardVO> 리스트
list의 요소 개수만큼 자동으로 반복하며, 하나씩 꺼내서 board 변수에 채워줌
-->
<c:forEach var="board" items="${list}">
<tr> <!-- 글 리스트로 출력 -->
<td>${board.bno}</td>
<td align="left"><a class="move" href="${board.bno}">${board.title}</a></td>
<td>${board.writer}</td>
<td><fmt:formatDate value="${board.regdate}" pattern="yy-MM-dd HH:mm"/></td>
<td><fmt:formatDate value="${board.updateDate}" pattern="yy-MM-dd HH:mm"/></td>
</tr>
</c:forEach>
</table>
<br/><br/>
<div align="center">
<%-- previous --%>
<c:if test="${pageMaker.prev}">
<a class="paging_btn" href="${pageMaker.startPage-1}" style="color: #77878F">< </a>
</c:if>
<%-- 페이지번호 --%>
<c:forEach var="num" begin="${pageMaker.startPage}" end="${pageMaker.endPage}" >
<a class="paging_btn" href="${num}" style="color: #77878F"> ${num} </a>
</c:forEach>
<%-- next --%>
<c:if test="${pageMaker.next}">
<a class="paging_btn" href="${pageMaker.endPage+1}" style="color: #77878F"> ></a>
</c:if>
</div>
<%--페이지 번호 누를 때 전송해줄 숨김 폼 태그 --%>
<form action="/board/list" method="get" id="pagingForm">
<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}"/>
<input type="hidden" name="listQty" value="${pageMaker.cri.listQty}"/>
</form>
<br/><br/><br/><br/>
<script>
$(document).ready(function(){
//글 작성후 list로 리다이렉트 되었을 때 alert 띄워주기
let result="${result}";
checkResult(result); // alert 띄울지 말지 함수 호출
//글 작성 처리 post -> 리스트로 이동 -> content로 갔다가 브라우저 뒤로하면 alert가 또 뜨기 때문에 수정해줌.
// 히스토리 삭제
history.replaceState({},null,null);
function checkResult(result){
//result 값이 없거나 historu 기록이 없으면 그냥 함수 종료
if(result=="" ||history.state){
return;
}
//result 넘어와서 글 고유번호가 0보다 크면, alert 띄워라
if(result == "success"){ // ==값이 같은 것, ===타입까지 같은 것
alert("요청 처리가 잘 처리되었습니다.")
}else if(parseInt(result)>0){
alert(result +"번 글이 등록 되었습니다.");
}
}//checkResult
//숨김 폼태그 가져오기
let pagingForm = $("#pagingForm");
$(".paging_btn").click(function(e){ //e가 a태그 객체를 가리키게 됨.
e.preventDefault(); //a 태그의 기본 기능 없애기
console.log("a 클릭!" + e);
//폼태그에서 name 속성이 pageNum인 input 태그를 찾아 input tag의 값을 클릭한 a 태그의 href 속성 값으로 변경
//<input value=a의 href값
pagingForm.find("input[name='pageNum']").val($(this).attr("href"));
pagingForm.submit(); //submit 버튼 누른 것과 동일한 효과.
}); //paging_btn click
//게시글 제목 클릭 시, content 페이지로 이동 처리
$(".move").click(function(e){
e.preventDefault();
//숨김 폼 태그에 bno input hidden으로 태그 추가
pagingForm.append("<input type='hidden' name='bno' value='"+ $(this).attr("href") + "' />");
//폼의 action 속성 값 (이동할 주소) content로 변경
pagingForm.attr("action", "/board/content")
pagingForm.submit(); //서브밋! 이동!
})
}); //ready
</script>
</body>
</html>
list.jsp
4. content, modify, delete
//조회 폼
@GetMapping({"content","modify","delete"})
public void content(@RequestParam("bno") Long bno,@ModelAttribute("cri") Criteria cri , Model model) {
model.addAttribute("board",boardService.get(bno));
}
//조회 처리
@PostMapping("modify")
public String modify(BoardVO board, Criteria cri,RedirectAttributes rttr) {
boolean res =boardService.modify(board);
if(res) {
rttr.addFlashAttribute("result","success");
System.out.println("수정 완료");
}
else System.out.println("수정 불가");
return "redirect:/board/list" + cri.getParameterLink();
}
@PostMapping("delete")
public String delete(@RequestParam("bno") Long bno,Criteria cri, RedirectAttributes rttr) {
if(boardService.remove(bno)){
rttr.addFlashAttribute("result","success");
}
return "redirect:/board/list"+ cri.getParameterLink();
}
controller
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Content</title>
<link href="/resources/css/style.css" rel="stylesheet" type="text/css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<br/>
<h1 align="center">Content</h1>
<table>
<tr>
<td>글 번호</td>
<td>${board.bno}</td>
</tr>
<tr>
<td>제목</td>
<td>${board.title}</td>
</tr>
<tr>
<td>작성자</td>
<td>${board.writer}</td>
</tr>
<tr>
<td>내용</td>
<td><textarea rows="10" cols="30" disabled>${board.content}</textarea></td>
</tr>
<tr>
<td>작성일</td>
<td><fmt:formatDate value="${board.regdate}" pattern="yyyy-MM-dd HH:mm"/></td>
</tr>
<tr>
<td>수정일</td>
<td><fmt:formatDate value="${board.updateDate}" pattern="yyyy-MM-dd HH:mm"/></td>
</tr>
<tr>
<td colspan="2">
<button class="btn" data-oper="modify" >수정</button> <!-- 하이픈 뒤에 이름은 우리가 변수 만들 듯이 지어주면 됨. 여기선 oper -->
<button class="btn" data-oper="delete">삭제</button>
<button class="btn" data-oper="list">리스트</button>
</td>
</tr>
</table>
<form action="/board/modify" method="get" >
<input type="hidden" name="bno" value="${board.bno}"/>
<input type="hidden" name="pageNum" value="${cri.pageNum}"/>
<input type="hidden" name="listQty" value="${cri.listQty}"/>
</form>
<script>
$(document).ready(function(){
//숨김 폼태그 가져오기
let formObj = $("form");
$("button.btn").click(function(e){
e.preventDefault();
let operation = $(this).data("oper");
if(operation === 'delete'){
formObj.attr("action", "/board/delete")
}else if(operation === 'list'){
formObj.attr("action","/board/list");
}
formObj.submit(); //이동
});
});
</script>
</body>
</html>
content.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>modify</title>
<link href="/resources/css/style.css" rel="stylesheet" type="text/css">
</head>
<body>
<br/>
<h1 align="center"> 글 수정 </h1>
<form action="/board/modify" method="post">
<input type="hidden" name="pageNum" value="${cri.pageNum}"/>
<input type="hidden" name="listQty" value="${cri.listQty}"/>
<table>
<tr>
<td>글 번호</td>
<td><input type="text" name="bno" value="${board.bno}" readonly = "readonly"/></td>
<%--<td><input type="text" name="title" value='<c:out value=${board.bno}"/> 이게 더 보안이 좋음 --%>
</tr>
<tr>
<td>제목</td>
<td><input type="text" name="title" value="${board.title}" /></td>
</tr>
<tr>
<td>내용</td>
<td><textarea rows="10" cols="30" name="content">${board.content}</textarea></td>
</tr>
<tr>
<td>작성자</td>
<td><input type="text" name="writer" value="${board.writer}" /></td>
</tr>
<tr>
<td>작성일</td>
<td><fmt:formatDate value="${board.regdate}" pattern="yyyy-MM-dd HH:MM"/></td>
</tr>
<tr>
<td>수정일</td>
<td><fmt:formatDate value="${board.updateDate}" pattern="yyyy-MM-dd HH:MM"/></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="수정" />
<input type="button" value="리스트" onclick="window.location='/board/list?pageNum=${cri.pageNum}&listQty=${cri.listQty}'"/>
</td>
</tr>
</table>
</form>
</body>
</html>
modify
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>delete</title>
<link href="/resources/css/style.css" rel="stylesheet" type="text/css">
</head>
<body>
<br/>
<h1> 게시글 삭제</h1>
<form action="/board/delete" method="post">
<table>
<tr>
<td> [ #${board.bno}. ${board.title} ] <br />
이 게시글을 삭제 하시겠습니까? <br/>
<input type="hidden" name="bno" value="${board.bno}" />
<input type="hidden" name="pageNum" value="${cri.pageNum}" />
<input type="hidden" name="listQty" value="${cri.listQty}" />
<input type="submit" value="삭제 확인"/>
<input type="button" value="취소" onclick="history.back()"/>
</td>
</tr>
</table>
</form>
</body>
</html>
delete.jsp