ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 코드로 배우는 스프링부트 웹 프로젝트 Day 15
    Spring/코드로 배우는 스프링부트 웹 프로젝트 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);
    
        }
    }
    

    Board 엔티티에 데이터가 추가된 것을 확인

     

     

    [ 게시물 목록 처리 ]

     

    게시물의 목록 처리는 이전 장에서 만들었던 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엔티티, 댓글의 수를 가져온다.

     

     

     

     

     

     

     

Designed by Tistory.