Skip to content

✨ Feat: 게시글 상세 조회 기능 구현#146

Open
limhb708 wants to merge 5 commits into
DoDo-Project:developfrom
limhb708:feature/145
Open

✨ Feat: 게시글 상세 조회 기능 구현#146
limhb708 wants to merge 5 commits into
DoDo-Project:developfrom
limhb708:feature/145

Conversation

@limhb708
Copy link
Copy Markdown
Collaborator

@limhb708 limhb708 commented Apr 17, 2026

📄 작업 내용 (Description)

이번 PR에서 변경되거나 추가된 주요 작업을 간단히 설명해주세요.

  • 게시글 ID 기반 상세 조회 API 구현
  • 게시글 조회 서비스 로직 구성 및 비즈니스 처리 추가
  • Entity → Response DTO 매핑 로직 구현
  • 조회 시 예외 처리 및 유효성 검증 로직 추가

🔗 관련 이슈 (Related Issues)

작업한 이슈 번호를 아래 형식으로 PULL REQUEST BODY에 작성해주세요.
(PR 머지 시 해당 이슈가 자동으로 종료됩니다.)


✅ 체크리스트 (Checklist)

PR을 보내기 전 아래 항목들을 모두 확인해주세요.

  • PR 제목은 커밋 컨벤션을 따랐습니다.
  • 관련 이슈를 연결했습니다.
  • 스스로 코드를 검토하고 불필요한 코드를 제거했습니다.
  • 코드 스타일이 프로젝트 규칙과 일치합니다. (Style)
  • 새로운 기능에 대한 테스트 코드를 추가했거나, 기존 테스트가 모두 통과했습니다. (Test)

📸 스크린샷 (Screenshots)

작업 내용과 관련된 스크린샷이 있다면 첨부해주세요. (UI 변경이 있는 경우)

Before After

💬 기타 사항 (Etc)

리뷰어에게 전달하고 싶은 추가 정보가 있다면 자유롭게 작성해주세요.

- 게시글 ID 기반 상세 조회 API 구현
- 게시글 조회 서비스 로직 구성 및 비즈니스 처리 추가
- Entity → Response DTO 매핑 로직 구현
- 조회 시 예외 처리 및 유효성 검증 로직 추가

Closes DoDo-Project#145
@limhb708 limhb708 self-assigned this Apr 17, 2026
@limhb708 limhb708 added ✨ Feature 새 기능 혹은 요구 사항 🦥 임현빈 임현빈 파트 labels Apr 17, 2026
@github-project-automation github-project-automation Bot moved this to 📝 할 일 in 칸반 보드 Apr 17, 2026
Copy link
Copy Markdown
Contributor

@WhiteBin-bin WhiteBin-bin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리뷰 남겼으니깐 그거 보고 수정해서 올려줘 그리고 cd도 돌아가는지 act로 확인하고 올려줘야해

