목차 | |
1. | search |
1. search
◈ build.gradle (boot_JPA)
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '3.2.11'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.ezen'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
implementation 'org.apache.tika:tika-core:2.4.1'
implementation 'org.apache.tika:tika-parsers:2.4.1'
implementation 'net.coobird:thumbnailator:0.4.17'
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
/*providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'*/
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
def querydslSrcDir='src/main/generated'
clean{
delete file(querydslSrcDir)
}
tasks.withType(JavaCompile){
options.generatedSourceOutputDirectory = file(querydslSrcDir)
}
tasks.named('test') {
useJUnitPlatform()
}
◈ list.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}">
<div layout:fragment="content">
<div class="container-md">
<h1>Board List Page</h1>
<!-- search line -->
<!--[[${pgvo}]]-->
<div class="container-fluid">
<form action="/board/list" method="get" class="d-flex" role="search">
<select class="form-select" name="type" id="inputGroupSelect01">
<option th:selected="${pgvo.type == null ? 'true' : 'false' }">Choose...</option>
<option th:value="t" th:selected="${pgvo.type == 't' ? 'true' : 'false' }">title</option>
<option th:value="w" th:selected="${pgvo.type == 'w' ? 'true' : 'false' }">writer</option>
<option th:value="c" th:selected="${pgvo.type == 'c' ? 'true' : 'false' }">content</option>
<option th:value="tw" th:selected="${pgvo.type == 'tw' ? 'true' : 'false' }">title + writer</option>
<option th:value="wc" th:selected="${pgvo.type == 'wc' ? 'true' : 'false' }">writer + content</option>
<option th:value="tc" th:selected="${pgvo.type == 'tc' ? 'true' : 'false' }">content + title</option>
<option th:value="twc" th:selected="${pgvo.type == 'twc' ? 'true' : 'false' }">all</option>
</select>
<input class="form-control me-2" name="keyword" type="text" placeholder="Search" th:value="${pgvo.keyword}" aria-label="Search">
<input type="hidden" name="pageNo" th:value="1">
<!-- <input type="hidden" name="qty" th:value="${pgvo.qty }">-->
<button type="submit" class="btn btn-primary position-relative">
search
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
[[${list.totalElements}]]
</span>
</button>
</form>
</div>
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>title</th>
<th>writer</th>
<th>regDate</th>
</tr>
</thead>
<tbody>
<tr th:each="bvo:${list}">
<td>[[${bvo.bno}]]</td>
<td><a th:href="@{/board/detail(bno=${bvo.bno})}">[[${bvo.title}]]</a></td>
<td>[[${bvo.writer}]]</td>
<td>[[${bvo.regAt}]]</td>
</tr>
</tbody>
</table>
<!-- 페이지네이션 라인 -->
<!-- th:classappend : 동적 클래스 추가 -->
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
<li th:if="${pgvo.hasPrev}" class="page-item">
<a class="page-link" th:href="@{/board/list(pageNo = ${pgvo.startPage - 1}, type=${pgvo.type}, keyword=${pgvo.keyword})}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<th:block th:each="i : ${#numbers.sequence(pgvo.startPage, pgvo.endPage)}">
<li class="page-item" aria-current="page" th:classappend="${pgvo.pageNo eq i ? 'active' : ''}">
<a class="page-link" th:href="@{/board/list(pageNo = ${i}, type=${pgvo.type}, keyword=${pgvo.keyword})}">[[${i}]]</a>
</li>
</th:block>
<li th:if="${pgvo.hasNext}" class="page-item">
<a class="page-link" th:href="@{/board/list(pageNo = ${pgvo.endPage + 1}, type=${pgvo.type}, keyword=${pgvo.keyword})}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
◈ PagingVO.java
package com.ezen.boot_JPA.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.data.domain.Page;
@Getter
@Setter
@ToString
public class PagingVO {
private int totalPage;
private int startPage;
private int endPage;
private boolean hasPrev, hasNext;
private int pageNo;
private String type;
private String keyword;
public PagingVO(Page<BoardDTO> list, int pageNo, String type, String keyword){
this.pageNo = pageNo + 1;
this.totalPage = list.getTotalPages();
this.type = type;
this.keyword = keyword;
this.endPage = (int)Math.ceil(this.pageNo / 10.0) * 10;
this.startPage = endPage - 9;
if(endPage > totalPage){
endPage = totalPage;
}
this.hasPrev = this.startPage > 10;
this.hasNext = this.endPage < this.totalPage;
}
}
◈ BoardController.java
package com.ezen.boot_JPA.controller;
import com.ezen.boot_JPA.dto.BoardDTO;
import com.ezen.boot_JPA.dto.BoardFileDTO;
import com.ezen.boot_JPA.dto.FileDTO;
import com.ezen.boot_JPA.dto.PagingVO;
import com.ezen.boot_JPA.handler.FileHandler;
import com.ezen.boot_JPA.handler.FileRemoveHandler;
import com.ezen.boot_JPA.service.BoardService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.List;
@Slf4j
@RequestMapping("/board/*")
@RequiredArgsConstructor
@Controller
public class BoardController {
private final BoardService boardService;
private final FileHandler fileHandler;
@GetMapping("/register")
public void register(){}
/* @PostMapping("/register")
public String register(BoardDTO boardDTO){
log.info(">>> boardDTO >>> {}", boardDTO);
// insert, update, delete => return 1 row
// jpa insert, update, delete => return id
Long bno = boardService.insert(boardDTO);
log.info(">>> insert >>> {}", bno > 0 ? "OK" : "FAIL");
return "/index";
}*/
@PostMapping("/register")
public String Register(BoardDTO boardDTO, @RequestParam(name = "files", required = false)
MultipartFile[] files){
List<FileDTO> flist = null;
if(files != null && files[0].getSize() > 0){
// 파일 핸들러 작업
flist = fileHandler.uploadFiles(files);
}
long bno = boardService.insert(new BoardFileDTO(boardDTO, flist));
return "/index";
}
/*@GetMapping("/list")
public void list(Model model){
// paging이 없는 케이스
List<BoardDTO> list = boardService.getList();
model.addAttribute("list", list);
}*/
/* @GetMapping("/list")
public void list(Model model, @RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo){
// 화면에서 들어오는 pageNo = 1 / 0으로 처리가 되어야 함
// 화면에서 들어오는 pageNo = 2 / 1로 처리가 되어야 함
log.info(">>> pageNo >>> {}", pageNo);
pageNo = (pageNo == 0 ? 0 : pageNo - 1);
log.info(">>> pageNo >>> {}", pageNo);
Page<BoardDTO> list = boardService.getList(pageNo);
log.info(">>> list >>> {}", list.toString());
log.info(">>> totalCount >>> {}", list.getTotalElements()); // 전체 글 수
log.info(">>> totalPage >>> {}", list.getTotalPages()); // 전체 페이지 수 => realEndPage
log.info(">>> pageNumber >>> {}", list.getNumber()); // 전체 페이지 번호 => pageNo
log.info(">>> pageSize >>> {}", list.getSize()); // 한 페이지에 표시되는 길이 => qty
log.info(">>> next >>> {}", list.hasNext()); // next 여부
log.info(">>> prev >>> {}", list.hasPrevious()); // prev 여부
PagingVO pgvo = new PagingVO(list, pageNo);
log.info(">>> pgvo >>> {}", pgvo.toString());
model.addAttribute("list", list);
model.addAttribute("pgvo", pgvo);
}*/
@GetMapping("/list")
public void list(Model model, @RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
@RequestParam(value = "type", required = false) String type,
@RequestParam(value = "keyword", required = false) String keyword) {
pageNo = (pageNo == 0 ? 0 : pageNo - 1);
Page<BoardDTO> list = boardService.getList(pageNo, type, keyword); // type, keyword 추가하여 서비스임플로 보내기
PagingVO pgvo = new PagingVO(list, pageNo, type, keyword);
model.addAttribute("list", list);
model.addAttribute("pgvo", pgvo);
}
@GetMapping("/detail")
public void modify(Model model, @RequestParam("bno") Long bno){
// BoardDTO boardDTO = boardService.getDetail(bno);
BoardFileDTO boardFileDTO = boardService.getDetail(bno);
model.addAttribute("boardFileDTO", boardFileDTO);
}
/* @PostMapping("/modify")
public String modify(BoardDTO boardDTO, RedirectAttributes redirectAttributes){
Long bno = boardService.modify(boardDTO);
redirectAttributes.addAttribute("bno", boardDTO.getBno());
return "redirect:/board/detail";
} */
@PostMapping("/modify")
public String modify(BoardDTO boardDTO, @RequestParam(name = "files", required = false) MultipartFile[] files, RedirectAttributes redirectAttributes){
List<FileDTO> flist = null;
if(files != null && files[0].getSize() > 0){
flist = fileHandler.uploadFiles(files);
}
Long bno = boardService.modify(new BoardFileDTO(boardDTO, flist));
redirectAttributes.addAttribute("bno", boardDTO.getBno());
return "redirect:/board/detail";
}
@GetMapping("/delete")
public String delete(@RequestParam("bno") Long bno){
boardService.delete(bno);
return "redirect:/board/list";
}
@ResponseBody
@DeleteMapping("/file/{uuid}")
public String fileRemove(@PathVariable("uuid") String uuid){
FileDTO fvo = boardService.getFile(uuid);
long bno = boardService.fileRemove(uuid);
FileRemoveHandler fr = new FileRemoveHandler();
boolean isDel = fr.deleteFile(fvo);
return (bno > 0 && isDel) ? "1" : "0";
}
}
◈ BoardService.java
package com.ezen.boot_JPA.service;
import com.ezen.boot_JPA.dto.BoardDTO;
import com.ezen.boot_JPA.dto.BoardFileDTO;
import com.ezen.boot_JPA.dto.FileDTO;
import com.ezen.boot_JPA.entity.Board;
import com.ezen.boot_JPA.entity.File;
import org.springframework.data.domain.Page;
import java.util.List;
public interface BoardService {
// 추상 메서드만 가능한 인터페이스
// 메서드가 default(접근제한자) 구현 가능
Long insert(BoardDTO boardDTO);
long insert(BoardFileDTO boardFileDTO);
// BoardDTO(class): bno title writer content regAt modAt
// Board(table) : bno title writer content
// BoardDTO => board 변환
// 화면에서 가져온 BoardDTO 객체를 저장을 위한 Board 객체로 변환
default Board convertDtoToEntity(BoardDTO boardDTO){
return Board.builder()
.bno(boardDTO.getBno())
.title(boardDTO.getTitle())
.writer(boardDTO.getWriter())
.content(boardDTO.getContent())
.build();
}
// board => BoardDTO 변환
// DB에서 가져온 Board 객체를 화면에 뿌리기 위한 BoardDTO 객체로 변환
default BoardDTO convertEntityToDto(Board board){
return BoardDTO.builder()
.bno(board.getBno())
.title(board.getTitle())
.writer(board.getWriter())
.content(board.getContent())
.regAt(board.getRegAt())
.modAt(board.getModAt())
.build();
}
// File 객체 convert
// FileDTO => File Entity
default File convertDtoToEntity(FileDTO fileDTO){
return File.builder()
.uuid(fileDTO.getUuid())
.saveDir(fileDTO.getSaveDir())
.fileName(fileDTO.getFileName())
.fileType(fileDTO.getFileType())
.bno(fileDTO.getBno())
.fileSize(fileDTO.getFileSize())
.build();
}
// File Entity => FileDTO
default FileDTO convertEntityToDto(File file){
return FileDTO.builder()
.uuid(file.getUuid())
.saveDir(file.getSaveDir())
.fileName(file.getFileName())
.fileType(file.getFileType())
.bno(file.getBno())
.fileSize(file.getFileSize())
.regAt(file.getRegAt())
.modAt(file.getModAt())
.build();
}
// List<BoardDTO> getList();
Page<BoardDTO> getList(int pageNo, String type, String keyword);
// BoardDTO getDetail(Long bno);
BoardFileDTO getDetail(Long bno);
// Long modify(BoardDTO boardDTO);
Long modify(BoardFileDTO boardFileDTO);
void delete(Long bno);
long fileRemove(String uuid);
FileDTO getFile(String uuid);
}
◈ BoardServiceImpl.java
package com.ezen.boot_JPA.service;
import com.ezen.boot_JPA.dto.BoardDTO;
import com.ezen.boot_JPA.dto.BoardFileDTO;
import com.ezen.boot_JPA.dto.FileDTO;
import com.ezen.boot_JPA.entity.Board;
import com.ezen.boot_JPA.entity.File;
import com.ezen.boot_JPA.repository.BoardRepository;
import com.ezen.boot_JPA.repository.FileRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Slf4j
@RequiredArgsConstructor
@Service
public class BoardServiceImpl implements BoardService{
private final BoardRepository boardRepository;
private final FileRepository fileRepository;
@Override
public Long insert(BoardDTO boardDTO) {
// 저장 객체는 Board
// save() : insert 후 저장 객체의 id를 리턴
// save() Entity 객체를 파라미터로 전송
return boardRepository.save(convertDtoToEntity(boardDTO)).getBno();
}
@Transactional
@Override
public long insert(BoardFileDTO boardFileDTO) {
// long bno = boardRepository.save(convertDtoToEntity(boardFileDTO.boardDTO())).getBno();
long bno = insert(boardFileDTO.getBoardDTO());
if (bno > 0 && boardFileDTO.getFileDTOList() != null){
for(FileDTO fileDTO : boardFileDTO.getFileDTOList()){
fileDTO.setBno(bno);
bno = fileRepository.save(convertDtoToEntity(fileDTO)).getBno();
}
}
return bno;
}
// @Override
// public List<BoardDTO> getList() {
// // 컨트롤러로 보내야 하는 리턴은 List<BoardDTO>
// // DB에서 가져오는 리턴은 List<Board> > BoardDTO 객체로 변환
// // findAll()
// // 정렬 : Sort.by(Sort.Direction.DESC, "정렬기준 칼럼명")
// List<Board> boardList = boardRepository.findAll(Sort.by(Sort.Direction.DESC, "bno"));
// /* List<BoardDTO> boardDTOList = new ArrayList<>();
// for(Board board : boardList){
// boardDTOList.add(convertEntityToDto(board));
// }*/
// List<BoardDTO> boardDTOList = boardList.stream()
// .map(b -> convertEntityToDto(b)).toList();
// return boardDTOList;
// }
@Override
public Page<BoardDTO> getList(int pageNo, String type, String keyword) {
// pageNo = 0부터 시작
// 0 => limit 0, 10 / 1 => limit 10, 10
Pageable pageable = PageRequest.of(pageNo, 10,
Sort.by("bno").descending());
// Page<Board> list = boardRepository.findAll(pageable);
// type, keyword, pageable 값을 주고, Page<Board> list 리턴 받는 메서드 생성
Page<Board> list = boardRepository.searchBoard(type, keyword, pageable);
Page<BoardDTO> boardDTOList = list.map(b -> convertEntityToDto(b));
return boardDTOList;
}
@Override
public BoardFileDTO getDetail(Long bno) {
Optional<Board> optional = boardRepository.findById(bno);
if(optional.isPresent()){
BoardDTO boardDTO = convertEntityToDto(optional.get());
// file bno에 일치하는 모든 파일 리스트를 가져오기
// select * from file where bno = #{bno}
List<File> flist = fileRepository.findByBno(bno);
List<FileDTO> fileDTOList = flist.stream()
.map(f -> convertEntityToDto(f)).toList();
BoardFileDTO boardFileDTO = new BoardFileDTO(boardDTO, fileDTOList);
log.info(">>> boardFileDTO >>> {}", boardFileDTO);
return boardFileDTO;
}
return null;
}
@Override
public Long modify(BoardFileDTO boardFileDTO) {
long bno = insert(boardFileDTO);
return bno;
/*Optional<Board> optional = boardRepository.findById(boardFileDTO.getBoardDTO().getBno());
if(optional.isPresent()){
Board board = optional.get();
board.setTitle(boardFileDTO.getBoardDTO().getTitle());
board.setContent(boardFileDTO.getBoardDTO().getContent());
long bno = boardRepository.save(board).getBno();
if (bno > 0 && boardFileDTO.getFileDTOList() != null) {
for (FileDTO fileDTO : boardFileDTO.getFileDTOList()) {
fileDTO.setBno(bno);
bno = fileRepository.save(convertDtoToEntity(fileDTO)).getBno();
}
return bno;
}
}
return 0L;*/
}
/* @Override
public BoardDTO getDetail(Long bno) {
*//* findById : 아이디(PK)를 주고 해당 객체를 리턴
findById의 리턴타입 Optional<Board> 타입으로 리턴
Optional<T> : nullPointException이 발생하지 않도록 도와줌.
Optional.isEmpty() : null일 경우 확인 가능 true / false
Optional.isPresent() : 값이 있는지 확인 true / false
Optional.get() : 객체 가져오기
* *//*
Optional<Board> optional = boardRepository.findById(bno);
if(optional.isPresent()){
BoardDTO boardDTO = convertEntityToDto(optional.get());
return boardDTO;
}
return null;
}*/
// @Override
// public Long modify(BoardDTO boardDTO) {
// // update : jpa는 업데이트가 없음.
// // 기존 객체를 가져와서 set 수정 후 다시 저장
// Optional<Board> optional = boardRepository.findById(boardDTO.getBno());
// if(optional.isPresent()){
// Board entity = optional.get();
// entity.setTitle(boardDTO.getTitle());
// entity.setContent(boardDTO.getContent());
// // 다시 저장 (기존 객체에 덮어쓰기)
// return boardRepository.save(entity).getBno();
// }
// return null;
// }
// 삭제 : deleteById(id)
@Override
public void delete(Long bno) {
boardRepository.deleteById(bno);
}
@Override
public long fileRemove(String uuid) {
Optional<File> optional = fileRepository.findById(uuid);
if(optional.isPresent()){
fileRepository.deleteById(uuid);
return optional.get().getBno();
}
return 0;
}
@Override
public FileDTO getFile(String uuid) {
Optional<File> optional = fileRepository.findById(uuid);
log.info(">>> op >>> {}", optional);
if(optional.isPresent()){
FileDTO fileDTO = convertEntityToDto(optional.get());
return fileDTO;
}
return null;
}
}
◈ BoardRepository.java
package com.ezen.boot_JPA.repository;
import com.ezen.boot_JPA.entity.Board;
import org.springframework.data.jpa.repository.JpaRepository;
/* JpaRepository<테이블, id> */
public interface BoardRepository extends JpaRepository<Board, Long>, BoardCustomRepository {
}
◈ BoardCustomRepository.java
package com.ezen.boot_JPA.repository;
import com.ezen.boot_JPA.entity.Board;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface BoardCustomRepository {
// type, keyword, pageable 값을 주고, Page<Board> list 리턴 받는 메서드 생성
Page<Board> searchBoard(String type, String keyword, Pageable pageable);
}
◈ BoardCustomRepositoryImpl.java
package com.ezen.boot_JPA.repository;
import com.ezen.boot_JPA.entity.Board;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import java.util.List;
import static com.ezen.boot_JPA.entity.QBoard.board;
public class BoardCustomRepositoryImpl implements BoardCustomRepository{
private final JPAQueryFactory queryFactory;
public BoardCustomRepositoryImpl(EntityManager em) {
this.queryFactory = new JPAQueryFactory(em);
}
// 실제 구현
@Override
public Page<Board> searchBoard(String type, String keyword, Pageable pageable) {
// 조건이 많을 경우
// select * from board where
// isDel = 'n' and title like '% aaa %';
// BooleanExpression condition = board.isDel.eq('N')
// condition = condition.and(board.title.containsIgnoreCase(keyword));
BooleanExpression condition = null;
// 동적 검색 조건 추가
if(type != null && keyword != null){
// 타입이 여러 개일 경우 추가되는 작업
String[] typearr = type.split("");
BooleanExpression dynamicCondition = null;
for (String t : typearr){
switch (type) {
case "t":
condition = (condition == null) ?
board.title.containsIgnoreCase(keyword)
: condition.or(board.title.containsIgnoreCase(keyword));
break;
case "w":
condition = (condition == null) ?
board.writer.containsIgnoreCase(keyword)
: condition.or(board.writer.containsIgnoreCase(keyword));
break;
case "c":
condition = (condition == null) ?
board.content.containsIgnoreCase(keyword)
: condition.or(board.content.containsIgnoreCase(keyword));
break;
}
if(dynamicCondition != null){
// condition = condition.and(dynamicCondition);
condition = dynamicCondition;
}
}
// switch (type){
// case "t" :
// condition = board.title.containsIgnoreCase(keyword);
// break;
// case "w" :
// condition = board.writer.containsIgnoreCase(keyword);
// break;
// case "c" :
// condition = board.content.containsIgnoreCase(keyword);
// break;
// case "tw":
// condition = (board.content.containsIgnoreCase(keyword)).or(board.writer.containsIgnoreCase(keyword));
// break;
// }
}
// 쿼리 작성 및 페이징 적용
List<Board> result = queryFactory
.selectFrom(board)
.where(condition)
.orderBy(board.bno.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
// 검색된 데이터의 전체 개수 조회
int total = queryFactory
.selectFrom(board)
.where(condition)
.fetch().size();
// .fetchCount(); => .fetch().size();
return new PageImpl<>(result, pageable, total);
}
}
▷ 출력
'Java > JPA' 카테고리의 다른 글
JPA 기초(security) - AWS 풀스택 과정 85일차 (0) | 2024.11.26 |
---|---|
JPA 기초(file) - AWS 풀스택 과정 84일차 (0) | 2024.11.25 |
JPA 기초(comment) - AWS 풀스택 과정 83일차 (0) | 2024.11.22 |
JPA 설정 및 기초 - AWS 풀스택 과정 82일차 (0) | 2024.11.21 |