-
코드로 배우는 스프링부트 웹 프로젝트 Day 15Spring/코드로 배우는 스프링부트 웹 프로젝트 2022. 9. 19. 09:56
/* Annotation들은 스프링부트 프로젝트의 Annotation 정리 페이지에 따로 정리해두었습니다. */
[ 게시물 등록 ]
게시물 등록은 BoardDTO 타입을 파라미터로 전달받고, 생성된 게시물의 번호를 반환하도록 작성
실제 처리 과정에서 DTO를 엔티티 타입으로 변환할 필요가 있음 => BoardService 인터페이스에 dtoToEntity()를 작성해서 처리
BoardService 인터페이스
public interface BoardService { Long register(BoardDTO dto); default Board dtoToEntity(BoardDTO dto) { Member member = Member.builder().email(dto.getWriterEmail()).build(); Board board = Board.builder() .bno(dto.getBno()) .title(dto.getTitle()) .content(dto.getContent()) .writer(member) .build(); return board; } }
dtoToEntity() 는 DTO가 연관관계를 가진 Board엔티티 객체와 Member 엔티티 객체를 구성해야하기 때문에 내부적으로 Member 엔티티 객체를 처리하는 과정을 거쳐야 함
BoardServiceImpl 클래스
package org.zerock.board2.service; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; import org.zerock.board2.dto.BoardDTO; import org.zerock.board2.entity.Board; import org.zerock.board2.repository.BoardRepository; @Service @RequiredArgsConstructor @Log4j2 public class BoardServiceImpl implements BoardService{ private final BoardRepository repository; // 자동 주입 final @Override public Long register(BoardDTO dto) { log.info(dto); Board board = dtoToEntity(dto); repository.save(board); return board.getBno(); } }
BoardDTO를 dtoToEntity()로 Board 엔티티 객체로 만들어 BoardRepository에 save() 한다.
test 폴더에 service 패키지를 생성하고 BoardServiceTests 클래스 생성
BoardServiceTests 클래스
package org.zerock.board2.service; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.zerock.board2.dto.BoardDTO; @SpringBootTest public class BoardServiceTests { @Autowired private BoardService boardService; @Test public void testRegister() { BoardDTO dto = BoardDTO.builder() .title("Test.") .content("Test...") .writerEmail("user55@aaa.com") // 현재 데이터베이스에 존재하는 회원 이메일 .build(); Long bno = boardService.register(dto); } }
[ 게시물 목록 처리 ]
게시물의 목록 처리는 이전 장에서 만들었던 PageRequestDTO와 PageResultDTO를 그대로 사용함
[ Object[] 을 DTO로 변환하기 ]
PageRequestDTO 클래스
package org.zerock.board2.dto; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @Builder @AllArgsConstructor @Data public class PageRequestDTO { private int page; private int size; private String type; private String keyword; public PageRequestDTO() { this.page = 1; this.size = 10; } public Pageable getPageable(Sort sort) { return PageRequest.of(page -1, size, sort); } }
PageResultDTO 클래스
package org.zerock.board2.dto; import lombok.Data; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @Data public class PageResultDTO<DTO, EN> { //DTO리스트 private List<DTO> dtoList; //총 페이지 번호 private int totalPage; //현재 페이지 번호 private int page; //목록 사이즈 private int size; //시작 페이지 번호, 끝 페이지 번호 private int start, end; //이전, 다음 private boolean prev, next; //페이지 번호 목록 private List<Integer> pageList; public PageResultDTO(Page<EN> result, Function<EN, DTO> fn) { dtoList = result.stream().map(fn).collect(Collectors.toList()); totalPage = result.getTotalPages(); makePageList(result.getPageable()); } private void makePageList(Pageable pageable) { this.page = pageable.getPageNumber() + 1; // 0 부터 시작하므로 1 추가 this.size = pageable.getPageSize(); //temp end page int tempEnd = (int)(Math.ceil(page/10.0)) * 10; start = tempEnd - 9; prev = start > 1; end = totalPage > tempEnd ? tempEnd: totalPage; next = totalPage > tempEnd; pageList = IntStream.rangeClosed(start, end).boxed().collect(Collectors.toList()); } }
PageResultDTO의 핵심은 JPQL의 결과로 나오는 Object[]을 DTO타입으로 변환하는 기능
이 기능은 java.util.Function을 이용해서 작성함
이때, JPQL의 실행 결과로 나오는 Object[]을 BoardDTO로 처리해주어야 함
*java.util.function.Function
function패키지의 Function 인터페이스
Function<T, R>으로 정의되어 있어, Generic 타입을 두 개 갖고있음
T는 입력 타입, R은 리턴 타입을 의미
즉, 타입 변환을 할 때 주로 사용
Object[]의 내용은 Board와 Member, 댓글의 수는 Long 타입으로 나오게 되므로 이를 파라미터로 전달 받아서 BoardDTO를 구성하도록 작성해야 함
이 기능은 BoardService 인터페이스에 entityToDTO()라는 메서드를 작성해서 처리
BoardService 인터페이스 추가
//BoardService 인터페이스에 추가하는 entityToDTO() default BoardDTO entityToDTO(Board board, Member member, Long replyCount) { BoardDTO boardDTO = BoardDTO.builder() .bno(board.getBno()) .title(board.getTitle()) .content(board.getContent()) .regDate(board.getRegDate()) .modDate(board.getModDate()) .writerEmail(member.getEmail()) .replyCount(replyCount.intValue()) //long으로 나오므로 int로 처리하도록 함 .build(); return boardDTO; }
default 접근 제어자를 사용하여 동일한 패키지 내에서만 접근이 가능한 entityToDTO 메소드를 만듦
BookService 인터페이스에 목록 처리를 하는 getList() 메소드 선언
PageResultDTO<BoardDTO, Object[]> getList(PageRequestDTO pageRequestDTO); //목록 처리
BookServiceImpl 클래스 추가
@Override public PageResultDTO<BoardDTO, Object[]> getList(PageRequestDTO pageRequestDTO) { log.info(pageRequestDTO); Function<Object[], BoardDTO> fn = (en -> entityToDTO((Board) en[0], (Member) en[1], (Long) en[2])); Page<Object[]> result = repository.getBoardWithReplyCount( pageRequestDTO.getPageable(Sort.by("bno").descending())); return new PageResultDTO<>(result, fn); }
getList() 메소드를 만들어 entityToDTO()를 이용하여 PageResultDTO 객체를 만들어 리턴하도록 했음
[ 목록 처리 테스트 ]
getList() 가 정상적으로 작동하는지 확인하는 test 코드를 만들 것이다.
BoardSericeTests 클래스 추가
@Test public void testList() { PageRequestDTO pageRequestDTO = new PageRequestDTO(); PageResultDTO<BoardDTO, Object[]> result = boardService.getList(pageRequestDTO); for (BoardDTO boardDTO : result.getDtoList()) { System.out.println(boardDTO); } }
위 테스트 코드를 실행시킨 결과, 목록의 한 화면에 필요한 10개의 BoardDTO 객체가 정상적으로 만들어진 것을 확인할 수 있음
[ 게시물 조회 처리 ]
게시물의 조회는 파라미터로 게시물의 번호(bno)를 파라미터로 받아서 처리하도록 BoardService와 BoardServiceImpl 클래스에 get() 메서드를 추가해서 작성
BoardService 인터페이스 추가
public interface BoardService { Long register(BoardDTO dto); PageResultDTO<BoardDTO, Object[]> getList(PageRequestDTO pageRequestDTO); //목록 처리 BoardDTO get(Long bno);
BoardServiceImpl 클래스 추가
@Override public BoardDTO get(Long bno) { Object result = repository.getBoardByBno(bno); Object[] arr = (Object[])result; return entityToDTO((Board) arr[0], (Member) arr[1], (Long) arr[2]); }
getBoardByBno()를 이용해서 Board 엔티티, Member엔티티, 댓글의 수를 가져온다.
'Spring > 코드로 배우는 스프링부트 웹 프로젝트' 카테고리의 다른 글
코드로 배우는 스프링부트 웹 프로젝트 Day 17 (0) 2022.11.11 코드로 배우는 스프링부트 웹 프로젝트 Day 16 (0) 2022.09.21 코드로 배우는 스프링부트 웹 프로젝트 Day 14 (0) 2022.09.14 코드로 배우는 스프링부트 웹 프로젝트 Day 13 (0) 2022.09.12 코드로 배우는 스프링부트 웹 프로젝트 Day 12 (0) 2022.09.07