value = "{\"status\": 500, \"message\": \"서버 내부 오류가 발생했습니다.\"}")))
})
@GetMapping("/{boardId}")
public ResponseEntity<BoardResponse.BoardDetailResponse> getBoardDetail(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

적용 잘해쓰

.boardId(board.getBoardId())
.boardTitle(board.getBoardTitle())
.boardContent(board.getBoardContent())
.imageFileUrl(null)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

게시글 상세 조회인데 imageFileUrl은 왜 null이야?? 그러면 이미지는 안오는거야?

*
* @param boardId 게시글 ID
* @return 게시글 상세 조회 응답 DTO
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static import 적용해줘

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

적용 확인해쓰

@Transactional(readOnly = true)
public BoardResponse.BoardDetailResponse getBoardDetail(Long boardId) {

Board board = getBoardById(boardId);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static import 이것도 적용해줘

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 확인해쓰

@github-project-automation github-project-automation Bot moved this from 📝 할 일 to 🏃 진행 중 in 칸반 보드 Apr 20, 2026
- 게시글 상세 조회 응답에 imageFileUrl 반영
- BoardService static import 적용
- BoardServiceImpl static import 적용

DoDo-Project#146 코드 리뷰 반영
.boardId(board.getBoardId())
.boardTitle(board.getBoardTitle())
.boardContent(board.getBoardContent())
.imageFileUrl(imageFileUrl)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정확인해쓰

Copy link
Copy Markdown
Contributor

@WhiteBin-bin WhiteBin-bin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번에 바꿔야할거 굉장히 많으니까 다 읽어보고 해줘

*
* @param boardId 게시글 ID
* @return 게시글 상세 조회 응답 DTO
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

적용 확인해쓰

@Transactional(readOnly = true)
public BoardResponse.BoardDetailResponse getBoardDetail(Long boardId) {

Board board = getBoardById(boardId);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 확인해쓰

* @param imageFileUrl 이미지 URL
* @return 수정된 row 수
*/
@Modifying(clearAutomatically = true, flushAutomatically = true)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

우리 CRUD에서 U랑 동적 쿼리는 MyBatis쓰기로 해서 JPQL로 하면 안됨 수정좀

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Modifying(clearAutomatically = true, flushAutomatically = true) 그리고 이런거 금지 왠만하면 저런거는 너무 하드해서 안쓰는게 맞음 함부로 건드렸다가 사용법 몰라서 터짐

* @param originalFilename 원본 파일명
* @return 저장된 row 수
*/
@Modifying(clearAutomatically = true, flushAutomatically = true)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 그냥 JpaRepository 기능 중 하나인 save() 메서드 써야지 그냥 이미지 파일 정보 저장하는건데

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Modifying(clearAutomatically = true, flushAutomatically = true) 얘도 이런거 금지

* @param boardId 게시글 ID
* @return 게시글 대표 이미지 URL
*/
@Query(value = """
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거는 조인도 안하는데 굳이 쿼리문 쓸 이유가 없어보임 Jpa Repository껄로 처리 가능함

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional<ImageFile> findFirstByBoardIdOrderByCreatedAtAsc(Long boardId); 이런식으로 가능함

@@ -127,4 +174,28 @@ private String detectMimeType(MultipartFile file) {
throw new UserException(INVALID_REQUEST);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 UserService로 이관해서 유저에서 에러 처리하는걸로 해줘 이거 UserException이라서

* @param boardId 게시글 ID
* @param imageFileUrl 이미지 URL
*/
private void saveBoardImage(Long boardId, String imageFileUrl) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 메서드의 존재 의의를 모르겠음 애초에 그냥 save 하는거 하면 되는데 update를 왜 하는건지 모르겠음

private UserService userService;

@Mock
private ImageFileService imageFileService; // ⭐ 추가
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

별 주석 지워줭 테스트에만 주석 다는거긴한데 // when // given // then 말고는 달지 말아줘

assertEquals(BoardStatus.PUBLISHED, board.getBoardStatus());
assertEquals(BoardType.FREE, board.getBoardType());
assertEquals(0, board.getViewCount());
// ⭐ 추가 검증
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

얘도 지워줘


given(boardRepository.findById(boardId)).willReturn(Optional.of(board));

// ⭐ 추가
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

얘도

- 게시글 이미지 저장 로직을 JPA saveAll() 방식으로 변경
- 이미지 URL optional 처리 (null/empty 허용)
- orElse(null) 제거 및 Optional 처리 방식 개선
- 불필요한 return 제거 및 예외 처리 보완

DoDo-Project#146 코드 리뷰 반영
Copy link
Copy Markdown
Contributor

@WhiteBin-bin WhiteBin-bin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리뷰 보고 고쳐주세요


Board board = getBoardById(boardId);

String imageFileUrl = imageFileRepository.findFirstByBoard_BoardIdOrderByImageFileCreatedAtAsc(boardId)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ImageFileService에서 저 메서드를 사용하는 함수를 만들어서 가져오는게 맞음 각 도메인 별 분리가 그럼 의미가 없어

/**
* 이미지 파일 저장 / 조회를 위한 Repository
*/
private final ImageFileRepository imageFileRepository;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거를 ImageFileService로 갖고와야지 왜냐면 도메인이 분리가 되야하니깐 그러고 그 service안에 그 레포지토리 불러서 가져오는 함수를 만들고


Board savedBoard = boardRepository.save(board);

saveBoardImages(savedBoard, request.getImageFileUrls());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분이 이해가 안됨 게시글 ID로 게시글 엔티티 조회라고 해놨는데 왜 갑자기 뜬금없이 save가 되는지 모르겠음.

*
* @param boardId 게시글 ID
*/
private void validateBoardId(Long boardId) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

만약에 외부 함수에서 게시글 ID를 검증하는게 필요하다면 이렇게 따로 빼서 하는게 맞고 아니면 지우는게 맞음

*/
private void saveBoardImages(Board board, List<String> imageFileUrls) {

if (board == null) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도 아까 위에부분을 만들었으면 굳이 따로 또 한번 더 만들 필요가 없음 이 부분 생각해서 만들어주면 좋을거 같음 바로 위 리뷰보고

* @param imageFileUrl 이미지 URL
* @return 추출된 파일명
*/
private String extractOriginalFilename(String imageFileUrl) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 잘했음


@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pet_id", nullable = false, unique = true)
@JoinColumn(name = "pet_id", unique = true)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

boardpetnullable해야지 null이 들어가도 되지 왜냐면 imageFilepet인지 board인지 둘중 하나만 저장해야되잖아 이거 수정해줘

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unique 넣으면 같은 키가 있는거는 들어오면 안되는거니깐 저거는 잘한듯


if (files == null || files.isEmpty()) {
throw new UserException(INVALID_REQUEST);
throw new UserException(UserErrorCode.INVALID_REQUEST);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 UserException이니깐 User에서 처리하던가 아니면 Image쪽도 커스텀 에러 정의해서 처리해줘 자꾸 도메인이 분리가 안되는데 도메인 분리는 철저하게 해줘야해

private String uploadSingleImage(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new UserException(INVALID_REQUEST);
throw new UserException(UserErrorCode.INVALID_REQUEST);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

얘도 똑같아

log.info("이미지가 포함된 게시글 작성 성공 테스트를 시작합니다.");

// given
// Given: 게시글 작성 요청 데이터와 인증 사용자 정보를 준비합니다.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

//given만 적어 뒤에 말 주저리 안적어도 됨 자바독으로 적잖아 우리가 주석을 안다는이유는 자바독으로 깔끔하게 만들어서 나중에 그 메서드에 마우스 커서만 올려놔도 보이게 만드는게 목적이야 주석은 // when, // given, // then 이것만 적는거야

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새 기능 혹은 요구 사항 🦥 임현빈 임현빈 파트

Projects

Status: 🏃 진행 중

Development

Successfully merging this pull request may close these issues.

[Feat] 게시글 상세 조회 기능 구현

2 participants