Project/2023.02~ ) Study toy 프로젝트

프로젝트 적용하기(Board)

shiherlis 2023. 3. 6. 14:26

테스트를 완료했으니 실제 웹 브라우저에서 불러온 데이터를 확인할 수 있도록 프로젝트 적용


1. DTO / 서비스 계층 작성

1) DTO

@Data
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BoardDto {
    private Long bno;
    private String title;
    private String content;
    private String writerEmail; //  작성자 이메일
    private String writerName;  // 작성자 이름
    private LocalDateTime regDate;
    private LocalDateTime modDate;
    private int replyCount;     // 해당 게시글의 댓글 수
}
  • Board 엔티티과의 차이점
    • Member를 참조하지 않음
    • 대신에 작성자 이메일, 작성자 이름으로 처리함
  • BoardDTO를 이용하기 때문에 replyCount 추가

2) Service

BoardDTO 타입을 파라미터로 전달받고, 생성된 번호를 반환하도록 작성

dto to entity

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;
    }
}
@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 null;
    }
}

3) Test 작성

게시글 등록 테스트

@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);
    }
}

 

DB에 게시글 추가된 것 확


2. 게시물 목록처리

PageRequestDTO / PageResultDTO 사용

1) BoardService 

PageResultDTO<BoardDTO, Object[]> getList(PageRequestDTO pageRequestDTO);   // 목록처리
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())
            .writerName(member.getName())
            .replyCount(replyCount.intValue())  //long으로 나오므로 int로 바꿔줌
            .build();
    
    return boardDTO;
}

2) BoardServiceImpl

@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);
}
  • DB에서 Entity 형태로 받아온 값을 파라미터로 
    entityToDTO() 에 넣어서 배열 형태로 fn 반환
  • PageResultDTO 함수에 담아서 반환

3) BoardServiceTest

@Test
public void testList(){
    PageRequestDTO pageRequestDTO = new PageRequestDTO();

    PageResultDTO<BoardDTO, Object[]> result = boardService.getList(pageRequestDTO);

    for(BoardDTO boardDTO : result.getDtoList()){
        System.out.println(boardDTO);
    }
}

테스트 실행 결과

  • BoardDTO 객체 내에 목록 화면에 필요한 10개의 BoardDTO 객체 생성 및 목록처리 필요한 내용 삽입

3. 게시글 조회 처리

1) Service/ServiceImpl

BoardDTO get(Long bno);
@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]);
}

2) Test

@Test
public void testGet(){
    Long bno = 100L;

    BoardDTO boardDTO = boardService.get(bno);

    System.out.println(boardDTO);
}

  • bno = 100 인 게시물을 가져옴

4. 게시물 삭제 처리

  • 게시물의 삭제를 위해서는 외래키로 게시물을 참조하고 있는 reply 테이블도 함께 삭제해야 함
  1. 해당 게시물의 모든 댓글 삭제
  2. 해당 게시물 삭제
  3. 두 작업은 하나의 트랜잭션으로 처리

1) ReplyRepository

public interface ReplyRepository extends JpaRepository<Reply, Long> {
    @Modifying
    @Query("delete from Reply r where r.board.bno = :bno ")
    void deleteByBno(Long bno);
}
  • 특정 게시물 번호를 받아 해당하는 댓글을 삭제하는 기능 추가
  • JPQL을 통해 update/delete 실행시 @Modifying 어노테이션 필요

2) BoardService/ ServiceImpl

void removeWithReplies(Long bno);   // 삭제 기능
 private final ReplyRepository replyRepository;
 
 @Transactional
    @Override
    public void removeWithReplies(Long bno) {
        // 댓글부터 삭제
        replyRepository.deleteByBno(bno);

        repository.deleteById(bno);
    }
  • 삭제 기능 추가
  • ReplyRepository를 주입받음
  • @Transactional 어노테이션 사용

3) Test

@Test
public void testRemove(){
    Long bno = 1L;

    boardService.removeWithReplies(bno);
}

 

testRemove 실행 전
testRemove 실행 후

  • bno = 1 인 댓글 3개 모두 삭제 확인

5. 게시물 수정 처리

  • BoardRepository 의 save() 를 이용하여 처리
  • 제목(title) 과 내용(content)만 수정 가능하도록 구현

1) Board 엔티티

public void changeTitle(String title){
    this.title = title;
}

public void changeContent(String content){
    this.content = content;
}
  • 기존의 setter() 를 대신 생성해주는 느낌
  • dto.getTitle() / dto.getContent() 를 통해 사용자로부터 받은 새 제목,내용을 받아 ( 데이터 가공 )
    엔티티에서 CRUD만 담당하도록 함
  • 엔티티는 DB와 연결된 중요한 데이터이므로 데이터에 쉽게 접근하지 못하도록 @Setter 어노테이션을 사용하지 않고
    dto에서는 변경된 값을 받아와  등록(save)하는 역할만 담당 

2) Service/ServiceImpl

void modify(BoardDTO boardDTO);
@Transactional 
@Override
public void modify(BoardDTO boardDTO) {

    Board board = repository.getOne(boardDTO.getBno());

    board.changeTitle(boardDTO.getTitle());
    board.changeContent(boardDTO.getContent());

    repository.save(board);
}
  • getOne() 
    • findById() 대신 이용
    • 지연 로딩 방식

💡@Transactional 어노테이션 미기재시 LazyInitializationExeption 오류 발생

3) Test

@Test
public void testModify(){
    BoardDTO boardDTO = BoardDTO.builder()
            .bno(2L)
            .title("제목 변경")
            .content("내용 변경")
            .build();
    
    boardService.modify(boardDTO);
}

  • 기존 DB에 있던 글을 가져온 다음, 새로운 제목/내용으로 update