Spring/코드로 배우는 스프링부트 웹 프로젝트

코드로 배우는 스프링부트 웹 프로젝트 Day 16

한 면만 쓴 종이 2022. 9. 21. 00:07

/* Annotation들은 스프링부트 프로젝트의 Annotation 정리 페이지에 따로 정리해두었습니다. */

 

[ 게시물 조회 테스트 ]

 

BoardServiceTests 클래스 추가

@Test
public void testGet() {

    Long bno = 100L;

    BoardDTO boardDTO = boardService.get(bno);

    System.out.println(boardDTO);

}

 

 

[ 게시물 삭제 처리 ]

 

게시물을 지우는 상황에서 게시물에 댓글이 없다면, 게시물의 작성자가 삭제하면 문제가 없지만, 게시물에 댓글이 있다면, 해당 댓글의 사용자들의 동의 없이 삭제되기 때문에 문제가 발생함

=> 실제 개발에서는 게시물의 상태를 칼럼으로 지정하고, 해당 상태를 변경하는 형태로 처리하는 것이 일반적인 방식

 

하지만, 예제에서는 이를 고민하지 않고 게시물을 삭제할 수 있도록 한다고 한다..

 

게시물을 삭제할 때, FK로 게시물을 참조하고 있는 reply 테이블도 삭제해야만 함

따라서, 게시물의 댓글들을 삭제하고, 게시물을 삭제하는 순서로 진행되어야 하며, 위 작업이 하나의 트랜잭션으로 처리되어야 함

 

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 을 같이 추가해야 함

 

 

BoardService 인터페이스 추가

public interface BoardService {

    Long register(BoardDTO dto);

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

    BoardDTO get(Long bno);
    
    void removeWithReplies(Long bno); // 삭제기능
    
    ```
}

 

BoardServiceImpl 클래스 수정

public class BoardServiceImpl implements BoardService{

    private final BoardRepository repository; // 자동 주입 final

    private final ReplyRepository replyRepository;
    
    ```
    
    @Transactional
    @Override
    public void removeWithReplies(Long bno) { // 삭제 기능 구현, 트랜잭션 추가

        // 댓글부터 삭제
        replyRepository.deleteByBno(bno);

        repository.deleteById(bno);
    }
}

 

[ 삭제 테스트 ]

 

BoardServiceTests 클래스 추가

@Test
public void testRemove() {

    Long bno = 1L;

    boardService.removeWithReplies(bno);

}

1번 게시글의 댓글들을 삭제하도록 하는 테스트

 

reply 테이블이 먼저 삭제되고, board 테이블을 조회한 후에 삭제됨

 

 

[ 게시물 수정 처리 ]

게시물의 수정은 제목과 내용에 한해서 수정이 가능하도록 설정

필요한 부분만 변경하고 BoardRepository의 save()를 이용해서 처리

 

Board 클래스 추가

@ManyToOne(fetch = FetchType.LAZY) // 명시적으로 Lazy 로딩 지정
private Member writer; // 연관관계 지정

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

public void changeContent(String content) {
    this.content = content;
}

 

 

BoardService 인터페이스 추가

public interface BoardService {
    ```
    void modify(BoardDTO boardDTO);
}

 

BoardServiceImpl 클래스 추가

@Override
public void modify(BoardDTO boardDTO) {

    Board board = repository.findById(boardDTO.getBno()).get();

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

    repository.save(board);

}

BoardDTO를 받아 데이터를 수정하는 modify 메소드 구현

 

 

BoardServiceTests 추가

@Test
public void testModify() {

    BoardDTO boardDTO = BoardDTO.builder()
            .bno(2L)
            .title("제목 변경합니다.")
            .content("내용 변경합니다.")
            .build();

    boardService.modify(boardDTO);
}

원래 Board 객체를 조회하고 update문이 실행됨

 

 

[ 컨트롤러와 화면 처리 ]

PageRequestDTO와 PageResultDTO를 동일하게 처리했기 때문에 이전 장에서 작성한 코드를 거의 그대로 사용 가능

 

controller 패키지 추가 + BoardController 클래스 작성

 

BoardController 클래스

package org.zerock.board2.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.zerock.board2.service.BoardService;

@Controller
@RequestMapping("/board/")
@Log4j2
@RequiredArgsConstructor
public class BoardController {
    
    private final BoardService boardService;
}