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