Service : Business Logic을 담당하는 부분이며 DB로부터 데이터를 받거나 전달해주는 역할을 한다.
++ 추가 설명
@Controller | Handler가 Scan 할 수 있는 Bean 객체가 되어 Servlet용 컨테이너에 생성된다. |
@Service, @Repository | 해당 Class를 루트 컨테이너에 Bean 객 체로 생성 |
BoardService : 게시판 Service
CustomOAuth2Service : SpringSecurity로 OAuth2 Google Login 관련 Service
** shop.pingping2.board.service.CustomOAuth2Service는 추후 SpringSecurity 부분에서 설명 **
shop.pingping2.board.service.BoardService.java
package shop.pingping2.board.service;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import shop.pingping2.board.domain.Board;
import shop.pingping2.board.repository.BoardRepository;
import shop.pingping2.board.dto.BoardDto;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@AllArgsConstructor
@Service
public class BoardService {
//boardRepository 객체 생성
private BoardRepository boardRepository;
private static final int BLOCK_PAGE_NUM_COUNT = 5; // 블럭에 존재하는 페이지 번호 수
private static final int PAGE_POST_COUNT = 4; // 한 페이지에 존재하는 게시글 수
// Entity -> Dto로 변환
private BoardDto convertEntityToDto(Board board) {
return BoardDto.builder()
.id(board.getId())
.title(board.getTitle())
.content(board.getContent())
.writer(board.getWriter())
.createdDate(board.getCreatedDate())
.modifiedDate(board.getModifiedDate())
.build();
}
@Transactional
public List<BoardDto> getBoardlist(Integer pageNum) {
Page<Board> page = boardRepository.findAll(PageRequest.of(
pageNum - 1, PAGE_POST_COUNT, Sort.by(Sort.Direction.ASC, "createdDate")));
List<Board> boardEntities = page.getContent();
List<BoardDto> boardDtoList = new ArrayList<>();
for (Board board : boardEntities) {
boardDtoList.add(this.convertEntityToDto(board));
}
return boardDtoList;
}
@Transactional
public BoardDto getPost(Long id) {
// Optional : NPE(NullPointerException) 방지
Optional<Board> boardWrapper = boardRepository.findById(id);
Board board = boardWrapper.get();
BoardDto boardDTO = BoardDto.builder()
.id(board.getId())
.title(board.getTitle())
.content(board.getContent())
.writer(board.getWriter())
.createdDate(board.getCreatedDate())
.modifiedDate(board.getModifiedDate())
.build();
return boardDTO;
}
@Transactional
public Long savePost(BoardDto boardDto) {
return boardRepository.save(boardDto.toEntity()).getId();
}
@Transactional
public void deletePost(Long id) {
boardRepository.deleteById(id);
}
// 검색 API
@Transactional
public List<BoardDto> searchPosts(String keyword) {
List<Board> boardEntities = boardRepository.findByTitleContaining(keyword);
List<BoardDto> boardDtoList = new ArrayList<>();
if (boardEntities.isEmpty()) return boardDtoList;
for (Board board : boardEntities) {
boardDtoList.add(this.convertEntityToDto(board));
}
return boardDtoList;
}
// 페이징
@Transactional
public Long getBoardCount() {
return boardRepository.count();
}
public Integer[] getPageList(Integer curPageNum) {
Integer[] pageList = new Integer[BLOCK_PAGE_NUM_COUNT];
// 총 게시글 갯수
Double postsTotalCount = Double.valueOf(this.getBoardCount());
// 총 게시글 기준으로 계산한 마지막 페이지 번호 계산 (올림으로 계산)
Integer totalLastPageNum = (int)(Math.ceil((postsTotalCount/PAGE_POST_COUNT)));
// 현재 페이지를 기준으로 블럭의 마지막 페이지 번호 계산
Integer blockLastPageNum = (totalLastPageNum > curPageNum + BLOCK_PAGE_NUM_COUNT)
? curPageNum + BLOCK_PAGE_NUM_COUNT
: totalLastPageNum;
// 페이지 시작 번호 조정
curPageNum = (curPageNum <= 3) ? 1 : curPageNum - 2;
// 페이지 번호 할당
for (int val = curPageNum, idx = 0; val <= blockLastPageNum; val++, idx++) {
pageList[idx] = val;
}
return pageList;
}
}
먼저 Paging 관련된 부분을 설명
@Transactional
public List<BoardDto> getBoardlist(Integer pageNum) {
Page<Board> page = boardRepository.findAll(PageRequest.of(
pageNum - 1, PAGE_POST_COUNT, Sort.by(Sort.Direction.ASC, "createdDate")));
List<Board> boardEntities = page.getContent();
List<BoardDto> boardDtoList = new ArrayList<>();
for (Board board : boardEntities) {
boardDtoList.add(this.convertEntityToDto(board));
}
return boardDtoList;
}
페이징을 할 수 있도록 구현
repository의 find() 관련 메서드를 호출할 때 Pageable 인터페이스를 구현한 Class(PageRequest.of())를 전달하면 Paging을 할 수 있다.
첫 번째와 두 번째 인자로 page와 size를 전달하고, 세 번째 인자로 정렬 방식을 결정하였다.
(createdDate 기준으로 오름차순 할 수 있도록 설정한 부분이다.)
=> 반환된 Page 객체의 getContent() 메서드를 호출하면, Entity를 List 형태로 꺼내올 수 있다. 이를 DTO로 Controller에게 전달하게 된다.
// 페이징
@Transactional
public Long getBoardCount() {
return boardRepository.count();
}
전체 게시글 개수를 가져온다.
// 페이징
@Transactional
public Long getBoardCount() {
return boardRepository.count();
}
public Integer[] getPageList(Integer curPageNum) {
Integer[] pageList = new Integer[BLOCK_PAGE_NUM_COUNT];
// 총 게시글 갯수
Double postsTotalCount = Double.valueOf(this.getBoardCount());
// 총 게시글 기준으로 계산한 마지막 페이지 번호 계산 (올림으로 계산)
Integer totalLastPageNum = (int)(Math.ceil((postsTotalCount/PAGE_POST_COUNT)));
// 현재 페이지를 기준으로 블럭의 마지막 페이지 번호 계산
Integer blockLastPageNum = (totalLastPageNum > curPageNum + BLOCK_PAGE_NUM_COUNT)
? curPageNum + BLOCK_PAGE_NUM_COUNT
: totalLastPageNum;
// 페이지 시작 번호 조정
curPageNum = (curPageNum <= 3) ? 1 : curPageNum - 2;
// 페이지 번호 할당
for (int val = curPageNum, idx = 0; val <= blockLastPageNum; val++, idx++) {
pageList[idx] = val;
}
return pageList;
}
- 하나의 Page : 4개의 게시글
- 총 5개의 번호를 노출
번- 호를 5개 채우지 못하면 (게시글이 20개가 되지 않으면) 존재하는 번호까지만 노출
private static final int BLOCK_PAGE_NUM_COUNT = 5; // 블럭에 존재하는 페이지 번호 수
private static final int PAGE_POST_COUNT = 4; // 한 페이지에 존재하는 게시글 수
후에 이런 식으로 Pagination이 수행된다.
// Entity -> Dto로 변환
private BoardDto convertEntityToDto(Board board) {
return BoardDto.builder()
.id(board.getId())
.title(board.getTitle())
.content(board.getContent())
.writer(board.getWriter())
.createdDate(board.getCreatedDate())
.modifiedDate(board.getModifiedDate())
.build();
}
Builder 패턴으로 Entity를 Dto로 변환해주는 Method이다.
@Transactional
public BoardDto getPost(Long id) {
// Optional : NPE(NullPointerException) 방지
Optional<Board> boardWrapper = boardRepository.findById(id);
Board board = boardWrapper.get();
BoardDto boardDTO = BoardDto.builder()
.id(board.getId())
.title(board.getTitle())
.content(board.getContent())
.writer(board.getWriter())
.createdDate(board.getCreatedDate())
.modifiedDate(board.getModifiedDate())
.build();
return boardDTO;
}
boardRepository의 findById(id) 메서드로 board 게시글 내용을 가져온 뒤
-> builder() 메서드를 활용하여 boardDTO 객체로 만들고
-> boadrDTO를 리턴 밸류로 전달해준다.
@Transactional
public Long savePost(BoardDto boardDto) {
return boardRepository.save(boardDto.toEntity()).getId();
}
boardRepository의 save 메서드를 사용하여 데이터를 저장한다.
그 뒤에 getter를 활용하여 Id를 받아오고 return 밸류를 전달해준다.
@Transactional
public void deletePost(Long id) {
boardRepository.deleteById(id);
}
deleteById 메서드로 게시글 삭제
// Repository에서 검색 결과를 받아와 비즈니스 로직을 실행하는 함수
@Transactional
public List<BoardDto> searchPosts(String keyword) {
List<Board> boardEntities = boardRepository.findByTitleContaining(keyword);
List<BoardDto> boardDtoList = new ArrayList<>();
if (boardEntities.isEmpty()) return boardDtoList;
for (Board board : boardEntities) {
boardDtoList.add(this.convertEntityToDto(board));
}
return boardDtoList;
}
사용자가 Front에서 keyword를 검색하면 Controller로부터 keyword를 전달받게 된다.
이 Keyword가 Entity 내에 있는지 확인하는 Method이다.
있을 경우, boardEntities를 for loop 돌아서 boardDtoList에 Element를 추가한 뒤 boardDtoList를 Controller에게 전달해주고, 없을 경우 빈 Array를 전달해준다.
Ref
'Programming > SpringBoot' 카테고리의 다른 글
[SpringBoot] 간단한 게시판 만들기 #7 - Thymeleaf를 사용한 Fornt view 구현 (5) | 2022.01.03 |
---|---|
[SpringBoot] 간단한 게시판 만들기 #6 - SpringSecurity 개념 및 구현 (2) | 2022.01.03 |
[SpringBoot] 간단한 게시판 만들기 #4 - DTO, Repository 구현 (0) | 2022.01.03 |
[SpringBoot] 간단한 게시판 만들기 #3 - domain(Entity) 구현 (0) | 2022.01.03 |
[SpringBoot] 간단한 게시판 만들기 #2 - Controller 구현 (1) | 2022.01.03 |