관리 메뉴

bright jazz music

[bootBoard] N:1(다대일) 연관관계: 9-4. 프로젝트 적용: 게시물 삭제 처리 본문

Framework/Spring

[bootBoard] N:1(다대일) 연관관계: 9-4. 프로젝트 적용: 게시물 삭제 처리

bright jazz music 2022. 10. 7. 21:18

삭제에 대한 고민

  • 실제 개발에서는 삭제 처리에 대한 고민 필요
  • 댓글이 있는 게시글은 게시물이 삭제될 시 거기에 달린 댓글까지 동의 없이 삭제되기 때문.
  • 따라서 실무에서는 게시물에 상태(state) 칼럼을 지정하고 이를 변경하는 형태로 처리하는 것이 일반적
  • 예를 들면 삭제 처리 시 실제로 삭제되는 것이 아닌 게시글의 상태가 "삭제"로 처리 된다고 할 수 있음.

여기 예제에서는 게시글 삭제 시 게시글과 댓글 모두 삭제된다고 가정한다.

board 테이블에서 데이터 삭제 시 FK로 board 테이블을 참조하는 reply 테이블에서도 삭제가 일어나야 한다.

 

순서1 : 해당 게시물의 모든 댓글 삭제

순서 2: 해당 게시물 삭제

 

이것은 개별 과정이지만 하나의 과정으로 처리되어야 하므로 @Transaction을 사용해야 한다.

 

1. ReplyRepository.java에 댓글 삭제 추상 메서드 추가

ReplyRepository.java

//ReplyRepository.java

package com.example.bootboard.repository;

import com.example.bootboard.entity.Reply;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

public interface ReplyRepository extends JpaRepository<Reply, Long> {
    
    //삭제처리 추가
    @Modifying
    @Query("delete from Reply r where r.board.bno =:bno ")
    void deleteByBno(Long bno);

}

 

 

 

2. BoardService.java에 게시글 삭제 추상 메서드 추가

//BoardService.java



public interface BoardService {

    Long register(BoardDTO dto);

    //getList() : 목록처리
    PageResultDTO<BoardDTO, Object[]> getList(PageRequestDTO pageRequestDTO);

    //조회 처리
    BoardDTO get(Long bno);

    //게시글 삭제 기능 방금 추가
    void removeWithReplies(Long bno);


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

    //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())
                .writerName(member.getName())
                .replyCount(replyCount.intValue()) //long으로 나오므로 int처리
                .build();

        return boardDTO;
    }

}

 

 

3. BoardServiceImpl.java에서 오버라이드

//BoardServiceImpl.java

import org.springframework.transaction.annotation.Transactional;
import java.util.function.Function;

@Service
@RequiredArgsConstructor
@Log4j2
public class BoardServiceImpl implements BoardService {

    private final BoardRepository repository; // 자동 주입 final
    private final ReplyRepository replyRepository; //새롭게 추가

    @Override
    public Long register(BoardDTO dto) {

        log.info(dto);
        Board board =  dtoToEntity(dto);

        repository.save(board);
        return board.getBno();
    }

    //목록처리
    @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]));
                                    //Board board, Member member, Long replyCount

        Page<Object[]> result = repository.getBoardWithReplyCount(
                pageRequestDTO.getPageable(Sort.by("bno").descending()));

        return new PageResultDTO<>(result, fn);
    }

    //게시글 조회 처리
    @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]);

    }

    //게시글 삭제 처리
    @Transactional
    @Override
    public void removeWithReplies(Long bno) {
        //댓글부터 삭제
        replyRepository.deleteByBno(bno);
        
        repository.deleteById(bno);
        
    }
}

 

4. 테스트

우선 댓글이 여러 개 달린 게시글을 DB에서 확인

72번 게시글에 댓글 2개, 73번 게시글에도 댓글 2개

 

//BoardServiceTests.java


@SpringBootTest
public class BoardServiceTests {

    @Autowired
    private BoardService boardService;

    //등록 처리 테스트
    @Test
    public void testRegister() {

        BoardDTO dto = BoardDTO.builder()
                .title("Test.")
                .content("Test ...")
                .writerEmail("user55@aaa.com") //현재 DB에 존재한느 회원 이메일
                .build();

        Long bno = boardService.register(dto);
    }

    //목록 처리 테스트
    @Test
    public void testList() {
        PageRequestDTO pageRequestDTO = new PageRequestDTO();

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

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

    //게시글 조회 처리 테스트
    @Test
    public void testGet() {
        Long bno = 100L;

        BoardDTO boardDTO = boardService.get(bno);

        System.out.println(boardDTO);
    }
    
    //게시글 삭제 처리 테스트 : 방금 추가
    @Test
    public void testRemove(){
        Long bno = 72L;
        boardService.removeWithReplies(bno);
    }

}

 

5. 결과

 

콘솔로그

2022-10-07 23:13:31.042  INFO 5604 --- [    Test worker] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2022-10-07 23:13:31.042  INFO 5604 --- [    Test worker] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2022-10-07 23:13:31.736  WARN 5604 --- [    Test worker] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2022-10-07 23:13:32.298  INFO 5604 --- [    Test worker] c.e.bootboard.service.BoardServiceTests  : Started BoardServiceTests in 3.811 seconds (JVM running for 5.223)
Hibernate: 
    delete 
    from
        reply 
    where
        board_bno=?
Hibernate: 
    select
        board0_.bno as bno1_0_0_,
        board0_.moddate as moddate2_0_0_,
        board0_.reg_date as reg_date3_0_0_,
        board0_.content as content4_0_0_,
        board0_.title as title5_0_0_,
        board0_.writer_email as writer_e6_0_0_ 
    from
        board board0_ 
    where
        board0_.bno=?
Hibernate: 
    delete 
    from
        board 
    where
        bno=?
2022-10-07 23:13:32.521  INFO 5604 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2022-10-07 23:13:32.524  INFO 5604 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2022-10-07 23:13:32.529  INFO 5604 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
BUILD SUCCESSFUL in 19s
4 actionable tasks: 3 executed, 1 up-to-date
오후 11:13:32: Task execution finished ':test --tests "com.example.bootboard.service.BoardServiceTests.testRemove"'.

 

DB

bno가 72인 게시글이 삭제되어 사라짐

 

 

 

 

 

Comments