✨ Feat: 게시글 상세 조회 기능 구현#146
Conversation
- 게시글 ID 기반 상세 조회 API 구현 - 게시글 조회 서비스 로직 구성 및 비즈니스 처리 추가 - Entity → Response DTO 매핑 로직 구현 - 조회 시 예외 처리 및 유효성 검증 로직 추가 Closes DoDo-Project#145
WhiteBin-bin
left a comment
There was a problem hiding this comment.
리뷰 남겼으니깐 그거 보고 수정해서 올려줘 그리고 cd도 돌아가는지 act로 확인하고 올려줘야해
| value = "{\"status\": 500, \"message\": \"서버 내부 오류가 발생했습니다.\"}"))) | ||
| }) | ||
| @GetMapping("/{boardId}") | ||
| public ResponseEntity<BoardResponse.BoardDetailResponse> getBoardDetail( |
| .boardId(board.getBoardId()) | ||
| .boardTitle(board.getBoardTitle()) | ||
| .boardContent(board.getBoardContent()) | ||
| .imageFileUrl(null) |
There was a problem hiding this comment.
게시글 상세 조회인데 imageFileUrl은 왜 null이야?? 그러면 이미지는 안오는거야?
| * | ||
| * @param boardId 게시글 ID | ||
| * @return 게시글 상세 조회 응답 DTO | ||
| */ |
| @Transactional(readOnly = true) | ||
| public BoardResponse.BoardDetailResponse getBoardDetail(Long boardId) { | ||
|
|
||
| Board board = getBoardById(boardId); |
There was a problem hiding this comment.
static import 이것도 적용해줘
- 게시글 상세 조회 응답에 imageFileUrl 반영 - BoardService static import 적용 - BoardServiceImpl static import 적용 DoDo-Project#146 코드 리뷰 반영
| .boardId(board.getBoardId()) | ||
| .boardTitle(board.getBoardTitle()) | ||
| .boardContent(board.getBoardContent()) | ||
| .imageFileUrl(imageFileUrl) |
WhiteBin-bin
left a comment
There was a problem hiding this comment.
이번에 바꿔야할거 굉장히 많으니까 다 읽어보고 해줘
| * | ||
| * @param boardId 게시글 ID | ||
| * @return 게시글 상세 조회 응답 DTO | ||
| */ |
| @Transactional(readOnly = true) | ||
| public BoardResponse.BoardDetailResponse getBoardDetail(Long boardId) { | ||
|
|
||
| Board board = getBoardById(boardId); |
| * @param imageFileUrl 이미지 URL | ||
| * @return 수정된 row 수 | ||
| */ | ||
| @Modifying(clearAutomatically = true, flushAutomatically = true) |
There was a problem hiding this comment.
우리 CRUD에서 U랑 동적 쿼리는 MyBatis쓰기로 해서 JPQL로 하면 안됨 수정좀
There was a problem hiding this comment.
@Modifying(clearAutomatically = true, flushAutomatically = true) 그리고 이런거 금지 왠만하면 저런거는 너무 하드해서 안쓰는게 맞음 함부로 건드렸다가 사용법 몰라서 터짐
| * @param originalFilename 원본 파일명 | ||
| * @return 저장된 row 수 | ||
| */ | ||
| @Modifying(clearAutomatically = true, flushAutomatically = true) |
There was a problem hiding this comment.
이것도 그냥 JpaRepository 기능 중 하나인 save() 메서드 써야지 그냥 이미지 파일 정보 저장하는건데
There was a problem hiding this comment.
@Modifying(clearAutomatically = true, flushAutomatically = true) 얘도 이런거 금지
| * @param boardId 게시글 ID | ||
| * @return 게시글 대표 이미지 URL | ||
| */ | ||
| @Query(value = """ |
There was a problem hiding this comment.
이거는 조인도 안하는데 굳이 쿼리문 쓸 이유가 없어보임 Jpa Repository껄로 처리 가능함
There was a problem hiding this comment.
Optional<ImageFile> findFirstByBoardIdOrderByCreatedAtAsc(Long boardId); 이런식으로 가능함
| @@ -127,4 +174,28 @@ private String detectMimeType(MultipartFile file) { | |||
| throw new UserException(INVALID_REQUEST); | |||
There was a problem hiding this comment.
이거 UserService로 이관해서 유저에서 에러 처리하는걸로 해줘 이거 UserException이라서
| * @param boardId 게시글 ID | ||
| * @param imageFileUrl 이미지 URL | ||
| */ | ||
| private void saveBoardImage(Long boardId, String imageFileUrl) { |
There was a problem hiding this comment.
이 메서드의 존재 의의를 모르겠음 애초에 그냥 save 하는거 하면 되는데 update를 왜 하는건지 모르겠음
| private UserService userService; | ||
|
|
||
| @Mock | ||
| private ImageFileService imageFileService; // ⭐ 추가 |
There was a problem hiding this comment.
별 주석 지워줭 테스트에만 주석 다는거긴한데 // when // given // then 말고는 달지 말아줘
| assertEquals(BoardStatus.PUBLISHED, board.getBoardStatus()); | ||
| assertEquals(BoardType.FREE, board.getBoardType()); | ||
| assertEquals(0, board.getViewCount()); | ||
| // ⭐ 추가 검증 |
|
|
||
| given(boardRepository.findById(boardId)).willReturn(Optional.of(board)); | ||
|
|
||
| // ⭐ 추가 |
- 게시글 이미지 저장 로직을 JPA saveAll() 방식으로 변경 - 이미지 URL optional 처리 (null/empty 허용) - orElse(null) 제거 및 Optional 처리 방식 개선 - 불필요한 return 제거 및 예외 처리 보완 DoDo-Project#146 코드 리뷰 반영
|
|
||
| Board board = getBoardById(boardId); | ||
|
|
||
| String imageFileUrl = imageFileRepository.findFirstByBoard_BoardIdOrderByImageFileCreatedAtAsc(boardId) |
There was a problem hiding this comment.
ImageFileService에서 저 메서드를 사용하는 함수를 만들어서 가져오는게 맞음 각 도메인 별 분리가 그럼 의미가 없어
| /** | ||
| * 이미지 파일 저장 / 조회를 위한 Repository | ||
| */ | ||
| private final ImageFileRepository imageFileRepository; |
There was a problem hiding this comment.
이거를 ImageFileService로 갖고와야지 왜냐면 도메인이 분리가 되야하니깐 그러고 그 service안에 그 레포지토리 불러서 가져오는 함수를 만들고
|
|
||
| Board savedBoard = boardRepository.save(board); | ||
|
|
||
| saveBoardImages(savedBoard, request.getImageFileUrls()); |
There was a problem hiding this comment.
이 부분이 이해가 안됨 게시글 ID로 게시글 엔티티 조회라고 해놨는데 왜 갑자기 뜬금없이 save가 되는지 모르겠음.
| * | ||
| * @param boardId 게시글 ID | ||
| */ | ||
| private void validateBoardId(Long boardId) { |
There was a problem hiding this comment.
만약에 외부 함수에서 게시글 ID를 검증하는게 필요하다면 이렇게 따로 빼서 하는게 맞고 아니면 지우는게 맞음
| */ | ||
| private void saveBoardImages(Board board, List<String> imageFileUrls) { | ||
|
|
||
| if (board == null) { |
There was a problem hiding this comment.
이 부분도 아까 위에부분을 만들었으면 굳이 따로 또 한번 더 만들 필요가 없음 이 부분 생각해서 만들어주면 좋을거 같음 바로 위 리뷰보고
| * @param imageFileUrl 이미지 URL | ||
| * @return 추출된 파일명 | ||
| */ | ||
| private String extractOriginalFilename(String imageFileUrl) { |
|
|
||
| @OneToOne(fetch = FetchType.LAZY) | ||
| @JoinColumn(name = "pet_id", nullable = false, unique = true) | ||
| @JoinColumn(name = "pet_id", unique = true) |
There was a problem hiding this comment.
board랑 pet은 nullable해야지 null이 들어가도 되지 왜냐면 imageFile이 pet인지 board인지 둘중 하나만 저장해야되잖아 이거 수정해줘
There was a problem hiding this comment.
unique 넣으면 같은 키가 있는거는 들어오면 안되는거니깐 저거는 잘한듯
|
|
||
| if (files == null || files.isEmpty()) { | ||
| throw new UserException(INVALID_REQUEST); | ||
| throw new UserException(UserErrorCode.INVALID_REQUEST); |
There was a problem hiding this comment.
이거 UserException이니깐 User에서 처리하던가 아니면 Image쪽도 커스텀 에러 정의해서 처리해줘 자꾸 도메인이 분리가 안되는데 도메인 분리는 철저하게 해줘야해
| private String uploadSingleImage(MultipartFile file) { | ||
| if (file == null || file.isEmpty()) { | ||
| throw new UserException(INVALID_REQUEST); | ||
| throw new UserException(UserErrorCode.INVALID_REQUEST); |
| log.info("이미지가 포함된 게시글 작성 성공 테스트를 시작합니다."); | ||
|
|
||
| // given | ||
| // Given: 게시글 작성 요청 데이터와 인증 사용자 정보를 준비합니다. |
There was a problem hiding this comment.
//given만 적어 뒤에 말 주저리 안적어도 됨 자바독으로 적잖아 우리가 주석을 안다는이유는 자바독으로 깔끔하게 만들어서 나중에 그 메서드에 마우스 커서만 올려놔도 보이게 만드는게 목적이야 주석은 // when, // given, // then 이것만 적는거야
📄 작업 내용 (Description)
🔗 관련 이슈 (Related Issues)
✅ 체크리스트 (Checklist)
Style)Test)📸 스크린샷 (Screenshots)
💬 기타 사항 (Etc)