Week 6

아야하면우유·2025년 5월 12일

HSL

목록 보기
4/6

게시글 조회 비즈니스 로직


게시글 단건 조회 - Get

  • postId로 findById
  • RequestBody - null
  • Controller
@GetMapping("/{postId}")
    public ResponseEntity<SuccessResponse<?>> getPostById(
    @PathVariable Long postId) {
        // 서비스 계층에 위임
        PostDetailRes postDetailRes = postService.getById(postId);

        // 반환
        return ResponseEntity
                .status(HttpStatus.OK)
                .body(SuccessResponse.ok(postDetailRes));
    }

(1) URL이 /api/post/{postId}이므로, Mapping
(2) findById로 찾은 값을 PostDetailRes에 그대로 저장
(3) 그 값을 그대로 반환 (상태나 반환이 성공적으로 이루어짐)

  • DTO - PostDetailRes
// API 명세상, data를 전부 반환해야 할 때 사용할 Record
public record PostDetailRes(
        Long id,
        String title,
        String content,
        String username,
        String password,
        PostState state,
        LocalDateTime createdAt,
        LocalDateTime updatedAt
) {
}

 

  • Service 계층
 @Override
    public PostDetailRes getById(Long postId) {
        // 1. postId에 해당하는 Post - DB에서 조회
        Post post = postRepository.findById(postId)
                // 404 - postId에
                .orElseThrow(PostNotFoundException::new);

        // 2. PostDetailRes 반환
        return new PostDetailRes(
                post.getId(),
                post.getTitle(),
                post.getContent(),
                post.getUsername(),
                post.getPassword(),
                post.getState(),
                post.getCreatedAt(),
                post.getUpdatedAt()
        );
    }
  • Exception 처리를 위해 새로운 패키지와 Exception 클래스를 만듦

게시글 전체 조회 - Get

  • findAll로 전체를 조회한다.
  • stream 같은 반복문으로 전체 게시글을 List화
  • Controller
@GetMapping
    public ResponseEntity<SuccessResponse<?>> getAllPosts() {
        // 서비스 로직
        PostSummaryRes postSummaryRes = postService.getAll();

        // 반환
        return ResponseEntity
                .status(HttpStatus.OK)
                .body(SuccessResponse.ok(postSummaryRes));
    }

ResponseEntity - 클라이언트 요청에 의해 서브되는 데이터(= 응답 데이터)
SuccessResponse - API 명세서 형식을 따르는 상태코드 등의 정보 포함 (개발자가 직접 짜야 하는 것 같다.)

  • PostSummaryRes - Java에서 제공되는 stream을 통하여 List에 모든 게시글 저장할 수 있는 클래스
  • 그 값을 그대로 반환한다.

 

  • DTO - PostSummaryRes
// 배려해주셔서 for문으로 작성하셨다. stream 사용법 숙지 요망
public record PostSummaryRes(
        List<PostSummary> postSummaryList
) {
    public record PostSummary(
            Long id,
            String title,
            String username,
            LocalDateTime createdAt
            ) {
    }
}

 

  • Service
@Override
    public PostSummaryRes getAll() {
        // 1. DB 에서 모든 Post 조회 (postRepository)
        List<Post> posts = postRepository.findAll();

        // 2. posts -> PostSummaryRes 변환
        List<PostSummary> postSummaryList = new ArrayList<>();
        for(Post post : posts) {
            PostSummary postSummary = new PostSummary(
                    post.getId(),
                    post.getTitle(),
                    post.getUsername(),
                    post.getCreatedAt()
            );
            postSummaryList.add(postSummary);
        }

        // 3. 반환
        return new PostSummaryRes(postSummaryList);
    }

게시글 수정 - Put

  • 비밀번호가 일치해야 수정할 수 있다.
  • 제목과 내용만 수정한다.
  • Controller
@PutMapping("/{postId}")
    public ResponseEntity<SuccessResponse<?>> modifyPost(
            @PathVariable Long postId,
            @RequestBody ModifyPostReq modifyPostReq
    ) {
        // 서비스
        PostDetailRes postDetailRes = postService.modifyOne(postId, modifyPostReq);
        // 반환
        return ResponseEntity
                .status(HttpStatus.OK)
                .body(SuccessResponse.ok(postDetailRes));
    }
  • URL Mapping
  • RequestBody도 있음
  • 서비스 계층에 위임

 

  • DTO - ModifyPostReq
@Getter
@NoArgsConstructor
public class ModifyPostReq {
    private String title;
    private String content;
    private String password;
}

 

  • Service
@Transactional
    @Override
    public PostDetailRes modifyOne(Long postId, ModifyPostReq modifyPostReq) {
        // 1. DB 에서 postId로 Post 찾기
        Post foundPost = postRepository.findById(postId)
            // 404 - 게시글 없음
                .orElseThrow(PostNotFoundException::new);

        // 2. 비밀번호 검증
        // 403 - 비밀번호 불일치
        if(!foundPost.getPassword().equals(modifyPostReq.getPassword())) {
            throw new InvalidPasswordException();
        }

        // 3. post 수정
        foundPost.modify(modifyPostReq.getTitle(), modifyPostReq.getContent());
        // PostDetailRes 반환
        return new PostDetailRes(
                foundPost.getId(),
                foundPost.getTitle(),
                foundPost.getContent(),
                foundPost.getUsername(),
                foundPost.getPassword(),
                foundPost.getState(),
                foundPost.getCreatedAt(),
                foundPost.getUpdatedAt()
        );
    }
  • 수정 등 정보의 변경이 동시에 이루어지면 안되는 작업 - Transactional Annotation
  • Post에 modify 메소드 생성하고, 그 메소드로 수정 (일종의 Setter)

게시글 삭제 - Delete

  • findById에 의해 delete 되어야 함

 

  • Controller
@DeleteMapping("/{postId}")
    public ResponseEntity<SuccessResponse<?>> deletePost(
            @PathVariable Long postId,
            @RequestBody DeletePostReq deletePostReq) {
        // 서비스 로직
        postService.deleteOne(postId, deletePostReq);
        // 반환
        return ResponseEntity
                .status(HttpStatus.OK)
                .body(SuccessResponse.empty());
    }
  • URL Mapping
  • empty - Data(API)가 null, 즉 아무런 값도 없을 때 어떠한 데이터도 입력받지 않으므로 새로 정의함. Success.ok(null)과 똑같이 작용한다.

 

  • Service
@Transactional
@Override
public void deleteOne(Long postId, DeletePostReq deletePostReq) {
    // 1. 게시글 존재 확인
    Post post = postRepository.findById(postId)
        // 404 - 게시글 존재하지 않음
        .orElseThrow(PostNotFoundException::new);

	// 2. 비밀번호 검증
    if(!post.getPassword().equals(deletePostReq.getPassword())) {
            // 403 - 비밀번호 불일치
            throw new InvalidPasswordException();
        }

	// 3. 삭제
	postRepository.delete(post);
}
  • 여태 작성하지 않았지만, Repository가 JpaRepository를 상속받았을 경우, save, add, delete 같은 명령어를 쓸 수 있다.
profile
우유가 넘어지면 아야

1개의 댓글

comment-user-thumbnail
2025년 5월 15일

귯귯

답글 달기