Spring Boot์์ ๊ฒ์๊ธ ๊ด๋ฆฌ ํด๋ณด๊ธฐ! ใฝ(โฟ๏พโฝ๏พ)ใ
- ์ฌ์ฉ IDE : IntelliJ IDEA Ultimate
- ์ฌ์ฉ DB : MySQL
- ์ฌ์ฉ ์ธ์ด & SDK : Java & Amazon correto 11
- ์ ๋ฆฌ๋ณธ์ ๋๋ค ์ฐธ๊ณ ์ฉ์ผ๋ก๋ง ๋ด์ฃผ์ธ์ :D
- ์ ๋ฒ์๊ฐ์ ๊ฒ์๊ธ ์ ์ฅ, ๋ชฉ๋ก์ถ๋ ฅ, ์์ธ์กฐํ๊น์ง ํ์ผ๋ ์ด๋ฒ์๋
๊ฒ์๊ธ ์์ & ์ญ์ & ํ์ด์ง์ฒ๋ฆฌ๊น์ง ์งํํด๋ด ์๋ค (ใฃใปโใป๏ผใฃ
์ด์ ๊ธ
๐ Spring Boot ์์ 1 (๊ฒ์๊ธ ๊ด๋ฆฌ) ใฝ(โฟ๏พโฝ๏พ)ใ
์ด๋ฒ์๋ ์์ ์ ํ ๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅ๋ฐ์ ๋น๋ฐ๋ฒํธ ์ผ์น ์ ์์ ์ด ๋๊ฒ๋ ์งํํ ์์ ์
๋๋ค.
์ค๋ช
์ DTO๋ถํฐ ํ๊ฒ ์ต๋๋ค:D
์ญ์ ๋ ๋งค์ฐ ๊ฐ๋จํ๊ธฐ ๋๋ฌธ์ ์ ๋ฐ์ดํธ ํ์ด์ง์์ ๊ฐ์ด ์งํํ๊ฒ ์ต๋๋ค ๊ทธ๋ผ ๋ฐ๋ก ๊ฐ์์ฃ !! (เนโนโโนเน)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BoardUpdateDTO {
private Long boardId;
private String boardWriter;
private String boardPassword;
private String boardTitle;
private String boardContents;
Update์ ๊ดํ DTO ๋ด์ฉ์ ์์๊ฐ์ด ์ค์ ํ๊ฒ ์ต๋๋ค.
์์ ์ ํ์ํ ๋ด์ฉ๋ง ๋ด๋๊ฑฐ๋ผ ํน๋ณํ ๋ด์ฉ์ด ์์ผ๋ฏ๋ก ์ค๋ช ์ ์๋ตํ๊ฒ ์ต๋๋ค :D
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>findById.html</h2>
<table>
<thead>
<tr>
<th>๋ฒํธ</th>
<th>์์ฑ์</th>
<th>์ ๋ชฉ</th>
<th>๋ด์ฉ</th>
<th>์์ฑ์๊ฐ</th>
<th>์์ ์๊ฐ</th>
<th>์์ </th>
</tr>
</thead>
<tbody>
<tr>
<th th:text="${boardDetailDTO.boardId}"></th>
<th th:text="${boardDetailDTO.boardWriter}"></th>
<th th:text="${boardDetailDTO.boardTitle}"></th>
<th th:text="${boardDetailDTO.boardContents}"></th>
<th th:text="${boardDetailDTO.createTime}"></th>
<th th:text="${boardDetailDTO.updateTime}"></th>
<!-- findById์ update ํผ์ผ๋ก ๊ฐ๊ธฐ ์ํ ๋งํฌ ์ถ๊ฐ -->
<th><a th:href="@{|/board/update/${boardDetailDTO.boardId}|}">์์ ํ์ด์ง</a></th>
</tr>
</tbody>
</table>
</body>
</html>
์ ๋ฐ์ดํธ ํ์ด์ง๋ฅผ ๋์ฐ๊ธฐ ์ํด์๋ boardId๋ฅผ ๊ฐ์ด ๋ณด๋ด์ค์ผํฉ๋๋ค.
๊ทธ๋์ ํ์๋ฆฌํ๋ฌธ๋ฒ ์ค ํ๋์ธ @{||}๋ฅผ ์ด์ฉํด boardId๋ฅผ ๊ฐ์ด ๋ณด๋ด์ฃผ์์ต๋๋ค :D
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script>
// ์๋ ์ฝ๋๋ ์ผ๋ฐ Post ๋ฐฉ์์ผ๋ก ์์ ํ๋ ๋ฐฉ๋ฒ, ์ค๋ช
์๋ต
// const update = () => {
// const inputPassword = document.getElementById("boardPassword").value
// const boardPassword = "[[${boardDetailDTO.boardPassword}]]"
// if (inputPassword==boardPassword) {
// updateForm.submit();
// } else {
// alert("๋น๋ฐ๋ฒํธ๊ฐ ํ๋ ธ์ต๋๋ค.")
// }
// }
const boardUpdate = () => {
const id = document.getElementById("boardId").value
const writer = document.getElementById("boardWriter").value
const title = document.getElementById("boardTitle").value
const contents = document.getElementById("boardContents").value
const inputPassword = $("#boardPassword").val(); // ajax๋ก value๊ฐ ๊ฐ์ ธ์ค๊ธฐ
const password = "[[${boardDetailDTO.boardPassword}]]"
// const boardDate = document.getElementById("boardDate").value
const updateData = JSON.stringify({
boardId: id,
boardWriter: writer,
boardTitle: title,
boardContents: contents,
boardPassword: password
// boardPassword: pw,
// boardDate: boardDate
})
console.log(updateData)
const reqUrl = "/board/"+id
if (inputPassword == password) { // ๋น๋ฐ๋ฒํธ ์ผ์น์ฌ๋ถ ์ฒดํฌ
$.ajax({
type: "put", // method๊ฐ put์ธ ๋ฉ์๋๋ก ๋ณด๋ธ๋ค๋ ๋ป
url: reqUrl, // /board/{boardId}
contentType: "application/json", // json์ ๋ณด๋ธ๋ค๋ฉด ๋ฐ๋์ ์์ฑ
data: updateData, // ์์์ ์ค์ ํ updateData๋ฅผ ๋ณด๋ (jsonํ์
)
success: function () {
location.href = "/board/"+id;
},
error: function () {
alert("ajax ์คํจ")
}
})
} else {
alert("๋น๋ฐ๋ฒํธ๊ฐ ํ๋ ธ์ต๋๋ค")
}
}
const boardDelet = () => {
const id = document.getElementById("boardId).value
reqUrl = "/board/"+id
$.ajax({
type: "delete",
url: reqURL,
success: function () {
location.href = "/board/"
},
error: function () {
alert("ajax ์คํจ")
}
})
}
</script>
</head>
<body>
<h2>update.html</h2>
<form action="/board/update" method="post" name="updateForm">
<input type="text" id="boardId" name="boardId" th:value="${boardDetailDTO.boardId}">
<input type="text" id="boardWriter" name="boardWriter" th:value="${boardDetailDTO.boardWriter}" placeholder="์์ฑ์" readonly>
<input type="text" id="boardPassword" name="boardPassword" placeholder="๋น๋ฐ๋ฒํธ">
<input type="text" id="boardTitle" name="boardTitle" th:value="${boardDetailDTO.boardTitle}" placeholder="์ ๋ชฉ">
<input type="text" id="boardContents" name="boardContents" th:value="${boardDetailDTO.boardContents}" placeholder="๋ด์ฉ">
<!-- <input type="button" th:onclick="update()" value="์์ "> -->
<!-- ์ Post๋ฐฉ์์ผ๋ก ์์ ํ๋ ๋ฐฉ๋ฒ์ ์๋ตํ๊ฒ ์ต๋๋ค. -->
<input type="button" th:onclick="boardUpdate()" value="์์ (put)">
<input type="button" th:onclick="boardDelete()" value="์ญ์ (delete)"
</form>
</body>
</html>
์ด๋ ๊ฒ update.html ๋ด์ฉ์ ์์ฑํ์ต๋๋ค.
Post๋ฐฉ์์ผ๋ก ์์ ํ๋ ๋ฐฉ๋ฒ์ Spring Framework ๋ถํฐ ๋ง์ด ์จ๋ดค๊ธฐ ๋๋ฌธ์ ์๋ตํ์์ต๋๋ค.
๋ด์ฉ์ ์ฃผ์์ผ๋ก ์ฒ๋ฆฌํ์ผ๋ ํ์ํ์ ๋ถ๋ค์ ์ฃผ์์ ํด์ ํ๊ณ ์ฌ์ฉํด๋ณด์๋ฉด ๋ ๊ฒ๋๋ค!๋น๋ฐ๋ฒํธ ์ผ์น์ฌ๋ถ ์ฒดํฌ๋ DTO์์ ๊ฐ์ ธ์จ ๊ฐํ๊ณ input์ ์ ๋ ฅํ ๊ฐ์ ์๋ก ๋น๊ตํด,
์ผ์นํ๋ฉด form์ ๋ด์ฉ์ด jsonํ์ ์ผ๋ก put๋ฉ์๋์ ๊ฐ๊ฒ๋ ์ค์ ํ์ต๋๋ค.
Controller์์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ ์์ ์ด ์ ์์ ์ผ๋ก ์ํ๋์๋ค๋ฉด success์
location.href="/board/"+id ์ฝ๋๋ฅผ ํตํด ์์ธ์กฐํ ํ์ด์ง๋ก ๊ฐ๊ฒ ์ค์ ํ์ต๋๋ค.
๊ทธ๋ผ html์ ์ ๋ถ ๋ง๋ค์์ผ๋ Controller๋ก ๊ฐ๋ณด์ค๊น์?? (เนหฬตแดหฬต)ู
// ์
๋ฐ์ดํธ ํ์ด์ง ์์ฒญ
@GetMapping("/update/{boardId}")
public String updateForm(@PathVariable Long boardId, Model model) {
BoardDetailDTO boardDetailDTO = bs.findById(boardId);
model.addAttribute("boardDetailDTO",boardDetailDTO);
return "board/update";
}
// ์์ ๋ด์ฉ ์ ์ฅ
@PutMapping("/{boardId}")
public ResponseEntity update2(@RequestBody BoardUpdateDTO boardUpdateDTO) {
bs.update(boardUpdateDTO);
return new ResponseEntity(HttpStatus.OK);
}
// ๊ฒ์๊ธ ์ญ์
@DeleteMapping("/{boardId}")
public ResponseEntity deleteById2(@PathVariable Long boardId) {
bs.deleteById(boardId);
return new ResponseEntity(HttpStatus.OK);
}
์ ๋ฐ์ดํธ ํ์ด์ง ์์ฒญ & ์ ๋ฐ์ดํธ ๋ด์ฉ ์ ์ฅ์ ๊ดํ ๋ฉ์๋์ ๋๋ค.
์ ๋ฐ์ดํธ ํ์ด์ง์ ๊ฐ๊ธฐ ์ findById๋ฅผ ํตํด ์ ๋ฐ์ดํธ ํ ๋ด์ฉ์ ๊ฐ์ ธ๊ฐ๊ณ ,
ajax์์ Put ๋ฐฉ์์ผ๋ก ์์ ๋ด์ฉ์ ์ ๋ฌ๋ฐ์ ์์ ์๋ฃ ์ ์ํ์ฝ๋ 200์ ๋ณด๋ ๋๋ค!!
ajax์์ 200์ด๋ผ๋ ์ํ์ฝ๋๋ฅผ ๋ฐ๊ฒ ๋๋ฉด ์๋์ผ๋ก success์ ํจ์๋ฅผ ์คํํฉ๋๋ค.
๋ํ ajax์์ json์ผ๋ก ๋ณด๋ธ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ธฐ ์ํด์ @RequestBody๋ฅผ ์ฌ์ฉํด์ผํฉ๋๋ค.
๊ทธ๋ผ Service๋ก ๋์ด๊ฐ์์ฃ :D
// ๊ฒ์๊ธ ์์
@Override
public Long update(BoardUpdateDTO boardUpdateDTO) {
BoardEntity boardEntity = BoardEntity.updateBoard(boardUpdateDTO);
return br.save(boardEntity).getId();
}
// ๊ฒ์๊ธ ์ญ์
@Override
public void deleteById(Long memberId) {
br.deleteById(boardId);
}
ํ์๊ด๋ฆฌ ์์ ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ฌ๊ธฐ์๋ Jpa์ save ๋ฉ์๋๋ฅผ ์ด์ฉํ์ต๋๋ค.
์๋ก์ด ๊ฐ์ด ๋ค์ด์จ๋ค๋ฉด ์๋์ผ๋ก insert,
pk๊ฐ ์๋ ๊ฐ์ด ๋ค์ด์จ๋ค๋ฉด ์๋์ผ๋ก update๋ฅผ ์ํํฉ๋๋ค.
ํน๋ณํ ๋ด์ฉ์ ์์ผ๋ฏ๋ก ์ค๋ช ์ ์๋ตํ๊ฒ ์ต๋๋ค :D
ํ์ด์ง ์ฒ๋ฆฌ์ ๋๋ค.
์ด๋ฒ์๋ Jpa๊ฐ ์ ๊ณตํ๋ Page ๊ฐ์ฒด๋ฅผ ์ด์ฉํ ์์ ์ด๋ฉฐ,
๋ง์ด ์ด๋ ค์ฐ๋ ์ ๋ฐ๋ผ์์ฃผ์๊ธธ ๋ฐ๋๋๋ค :D
๊ทธ๋ผ Page์ฉ DTO๋ถํฐ ์์ฑํ๋ฌ ๊ฐ์๋ค ูฉ( แ )ู
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BoardPagingDTO {
private Long boardId;
private String boardWriter;
private String boardTitle;
}
PagingDTO์์๋ ๋ณ ๋ค๋ฅธ ๋ด์ฉ์ด ์์ผ๋ฏ๋ก ์ค๋ช ์ ์๋ตํ๊ณ ๋์ด๊ฐ๊ฒ ์ต๋๋ค.
public class PagingConst {
public static final int PAGE_LIMIT = 5; // ํ ํ์ด์ง์ ๋ณด์ฌ์ค ๊ธ ๊ฐฏ์
public static final int BLOCK_LIMIT = 3; // ํ ํ๋ฉด์ ํ์ด์ง ๊ฐฏ์
}
ํ์ด์ง์ฒ๋ฆฌ๋ฅผ ๋์์ฃผ๊ธฐ ์ํด PagingConst๋ฅผ ์์ฑํ์ต๋๋ค.
๋์น๊ฐ ๋น ๋ฅด์ ๋ถ๋ค์ด๋ฉด ๊ฐ ํ๋๊ฐ ๋ฌด์จ ์ญํ ์ ํ๋์ง ์์ค ์ ์์ต๋๋ค.
Jpa์์ ํ์ด์ง ์ฒ๋ฆฌ๋ฅผ ๋์์ฃผ์ง๋ง ํ ํ์ด์ง์ ๋ณด์ฌ์ค ๊ธ ๊ฐฏ์์ ํ์ด์ง ๊ฐฏ์๋ ์ง์ ์ค์ ํด์ค์ผ ํด์
์์ ๊ฐ์ ํด๋์ค๋ฅผ ์์ฑํด์ฃผ์์ต๋๋ค. ์ด๋ ค์ด ๋ด์ฉ ์๋๋ ์ ๋ฐ๋ผ์ ์ฃผ์๊ธธ ๋ฐ๋๋๋ค :D
์ ๋ ํ ํ์ด์ง๋น ๊ธ ๊ฐฏ์ 5๊ฐ, ํ์ด์ง ๊ฐฏ์๋ 3๊ฐ๋ก ํ์ต๋๋ค.
Controller์์๋ถํฐ ๋ณธ๊ฒฉ์ ์ธ ํ์ด์ง ์ฒ๋ฆฌ ์์ ์ด ์์๋ฉ๋๋ค.
์คํ ์๋๊ฒ ์ ๋ฐ๋ผ์์ฃผ์ธ์ :D
๊ทธ ์ ์ ์ผํญ ์ฐ์ฐ์์ ๋ํด ์์๋ณด๋ ์๊ฐ์ ๊ฐ์ง๋๋ก ํ๊ฒ ์ต๋๋ค.
int num = 10, num2 = 0;
if(num == 10) {
num2 =5;
} else {
num2 = 100;
}
// ์ if ์ ์๋ ์ฝ๋๋ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅ
num2 = (num==10)? 5: 100;
// ๊ธฐ๋ณธ์ ์ธ ๊ตฌ์กฐ
// ๋ณ์ = (์กฐ๊ฑด์) ? true์ผ ๋ ๊ฐ : false์ผ ๋ ๊ฐ
// ์กฐ๊ฑด์ด ๋ง์ผ๋ฉด true์ผ ๋ ๊ฐ์ด ๋ณ์์ ๋ด๊น, false์ผ ๋๋ ๋ฐ๋
// ๋จ์ํ if else์ผ ๋ ์์ ๊ฐ์ ์ผํญ ์ฐ์ฐ์ ์ฌ์ฉ ๊ฐ๋ฅ
// if else์ ๊ฐ์ ๋ณ์๋ก ๊ฐ์ ์ฐจ์ด๋ฅผ ๋ ๋ ์ฃผ๋ก ์ฌ์ฉ
์ด๋ ๊ฒ ์ผํญ ์ฐ์ฐ์์ ๋ํด ๊ฐ๋ตํ๊ฒ ์์๋ณด์์ต๋๋ค.
if else์ ๋ณ ๋ค๋ฅธ ์ฐจ์ด์ ์ ์์ผ๋ ๋นํฉํ์ง ๋ง์๊ณ ์ด๋ฐ ์์์ ์ฝ๋๊ฐ ๋์ค๋ฉด
์ผํญ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๊ตฌ๋ ๋ผ๊ณ ์๊ฐํ์๋ฉด ๋ฉ๋๋ค.
๊ทธ๋ผ Controller๋ก ๋ค์ ๋์ด๊ฐ๋ณด๊ฒ ์ต๋๋ค.
// ํ์ด์ง์ฒ๋ฆฌ(board?page=5)
// 5๋ฒ๊ธ(/board/5)
// @PageableDefault(page=1) : ๋ณ๋ค๋ฅธ ํ์ด์ง ์์ฒญ์ด ์์ ๋ (์ฒ์ ์์ฒญ) 1ํ์ด์ง๋ฅผ ๋ด๋ณด๋ด๊ฒ ๋ค.
@GetMapping
public String paging(@PageableDefault(page = 1)Pageable pageable ,Model model) {
Page<BoardPagingDTO> boardList = bs.paging(pageable);
model.addAttribute("boardList", boardList);
// startPage, endPage ๊ณ์ฐ
// ํ์ฌ 2ํ์ด์ง ์ผ ๋ ์์ ํ์ด์ง 1, ๋ ํ์ด์ง 3
// ํ์ฌ 7ํ์ด์ง ์ผ ๋ ์์ ํ์ด์ง 6, ๋ ํ์ด์ง 8
int startPage = (((int)(Math.ceil((double)pageable.getPageNumber()/PagingConst.BLOCK_LIMIT)))-1)*PagingConst.BLOCK_LIMIT+1;
int endPage = (startPage+PagingConst.BLOCK_LIMIT-1)<boardList.getTotalPages())?startPage+PagingConst.BLOCK_LIMIT-1 : boardList.getTotalPages();
model.addAttribute("startPage", startPage);
model.addAttribute("endPage", endPage);
return "board/paging";
}
๊ฐ์๊ธฐ ์ด๋ ค์ด ๋ด์ฉ์ด ๋์์ต๋๋ค๋ง ์ผ๋จ Service๊น์ง ์ค๋ช ํ๊ณ ,
Test ์ฝ๋๋ฅผ ํตํด ์์ธํ ์๋ ค๋๋ฆฌ๊ฒ ์ต๋๋ค.
startPage, endPage๋ Spring Framework์์๋ ์ผ๋ ๋ด์ฉ์ด๋ฏ๋ก ์๋ตํ๊ฒ ์ต๋๋ค.
@Override
public Page<BoardPagingDTO> paging(Pageable pageable) {
int page = pageable.getPageNumber(); // pageable ๊ฐ์ฒด์์ .get์ ํตํด page ์ ๋ณด๋ฅผ ๊บผ๋ผ ์ ์์.
// JPA๊ฐ ๊ด๋ฆฌํ๋ ํ์ด์ง ๊ฐ์ฒด๋ 0๋ฒ๋ถํฐ ๊ด๋ฆฌ
// ๊ทธ๋์ ์ผํญ ์ฐ์ฐ์๊ฐ ํ์
// ์์ฒญํ ํ์ด์ง๊ฐ 1์ด๋ฉด ํ์ด์ง ๊ฐ์ 0์ผ๋ก ํ๊ณ , 1์ด ์๋๋ฉด ์์ฒญ ํ์ด์ง์์ 1์ ๋บ๋ค.
// page = page-1; // ์ด๋ฐ์์ผ๋ก ์จ๋ ๋์ง๋ง ์ผํญ์ฐ์ฐ์๋ฅผ ์ด์ฉํด๋ณด๊ฒ ์ต๋๋ค.
page = (page==1)? 0:(page-1);
// Pageable ํ์
์ pagealbe ๊ฐ์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋ findAll() ํธ์ถ
Page<BoardEntity> boardEntities = br.findAll(PageRequest.of(page, PagingConst.PAGE_LIMIT, Sort.by(Sort.Direction.DESC, "id")));
// findAll(PageRequest.of(์ด๋ค ํ์ด์ง๋ฅผ, ์ด๋ค ๊ฐฏ์๋ก), ์ ๋ ฌ (์ด๋ค ์ ๋ ฌ ,"๊ธฐ์ค์ผ๋ก ์ผ์ Entity ํด๋์ค์ ํ๋์ด๋ฆ"))
// ๊ธฐ์ค์ผ๋ก ์ผ์ Entity ํด๋์ค์ ํ๋์ด๋ฆ์ ์ธ๋๋ฐ( _ ) ๊ฐ ํฌํจ๋์ด์์ผ๋ฉด JPA ๊ฐ ์ธ์์ ๋ชปํด ์ค๋ฅ ๋ฐ์
// findAll์ ๋ฆฌํด๊ฐ์ Page<Entityํ์
>๋ก ๋์ด์ด. ๋ฐ๋ผ์ DTO๋ก ๋ณํํด์ฃผ๋ ์์
์ด ํ์ํจ.
// Page<BoardEntity> -> Page<BoardPagingDTO>
// ๊ธฐ์กด DTO์์ ๋ณํํด์ฃผ๋ ์์
์ ํ ํ์ ์์ด Page๊ฐ์ฒด๊ฐ ์ ๊ณตํด์ฃผ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์๋์ผ๋ก ๋ณํ์์ผ์ค
// ์๋์ ๊ฐ์ ๋ณํ์ฉ ์ฝ๋๋ก ์ฌ์ฉ
Page<BoardPagingDTO> boardList = boardEntities.map(
board -> new BoardPagingDTO(board.getId(),
board.getBoardWriter(),
board.getBoardTitle())
);
return boardList;
}
jpa๋ ํ์ด์ง๋ฅผ 0๋ถํฐ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ 1ํ์ด์ง๋ฅผ ์์ฒญํ๋ ค๋ฉด 0์, 4ํ์ด์ง๋ฅผ ์์ฒญํ๋ ค๋ฉด 3์ ์์ฒญํด์ผํฉ๋๋ค.
๋ํPage<Entity>
๊ฐ์ฒด๋ก ๋์ด์จ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ์กด ๋ฐฉ์์ผ๋ก DTO๋ก ๋ณํํ๋ฉด Jpa์ Page ๊ด๋ จ ๋ฉ์๋๋ค์ ์ฌ์ฉ ๋ชปํ๊ธฐ ๋๋ฌธ์ ์์ ๊ฐ์ด .map()์ผ๋ก ๋ณํ ์์ผ์ฃผ๋ ์์ ์ ์ํํด์ผ ํฉ๋๋ค.
์์ธํ ๋ด์ฉ์ Test์ฝ๋์์ ํ์ธํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
@Test
@Transactional
@DisplayName("ํ์ด์ง ํ
์คํธ")
public void pagingTest() {
// ๊ธ๊ฐฏ์ 30๊ฐ ๊ธฐ์ค ํํ์ด์ง 5๊ฐ ๊ธฐ์ค ํ์ด์ง ์ฒ๋ฆฌ
// int page = 0; // JPA ๊ธฐ์ค 1ํ์ด์ง (์ฒซ๋ฒ์งธ ํ์ด์ง)
int page = 5; // JPA ๊ธฐ์ค 6ํ์ด์ง (๋ง์ง๋ง ํ์ด์ง)
Page<BoardEntity> boardEntities = br.findAll(PageRequest.of(page, PagingConst.PAGE_LIMIT, Sort.by(Sort.Direction.DESC, "id")));
// Page ๊ฐ์ฒด๊ฐ ์ ๊ณตํด์ฃผ๋ ๋งค์๋ ํ์ธ
System.out.println("boardEntities.getContent() = " + boardEntities.getContent()); // ์์ฒญ ํ์ด์ง์ ๋ค์ด์๋ ๋ฐ์ดํฐ, toString์ด ์๊ธฐ ๋๋ฌธ์ ์ฃผ์๊ฐ์ด ์ถ๋ ฅ
System.out.println("boardEntities.getTotalElements() = " + boardEntities.getTotalElements()); // ์ ์ฒด ๊ธ ๊ฐฏ์
System.out.println("boardEntities.getNumber() = " + boardEntities.getNumber()); // JPA ๊ธฐ์ค ์์ฒญ ํ์ด์ง
System.out.println("boardEntities.getTotalPages() = " + boardEntities.getTotalPages()); // ์ ์ฒด ํ์ด์ง ๊ฐฏ์
System.out.println("boardEntities.getSize() = " + boardEntities.getSize()); // ํ ํ์ด์ง์ ๋ณด์ฌ์ง๋ ๊ธ ๊ฐฏ์
System.out.println("boardEntities.hasPrevious() = " + boardEntities.hasPrevious()); // ์ด์ ํ์ด์ง ์กด์ฌ ์ฌ๋ถ
System.out.println("boardEntities.isFirst() = " + boardEntities.isFirst()); // ์ฒซ ํ์ด์ง์ธ์ง ์ฌ๋ถ
System.out.println("boardEntities.isLast() = " + boardEntities.isLast()); // ๋ง์ง๋ง ํ์ด์ง์ธ์ง ์ฌ๋ถ
// Page<BoardEntity> -> Page<BoardPagingDTO>
// ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก ๋ณํํ๋ฉด ํ์ด์ง๊ฐ์ฒด๊ฐ ์ ๊ณตํ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉ ๋ชปํจ.
// .map() : Entity ๊ฐ ๋ด๊ธด ํ์ด์ง ๊ฐ์ฒด๋ฅผ dto ๊ฐ ๋ด๊ธด ํ์ด์ง ๊ฐ์ฒด๋ก ๋ณํํด์ฃผ๋ ์ญํ
// board : ๋ฐ๋ณต์ฉ ๋ณ์๋ก ๋ง๋ ๋ณ์, foreach ๋ฌธ์ ๋ฐ๋ณต ๋ณ์์ ๋์ผํ ๊ฐ๋
// ์ฌ๊ธฐ์์ ๋ฐ๋ณต๋ณ์(board)๋ Entity ๊ฐ์ฒด์. Entity์ ๋ด๊ธด ์ ๋ณด๋ฅผ BoardPagingDTO์ ๋ด์.
Page<BoardPagingDTO> boardList = boardEntities.map(
board -> new BoardPagingDTO(board.getId(),
board.getBoardWriter(),
board.getBoardTitle())
);
// ์ ๋๋ก ๋ณํ์ด ๋์๋ค๋ฉด Page<BoardPagingDTO>์์๋ Jpa์ Page ๊ด๋ จ ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์๋ค.
System.out.println("boardList.getContent() = " + boardList.getContent());
System.out.println("boardList.getTotalElements() = " + boardList.getTotalElements());
System.out.println("boardList.getNumber() = " + boardList.getNumber());
System.out.println("boardList.getTotalPages() = " + boardList.getTotalPages());
System.out.println("boardList.getSize() = " + boardList.getSize());
System.out.println("boardList.hasPrevious() = " + boardList.hasPrevious());
System.out.println("boardList.isFirst() = " + boardList.isFirst());
System.out.println("boardList.isLast() = " + boardList.isLast());
}
์ค์ ๋ก ์คํํด๋ณด์๋ฉด (๋จ, DB์ ๋ฐ์ดํฐ๊ฐ ๋ค์ด์์ ๋)
๊ฐ์ด ์ ๋ถ ์ ๋์ค๋๊ฑฐ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
์ด ๊ฐ์ข ๋ฉ์๋๋ค์ ํ์๋ฆฌํ๋ฅผ ํตํด paging.html์์ ์ฌ์ฉํ ์์ ์ด๋ฏ๋ก ๊ฐ ๋ฉ์๋๊ฐ ๋ฌด์จ ์ญํ ์ ํ๋์ง
์ ์์๋์ ์ผ ํฉ๋๋ค. ๊ทธ๋ผ html์ ๋ง๋ค๋ฌ ๊ฐ๋ณด๊ฒ ์ต๋๋ค!! :D
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<body class="container">
<h2>ํ์์ ๊ฒ์ํ</h2>
<table class="table table-hover">
<thead>
<tr>
<th scope="col">๊ธ ๋ฒํธ</th>
<th scope="col">๊ธ์ด์ด</th>
<th scope="col">๊ธ ์ ๋ชฉ</th>
</tr>
</thead>
<tbody>
<tr th:each="board: ${boardList}">
<td th:text="${board.boardId}"></td>
<td th:text="${board.boardWriter}"></td>
<td><a th:href="@{|/board/${board.boardId}|}" th:text="${board.boardTitle}">์ ๋ชฉ</a></td>
</tr>
</tbody>
</table>
<!--
/board
๋ธ๋ผ์ฐ์ ์ฃผ์์ฐฝ์ ๋ณด์ด๋ ์ฃผ์๊ฐ : /board?page=1
html์์ ํ์๋ฆฌํ๋ก ์์ฑํ๋ ์ฃผ์๊ฐ : /board(page=1)
/board/*
/board/?page=1
/board/(page=1)
-->
<div class="container">
<ul class="pagination">
<li class="page-item">
<!-- ์ฒซํ์ด์ง๋ก ๊ฐ๋ ๋งํฌ -->
<a class="page-link" th:href="@{/board(page=1)}">
<span>First</span>
</a>
</li>
<li th:class="${boardList.first} ? 'disabled'" class="page-item">
<!-- ์ ์ฝ๋ ํด์ : ์ฒซ๋ฒ์งธ ํ์ด์ง๋ผ๋ฉด 'disabled'๋ผ๋ ์์ฑ ๋ถ์ฌ -->
<!-- boardList.first : isFirst() ์ฒซ๋ฒ์งธ ํ์ด์ง์ธ์ง ์กฐ๊ฑด์ ๊ฒ -->
<!-- # : ์๋ฌด ์์ฒญ์ ์๋ณด๋ -->
<!-- boardList.number() : getNumber ์ด์ ํ์ด์ง ์์ฒญ -->
<a class="page-link" th:href="${boardList.first} ? '#' : @{/board(page=${boardList.number})}"> <!-- Page๊ฐ์ฒด๊ฐ ์ ๊ณตํ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๋ ์ด๋ฆ์ด ์ด์ง ๋ณ๊ฒฝ๋จ. -->
<!-- ํ์ด์ง๊ฐ ์ฒซ๋ฒ์งธ ํ์ด์ง๋ผ๋ฉด < ์ ๋๋ ์ ๋ ์ปจํธ๋กค๋ฌ์ ์์ฒญ์ ์ํจ -->
<!-- ์ฒซํ์ด์ง๊ฐ ์๋๋ผ๋ฉด ์ด์ ํ์ด์ง๋ฅผ ์์ฒญ -->
<span><</span> <!-- <๋ฅผ ๊ทธ๋ฅ ์ฐ๋ฉด html์์ ์ฒ๋ฆฌ๋ฅผ ๋ชปํ ์ ์๊ธฐ ๋๋ฌธ์ html ํน์๊ธฐํธ ํ์ ์๋ ์ฝ๋๋ฅผ ์ฌ์ฉ -->
</a>
</li>
<!-- startPage ~ endPage ๊น์ง ์ซ์๋ฅผ ๋ง๋ค์ด์ฃผ๋ ์ญํ -->
<!--
th:each="page: ${#numbers.sequence(startPage, endPage)}
th:each -> ๋ฐ๋ณต
page -> ๋ฐ๋ณต ๋ณ์
${#number.sequence(์์๊ฐ, ๋๊ฐ)} -> ์ผ๋ง๋ ๋ฐ๋ณต
-->
<li th:each="page: ${#numbers.sequence(startPage, endPage)}"
th:class="${page == boardList.number + 1} ? 'page-item active'">
<a class="page-link" th:text="${page}" th:href="@{/board(page=${page})}"></a>
<!-- ํด๋น ์ซ์๊ฐ์ผ๋ก ์ปจํธ๋กค๋ฌ์ ์์ฒญ -->
</li>
<!--
๋ค์ ํ์ด์ง ์์ฒญ
ํ์ฌ 3ํ์ด์ง๋ฅผ ๋ณด๊ณ ์๋ค๋ฉด ๋ค์ ํ์ด์ง๋ 4ํ์ด์ง์.
getNumber()๊ฐ์ 2์.
๋ฐ๋ผ์ 4ํ์ด์ง๋ฅผ ๋ณด๊ณ ์ถ๋ค๋ฉด getNumber()+2๋ฅผ ํด์ผ ์ปจํธ๋กค๋ฌ์ 4๋ฅผ ์์ฒญํ ์ ์๋ค.
-->
<li th:class="${boardList.last} ? 'disabled'">
<a class="page-link" th:href="${boardList.last} ? '#' : @{/board(page=${boardList.number + 2})}">
<span>></span>
</a>
</li>
<li class="page-item">
<a class="page-link" th:href="@{/board(page=${boardList.totalPages})}">
<span>Last</span>
</a>
</li>
</ul>
</div>
</body>
</html>
ํ์ด์ง ์ฒ๋ฆฌ ์ฝ๋๊ฐ ๋ง์ด ๋ณต์กํ๊ธด ํ์ง๋ง ์ด์ฉ ์ ์์ต๋๋ค. ลฬฅฬฅฬฅฬฅืลฬฅฬฅฬฅฬฅ
์ค๋ช ์ด ํ์ํ๋ค ์๊ฐ๋๋๊ฒ์ ์ฃผ์์ผ๋ก ๋ฌ์๋์์ผ๋ ์ฐธ๊ณ ํด์ฃผ์ธ์!
์ ๋ฐ๋ผ์ค์ จ๋ค๋ฉด ํ์ด์ง์ฒ๋ฆฌ๊น์ง ๋ฌธ์ ์์ด ์ ๋์ จ์๊ฒ๋๋ค :D
์ด๋ ๊ฒ ๊ฒ์๊ธ ์์ & ์ญ์ & ํ์ด์ง ์ฒ๋ฆฌ๊น์ง ์ ๋ถ ํด๋ณด์์ต๋๋ค.
ํ์๊ด๋ฆฌ ์์ ์ ๋น์ทํ ์ ์ด ๋ง์ ์ค๋ช ์ ๋ง์ด ์๋ตํ๊ธด ํ์ผ๋ ๋ค๋ค ์ ๋ฐ๋ผ์ค์ จ์๊ฑฐ๋ผ ๋ฏฟ์ต๋๋ค :D
๋ค์์ ๋ ์ถ๊ฐ๋๋ ๋ด์ฉ์ด ์๋ค๋ฉด ๊ทธ๋ ๋ค์ ๋ง๋๋๊ฑธ๋ก ํ๊ฒ ์ต๋๋ค!!
๋ค๋ค ๋ค์์ ๊ฑด๊ฐํ ๋ชจ์ต์ผ๋ก ๋ง๋์~ ( แฆ'แด'แฆ )